aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/bonding/bond_main.c53
-rw-r--r--drivers/net/macvlan.c10
-rw-r--r--drivers/net/team/team.c34
-rw-r--r--include/linux/if_vlan.h12
-rw-r--r--net/8021q/vlan.c14
-rw-r--r--net/8021q/vlan_core.c23
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,
431static int bond_vlan_rx_add_vid(struct net_device *bond_dev, uint16_t vid) 431static 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
452unwind:
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)
488static void bond_add_vlans_on_slave(struct bonding *bond, struct net_device *slave_dev) 485static 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
501static void bond_del_vlans_from_slave(struct bonding *bond, 499static 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
535static int macvlan_vlan_rx_kill_vid(struct net_device *dev, 533static 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
926unwind:
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
922static int team_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid) 934static 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);
109extern bool vlan_do_receive(struct sk_buff **skb, bool last_handler); 109extern bool vlan_do_receive(struct sk_buff **skb, bool last_handler);
110extern struct sk_buff *vlan_untag(struct sk_buff *skb); 110extern struct sk_buff *vlan_untag(struct sk_buff *skb);
111 111
112extern int vlan_vid_add(struct net_device *dev, unsigned short vid);
113extern void vlan_vid_del(struct net_device *dev, unsigned short vid);
114
112#else 115#else
113static inline struct net_device * 116static 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
146static inline int vlan_vid_add(struct net_device *dev, unsigned short vid)
147{
148 return 0;
149}
150
151static 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
150int 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}
160EXPORT_SYMBOL(vlan_vid_add);
161
162void 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}
171EXPORT_SYMBOL(vlan_vid_del);