diff options
author | Jay Vosburgh <fubar@us.ibm.com> | 2010-07-21 08:14:47 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-07-22 17:14:46 -0400 |
commit | f35188faa0fbabefac476536994f4b6f3677380f (patch) | |
tree | 460c54e3d8505fd0ce42d16a1798c1f8c371d4a9 | |
parent | 4bee1f9ac066ef0350b961eab9fedc4d0bd0a549 (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.c | 4 | ||||
-rw-r--r-- | drivers/net/bonding/bond_main.c | 30 |
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) | |||
4686 | static void bond_uninit(struct net_device *bond_dev) | 4696 | static 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 ---------------------------*/ |