Commit 87002b03baabd2b8f6281ab6411ed88d24958de1
Committed by
David S. Miller
1 parent
8e586137e6
Exists in
master
and in
6 other branches
net: introduce vlan_vid_[add/del] and use them instead of direct [add/kill]_vid ndo calls
This patch adds wrapper for ndo_vlan_rx_add_vid/ndo_vlan_rx_kill_vid functions. Check for NETIF_F_HW_VLAN_FILTER feature is done in this wrapper. Signed-off-by: Jiri Pirko <jpirko@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Showing 6 changed files with 87 additions and 59 deletions Side-by-side Diff
drivers/net/bonding/bond_main.c
... | ... | @@ -431,17 +431,13 @@ |
431 | 431 | static int bond_vlan_rx_add_vid(struct net_device *bond_dev, uint16_t vid) |
432 | 432 | { |
433 | 433 | struct bonding *bond = netdev_priv(bond_dev); |
434 | - struct slave *slave; | |
434 | + struct slave *slave, *stop_at; | |
435 | 435 | int i, res; |
436 | 436 | |
437 | 437 | bond_for_each_slave(bond, slave, i) { |
438 | - struct net_device *slave_dev = slave->dev; | |
439 | - const struct net_device_ops *slave_ops = slave_dev->netdev_ops; | |
440 | - | |
441 | - if ((slave_dev->features & NETIF_F_HW_VLAN_FILTER) && | |
442 | - slave_ops->ndo_vlan_rx_add_vid) { | |
443 | - slave_ops->ndo_vlan_rx_add_vid(slave_dev, vid); | |
444 | - } | |
438 | + res = vlan_vid_add(slave->dev, vid); | |
439 | + if (res) | |
440 | + goto unwind; | |
445 | 441 | } |
446 | 442 | |
447 | 443 | res = bond_add_vlan(bond, vid); |
... | ... | @@ -452,6 +448,14 @@ |
452 | 448 | } |
453 | 449 | |
454 | 450 | return 0; |
451 | + | |
452 | +unwind: | |
453 | + /* unwind from head to the slave that failed */ | |
454 | + stop_at = slave; | |
455 | + bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at) | |
456 | + vlan_vid_del(slave->dev, vid); | |
457 | + | |
458 | + return res; | |
455 | 459 | } |
456 | 460 | |
457 | 461 | /** |
458 | 462 | |
... | ... | @@ -465,16 +469,9 @@ |
465 | 469 | struct slave *slave; |
466 | 470 | int i, res; |
467 | 471 | |
468 | - bond_for_each_slave(bond, slave, i) { | |
469 | - struct net_device *slave_dev = slave->dev; | |
470 | - const struct net_device_ops *slave_ops = slave_dev->netdev_ops; | |
472 | + bond_for_each_slave(bond, slave, i) | |
473 | + vlan_vid_del(slave->dev, vid); | |
471 | 474 | |
472 | - if ((slave_dev->features & NETIF_F_HW_VLAN_FILTER) && | |
473 | - slave_ops->ndo_vlan_rx_kill_vid) { | |
474 | - slave_ops->ndo_vlan_rx_kill_vid(slave_dev, vid); | |
475 | - } | |
476 | - } | |
477 | - | |
478 | 475 | res = bond_del_vlan(bond, vid); |
479 | 476 | if (res) { |
480 | 477 | pr_err("%s: Error: Failed to remove vlan id %d\n", |
481 | 478 | |
482 | 479 | |
483 | 480 | |
484 | 481 | |
... | ... | @@ -488,30 +485,26 @@ |
488 | 485 | static void bond_add_vlans_on_slave(struct bonding *bond, struct net_device *slave_dev) |
489 | 486 | { |
490 | 487 | struct vlan_entry *vlan; |
491 | - const struct net_device_ops *slave_ops = slave_dev->netdev_ops; | |
488 | + int res; | |
492 | 489 | |
493 | - if (!(slave_dev->features & NETIF_F_HW_VLAN_FILTER) || | |
494 | - !(slave_ops->ndo_vlan_rx_add_vid)) | |
495 | - return; | |
496 | - | |
497 | - list_for_each_entry(vlan, &bond->vlan_list, vlan_list) | |
498 | - slave_ops->ndo_vlan_rx_add_vid(slave_dev, vlan->vlan_id); | |
490 | + list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { | |
491 | + res = vlan_vid_add(slave_dev, vlan->vlan_id); | |
492 | + if (res) | |
493 | + pr_warning("%s: Failed to add vlan id %d to device %s\n", | |
494 | + bond->dev->name, vlan->vlan_id, | |
495 | + slave_dev->name); | |
496 | + } | |
499 | 497 | } |
500 | 498 | |
501 | 499 | static void bond_del_vlans_from_slave(struct bonding *bond, |
502 | 500 | struct net_device *slave_dev) |
503 | 501 | { |
504 | - const struct net_device_ops *slave_ops = slave_dev->netdev_ops; | |
505 | 502 | struct vlan_entry *vlan; |
506 | 503 | |
507 | - if (!(slave_dev->features & NETIF_F_HW_VLAN_FILTER) || | |
508 | - !(slave_ops->ndo_vlan_rx_kill_vid)) | |
509 | - return; | |
510 | - | |
511 | 504 | list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { |
512 | 505 | if (!vlan->vlan_id) |
513 | 506 | continue; |
514 | - slave_ops->ndo_vlan_rx_kill_vid(slave_dev, vlan->vlan_id); | |
507 | + vlan_vid_del(slave_dev, vlan->vlan_id); | |
515 | 508 | } |
516 | 509 | } |
517 | 510 |
drivers/net/macvlan.c
... | ... | @@ -26,6 +26,7 @@ |
26 | 26 | #include <linux/etherdevice.h> |
27 | 27 | #include <linux/ethtool.h> |
28 | 28 | #include <linux/if_arp.h> |
29 | +#include <linux/if_vlan.h> | |
29 | 30 | #include <linux/if_link.h> |
30 | 31 | #include <linux/if_macvlan.h> |
31 | 32 | #include <net/rtnetlink.h> |
32 | 33 | |
... | ... | @@ -525,11 +526,8 @@ |
525 | 526 | { |
526 | 527 | struct macvlan_dev *vlan = netdev_priv(dev); |
527 | 528 | struct net_device *lowerdev = vlan->lowerdev; |
528 | - const struct net_device_ops *ops = lowerdev->netdev_ops; | |
529 | 529 | |
530 | - if (ops->ndo_vlan_rx_add_vid) | |
531 | - return ops->ndo_vlan_rx_add_vid(lowerdev, vid); | |
532 | - return 0; | |
530 | + return vlan_vid_add(lowerdev, vid); | |
533 | 531 | } |
534 | 532 | |
535 | 533 | static int macvlan_vlan_rx_kill_vid(struct net_device *dev, |
536 | 534 | |
... | ... | @@ -537,10 +535,8 @@ |
537 | 535 | { |
538 | 536 | struct macvlan_dev *vlan = netdev_priv(dev); |
539 | 537 | struct net_device *lowerdev = vlan->lowerdev; |
540 | - const struct net_device_ops *ops = lowerdev->netdev_ops; | |
541 | 538 | |
542 | - if (ops->ndo_vlan_rx_kill_vid) | |
543 | - return ops->ndo_vlan_rx_kill_vid(lowerdev, vid); | |
539 | + vlan_vid_del(lowerdev, vid); | |
544 | 540 | return 0; |
545 | 541 | } |
546 | 542 |
drivers/net/team/team.c
... | ... | @@ -18,6 +18,7 @@ |
18 | 18 | #include <linux/ctype.h> |
19 | 19 | #include <linux/notifier.h> |
20 | 20 | #include <linux/netdevice.h> |
21 | +#include <linux/if_vlan.h> | |
21 | 22 | #include <linux/if_arp.h> |
22 | 23 | #include <linux/socket.h> |
23 | 24 | #include <linux/etherdevice.h> |
24 | 25 | |
25 | 26 | |
26 | 27 | |
... | ... | @@ -906,17 +907,28 @@ |
906 | 907 | { |
907 | 908 | struct team *team = netdev_priv(dev); |
908 | 909 | struct team_port *port; |
910 | + int err; | |
909 | 911 | |
910 | - rcu_read_lock(); | |
911 | - list_for_each_entry_rcu(port, &team->port_list, list) { | |
912 | - const struct net_device_ops *ops = port->dev->netdev_ops; | |
913 | - | |
914 | - if (ops->ndo_vlan_rx_add_vid) | |
915 | - ops->ndo_vlan_rx_add_vid(port->dev, vid); | |
912 | + /* | |
913 | + * Alhough this is reader, it's guarded by team lock. It's not possible | |
914 | + * to traverse list in reverse under rcu_read_lock | |
915 | + */ | |
916 | + mutex_lock(&team->lock); | |
917 | + list_for_each_entry(port, &team->port_list, list) { | |
918 | + err = vlan_vid_add(port->dev, vid); | |
919 | + if (err) | |
920 | + goto unwind; | |
916 | 921 | } |
917 | - rcu_read_unlock(); | |
922 | + mutex_unlock(&team->lock); | |
918 | 923 | |
919 | 924 | return 0; |
925 | + | |
926 | +unwind: | |
927 | + list_for_each_entry_continue_reverse(port, &team->port_list, list) | |
928 | + vlan_vid_del(port->dev, vid); | |
929 | + mutex_unlock(&team->lock); | |
930 | + | |
931 | + return err; | |
920 | 932 | } |
921 | 933 | |
922 | 934 | static int team_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid) |
... | ... | @@ -925,12 +937,8 @@ |
925 | 937 | struct team_port *port; |
926 | 938 | |
927 | 939 | rcu_read_lock(); |
928 | - list_for_each_entry_rcu(port, &team->port_list, list) { | |
929 | - const struct net_device_ops *ops = port->dev->netdev_ops; | |
930 | - | |
931 | - if (ops->ndo_vlan_rx_kill_vid) | |
932 | - ops->ndo_vlan_rx_kill_vid(port->dev, vid); | |
933 | - } | |
940 | + list_for_each_entry_rcu(port, &team->port_list, list) | |
941 | + vlan_vid_del(port->dev, vid); | |
934 | 942 | rcu_read_unlock(); |
935 | 943 | |
936 | 944 | return 0; |
include/linux/if_vlan.h
... | ... | @@ -109,6 +109,9 @@ |
109 | 109 | extern bool vlan_do_receive(struct sk_buff **skb, bool last_handler); |
110 | 110 | extern struct sk_buff *vlan_untag(struct sk_buff *skb); |
111 | 111 | |
112 | +extern int vlan_vid_add(struct net_device *dev, unsigned short vid); | |
113 | +extern void vlan_vid_del(struct net_device *dev, unsigned short vid); | |
114 | + | |
112 | 115 | #else |
113 | 116 | static inline struct net_device * |
114 | 117 | __vlan_find_dev_deep(struct net_device *real_dev, u16 vlan_id) |
... | ... | @@ -138,6 +141,15 @@ |
138 | 141 | static inline struct sk_buff *vlan_untag(struct sk_buff *skb) |
139 | 142 | { |
140 | 143 | return skb; |
144 | +} | |
145 | + | |
146 | +static inline int vlan_vid_add(struct net_device *dev, unsigned short vid) | |
147 | +{ | |
148 | + return 0; | |
149 | +} | |
150 | + | |
151 | +static inline void vlan_vid_del(struct net_device *dev, unsigned short vid) | |
152 | +{ | |
141 | 153 | } |
142 | 154 | #endif |
143 | 155 |
net/8021q/vlan.c
... | ... | @@ -101,7 +101,6 @@ |
101 | 101 | { |
102 | 102 | struct vlan_dev_priv *vlan = vlan_dev_priv(dev); |
103 | 103 | struct net_device *real_dev = vlan->real_dev; |
104 | - const struct net_device_ops *ops = real_dev->netdev_ops; | |
105 | 104 | struct vlan_group *grp; |
106 | 105 | u16 vlan_id = vlan->vlan_id; |
107 | 106 | |
... | ... | @@ -114,8 +113,8 @@ |
114 | 113 | * HW accelerating devices or SW vlan input packet processing if |
115 | 114 | * VLAN is not 0 (leave it there for 802.1p). |
116 | 115 | */ |
117 | - if (vlan_id && (real_dev->features & NETIF_F_HW_VLAN_FILTER)) | |
118 | - ops->ndo_vlan_rx_kill_vid(real_dev, vlan_id); | |
116 | + if (vlan_id) | |
117 | + vlan_vid_del(real_dev, vlan_id); | |
119 | 118 | |
120 | 119 | grp->nr_vlans--; |
121 | 120 | |
... | ... | @@ -169,7 +168,6 @@ |
169 | 168 | { |
170 | 169 | struct vlan_dev_priv *vlan = vlan_dev_priv(dev); |
171 | 170 | struct net_device *real_dev = vlan->real_dev; |
172 | - const struct net_device_ops *ops = real_dev->netdev_ops; | |
173 | 171 | u16 vlan_id = vlan->vlan_id; |
174 | 172 | struct vlan_group *grp, *ngrp = NULL; |
175 | 173 | int err; |
... | ... | @@ -207,8 +205,7 @@ |
207 | 205 | if (ngrp) { |
208 | 206 | rcu_assign_pointer(real_dev->vlgrp, ngrp); |
209 | 207 | } |
210 | - if (real_dev->features & NETIF_F_HW_VLAN_FILTER) | |
211 | - ops->ndo_vlan_rx_add_vid(real_dev, vlan_id); | |
208 | + vlan_vid_add(real_dev, vlan_id); | |
212 | 209 | |
213 | 210 | return 0; |
214 | 211 | |
215 | 212 | |
... | ... | @@ -369,11 +366,10 @@ |
369 | 366 | __vlan_device_event(dev, event); |
370 | 367 | |
371 | 368 | if ((event == NETDEV_UP) && |
372 | - (dev->features & NETIF_F_HW_VLAN_FILTER) && | |
373 | - dev->netdev_ops->ndo_vlan_rx_add_vid) { | |
369 | + (dev->features & NETIF_F_HW_VLAN_FILTER)) { | |
374 | 370 | pr_info("adding VLAN 0 to HW filter on device %s\n", |
375 | 371 | dev->name); |
376 | - dev->netdev_ops->ndo_vlan_rx_add_vid(dev, 0); | |
372 | + vlan_vid_add(dev, 0); | |
377 | 373 | } |
378 | 374 | |
379 | 375 | grp = rtnl_dereference(dev->vlgrp); |
net/8021q/vlan_core.c
... | ... | @@ -146,4 +146,27 @@ |
146 | 146 | kfree_skb(skb); |
147 | 147 | return NULL; |
148 | 148 | } |
149 | + | |
150 | +int vlan_vid_add(struct net_device *dev, unsigned short vid) | |
151 | +{ | |
152 | + const struct net_device_ops *ops = dev->netdev_ops; | |
153 | + | |
154 | + if ((dev->features & NETIF_F_HW_VLAN_FILTER) && | |
155 | + ops->ndo_vlan_rx_add_vid) { | |
156 | + return ops->ndo_vlan_rx_add_vid(dev, vid); | |
157 | + } | |
158 | + return 0; | |
159 | +} | |
160 | +EXPORT_SYMBOL(vlan_vid_add); | |
161 | + | |
162 | +void vlan_vid_del(struct net_device *dev, unsigned short vid) | |
163 | +{ | |
164 | + const struct net_device_ops *ops = dev->netdev_ops; | |
165 | + | |
166 | + if ((dev->features & NETIF_F_HW_VLAN_FILTER) && | |
167 | + ops->ndo_vlan_rx_kill_vid) { | |
168 | + ops->ndo_vlan_rx_kill_vid(dev, vid); | |
169 | + } | |
170 | +} | |
171 | +EXPORT_SYMBOL(vlan_vid_del); |