aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJay Vosburgh <fubar@us.ibm.com>2010-07-21 08:14:47 -0400
committerDavid S. Miller <davem@davemloft.net>2010-07-22 17:14:46 -0400
commitf35188faa0fbabefac476536994f4b6f3677380f (patch)
tree460c54e3d8505fd0ce42d16a1798c1f8c371d4a9
parent4bee1f9ac066ef0350b961eab9fedc4d0bd0a549 (diff)
bonding: change test for presence of VLANs
After commit ad1afb00393915a51c21b1ae8704562bf036855f ("vlan_dev: VLAN 0 should be treated as "no vlan tag" (802.1p packet)") it is now regular practice for a VLAN "add vid" for VLAN 0 to arrive prior to any VLAN registration or creation of a vlan_group. This patch updates the bonding code that tests for the presence of VLANs configured above bonding. The new logic tests for bond->vlgrp to determine if a registration has occured, instead of testing that bonding's internal vlan_list is empty. The old code would panic when vlan_list was not empty, but vlgrp was still NULL (because only an "add vid" for VLAN 0 had occured). Bonding still adds VLAN 0 to its internal list so that 802.1p frames are handled correctly on transmit when non-VLAN accelerated slaves are members of the bond. The test against bond->vlan_list remains in bond_dev_queue_xmit for this reason. Modification to the bond->vlgrp now occurs under lock (in addition to RTNL), because not all inspections of it occur under RTNL. Additionally, because 8021q will never issue a "kill vid" for VLAN 0, there is now logic in bond_uninit to release any remaining entries from vlan_list. Signed-off-by: Jay Vosburgh <fubar@us.ibm.com> Cc: Pedro Garcia <pedro.netdev@dondevamos.com> Cc: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/bonding/bond_alb.c4
-rw-r--r--drivers/net/bonding/bond_main.c30
2 files changed, 25 insertions, 9 deletions
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 3662d6e446a9..e3b35d0b4284 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -682,7 +682,7 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon
682 client_info->ntt = 0; 682 client_info->ntt = 0;
683 } 683 }
684 684
685 if (!list_empty(&bond->vlan_list)) { 685 if (bond->vlgrp) {
686 if (!vlan_get_tag(skb, &client_info->vlan_id)) 686 if (!vlan_get_tag(skb, &client_info->vlan_id))
687 client_info->tag = 1; 687 client_info->tag = 1;
688 } 688 }
@@ -904,7 +904,7 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[])
904 skb->priority = TC_PRIO_CONTROL; 904 skb->priority = TC_PRIO_CONTROL;
905 skb->dev = slave->dev; 905 skb->dev = slave->dev;
906 906
907 if (!list_empty(&bond->vlan_list)) { 907 if (bond->vlgrp) {
908 struct vlan_entry *vlan; 908 struct vlan_entry *vlan;
909 909
910 vlan = bond_next_vlan(bond, 910 vlan = bond_next_vlan(bond,
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 20f45cbf961a..f3b01ce4f629 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -424,6 +424,7 @@ int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb,
424{ 424{
425 unsigned short uninitialized_var(vlan_id); 425 unsigned short uninitialized_var(vlan_id);
426 426
427 /* Test vlan_list not vlgrp to catch and handle 802.1p tags */
427 if (!list_empty(&bond->vlan_list) && 428 if (!list_empty(&bond->vlan_list) &&
428 !(slave_dev->features & NETIF_F_HW_VLAN_TX) && 429 !(slave_dev->features & NETIF_F_HW_VLAN_TX) &&
429 vlan_get_tag(skb, &vlan_id) == 0) { 430 vlan_get_tag(skb, &vlan_id) == 0) {
@@ -487,7 +488,9 @@ static void bond_vlan_rx_register(struct net_device *bond_dev,
487 struct slave *slave; 488 struct slave *slave;
488 int i; 489 int i;
489 490
491 write_lock(&bond->lock);
490 bond->vlgrp = grp; 492 bond->vlgrp = grp;
493 write_unlock(&bond->lock);
491 494
492 bond_for_each_slave(bond, slave, i) { 495 bond_for_each_slave(bond, slave, i) {
493 struct net_device *slave_dev = slave->dev; 496 struct net_device *slave_dev = slave->dev;
@@ -569,7 +572,7 @@ static void bond_add_vlans_on_slave(struct bonding *bond, struct net_device *sla
569 572
570 write_lock_bh(&bond->lock); 573 write_lock_bh(&bond->lock);
571 574
572 if (list_empty(&bond->vlan_list)) 575 if (!bond->vlgrp)
573 goto out; 576 goto out;
574 577
575 if ((slave_dev->features & NETIF_F_HW_VLAN_RX) && 578 if ((slave_dev->features & NETIF_F_HW_VLAN_RX) &&
@@ -596,7 +599,7 @@ static void bond_del_vlans_from_slave(struct bonding *bond,
596 599
597 write_lock_bh(&bond->lock); 600 write_lock_bh(&bond->lock);
598 601
599 if (list_empty(&bond->vlan_list)) 602 if (!bond->vlgrp)
600 goto out; 603 goto out;
601 604
602 if (!(slave_dev->features & NETIF_F_HW_VLAN_FILTER) || 605 if (!(slave_dev->features & NETIF_F_HW_VLAN_FILTER) ||
@@ -604,6 +607,8 @@ static void bond_del_vlans_from_slave(struct bonding *bond,
604 goto unreg; 607 goto unreg;
605 608
606 list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { 609 list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
610 if (!vlan->vlan_id)
611 continue;
607 /* Save and then restore vlan_dev in the grp array, 612 /* Save and then restore vlan_dev in the grp array,
608 * since the slave's driver might clear it. 613 * since the slave's driver might clear it.
609 */ 614 */
@@ -1443,7 +1448,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
1443 /* no need to lock since we're protected by rtnl_lock */ 1448 /* no need to lock since we're protected by rtnl_lock */
1444 if (slave_dev->features & NETIF_F_VLAN_CHALLENGED) { 1449 if (slave_dev->features & NETIF_F_VLAN_CHALLENGED) {
1445 pr_debug("%s: NETIF_F_VLAN_CHALLENGED\n", slave_dev->name); 1450 pr_debug("%s: NETIF_F_VLAN_CHALLENGED\n", slave_dev->name);
1446 if (!list_empty(&bond->vlan_list)) { 1451 if (bond->vlgrp) {
1447 pr_err("%s: Error: cannot enslave VLAN challenged slave %s on VLAN enabled bond %s\n", 1452 pr_err("%s: Error: cannot enslave VLAN challenged slave %s on VLAN enabled bond %s\n",
1448 bond_dev->name, slave_dev->name, bond_dev->name); 1453 bond_dev->name, slave_dev->name, bond_dev->name);
1449 return -EPERM; 1454 return -EPERM;
@@ -1942,7 +1947,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
1942 */ 1947 */
1943 memset(bond_dev->dev_addr, 0, bond_dev->addr_len); 1948 memset(bond_dev->dev_addr, 0, bond_dev->addr_len);
1944 1949
1945 if (list_empty(&bond->vlan_list)) { 1950 if (!bond->vlgrp) {
1946 bond_dev->features |= NETIF_F_VLAN_CHALLENGED; 1951 bond_dev->features |= NETIF_F_VLAN_CHALLENGED;
1947 } else { 1952 } else {
1948 pr_warning("%s: Warning: clearing HW address of %s while it still has VLANs.\n", 1953 pr_warning("%s: Warning: clearing HW address of %s while it still has VLANs.\n",
@@ -2134,9 +2139,9 @@ static int bond_release_all(struct net_device *bond_dev)
2134 */ 2139 */
2135 memset(bond_dev->dev_addr, 0, bond_dev->addr_len); 2140 memset(bond_dev->dev_addr, 0, bond_dev->addr_len);
2136 2141
2137 if (list_empty(&bond->vlan_list)) 2142 if (!bond->vlgrp) {
2138 bond_dev->features |= NETIF_F_VLAN_CHALLENGED; 2143 bond_dev->features |= NETIF_F_VLAN_CHALLENGED;
2139 else { 2144 } else {
2140 pr_warning("%s: Warning: clearing HW address of %s while it still has VLANs.\n", 2145 pr_warning("%s: Warning: clearing HW address of %s while it still has VLANs.\n",
2141 bond_dev->name, bond_dev->name); 2146 bond_dev->name, bond_dev->name);
2142 pr_warning("%s: When re-adding slaves, make sure the bond's HW address matches its VLANs'.\n", 2147 pr_warning("%s: When re-adding slaves, make sure the bond's HW address matches its VLANs'.\n",
@@ -2569,7 +2574,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
2569 if (!targets[i]) 2574 if (!targets[i])
2570 break; 2575 break;
2571 pr_debug("basa: target %x\n", targets[i]); 2576 pr_debug("basa: target %x\n", targets[i]);
2572 if (list_empty(&bond->vlan_list)) { 2577 if (!bond->vlgrp) {
2573 pr_debug("basa: empty vlan: arp_send\n"); 2578 pr_debug("basa: empty vlan: arp_send\n");
2574 bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i], 2579 bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i],
2575 bond->master_ip, 0); 2580 bond->master_ip, 0);
@@ -2658,6 +2663,9 @@ static void bond_send_gratuitous_arp(struct bonding *bond)
2658 bond->master_ip, 0); 2663 bond->master_ip, 0);
2659 } 2664 }
2660 2665
2666 if (!bond->vlgrp)
2667 return;
2668
2661 list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { 2669 list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
2662 vlan_dev = vlan_group_get_device(bond->vlgrp, vlan->vlan_id); 2670 vlan_dev = vlan_group_get_device(bond->vlgrp, vlan->vlan_id);
2663 if (vlan->vlan_ip) { 2671 if (vlan->vlan_ip) {
@@ -3590,6 +3598,8 @@ static int bond_inetaddr_event(struct notifier_block *this, unsigned long event,
3590 } 3598 }
3591 3599
3592 list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { 3600 list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
3601 if (!bond->vlgrp)
3602 continue;
3593 vlan_dev = vlan_group_get_device(bond->vlgrp, vlan->vlan_id); 3603 vlan_dev = vlan_group_get_device(bond->vlgrp, vlan->vlan_id);
3594 if (vlan_dev == event_dev) { 3604 if (vlan_dev == event_dev) {
3595 switch (event) { 3605 switch (event) {
@@ -4686,6 +4696,7 @@ static void bond_work_cancel_all(struct bonding *bond)
4686static void bond_uninit(struct net_device *bond_dev) 4696static void bond_uninit(struct net_device *bond_dev)
4687{ 4697{
4688 struct bonding *bond = netdev_priv(bond_dev); 4698 struct bonding *bond = netdev_priv(bond_dev);
4699 struct vlan_entry *vlan, *tmp;
4689 4700
4690 bond_netpoll_cleanup(bond_dev); 4701 bond_netpoll_cleanup(bond_dev);
4691 4702
@@ -4699,6 +4710,11 @@ static void bond_uninit(struct net_device *bond_dev)
4699 bond_remove_proc_entry(bond); 4710 bond_remove_proc_entry(bond);
4700 4711
4701 __hw_addr_flush(&bond->mc_list); 4712 __hw_addr_flush(&bond->mc_list);
4713
4714 list_for_each_entry_safe(vlan, tmp, &bond->vlan_list, vlan_list) {
4715 list_del(&vlan->vlan_list);
4716 kfree(vlan);
4717 }
4702} 4718}
4703 4719
4704/*------------------------- Module initialization ---------------------------*/ 4720/*------------------------- Module initialization ---------------------------*/