diff options
author | Jiri Pirko <jpirko@redhat.com> | 2011-12-07 23:11:17 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-12-08 19:52:42 -0500 |
commit | 87002b03baabd2b8f6281ab6411ed88d24958de1 (patch) | |
tree | 0e5730c0d1ba887488ba420d4ea89a230f272c51 | |
parent | 8e586137e6b63af1e881b328466ab5ffbe562510 (diff) |
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>
-rw-r--r-- | drivers/net/bonding/bond_main.c | 53 | ||||
-rw-r--r-- | drivers/net/macvlan.c | 10 | ||||
-rw-r--r-- | drivers/net/team/team.c | 34 | ||||
-rw-r--r-- | include/linux/if_vlan.h | 12 | ||||
-rw-r--r-- | net/8021q/vlan.c | 14 | ||||
-rw-r--r-- | net/8021q/vlan_core.c | 23 |
6 files changed, 87 insertions, 59 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index d72c37f03e50..0c0dacba1f51 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c | |||
@@ -431,17 +431,13 @@ int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, | |||
431 | static int bond_vlan_rx_add_vid(struct net_device *bond_dev, uint16_t vid) | 431 | static int bond_vlan_rx_add_vid(struct net_device *bond_dev, uint16_t vid) |
432 | { | 432 | { |
433 | struct bonding *bond = netdev_priv(bond_dev); | 433 | struct bonding *bond = netdev_priv(bond_dev); |
434 | struct slave *slave; | 434 | struct slave *slave, *stop_at; |
435 | int i, res; | 435 | int i, res; |
436 | 436 | ||
437 | bond_for_each_slave(bond, slave, i) { | 437 | bond_for_each_slave(bond, slave, i) { |
438 | struct net_device *slave_dev = slave->dev; | 438 | res = vlan_vid_add(slave->dev, vid); |
439 | const struct net_device_ops *slave_ops = slave_dev->netdev_ops; | 439 | if (res) |
440 | 440 | goto unwind; | |
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 | } | ||
445 | } | 441 | } |
446 | 442 | ||
447 | res = bond_add_vlan(bond, vid); | 443 | res = bond_add_vlan(bond, vid); |
@@ -452,6 +448,14 @@ static int bond_vlan_rx_add_vid(struct net_device *bond_dev, uint16_t vid) | |||
452 | } | 448 | } |
453 | 449 | ||
454 | return 0; | 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 | /** |
@@ -465,15 +469,8 @@ static int bond_vlan_rx_kill_vid(struct net_device *bond_dev, uint16_t vid) | |||
465 | struct slave *slave; | 469 | struct slave *slave; |
466 | int i, res; | 470 | int i, res; |
467 | 471 | ||
468 | bond_for_each_slave(bond, slave, i) { | 472 | bond_for_each_slave(bond, slave, i) |
469 | struct net_device *slave_dev = slave->dev; | 473 | vlan_vid_del(slave->dev, vid); |
470 | const struct net_device_ops *slave_ops = slave_dev->netdev_ops; | ||
471 | |||
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 | 474 | ||
478 | res = bond_del_vlan(bond, vid); | 475 | res = bond_del_vlan(bond, vid); |
479 | if (res) { | 476 | if (res) { |
@@ -488,30 +485,26 @@ static int bond_vlan_rx_kill_vid(struct net_device *bond_dev, uint16_t vid) | |||
488 | static void bond_add_vlans_on_slave(struct bonding *bond, struct net_device *slave_dev) | 485 | static void bond_add_vlans_on_slave(struct bonding *bond, struct net_device *slave_dev) |
489 | { | 486 | { |
490 | struct vlan_entry *vlan; | 487 | struct vlan_entry *vlan; |
491 | const struct net_device_ops *slave_ops = slave_dev->netdev_ops; | 488 | int res; |
492 | |||
493 | if (!(slave_dev->features & NETIF_F_HW_VLAN_FILTER) || | ||
494 | !(slave_ops->ndo_vlan_rx_add_vid)) | ||
495 | return; | ||
496 | 489 | ||
497 | list_for_each_entry(vlan, &bond->vlan_list, vlan_list) | 490 | list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { |
498 | slave_ops->ndo_vlan_rx_add_vid(slave_dev, vlan->vlan_id); | 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 | static void bond_del_vlans_from_slave(struct bonding *bond, | 499 | static void bond_del_vlans_from_slave(struct bonding *bond, |
502 | struct net_device *slave_dev) | 500 | struct net_device *slave_dev) |
503 | { | 501 | { |
504 | const struct net_device_ops *slave_ops = slave_dev->netdev_ops; | ||
505 | struct vlan_entry *vlan; | 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 | list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { | 504 | list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { |
512 | if (!vlan->vlan_id) | 505 | if (!vlan->vlan_id) |
513 | continue; | 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 | ||
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 2511bc5c34f3..f2f820c4b40a 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/etherdevice.h> | 26 | #include <linux/etherdevice.h> |
27 | #include <linux/ethtool.h> | 27 | #include <linux/ethtool.h> |
28 | #include <linux/if_arp.h> | 28 | #include <linux/if_arp.h> |
29 | #include <linux/if_vlan.h> | ||
29 | #include <linux/if_link.h> | 30 | #include <linux/if_link.h> |
30 | #include <linux/if_macvlan.h> | 31 | #include <linux/if_macvlan.h> |
31 | #include <net/rtnetlink.h> | 32 | #include <net/rtnetlink.h> |
@@ -525,11 +526,8 @@ static int macvlan_vlan_rx_add_vid(struct net_device *dev, | |||
525 | { | 526 | { |
526 | struct macvlan_dev *vlan = netdev_priv(dev); | 527 | struct macvlan_dev *vlan = netdev_priv(dev); |
527 | struct net_device *lowerdev = vlan->lowerdev; | 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) | 530 | return vlan_vid_add(lowerdev, vid); |
531 | return ops->ndo_vlan_rx_add_vid(lowerdev, vid); | ||
532 | return 0; | ||
533 | } | 531 | } |
534 | 532 | ||
535 | static int macvlan_vlan_rx_kill_vid(struct net_device *dev, | 533 | static int macvlan_vlan_rx_kill_vid(struct net_device *dev, |
@@ -537,10 +535,8 @@ static int macvlan_vlan_rx_kill_vid(struct net_device *dev, | |||
537 | { | 535 | { |
538 | struct macvlan_dev *vlan = netdev_priv(dev); | 536 | struct macvlan_dev *vlan = netdev_priv(dev); |
539 | struct net_device *lowerdev = vlan->lowerdev; | 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) | 539 | vlan_vid_del(lowerdev, vid); |
543 | return ops->ndo_vlan_rx_kill_vid(lowerdev, vid); | ||
544 | return 0; | 540 | return 0; |
545 | } | 541 | } |
546 | 542 | ||
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index 8e8bf958539e..79c2d1b52eb6 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/ctype.h> | 18 | #include <linux/ctype.h> |
19 | #include <linux/notifier.h> | 19 | #include <linux/notifier.h> |
20 | #include <linux/netdevice.h> | 20 | #include <linux/netdevice.h> |
21 | #include <linux/if_vlan.h> | ||
21 | #include <linux/if_arp.h> | 22 | #include <linux/if_arp.h> |
22 | #include <linux/socket.h> | 23 | #include <linux/socket.h> |
23 | #include <linux/etherdevice.h> | 24 | #include <linux/etherdevice.h> |
@@ -906,17 +907,28 @@ static int team_vlan_rx_add_vid(struct net_device *dev, uint16_t vid) | |||
906 | { | 907 | { |
907 | struct team *team = netdev_priv(dev); | 908 | struct team *team = netdev_priv(dev); |
908 | struct team_port *port; | 909 | struct team_port *port; |
910 | int err; | ||
909 | 911 | ||
910 | rcu_read_lock(); | 912 | /* |
911 | list_for_each_entry_rcu(port, &team->port_list, list) { | 913 | * Alhough this is reader, it's guarded by team lock. It's not possible |
912 | const struct net_device_ops *ops = port->dev->netdev_ops; | 914 | * to traverse list in reverse under rcu_read_lock |
913 | 915 | */ | |
914 | if (ops->ndo_vlan_rx_add_vid) | 916 | mutex_lock(&team->lock); |
915 | ops->ndo_vlan_rx_add_vid(port->dev, vid); | 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 | return 0; | 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 | static int team_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid) | 934 | static int team_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid) |
@@ -925,12 +937,8 @@ static int team_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid) | |||
925 | struct team_port *port; | 937 | struct team_port *port; |
926 | 938 | ||
927 | rcu_read_lock(); | 939 | rcu_read_lock(); |
928 | list_for_each_entry_rcu(port, &team->port_list, list) { | 940 | list_for_each_entry_rcu(port, &team->port_list, list) |
929 | const struct net_device_ops *ops = port->dev->netdev_ops; | 941 | vlan_vid_del(port->dev, vid); |
930 | |||
931 | if (ops->ndo_vlan_rx_kill_vid) | ||
932 | ops->ndo_vlan_rx_kill_vid(port->dev, vid); | ||
933 | } | ||
934 | rcu_read_unlock(); | 942 | rcu_read_unlock(); |
935 | 943 | ||
936 | return 0; | 944 | return 0; |
diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h index 31d7c976f063..71168a6f3347 100644 --- a/include/linux/if_vlan.h +++ b/include/linux/if_vlan.h | |||
@@ -109,6 +109,9 @@ extern u16 vlan_dev_vlan_id(const struct net_device *dev); | |||
109 | extern bool vlan_do_receive(struct sk_buff **skb, bool last_handler); | 109 | extern bool vlan_do_receive(struct sk_buff **skb, bool last_handler); |
110 | extern struct sk_buff *vlan_untag(struct sk_buff *skb); | 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 | #else | 115 | #else |
113 | static inline struct net_device * | 116 | static inline struct net_device * |
114 | __vlan_find_dev_deep(struct net_device *real_dev, u16 vlan_id) | 117 | __vlan_find_dev_deep(struct net_device *real_dev, u16 vlan_id) |
@@ -139,6 +142,15 @@ static inline struct sk_buff *vlan_untag(struct sk_buff *skb) | |||
139 | { | 142 | { |
140 | return skb; | 143 | return skb; |
141 | } | 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 | { | ||
153 | } | ||
142 | #endif | 154 | #endif |
143 | 155 | ||
144 | /** | 156 | /** |
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index e075625efeeb..dd9aa400888b 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c | |||
@@ -101,7 +101,6 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head) | |||
101 | { | 101 | { |
102 | struct vlan_dev_priv *vlan = vlan_dev_priv(dev); | 102 | struct vlan_dev_priv *vlan = vlan_dev_priv(dev); |
103 | struct net_device *real_dev = vlan->real_dev; | 103 | struct net_device *real_dev = vlan->real_dev; |
104 | const struct net_device_ops *ops = real_dev->netdev_ops; | ||
105 | struct vlan_group *grp; | 104 | struct vlan_group *grp; |
106 | u16 vlan_id = vlan->vlan_id; | 105 | u16 vlan_id = vlan->vlan_id; |
107 | 106 | ||
@@ -114,8 +113,8 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head) | |||
114 | * HW accelerating devices or SW vlan input packet processing if | 113 | * HW accelerating devices or SW vlan input packet processing if |
115 | * VLAN is not 0 (leave it there for 802.1p). | 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)) | 116 | if (vlan_id) |
118 | ops->ndo_vlan_rx_kill_vid(real_dev, vlan_id); | 117 | vlan_vid_del(real_dev, vlan_id); |
119 | 118 | ||
120 | grp->nr_vlans--; | 119 | grp->nr_vlans--; |
121 | 120 | ||
@@ -169,7 +168,6 @@ int register_vlan_dev(struct net_device *dev) | |||
169 | { | 168 | { |
170 | struct vlan_dev_priv *vlan = vlan_dev_priv(dev); | 169 | struct vlan_dev_priv *vlan = vlan_dev_priv(dev); |
171 | struct net_device *real_dev = vlan->real_dev; | 170 | struct net_device *real_dev = vlan->real_dev; |
172 | const struct net_device_ops *ops = real_dev->netdev_ops; | ||
173 | u16 vlan_id = vlan->vlan_id; | 171 | u16 vlan_id = vlan->vlan_id; |
174 | struct vlan_group *grp, *ngrp = NULL; | 172 | struct vlan_group *grp, *ngrp = NULL; |
175 | int err; | 173 | int err; |
@@ -207,8 +205,7 @@ int register_vlan_dev(struct net_device *dev) | |||
207 | if (ngrp) { | 205 | if (ngrp) { |
208 | rcu_assign_pointer(real_dev->vlgrp, ngrp); | 206 | rcu_assign_pointer(real_dev->vlgrp, ngrp); |
209 | } | 207 | } |
210 | if (real_dev->features & NETIF_F_HW_VLAN_FILTER) | 208 | vlan_vid_add(real_dev, vlan_id); |
211 | ops->ndo_vlan_rx_add_vid(real_dev, vlan_id); | ||
212 | 209 | ||
213 | return 0; | 210 | return 0; |
214 | 211 | ||
@@ -369,11 +366,10 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
369 | __vlan_device_event(dev, event); | 366 | __vlan_device_event(dev, event); |
370 | 367 | ||
371 | if ((event == NETDEV_UP) && | 368 | if ((event == NETDEV_UP) && |
372 | (dev->features & NETIF_F_HW_VLAN_FILTER) && | 369 | (dev->features & NETIF_F_HW_VLAN_FILTER)) { |
373 | dev->netdev_ops->ndo_vlan_rx_add_vid) { | ||
374 | pr_info("adding VLAN 0 to HW filter on device %s\n", | 370 | pr_info("adding VLAN 0 to HW filter on device %s\n", |
375 | dev->name); | 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 | grp = rtnl_dereference(dev->vlgrp); | 375 | grp = rtnl_dereference(dev->vlgrp); |
diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c index 85241f044294..544f9cb9678c 100644 --- a/net/8021q/vlan_core.c +++ b/net/8021q/vlan_core.c | |||
@@ -146,3 +146,26 @@ err_free: | |||
146 | kfree_skb(skb); | 146 | kfree_skb(skb); |
147 | return NULL; | 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); | ||