diff options
Diffstat (limited to 'net/8021q/vlan.c')
-rw-r--r-- | net/8021q/vlan.c | 93 |
1 files changed, 24 insertions, 69 deletions
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index a2ad15250575..05b867e43757 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c | |||
@@ -44,9 +44,6 @@ | |||
44 | 44 | ||
45 | int vlan_net_id __read_mostly; | 45 | int vlan_net_id __read_mostly; |
46 | 46 | ||
47 | /* Our listing of VLAN group(s) */ | ||
48 | static struct hlist_head vlan_group_hash[VLAN_GRP_HASH_SIZE]; | ||
49 | |||
50 | const char vlan_fullname[] = "802.1Q VLAN Support"; | 47 | const char vlan_fullname[] = "802.1Q VLAN Support"; |
51 | const char vlan_version[] = DRV_VERSION; | 48 | const char vlan_version[] = DRV_VERSION; |
52 | static const char vlan_copyright[] = "Ben Greear <greearb@candelatech.com>"; | 49 | static const char vlan_copyright[] = "Ben Greear <greearb@candelatech.com>"; |
@@ -59,40 +56,6 @@ static struct packet_type vlan_packet_type __read_mostly = { | |||
59 | 56 | ||
60 | /* End of global variables definitions. */ | 57 | /* End of global variables definitions. */ |
61 | 58 | ||
62 | static inline unsigned int vlan_grp_hashfn(unsigned int idx) | ||
63 | { | ||
64 | return ((idx >> VLAN_GRP_HASH_SHIFT) ^ idx) & VLAN_GRP_HASH_MASK; | ||
65 | } | ||
66 | |||
67 | /* Must be invoked with RCU read lock (no preempt) */ | ||
68 | static struct vlan_group *__vlan_find_group(struct net_device *real_dev) | ||
69 | { | ||
70 | struct vlan_group *grp; | ||
71 | struct hlist_node *n; | ||
72 | int hash = vlan_grp_hashfn(real_dev->ifindex); | ||
73 | |||
74 | hlist_for_each_entry_rcu(grp, n, &vlan_group_hash[hash], hlist) { | ||
75 | if (grp->real_dev == real_dev) | ||
76 | return grp; | ||
77 | } | ||
78 | |||
79 | return NULL; | ||
80 | } | ||
81 | |||
82 | /* Find the protocol handler. Assumes VID < VLAN_VID_MASK. | ||
83 | * | ||
84 | * Must be invoked with RCU read lock (no preempt) | ||
85 | */ | ||
86 | struct net_device *__find_vlan_dev(struct net_device *real_dev, u16 vlan_id) | ||
87 | { | ||
88 | struct vlan_group *grp = __vlan_find_group(real_dev); | ||
89 | |||
90 | if (grp) | ||
91 | return vlan_group_get_device(grp, vlan_id); | ||
92 | |||
93 | return NULL; | ||
94 | } | ||
95 | |||
96 | static void vlan_group_free(struct vlan_group *grp) | 59 | static void vlan_group_free(struct vlan_group *grp) |
97 | { | 60 | { |
98 | int i; | 61 | int i; |
@@ -111,8 +74,6 @@ static struct vlan_group *vlan_group_alloc(struct net_device *real_dev) | |||
111 | return NULL; | 74 | return NULL; |
112 | 75 | ||
113 | grp->real_dev = real_dev; | 76 | grp->real_dev = real_dev; |
114 | hlist_add_head_rcu(&grp->hlist, | ||
115 | &vlan_group_hash[vlan_grp_hashfn(real_dev->ifindex)]); | ||
116 | return grp; | 77 | return grp; |
117 | } | 78 | } |
118 | 79 | ||
@@ -151,7 +112,7 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head) | |||
151 | 112 | ||
152 | ASSERT_RTNL(); | 113 | ASSERT_RTNL(); |
153 | 114 | ||
154 | grp = __vlan_find_group(real_dev); | 115 | grp = real_dev->vlgrp; |
155 | BUG_ON(!grp); | 116 | BUG_ON(!grp); |
156 | 117 | ||
157 | /* Take it out of our own structures, but be sure to interlock with | 118 | /* Take it out of our own structures, but be sure to interlock with |
@@ -173,11 +134,10 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head) | |||
173 | if (grp->nr_vlans == 0) { | 134 | if (grp->nr_vlans == 0) { |
174 | vlan_gvrp_uninit_applicant(real_dev); | 135 | vlan_gvrp_uninit_applicant(real_dev); |
175 | 136 | ||
176 | if (real_dev->features & NETIF_F_HW_VLAN_RX) | 137 | rcu_assign_pointer(real_dev->vlgrp, NULL); |
138 | if (ops->ndo_vlan_rx_register) | ||
177 | ops->ndo_vlan_rx_register(real_dev, NULL); | 139 | ops->ndo_vlan_rx_register(real_dev, NULL); |
178 | 140 | ||
179 | hlist_del_rcu(&grp->hlist); | ||
180 | |||
181 | /* Free the group, after all cpu's are done. */ | 141 | /* Free the group, after all cpu's are done. */ |
182 | call_rcu(&grp->rcu, vlan_rcu_free); | 142 | call_rcu(&grp->rcu, vlan_rcu_free); |
183 | } | 143 | } |
@@ -196,18 +156,13 @@ int vlan_check_real_dev(struct net_device *real_dev, u16 vlan_id) | |||
196 | return -EOPNOTSUPP; | 156 | return -EOPNOTSUPP; |
197 | } | 157 | } |
198 | 158 | ||
199 | if ((real_dev->features & NETIF_F_HW_VLAN_RX) && !ops->ndo_vlan_rx_register) { | ||
200 | pr_info("8021q: device %s has buggy VLAN hw accel\n", name); | ||
201 | return -EOPNOTSUPP; | ||
202 | } | ||
203 | |||
204 | if ((real_dev->features & NETIF_F_HW_VLAN_FILTER) && | 159 | if ((real_dev->features & NETIF_F_HW_VLAN_FILTER) && |
205 | (!ops->ndo_vlan_rx_add_vid || !ops->ndo_vlan_rx_kill_vid)) { | 160 | (!ops->ndo_vlan_rx_add_vid || !ops->ndo_vlan_rx_kill_vid)) { |
206 | pr_info("8021q: Device %s has buggy VLAN hw accel\n", name); | 161 | pr_info("8021q: Device %s has buggy VLAN hw accel\n", name); |
207 | return -EOPNOTSUPP; | 162 | return -EOPNOTSUPP; |
208 | } | 163 | } |
209 | 164 | ||
210 | if (__find_vlan_dev(real_dev, vlan_id) != NULL) | 165 | if (vlan_find_dev(real_dev, vlan_id) != NULL) |
211 | return -EEXIST; | 166 | return -EEXIST; |
212 | 167 | ||
213 | return 0; | 168 | return 0; |
@@ -222,7 +177,7 @@ int register_vlan_dev(struct net_device *dev) | |||
222 | struct vlan_group *grp, *ngrp = NULL; | 177 | struct vlan_group *grp, *ngrp = NULL; |
223 | int err; | 178 | int err; |
224 | 179 | ||
225 | grp = __vlan_find_group(real_dev); | 180 | grp = real_dev->vlgrp; |
226 | if (!grp) { | 181 | if (!grp) { |
227 | ngrp = grp = vlan_group_alloc(real_dev); | 182 | ngrp = grp = vlan_group_alloc(real_dev); |
228 | if (!grp) | 183 | if (!grp) |
@@ -252,8 +207,11 @@ int register_vlan_dev(struct net_device *dev) | |||
252 | vlan_group_set_device(grp, vlan_id, dev); | 207 | vlan_group_set_device(grp, vlan_id, dev); |
253 | grp->nr_vlans++; | 208 | grp->nr_vlans++; |
254 | 209 | ||
255 | if (ngrp && real_dev->features & NETIF_F_HW_VLAN_RX) | 210 | if (ngrp) { |
256 | ops->ndo_vlan_rx_register(real_dev, ngrp); | 211 | if (ops->ndo_vlan_rx_register) |
212 | ops->ndo_vlan_rx_register(real_dev, ngrp); | ||
213 | rcu_assign_pointer(real_dev->vlgrp, ngrp); | ||
214 | } | ||
257 | if (real_dev->features & NETIF_F_HW_VLAN_FILTER) | 215 | if (real_dev->features & NETIF_F_HW_VLAN_FILTER) |
258 | ops->ndo_vlan_rx_add_vid(real_dev, vlan_id); | 216 | ops->ndo_vlan_rx_add_vid(real_dev, vlan_id); |
259 | 217 | ||
@@ -264,7 +222,6 @@ out_uninit_applicant: | |||
264 | vlan_gvrp_uninit_applicant(real_dev); | 222 | vlan_gvrp_uninit_applicant(real_dev); |
265 | out_free_group: | 223 | out_free_group: |
266 | if (ngrp) { | 224 | if (ngrp) { |
267 | hlist_del_rcu(&ngrp->hlist); | ||
268 | /* Free the group, after all cpu's are done. */ | 225 | /* Free the group, after all cpu's are done. */ |
269 | call_rcu(&ngrp->rcu, vlan_rcu_free); | 226 | call_rcu(&ngrp->rcu, vlan_rcu_free); |
270 | } | 227 | } |
@@ -321,7 +278,7 @@ static int register_vlan_device(struct net_device *real_dev, u16 vlan_id) | |||
321 | if (new_dev == NULL) | 278 | if (new_dev == NULL) |
322 | return -ENOBUFS; | 279 | return -ENOBUFS; |
323 | 280 | ||
324 | new_dev->real_num_tx_queues = real_dev->real_num_tx_queues; | 281 | netif_copy_real_num_queues(new_dev, real_dev); |
325 | dev_net_set(new_dev, net); | 282 | dev_net_set(new_dev, net); |
326 | /* need 4 bytes for extra VLAN header info, | 283 | /* need 4 bytes for extra VLAN header info, |
327 | * hope the underlying device can handle it. | 284 | * hope the underlying device can handle it. |
@@ -428,7 +385,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
428 | dev->netdev_ops->ndo_vlan_rx_add_vid(dev, 0); | 385 | dev->netdev_ops->ndo_vlan_rx_add_vid(dev, 0); |
429 | } | 386 | } |
430 | 387 | ||
431 | grp = __vlan_find_group(dev); | 388 | grp = dev->vlgrp; |
432 | if (!grp) | 389 | if (!grp) |
433 | goto out; | 390 | goto out; |
434 | 391 | ||
@@ -439,7 +396,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
439 | switch (event) { | 396 | switch (event) { |
440 | case NETDEV_CHANGE: | 397 | case NETDEV_CHANGE: |
441 | /* Propagate real device state to vlan devices */ | 398 | /* Propagate real device state to vlan devices */ |
442 | for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { | 399 | for (i = 0; i < VLAN_N_VID; i++) { |
443 | vlandev = vlan_group_get_device(grp, i); | 400 | vlandev = vlan_group_get_device(grp, i); |
444 | if (!vlandev) | 401 | if (!vlandev) |
445 | continue; | 402 | continue; |
@@ -450,7 +407,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
450 | 407 | ||
451 | case NETDEV_CHANGEADDR: | 408 | case NETDEV_CHANGEADDR: |
452 | /* Adjust unicast filters on underlying device */ | 409 | /* Adjust unicast filters on underlying device */ |
453 | for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { | 410 | for (i = 0; i < VLAN_N_VID; i++) { |
454 | vlandev = vlan_group_get_device(grp, i); | 411 | vlandev = vlan_group_get_device(grp, i); |
455 | if (!vlandev) | 412 | if (!vlandev) |
456 | continue; | 413 | continue; |
@@ -464,7 +421,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
464 | break; | 421 | break; |
465 | 422 | ||
466 | case NETDEV_CHANGEMTU: | 423 | case NETDEV_CHANGEMTU: |
467 | for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { | 424 | for (i = 0; i < VLAN_N_VID; i++) { |
468 | vlandev = vlan_group_get_device(grp, i); | 425 | vlandev = vlan_group_get_device(grp, i); |
469 | if (!vlandev) | 426 | if (!vlandev) |
470 | continue; | 427 | continue; |
@@ -478,7 +435,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
478 | 435 | ||
479 | case NETDEV_FEAT_CHANGE: | 436 | case NETDEV_FEAT_CHANGE: |
480 | /* Propagate device features to underlying device */ | 437 | /* Propagate device features to underlying device */ |
481 | for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { | 438 | for (i = 0; i < VLAN_N_VID; i++) { |
482 | vlandev = vlan_group_get_device(grp, i); | 439 | vlandev = vlan_group_get_device(grp, i); |
483 | if (!vlandev) | 440 | if (!vlandev) |
484 | continue; | 441 | continue; |
@@ -490,7 +447,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
490 | 447 | ||
491 | case NETDEV_DOWN: | 448 | case NETDEV_DOWN: |
492 | /* Put all VLANs for this dev in the down state too. */ | 449 | /* Put all VLANs for this dev in the down state too. */ |
493 | for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { | 450 | for (i = 0; i < VLAN_N_VID; i++) { |
494 | vlandev = vlan_group_get_device(grp, i); | 451 | vlandev = vlan_group_get_device(grp, i); |
495 | if (!vlandev) | 452 | if (!vlandev) |
496 | continue; | 453 | continue; |
@@ -508,7 +465,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
508 | 465 | ||
509 | case NETDEV_UP: | 466 | case NETDEV_UP: |
510 | /* Put all VLANs for this dev in the up state too. */ | 467 | /* Put all VLANs for this dev in the up state too. */ |
511 | for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { | 468 | for (i = 0; i < VLAN_N_VID; i++) { |
512 | vlandev = vlan_group_get_device(grp, i); | 469 | vlandev = vlan_group_get_device(grp, i); |
513 | if (!vlandev) | 470 | if (!vlandev) |
514 | continue; | 471 | continue; |
@@ -525,10 +482,14 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
525 | break; | 482 | break; |
526 | 483 | ||
527 | case NETDEV_UNREGISTER: | 484 | case NETDEV_UNREGISTER: |
485 | /* twiddle thumbs on netns device moves */ | ||
486 | if (dev->reg_state != NETREG_UNREGISTERING) | ||
487 | break; | ||
488 | |||
528 | /* Delete all VLANs for this dev. */ | 489 | /* Delete all VLANs for this dev. */ |
529 | grp->killall = 1; | 490 | grp->killall = 1; |
530 | 491 | ||
531 | for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { | 492 | for (i = 0; i < VLAN_N_VID; i++) { |
532 | vlandev = vlan_group_get_device(grp, i); | 493 | vlandev = vlan_group_get_device(grp, i); |
533 | if (!vlandev) | 494 | if (!vlandev) |
534 | continue; | 495 | continue; |
@@ -536,7 +497,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
536 | /* unregistration of last vlan destroys group, abort | 497 | /* unregistration of last vlan destroys group, abort |
537 | * afterwards */ | 498 | * afterwards */ |
538 | if (grp->nr_vlans == 1) | 499 | if (grp->nr_vlans == 1) |
539 | i = VLAN_GROUP_ARRAY_LEN; | 500 | i = VLAN_N_VID; |
540 | 501 | ||
541 | unregister_vlan_dev(vlandev, &list); | 502 | unregister_vlan_dev(vlandev, &list); |
542 | } | 503 | } |
@@ -742,8 +703,6 @@ err0: | |||
742 | 703 | ||
743 | static void __exit vlan_cleanup_module(void) | 704 | static void __exit vlan_cleanup_module(void) |
744 | { | 705 | { |
745 | unsigned int i; | ||
746 | |||
747 | vlan_ioctl_set(NULL); | 706 | vlan_ioctl_set(NULL); |
748 | vlan_netlink_fini(); | 707 | vlan_netlink_fini(); |
749 | 708 | ||
@@ -751,10 +710,6 @@ static void __exit vlan_cleanup_module(void) | |||
751 | 710 | ||
752 | dev_remove_pack(&vlan_packet_type); | 711 | dev_remove_pack(&vlan_packet_type); |
753 | 712 | ||
754 | /* This table must be empty if there are no module references left. */ | ||
755 | for (i = 0; i < VLAN_GRP_HASH_SIZE; i++) | ||
756 | BUG_ON(!hlist_empty(&vlan_group_hash[i])); | ||
757 | |||
758 | unregister_pernet_subsys(&vlan_net_ops); | 713 | unregister_pernet_subsys(&vlan_net_ops); |
759 | rcu_barrier(); /* Wait for completion of call_rcu()'s */ | 714 | rcu_barrier(); /* Wait for completion of call_rcu()'s */ |
760 | 715 | ||