aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/bridge/br_netlink.c11
-rw-r--r--net/bridge/br_private.h8
-rw-r--r--net/bridge/br_vlan.c47
3 files changed, 49 insertions, 17 deletions
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index fe1980d5a7e4..e044cc0b5650 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -120,6 +120,7 @@ static int br_fill_ifinfo(struct sk_buff *skb,
120 const struct net_port_vlans *pv; 120 const struct net_port_vlans *pv;
121 struct bridge_vlan_info vinfo; 121 struct bridge_vlan_info vinfo;
122 u16 vid; 122 u16 vid;
123 u16 pvid;
123 124
124 if (port) 125 if (port)
125 pv = nbp_get_vlan_info(port); 126 pv = nbp_get_vlan_info(port);
@@ -133,12 +134,15 @@ static int br_fill_ifinfo(struct sk_buff *skb,
133 if (!af) 134 if (!af)
134 goto nla_put_failure; 135 goto nla_put_failure;
135 136
137 pvid = br_get_pvid(pv);
136 for (vid = find_first_bit(pv->vlan_bitmap, BR_VLAN_BITMAP_LEN); 138 for (vid = find_first_bit(pv->vlan_bitmap, BR_VLAN_BITMAP_LEN);
137 vid < BR_VLAN_BITMAP_LEN; 139 vid < BR_VLAN_BITMAP_LEN;
138 vid = find_next_bit(pv->vlan_bitmap, 140 vid = find_next_bit(pv->vlan_bitmap,
139 BR_VLAN_BITMAP_LEN, vid+1)) { 141 BR_VLAN_BITMAP_LEN, vid+1)) {
140 vinfo.vid = vid; 142 vinfo.vid = vid;
141 vinfo.flags = 0; 143 vinfo.flags = 0;
144 if (vid == pvid)
145 vinfo.flags |= BRIDGE_VLAN_INFO_PVID;
142 if (nla_put(skb, IFLA_BRIDGE_VLAN_INFO, 146 if (nla_put(skb, IFLA_BRIDGE_VLAN_INFO,
143 sizeof(vinfo), &vinfo)) 147 sizeof(vinfo), &vinfo))
144 goto nla_put_failure; 148 goto nla_put_failure;
@@ -239,14 +243,15 @@ static int br_afspec(struct net_bridge *br,
239 switch (cmd) { 243 switch (cmd) {
240 case RTM_SETLINK: 244 case RTM_SETLINK:
241 if (p) { 245 if (p) {
242 err = nbp_vlan_add(p, vinfo->vid); 246 err = nbp_vlan_add(p, vinfo->vid, vinfo->flags);
243 if (err) 247 if (err)
244 break; 248 break;
245 249
246 if (vinfo->flags & BRIDGE_VLAN_INFO_MASTER) 250 if (vinfo->flags & BRIDGE_VLAN_INFO_MASTER)
247 err = br_vlan_add(p->br, vinfo->vid); 251 err = br_vlan_add(p->br, vinfo->vid,
252 vinfo->flags);
248 } else 253 } else
249 err = br_vlan_add(br, vinfo->vid); 254 err = br_vlan_add(br, vinfo->vid, vinfo->flags);
250 255
251 if (err) 256 if (err)
252 break; 257 break;
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index ea8e7efd9137..1ae6395a0369 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -562,11 +562,11 @@ extern bool br_allowed_egress(struct net_bridge *br,
562extern struct sk_buff *br_handle_vlan(struct net_bridge *br, 562extern struct sk_buff *br_handle_vlan(struct net_bridge *br,
563 const struct net_port_vlans *v, 563 const struct net_port_vlans *v,
564 struct sk_buff *skb); 564 struct sk_buff *skb);
565extern int br_vlan_add(struct net_bridge *br, u16 vid); 565extern int br_vlan_add(struct net_bridge *br, u16 vid, u16 flags);
566extern int br_vlan_delete(struct net_bridge *br, u16 vid); 566extern int br_vlan_delete(struct net_bridge *br, u16 vid);
567extern void br_vlan_flush(struct net_bridge *br); 567extern void br_vlan_flush(struct net_bridge *br);
568extern int br_vlan_filter_toggle(struct net_bridge *br, unsigned long val); 568extern int br_vlan_filter_toggle(struct net_bridge *br, unsigned long val);
569extern int nbp_vlan_add(struct net_bridge_port *port, u16 vid); 569extern int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags);
570extern int nbp_vlan_delete(struct net_bridge_port *port, u16 vid); 570extern int nbp_vlan_delete(struct net_bridge_port *port, u16 vid);
571extern void nbp_vlan_flush(struct net_bridge_port *port); 571extern void nbp_vlan_flush(struct net_bridge_port *port);
572 572
@@ -633,7 +633,7 @@ static inline struct sk_buff *br_handle_vlan(struct net_bridge *br,
633 return skb; 633 return skb;
634} 634}
635 635
636static inline int br_vlan_add(struct net_bridge *br, u16 vid) 636static inline int br_vlan_add(struct net_bridge *br, u16 vid, u16 flags)
637{ 637{
638 return -EOPNOTSUPP; 638 return -EOPNOTSUPP;
639} 639}
@@ -647,7 +647,7 @@ static inline void br_vlan_flush(struct net_bridge *br)
647{ 647{
648} 648}
649 649
650static inline int nbp_vlan_add(struct net_bridge_port *port, u16 vid) 650static inline int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags)
651{ 651{
652 return -EOPNOTSUPP; 652 return -EOPNOTSUPP;
653} 653}
diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c
index 20057de56db0..c79940cff3a1 100644
--- a/net/bridge/br_vlan.c
+++ b/net/bridge/br_vlan.c
@@ -5,12 +5,33 @@
5 5
6#include "br_private.h" 6#include "br_private.h"
7 7
8static int __vlan_add(struct net_port_vlans *v, u16 vid) 8static void __vlan_add_pvid(struct net_port_vlans *v, u16 vid)
9{
10 if (v->pvid == vid)
11 return;
12
13 smp_wmb();
14 v->pvid = vid;
15}
16
17static void __vlan_delete_pvid(struct net_port_vlans *v, u16 vid)
18{
19 if (v->pvid != vid)
20 return;
21
22 smp_wmb();
23 v->pvid = 0;
24}
25
26static int __vlan_add(struct net_port_vlans *v, u16 vid, u16 flags)
9{ 27{
10 int err; 28 int err;
11 29
12 if (test_bit(vid, v->vlan_bitmap)) 30 if (test_bit(vid, v->vlan_bitmap)) {
13 return -EEXIST; 31 if (flags & BRIDGE_VLAN_INFO_PVID)
32 __vlan_add_pvid(v, vid);
33 return 0;
34 }
14 35
15 if (v->port_idx && vid) { 36 if (v->port_idx && vid) {
16 struct net_device *dev = v->parent.port->dev; 37 struct net_device *dev = v->parent.port->dev;
@@ -29,6 +50,9 @@ static int __vlan_add(struct net_port_vlans *v, u16 vid)
29 50
30 set_bit(vid, v->vlan_bitmap); 51 set_bit(vid, v->vlan_bitmap);
31 v->num_vlans++; 52 v->num_vlans++;
53 if (flags & BRIDGE_VLAN_INFO_PVID)
54 __vlan_add_pvid(v, vid);
55
32 return 0; 56 return 0;
33} 57}
34 58
@@ -37,6 +61,8 @@ static int __vlan_del(struct net_port_vlans *v, u16 vid)
37 if (!test_bit(vid, v->vlan_bitmap)) 61 if (!test_bit(vid, v->vlan_bitmap))
38 return -EINVAL; 62 return -EINVAL;
39 63
64 __vlan_delete_pvid(v, vid);
65
40 if (v->port_idx && vid) { 66 if (v->port_idx && vid) {
41 struct net_device *dev = v->parent.port->dev; 67 struct net_device *dev = v->parent.port->dev;
42 68
@@ -58,6 +84,8 @@ static int __vlan_del(struct net_port_vlans *v, u16 vid)
58 84
59static void __vlan_flush(struct net_port_vlans *v) 85static void __vlan_flush(struct net_port_vlans *v)
60{ 86{
87 smp_wmb();
88 v->pvid = 0;
61 bitmap_zero(v->vlan_bitmap, BR_VLAN_BITMAP_LEN); 89 bitmap_zero(v->vlan_bitmap, BR_VLAN_BITMAP_LEN);
62 if (v->port_idx) 90 if (v->port_idx)
63 rcu_assign_pointer(v->parent.port->vlan_info, NULL); 91 rcu_assign_pointer(v->parent.port->vlan_info, NULL);
@@ -185,7 +213,7 @@ bool br_allowed_egress(struct net_bridge *br,
185} 213}
186 214
187/* Must be protected by RTNL */ 215/* Must be protected by RTNL */
188int br_vlan_add(struct net_bridge *br, u16 vid) 216int br_vlan_add(struct net_bridge *br, u16 vid, u16 flags)
189{ 217{
190 struct net_port_vlans *pv = NULL; 218 struct net_port_vlans *pv = NULL;
191 int err; 219 int err;
@@ -194,7 +222,7 @@ int br_vlan_add(struct net_bridge *br, u16 vid)
194 222
195 pv = rtnl_dereference(br->vlan_info); 223 pv = rtnl_dereference(br->vlan_info);
196 if (pv) 224 if (pv)
197 return __vlan_add(pv, vid); 225 return __vlan_add(pv, vid, flags);
198 226
199 /* Create port vlan infomration 227 /* Create port vlan infomration
200 */ 228 */
@@ -203,7 +231,7 @@ int br_vlan_add(struct net_bridge *br, u16 vid)
203 return -ENOMEM; 231 return -ENOMEM;
204 232
205 pv->parent.br = br; 233 pv->parent.br = br;
206 err = __vlan_add(pv, vid); 234 err = __vlan_add(pv, vid, flags);
207 if (err) 235 if (err)
208 goto out; 236 goto out;
209 237
@@ -234,7 +262,6 @@ void br_vlan_flush(struct net_bridge *br)
234 struct net_port_vlans *pv; 262 struct net_port_vlans *pv;
235 263
236 ASSERT_RTNL(); 264 ASSERT_RTNL();
237
238 pv = rtnl_dereference(br->vlan_info); 265 pv = rtnl_dereference(br->vlan_info);
239 if (!pv) 266 if (!pv)
240 return; 267 return;
@@ -258,7 +285,7 @@ unlock:
258} 285}
259 286
260/* Must be protected by RTNL */ 287/* Must be protected by RTNL */
261int nbp_vlan_add(struct net_bridge_port *port, u16 vid) 288int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags)
262{ 289{
263 struct net_port_vlans *pv = NULL; 290 struct net_port_vlans *pv = NULL;
264 int err; 291 int err;
@@ -267,7 +294,7 @@ int nbp_vlan_add(struct net_bridge_port *port, u16 vid)
267 294
268 pv = rtnl_dereference(port->vlan_info); 295 pv = rtnl_dereference(port->vlan_info);
269 if (pv) 296 if (pv)
270 return __vlan_add(pv, vid); 297 return __vlan_add(pv, vid, flags);
271 298
272 /* Create port vlan infomration 299 /* Create port vlan infomration
273 */ 300 */
@@ -279,7 +306,7 @@ int nbp_vlan_add(struct net_bridge_port *port, u16 vid)
279 306
280 pv->port_idx = port->port_no; 307 pv->port_idx = port->port_no;
281 pv->parent.port = port; 308 pv->parent.port = port;
282 err = __vlan_add(pv, vid); 309 err = __vlan_add(pv, vid, flags);
283 if (err) 310 if (err)
284 goto clean_up; 311 goto clean_up;
285 312