]>
Commit | Line | Data |
---|---|---|
243a2e63 VY |
1 | #include <linux/kernel.h> |
2 | #include <linux/netdevice.h> | |
3 | #include <linux/rtnetlink.h> | |
4 | #include <linux/slab.h> | |
7f109539 | 5 | #include <net/switchdev.h> |
243a2e63 VY |
6 | |
7 | #include "br_private.h" | |
efa5356b | 8 | #include "br_private_tunnel.h" |
243a2e63 | 9 | |
2594e906 NA |
10 | static inline int br_vlan_cmp(struct rhashtable_compare_arg *arg, |
11 | const void *ptr) | |
552406c4 | 12 | { |
2594e906 NA |
13 | const struct net_bridge_vlan *vle = ptr; |
14 | u16 vid = *(u16 *)arg->key; | |
15 | ||
16 | return vle->vid != vid; | |
17 | } | |
18 | ||
19 | static const struct rhashtable_params br_vlan_rht_params = { | |
20 | .head_offset = offsetof(struct net_bridge_vlan, vnode), | |
21 | .key_offset = offsetof(struct net_bridge_vlan, vid), | |
22 | .key_len = sizeof(u16), | |
8af78b64 NA |
23 | .nelem_hint = 3, |
24 | .locks_mul = 1, | |
2594e906 NA |
25 | .max_size = VLAN_N_VID, |
26 | .obj_cmpfn = br_vlan_cmp, | |
27 | .automatic_shrinking = true, | |
28 | }; | |
29 | ||
30 | static struct net_bridge_vlan *br_vlan_lookup(struct rhashtable *tbl, u16 vid) | |
31 | { | |
32 | return rhashtable_lookup_fast(tbl, &vid, br_vlan_rht_params); | |
33 | } | |
34 | ||
f418af63 | 35 | static bool __vlan_add_pvid(struct net_bridge_vlan_group *vg, u16 vid) |
2594e906 | 36 | { |
77751ee8 | 37 | if (vg->pvid == vid) |
f418af63 | 38 | return false; |
552406c4 VY |
39 | |
40 | smp_wmb(); | |
77751ee8 | 41 | vg->pvid = vid; |
f418af63 NA |
42 | |
43 | return true; | |
552406c4 VY |
44 | } |
45 | ||
f418af63 | 46 | static bool __vlan_delete_pvid(struct net_bridge_vlan_group *vg, u16 vid) |
552406c4 | 47 | { |
77751ee8 | 48 | if (vg->pvid != vid) |
f418af63 | 49 | return false; |
552406c4 VY |
50 | |
51 | smp_wmb(); | |
77751ee8 | 52 | vg->pvid = 0; |
f418af63 NA |
53 | |
54 | return true; | |
552406c4 VY |
55 | } |
56 | ||
f418af63 NA |
57 | /* return true if anything changed, false otherwise */ |
58 | static bool __vlan_add_flags(struct net_bridge_vlan *v, u16 flags) | |
35e03f3a | 59 | { |
77751ee8 | 60 | struct net_bridge_vlan_group *vg; |
f418af63 NA |
61 | u16 old_flags = v->flags; |
62 | bool ret; | |
77751ee8 NA |
63 | |
64 | if (br_vlan_is_master(v)) | |
907b1e6e | 65 | vg = br_vlan_group(v->br); |
77751ee8 | 66 | else |
907b1e6e | 67 | vg = nbp_vlan_group(v->port); |
77751ee8 NA |
68 | |
69 | if (flags & BRIDGE_VLAN_INFO_PVID) | |
f418af63 | 70 | ret = __vlan_add_pvid(vg, v->vid); |
77751ee8 | 71 | else |
f418af63 | 72 | ret = __vlan_delete_pvid(vg, v->vid); |
35e03f3a VY |
73 | |
74 | if (flags & BRIDGE_VLAN_INFO_UNTAGGED) | |
2594e906 | 75 | v->flags |= BRIDGE_VLAN_INFO_UNTAGGED; |
635126b7 | 76 | else |
2594e906 | 77 | v->flags &= ~BRIDGE_VLAN_INFO_UNTAGGED; |
f418af63 NA |
78 | |
79 | return ret || !!(old_flags ^ v->flags); | |
35e03f3a VY |
80 | } |
81 | ||
7f109539 SF |
82 | static int __vlan_vid_add(struct net_device *dev, struct net_bridge *br, |
83 | u16 vid, u16 flags) | |
84 | { | |
0944d6b5 | 85 | struct switchdev_obj_port_vlan v = { |
6ff64f6f | 86 | .obj.orig_dev = dev, |
0944d6b5 JP |
87 | .obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN, |
88 | .flags = flags, | |
89 | .vid_begin = vid, | |
90 | .vid_end = vid, | |
91 | }; | |
7f109539 SF |
92 | int err; |
93 | ||
0944d6b5 JP |
94 | /* Try switchdev op first. In case it is not supported, fallback to |
95 | * 8021q add. | |
7f109539 | 96 | */ |
0944d6b5 JP |
97 | err = switchdev_port_obj_add(dev, &v.obj); |
98 | if (err == -EOPNOTSUPP) | |
99 | return vlan_vid_add(dev, br->vlan_proto, vid); | |
7f109539 SF |
100 | return err; |
101 | } | |
102 | ||
2594e906 | 103 | static void __vlan_add_list(struct net_bridge_vlan *v) |
243a2e63 | 104 | { |
907b1e6e | 105 | struct net_bridge_vlan_group *vg; |
2594e906 NA |
106 | struct list_head *headp, *hpos; |
107 | struct net_bridge_vlan *vent; | |
bc9a25d2 | 108 | |
907b1e6e NA |
109 | if (br_vlan_is_master(v)) |
110 | vg = br_vlan_group(v->br); | |
111 | else | |
112 | vg = nbp_vlan_group(v->port); | |
113 | ||
114 | headp = &vg->vlan_list; | |
2594e906 NA |
115 | list_for_each_prev(hpos, headp) { |
116 | vent = list_entry(hpos, struct net_bridge_vlan, vlist); | |
117 | if (v->vid < vent->vid) | |
118 | continue; | |
119 | else | |
120 | break; | |
243a2e63 | 121 | } |
586c2b57 | 122 | list_add_rcu(&v->vlist, hpos); |
2594e906 | 123 | } |
243a2e63 | 124 | |
2594e906 NA |
125 | static void __vlan_del_list(struct net_bridge_vlan *v) |
126 | { | |
586c2b57 | 127 | list_del_rcu(&v->vlist); |
243a2e63 VY |
128 | } |
129 | ||
bf361ad3 VD |
130 | static int __vlan_vid_del(struct net_device *dev, struct net_bridge *br, |
131 | u16 vid) | |
7f109539 | 132 | { |
0944d6b5 | 133 | struct switchdev_obj_port_vlan v = { |
6ff64f6f | 134 | .obj.orig_dev = dev, |
0944d6b5 JP |
135 | .obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN, |
136 | .vid_begin = vid, | |
137 | .vid_end = vid, | |
138 | }; | |
139 | int err; | |
7f109539 | 140 | |
0944d6b5 JP |
141 | /* Try switchdev op first. In case it is not supported, fallback to |
142 | * 8021q del. | |
7f109539 | 143 | */ |
0944d6b5 JP |
144 | err = switchdev_port_obj_del(dev, &v.obj); |
145 | if (err == -EOPNOTSUPP) { | |
7f109539 | 146 | vlan_vid_del(dev, br->vlan_proto, vid); |
0944d6b5 | 147 | return 0; |
7f109539 | 148 | } |
bf361ad3 | 149 | return err; |
7f109539 SF |
150 | } |
151 | ||
f8ed289f NA |
152 | /* Returns a master vlan, if it didn't exist it gets created. In all cases a |
153 | * a reference is taken to the master vlan before returning. | |
154 | */ | |
155 | static struct net_bridge_vlan *br_vlan_get_master(struct net_bridge *br, u16 vid) | |
156 | { | |
907b1e6e | 157 | struct net_bridge_vlan_group *vg; |
f8ed289f NA |
158 | struct net_bridge_vlan *masterv; |
159 | ||
907b1e6e NA |
160 | vg = br_vlan_group(br); |
161 | masterv = br_vlan_find(vg, vid); | |
f8ed289f | 162 | if (!masterv) { |
f418af63 NA |
163 | bool changed; |
164 | ||
f8ed289f | 165 | /* missing global ctx, create it now */ |
f418af63 | 166 | if (br_vlan_add(br, vid, 0, &changed)) |
f8ed289f | 167 | return NULL; |
907b1e6e | 168 | masterv = br_vlan_find(vg, vid); |
f8ed289f NA |
169 | if (WARN_ON(!masterv)) |
170 | return NULL; | |
171 | } | |
25127759 | 172 | refcount_inc(&masterv->refcnt); |
f8ed289f NA |
173 | |
174 | return masterv; | |
175 | } | |
176 | ||
6dada9b1 NA |
177 | static void br_master_vlan_rcu_free(struct rcu_head *rcu) |
178 | { | |
179 | struct net_bridge_vlan *v; | |
180 | ||
181 | v = container_of(rcu, struct net_bridge_vlan, rcu); | |
182 | WARN_ON(!br_vlan_is_master(v)); | |
183 | free_percpu(v->stats); | |
184 | v->stats = NULL; | |
185 | kfree(v); | |
186 | } | |
187 | ||
f8ed289f NA |
188 | static void br_vlan_put_master(struct net_bridge_vlan *masterv) |
189 | { | |
907b1e6e NA |
190 | struct net_bridge_vlan_group *vg; |
191 | ||
f8ed289f NA |
192 | if (!br_vlan_is_master(masterv)) |
193 | return; | |
194 | ||
907b1e6e | 195 | vg = br_vlan_group(masterv->br); |
25127759 | 196 | if (refcount_dec_and_test(&masterv->refcnt)) { |
907b1e6e | 197 | rhashtable_remove_fast(&vg->vlan_hash, |
f8ed289f NA |
198 | &masterv->vnode, br_vlan_rht_params); |
199 | __vlan_del_list(masterv); | |
6dada9b1 | 200 | call_rcu(&masterv->rcu, br_master_vlan_rcu_free); |
f8ed289f NA |
201 | } |
202 | } | |
203 | ||
2594e906 NA |
204 | /* This is the shared VLAN add function which works for both ports and bridge |
205 | * devices. There are four possible calls to this function in terms of the | |
206 | * vlan entry type: | |
207 | * 1. vlan is being added on a port (no master flags, global entry exists) | |
ddd611d3 | 208 | * 2. vlan is being added on a bridge (both master and brentry flags) |
2594e906 | 209 | * 3. vlan is being added on a port, but a global entry didn't exist which |
ddd611d3 | 210 | * is being created right now (master flag set, brentry flag unset), the |
2594e906 | 211 | * global entry is used for global per-vlan features, but not for filtering |
ddd611d3 | 212 | * 4. same as 3 but with both master and brentry flags set so the entry |
2594e906 NA |
213 | * will be used for filtering in both the port and the bridge |
214 | */ | |
215 | static int __vlan_add(struct net_bridge_vlan *v, u16 flags) | |
243a2e63 | 216 | { |
2594e906 NA |
217 | struct net_bridge_vlan *masterv = NULL; |
218 | struct net_bridge_port *p = NULL; | |
6be144f6 | 219 | struct net_bridge_vlan_group *vg; |
2594e906 NA |
220 | struct net_device *dev; |
221 | struct net_bridge *br; | |
222 | int err; | |
223 | ||
224 | if (br_vlan_is_master(v)) { | |
225 | br = v->br; | |
226 | dev = br->dev; | |
907b1e6e | 227 | vg = br_vlan_group(br); |
2594e906 NA |
228 | } else { |
229 | p = v->port; | |
230 | br = p->br; | |
231 | dev = p->dev; | |
907b1e6e | 232 | vg = nbp_vlan_group(p); |
2594e906 NA |
233 | } |
234 | ||
235 | if (p) { | |
2594e906 NA |
236 | /* Add VLAN to the device filter if it is supported. |
237 | * This ensures tagged traffic enters the bridge when | |
238 | * promiscuous mode is disabled by br_manage_promisc(). | |
239 | */ | |
240 | err = __vlan_vid_add(dev, br, v->vid, flags); | |
241 | if (err) | |
242 | goto out; | |
243 | ||
244 | /* need to work on the master vlan too */ | |
245 | if (flags & BRIDGE_VLAN_INFO_MASTER) { | |
f418af63 NA |
246 | bool changed; |
247 | ||
248 | err = br_vlan_add(br, v->vid, | |
249 | flags | BRIDGE_VLAN_INFO_BRENTRY, | |
250 | &changed); | |
2594e906 NA |
251 | if (err) |
252 | goto out_filt; | |
253 | } | |
254 | ||
f8ed289f NA |
255 | masterv = br_vlan_get_master(br, v->vid); |
256 | if (!masterv) | |
257 | goto out_filt; | |
2594e906 | 258 | v->brvlan = masterv; |
6dada9b1 | 259 | v->stats = masterv->stats; |
2594e906 NA |
260 | } |
261 | ||
6be144f6 | 262 | /* Add the dev mac and count the vlan only if it's usable */ |
2594e906 NA |
263 | if (br_vlan_should_use(v)) { |
264 | err = br_fdb_insert(br, p, dev->dev_addr, v->vid); | |
265 | if (err) { | |
266 | br_err(br, "failed insert local address into bridge forwarding table\n"); | |
267 | goto out_filt; | |
268 | } | |
6be144f6 | 269 | vg->num_vlans++; |
2594e906 NA |
270 | } |
271 | ||
6be144f6 NA |
272 | err = rhashtable_lookup_insert_fast(&vg->vlan_hash, &v->vnode, |
273 | br_vlan_rht_params); | |
2594e906 NA |
274 | if (err) |
275 | goto out_fdb_insert; | |
243a2e63 | 276 | |
2594e906 NA |
277 | __vlan_add_list(v); |
278 | __vlan_add_flags(v, flags); | |
2594e906 NA |
279 | out: |
280 | return err; | |
281 | ||
282 | out_fdb_insert: | |
6be144f6 NA |
283 | if (br_vlan_should_use(v)) { |
284 | br_fdb_find_delete_local(br, p, dev->dev_addr, v->vid); | |
285 | vg->num_vlans--; | |
286 | } | |
2594e906 NA |
287 | |
288 | out_filt: | |
289 | if (p) { | |
290 | __vlan_vid_del(dev, br, v->vid); | |
291 | if (masterv) { | |
f8ed289f | 292 | br_vlan_put_master(masterv); |
2594e906 NA |
293 | v->brvlan = NULL; |
294 | } | |
295 | } | |
296 | ||
297 | goto out; | |
298 | } | |
299 | ||
300 | static int __vlan_del(struct net_bridge_vlan *v) | |
301 | { | |
302 | struct net_bridge_vlan *masterv = v; | |
77751ee8 | 303 | struct net_bridge_vlan_group *vg; |
2594e906 | 304 | struct net_bridge_port *p = NULL; |
2594e906 | 305 | int err = 0; |
552406c4 | 306 | |
2594e906 | 307 | if (br_vlan_is_master(v)) { |
907b1e6e | 308 | vg = br_vlan_group(v->br); |
2594e906 NA |
309 | } else { |
310 | p = v->port; | |
907b1e6e | 311 | vg = nbp_vlan_group(v->port); |
2594e906 | 312 | masterv = v->brvlan; |
2594e906 | 313 | } |
bf361ad3 | 314 | |
77751ee8 | 315 | __vlan_delete_pvid(vg, v->vid); |
2594e906 NA |
316 | if (p) { |
317 | err = __vlan_vid_del(p->dev, p->br, v->vid); | |
bf361ad3 | 318 | if (err) |
2594e906 | 319 | goto out; |
8580e211 | 320 | } |
243a2e63 | 321 | |
6be144f6 NA |
322 | if (br_vlan_should_use(v)) { |
323 | v->flags &= ~BRIDGE_VLAN_INFO_BRENTRY; | |
324 | vg->num_vlans--; | |
2594e906 NA |
325 | } |
326 | ||
327 | if (masterv != v) { | |
efa5356b | 328 | vlan_tunnel_info_del(vg, v); |
77751ee8 NA |
329 | rhashtable_remove_fast(&vg->vlan_hash, &v->vnode, |
330 | br_vlan_rht_params); | |
2594e906 | 331 | __vlan_del_list(v); |
243a2e63 VY |
332 | kfree_rcu(v, rcu); |
333 | } | |
2594e906 | 334 | |
f8ed289f | 335 | br_vlan_put_master(masterv); |
2594e906 NA |
336 | out: |
337 | return err; | |
243a2e63 VY |
338 | } |
339 | ||
f409d0ed NA |
340 | static void __vlan_group_free(struct net_bridge_vlan_group *vg) |
341 | { | |
342 | WARN_ON(!list_empty(&vg->vlan_list)); | |
343 | rhashtable_destroy(&vg->vlan_hash); | |
efa5356b | 344 | vlan_tunnel_deinit(vg); |
f409d0ed NA |
345 | kfree(vg); |
346 | } | |
347 | ||
348 | static void __vlan_flush(struct net_bridge_vlan_group *vg) | |
243a2e63 | 349 | { |
2594e906 NA |
350 | struct net_bridge_vlan *vlan, *tmp; |
351 | ||
f409d0ed NA |
352 | __vlan_delete_pvid(vg, vg->pvid); |
353 | list_for_each_entry_safe(vlan, tmp, &vg->vlan_list, vlist) | |
2594e906 | 354 | __vlan_del(vlan); |
243a2e63 VY |
355 | } |
356 | ||
78851988 | 357 | struct sk_buff *br_handle_vlan(struct net_bridge *br, |
11538d03 | 358 | const struct net_bridge_port *p, |
2594e906 | 359 | struct net_bridge_vlan_group *vg, |
78851988 | 360 | struct sk_buff *skb) |
a37b85c9 | 361 | { |
6dada9b1 | 362 | struct br_vlan_stats *stats; |
2594e906 | 363 | struct net_bridge_vlan *v; |
a37b85c9 VY |
364 | u16 vid; |
365 | ||
20adfa1a VY |
366 | /* If this packet was not filtered at input, let it pass */ |
367 | if (!BR_INPUT_SKB_CB(skb)->vlan_filtered) | |
78851988 VY |
368 | goto out; |
369 | ||
2594e906 NA |
370 | /* At this point, we know that the frame was filtered and contains |
371 | * a valid vlan id. If the vlan id has untagged flag set, | |
372 | * send untagged; otherwise, send tagged. | |
373 | */ | |
374 | br_vlan_get_tag(skb, &vid); | |
375 | v = br_vlan_find(vg, vid); | |
376 | /* Vlan entry must be configured at this point. The | |
fc92f745 VY |
377 | * only exception is the bridge is set in promisc mode and the |
378 | * packet is destined for the bridge device. In this case | |
379 | * pass the packet as is. | |
380 | */ | |
2594e906 | 381 | if (!v || !br_vlan_should_use(v)) { |
fc92f745 VY |
382 | if ((br->dev->flags & IFF_PROMISC) && skb->dev == br->dev) { |
383 | goto out; | |
384 | } else { | |
385 | kfree_skb(skb); | |
386 | return NULL; | |
387 | } | |
388 | } | |
6dada9b1 NA |
389 | if (br->vlan_stats_enabled) { |
390 | stats = this_cpu_ptr(v->stats); | |
391 | u64_stats_update_begin(&stats->syncp); | |
392 | stats->tx_bytes += skb->len; | |
393 | stats->tx_packets++; | |
394 | u64_stats_update_end(&stats->syncp); | |
395 | } | |
396 | ||
2594e906 | 397 | if (v->flags & BRIDGE_VLAN_INFO_UNTAGGED) |
99b192da | 398 | skb->vlan_tci = 0; |
11538d03 RP |
399 | |
400 | if (p && (p->flags & BR_VLAN_TUNNEL) && | |
401 | br_handle_egress_vlan_tunnel(skb, v)) { | |
402 | kfree_skb(skb); | |
403 | return NULL; | |
404 | } | |
78851988 VY |
405 | out: |
406 | return skb; | |
407 | } | |
408 | ||
409 | /* Called under RCU */ | |
6dada9b1 NA |
410 | static bool __allowed_ingress(const struct net_bridge *br, |
411 | struct net_bridge_vlan_group *vg, | |
2594e906 | 412 | struct sk_buff *skb, u16 *vid) |
78851988 | 413 | { |
6dada9b1 NA |
414 | struct br_vlan_stats *stats; |
415 | struct net_bridge_vlan *v; | |
8580e211 | 416 | bool tagged; |
a37b85c9 | 417 | |
20adfa1a | 418 | BR_INPUT_SKB_CB(skb)->vlan_filtered = true; |
12464bb8 TM |
419 | /* If vlan tx offload is disabled on bridge device and frame was |
420 | * sent from vlan device on the bridge device, it does not have | |
421 | * HW accelerated vlan tag. | |
422 | */ | |
df8a39de | 423 | if (unlikely(!skb_vlan_tag_present(skb) && |
6dada9b1 | 424 | skb->protocol == br->vlan_proto)) { |
0d5501c1 | 425 | skb = skb_vlan_untag(skb); |
12464bb8 TM |
426 | if (unlikely(!skb)) |
427 | return false; | |
428 | } | |
429 | ||
8580e211 TM |
430 | if (!br_vlan_get_tag(skb, vid)) { |
431 | /* Tagged frame */ | |
6dada9b1 | 432 | if (skb->vlan_proto != br->vlan_proto) { |
8580e211 TM |
433 | /* Protocol-mismatch, empty out vlan_tci for new tag */ |
434 | skb_push(skb, ETH_HLEN); | |
62749e2c | 435 | skb = vlan_insert_tag_set_proto(skb, skb->vlan_proto, |
df8a39de | 436 | skb_vlan_tag_get(skb)); |
8580e211 TM |
437 | if (unlikely(!skb)) |
438 | return false; | |
439 | ||
440 | skb_pull(skb, ETH_HLEN); | |
441 | skb_reset_mac_len(skb); | |
442 | *vid = 0; | |
443 | tagged = false; | |
444 | } else { | |
445 | tagged = true; | |
446 | } | |
447 | } else { | |
448 | /* Untagged frame */ | |
449 | tagged = false; | |
450 | } | |
451 | ||
b90356ce | 452 | if (!*vid) { |
77751ee8 NA |
453 | u16 pvid = br_get_pvid(vg); |
454 | ||
b90356ce TM |
455 | /* Frame had a tag with VID 0 or did not have a tag. |
456 | * See if pvid is set on this port. That tells us which | |
457 | * vlan untagged or priority-tagged traffic belongs to. | |
78851988 | 458 | */ |
3df6bf45 | 459 | if (!pvid) |
eb707618 | 460 | goto drop; |
78851988 | 461 | |
b90356ce TM |
462 | /* PVID is set on this port. Any untagged or priority-tagged |
463 | * ingress frame is considered to belong to this vlan. | |
78851988 | 464 | */ |
dfb5fa32 | 465 | *vid = pvid; |
8580e211 | 466 | if (likely(!tagged)) |
b90356ce | 467 | /* Untagged Frame. */ |
6dada9b1 | 468 | __vlan_hwaccel_put_tag(skb, br->vlan_proto, pvid); |
b90356ce TM |
469 | else |
470 | /* Priority-tagged Frame. | |
471 | * At this point, We know that skb->vlan_tci had | |
472 | * VLAN_TAG_PRESENT bit and its VID field was 0x000. | |
473 | * We update only VID field and preserve PCP field. | |
474 | */ | |
475 | skb->vlan_tci |= pvid; | |
476 | ||
6dada9b1 NA |
477 | /* if stats are disabled we can avoid the lookup */ |
478 | if (!br->vlan_stats_enabled) | |
479 | return true; | |
78851988 | 480 | } |
77751ee8 | 481 | v = br_vlan_find(vg, *vid); |
6dada9b1 NA |
482 | if (!v || !br_vlan_should_use(v)) |
483 | goto drop; | |
484 | ||
485 | if (br->vlan_stats_enabled) { | |
486 | stats = this_cpu_ptr(v->stats); | |
487 | u64_stats_update_begin(&stats->syncp); | |
488 | stats->rx_bytes += skb->len; | |
489 | stats->rx_packets++; | |
490 | u64_stats_update_end(&stats->syncp); | |
491 | } | |
492 | ||
493 | return true; | |
494 | ||
eb707618 TM |
495 | drop: |
496 | kfree_skb(skb); | |
a37b85c9 VY |
497 | return false; |
498 | } | |
499 | ||
77751ee8 NA |
500 | bool br_allowed_ingress(const struct net_bridge *br, |
501 | struct net_bridge_vlan_group *vg, struct sk_buff *skb, | |
502 | u16 *vid) | |
2594e906 NA |
503 | { |
504 | /* If VLAN filtering is disabled on the bridge, all packets are | |
505 | * permitted. | |
506 | */ | |
507 | if (!br->vlan_enabled) { | |
508 | BR_INPUT_SKB_CB(skb)->vlan_filtered = false; | |
509 | return true; | |
510 | } | |
511 | ||
6dada9b1 | 512 | return __allowed_ingress(br, vg, skb, vid); |
2594e906 NA |
513 | } |
514 | ||
85f46c6b | 515 | /* Called under RCU. */ |
2594e906 | 516 | bool br_allowed_egress(struct net_bridge_vlan_group *vg, |
85f46c6b VY |
517 | const struct sk_buff *skb) |
518 | { | |
2594e906 | 519 | const struct net_bridge_vlan *v; |
85f46c6b VY |
520 | u16 vid; |
521 | ||
20adfa1a VY |
522 | /* If this packet was not filtered at input, let it pass */ |
523 | if (!BR_INPUT_SKB_CB(skb)->vlan_filtered) | |
85f46c6b VY |
524 | return true; |
525 | ||
85f46c6b | 526 | br_vlan_get_tag(skb, &vid); |
2594e906 NA |
527 | v = br_vlan_find(vg, vid); |
528 | if (v && br_vlan_should_use(v)) | |
85f46c6b VY |
529 | return true; |
530 | ||
531 | return false; | |
532 | } | |
533 | ||
e0d7968a TM |
534 | /* Called under RCU */ |
535 | bool br_should_learn(struct net_bridge_port *p, struct sk_buff *skb, u16 *vid) | |
536 | { | |
468e7944 | 537 | struct net_bridge_vlan_group *vg; |
e0d7968a | 538 | struct net_bridge *br = p->br; |
e0d7968a | 539 | |
20adfa1a | 540 | /* If filtering was disabled at input, let it pass. */ |
c095f248 | 541 | if (!br->vlan_enabled) |
e0d7968a TM |
542 | return true; |
543 | ||
eca1e006 | 544 | vg = nbp_vlan_group_rcu(p); |
468e7944 | 545 | if (!vg || !vg->num_vlans) |
e0d7968a TM |
546 | return false; |
547 | ||
8580e211 TM |
548 | if (!br_vlan_get_tag(skb, vid) && skb->vlan_proto != br->vlan_proto) |
549 | *vid = 0; | |
550 | ||
e0d7968a | 551 | if (!*vid) { |
77751ee8 | 552 | *vid = br_get_pvid(vg); |
3df6bf45 | 553 | if (!*vid) |
e0d7968a TM |
554 | return false; |
555 | ||
556 | return true; | |
557 | } | |
558 | ||
77751ee8 | 559 | if (br_vlan_find(vg, *vid)) |
e0d7968a TM |
560 | return true; |
561 | ||
562 | return false; | |
563 | } | |
564 | ||
8adff41c TM |
565 | /* Must be protected by RTNL. |
566 | * Must be called with vid in range from 1 to 4094 inclusive. | |
f418af63 | 567 | * changed must be true only if the vlan was created or updated |
8adff41c | 568 | */ |
f418af63 | 569 | int br_vlan_add(struct net_bridge *br, u16 vid, u16 flags, bool *changed) |
243a2e63 | 570 | { |
907b1e6e | 571 | struct net_bridge_vlan_group *vg; |
2594e906 NA |
572 | struct net_bridge_vlan *vlan; |
573 | int ret; | |
243a2e63 VY |
574 | |
575 | ASSERT_RTNL(); | |
576 | ||
f418af63 | 577 | *changed = false; |
907b1e6e NA |
578 | vg = br_vlan_group(br); |
579 | vlan = br_vlan_find(vg, vid); | |
2594e906 NA |
580 | if (vlan) { |
581 | if (!br_vlan_is_brentry(vlan)) { | |
582 | /* Trying to change flags of non-existent bridge vlan */ | |
583 | if (!(flags & BRIDGE_VLAN_INFO_BRENTRY)) | |
584 | return -EINVAL; | |
585 | /* It was only kept for port vlans, now make it real */ | |
586 | ret = br_fdb_insert(br, NULL, br->dev->dev_addr, | |
587 | vlan->vid); | |
588 | if (ret) { | |
589 | br_err(br, "failed insert local address into bridge forwarding table\n"); | |
590 | return ret; | |
591 | } | |
25127759 | 592 | refcount_inc(&vlan->refcnt); |
2594e906 | 593 | vlan->flags |= BRIDGE_VLAN_INFO_BRENTRY; |
907b1e6e | 594 | vg->num_vlans++; |
f418af63 | 595 | *changed = true; |
2594e906 | 596 | } |
f418af63 NA |
597 | if (__vlan_add_flags(vlan, flags)) |
598 | *changed = true; | |
599 | ||
2594e906 NA |
600 | return 0; |
601 | } | |
243a2e63 | 602 | |
2594e906 NA |
603 | vlan = kzalloc(sizeof(*vlan), GFP_KERNEL); |
604 | if (!vlan) | |
243a2e63 VY |
605 | return -ENOMEM; |
606 | ||
6dada9b1 NA |
607 | vlan->stats = netdev_alloc_pcpu_stats(struct br_vlan_stats); |
608 | if (!vlan->stats) { | |
609 | kfree(vlan); | |
610 | return -ENOMEM; | |
611 | } | |
2594e906 NA |
612 | vlan->vid = vid; |
613 | vlan->flags = flags | BRIDGE_VLAN_INFO_MASTER; | |
614 | vlan->flags &= ~BRIDGE_VLAN_INFO_PVID; | |
615 | vlan->br = br; | |
616 | if (flags & BRIDGE_VLAN_INFO_BRENTRY) | |
25127759 | 617 | refcount_set(&vlan->refcnt, 1); |
2594e906 | 618 | ret = __vlan_add(vlan, flags); |
6dada9b1 NA |
619 | if (ret) { |
620 | free_percpu(vlan->stats); | |
2594e906 | 621 | kfree(vlan); |
f418af63 NA |
622 | } else { |
623 | *changed = true; | |
6dada9b1 | 624 | } |
243a2e63 | 625 | |
2594e906 | 626 | return ret; |
243a2e63 VY |
627 | } |
628 | ||
8adff41c TM |
629 | /* Must be protected by RTNL. |
630 | * Must be called with vid in range from 1 to 4094 inclusive. | |
631 | */ | |
243a2e63 VY |
632 | int br_vlan_delete(struct net_bridge *br, u16 vid) |
633 | { | |
907b1e6e | 634 | struct net_bridge_vlan_group *vg; |
2594e906 | 635 | struct net_bridge_vlan *v; |
243a2e63 VY |
636 | |
637 | ASSERT_RTNL(); | |
638 | ||
907b1e6e NA |
639 | vg = br_vlan_group(br); |
640 | v = br_vlan_find(vg, vid); | |
2594e906 NA |
641 | if (!v || !br_vlan_is_brentry(v)) |
642 | return -ENOENT; | |
243a2e63 | 643 | |
424bb9c9 | 644 | br_fdb_find_delete_local(br, NULL, br->dev->dev_addr, vid); |
3741873b | 645 | br_fdb_delete_by_port(br, NULL, vid, 0); |
bc9a25d2 | 646 | |
efa5356b RP |
647 | vlan_tunnel_info_del(vg, v); |
648 | ||
2594e906 | 649 | return __vlan_del(v); |
243a2e63 VY |
650 | } |
651 | ||
652 | void br_vlan_flush(struct net_bridge *br) | |
653 | { | |
f409d0ed NA |
654 | struct net_bridge_vlan_group *vg; |
655 | ||
243a2e63 | 656 | ASSERT_RTNL(); |
243a2e63 | 657 | |
f409d0ed NA |
658 | vg = br_vlan_group(br); |
659 | __vlan_flush(vg); | |
660 | RCU_INIT_POINTER(br->vlgrp, NULL); | |
661 | synchronize_rcu(); | |
662 | __vlan_group_free(vg); | |
243a2e63 VY |
663 | } |
664 | ||
2594e906 | 665 | struct net_bridge_vlan *br_vlan_find(struct net_bridge_vlan_group *vg, u16 vid) |
2b292fb4 | 666 | { |
2594e906 NA |
667 | if (!vg) |
668 | return NULL; | |
2b292fb4 | 669 | |
2594e906 | 670 | return br_vlan_lookup(&vg->vlan_hash, vid); |
2b292fb4 TM |
671 | } |
672 | ||
204177f3 TM |
673 | /* Must be protected by RTNL. */ |
674 | static void recalculate_group_addr(struct net_bridge *br) | |
675 | { | |
676 | if (br->group_addr_set) | |
677 | return; | |
678 | ||
679 | spin_lock_bh(&br->lock); | |
680 | if (!br->vlan_enabled || br->vlan_proto == htons(ETH_P_8021Q)) { | |
681 | /* Bridge Group Address */ | |
682 | br->group_addr[5] = 0x00; | |
683 | } else { /* vlan_enabled && ETH_P_8021AD */ | |
684 | /* Provider Bridge Group Address */ | |
685 | br->group_addr[5] = 0x08; | |
686 | } | |
687 | spin_unlock_bh(&br->lock); | |
688 | } | |
689 | ||
690 | /* Must be protected by RTNL. */ | |
691 | void br_recalculate_fwd_mask(struct net_bridge *br) | |
692 | { | |
693 | if (!br->vlan_enabled || br->vlan_proto == htons(ETH_P_8021Q)) | |
694 | br->group_fwd_mask_required = BR_GROUPFWD_DEFAULT; | |
695 | else /* vlan_enabled && ETH_P_8021AD */ | |
696 | br->group_fwd_mask_required = BR_GROUPFWD_8021AD & | |
697 | ~(1u << br->group_addr[5]); | |
698 | } | |
699 | ||
a7854037 | 700 | int __br_vlan_filter_toggle(struct net_bridge *br, unsigned long val) |
243a2e63 | 701 | { |
6b72a770 ER |
702 | struct switchdev_attr attr = { |
703 | .orig_dev = br->dev, | |
704 | .id = SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING, | |
705 | .flags = SWITCHDEV_F_SKIP_EOPNOTSUPP, | |
706 | .u.vlan_filtering = val, | |
707 | }; | |
708 | int err; | |
709 | ||
243a2e63 | 710 | if (br->vlan_enabled == val) |
a7854037 | 711 | return 0; |
243a2e63 | 712 | |
6b72a770 ER |
713 | err = switchdev_port_attr_set(br->dev, &attr); |
714 | if (err && err != -EOPNOTSUPP) | |
715 | return err; | |
716 | ||
243a2e63 | 717 | br->vlan_enabled = val; |
2796d0c6 | 718 | br_manage_promisc(br); |
204177f3 TM |
719 | recalculate_group_addr(br); |
720 | br_recalculate_fwd_mask(br); | |
243a2e63 | 721 | |
a7854037 NA |
722 | return 0; |
723 | } | |
724 | ||
725 | int br_vlan_filter_toggle(struct net_bridge *br, unsigned long val) | |
726 | { | |
047831a9 | 727 | return __br_vlan_filter_toggle(br, val); |
243a2e63 VY |
728 | } |
729 | ||
1f51445a IS |
730 | bool br_vlan_enabled(const struct net_device *dev) |
731 | { | |
732 | struct net_bridge *br = netdev_priv(dev); | |
733 | ||
734 | return !!br->vlan_enabled; | |
735 | } | |
736 | EXPORT_SYMBOL_GPL(br_vlan_enabled); | |
737 | ||
d2d427b3 | 738 | int __br_vlan_set_proto(struct net_bridge *br, __be16 proto) |
204177f3 TM |
739 | { |
740 | int err = 0; | |
741 | struct net_bridge_port *p; | |
2594e906 | 742 | struct net_bridge_vlan *vlan; |
907b1e6e | 743 | struct net_bridge_vlan_group *vg; |
d2d427b3 | 744 | __be16 oldproto; |
204177f3 | 745 | |
204177f3 | 746 | if (br->vlan_proto == proto) |
d2d427b3 | 747 | return 0; |
204177f3 TM |
748 | |
749 | /* Add VLANs for the new proto to the device filter. */ | |
750 | list_for_each_entry(p, &br->port_list, list) { | |
907b1e6e NA |
751 | vg = nbp_vlan_group(p); |
752 | list_for_each_entry(vlan, &vg->vlan_list, vlist) { | |
2594e906 | 753 | err = vlan_vid_add(p->dev, proto, vlan->vid); |
204177f3 TM |
754 | if (err) |
755 | goto err_filt; | |
756 | } | |
757 | } | |
758 | ||
759 | oldproto = br->vlan_proto; | |
760 | br->vlan_proto = proto; | |
761 | ||
762 | recalculate_group_addr(br); | |
763 | br_recalculate_fwd_mask(br); | |
764 | ||
765 | /* Delete VLANs for the old proto from the device filter. */ | |
907b1e6e NA |
766 | list_for_each_entry(p, &br->port_list, list) { |
767 | vg = nbp_vlan_group(p); | |
768 | list_for_each_entry(vlan, &vg->vlan_list, vlist) | |
2594e906 | 769 | vlan_vid_del(p->dev, oldproto, vlan->vid); |
907b1e6e | 770 | } |
204177f3 | 771 | |
d2d427b3 | 772 | return 0; |
204177f3 TM |
773 | |
774 | err_filt: | |
907b1e6e | 775 | list_for_each_entry_continue_reverse(vlan, &vg->vlan_list, vlist) |
2594e906 | 776 | vlan_vid_del(p->dev, proto, vlan->vid); |
204177f3 | 777 | |
907b1e6e NA |
778 | list_for_each_entry_continue_reverse(p, &br->port_list, list) { |
779 | vg = nbp_vlan_group(p); | |
780 | list_for_each_entry(vlan, &vg->vlan_list, vlist) | |
2594e906 | 781 | vlan_vid_del(p->dev, proto, vlan->vid); |
907b1e6e | 782 | } |
204177f3 | 783 | |
d2d427b3 TM |
784 | return err; |
785 | } | |
786 | ||
787 | int br_vlan_set_proto(struct net_bridge *br, unsigned long val) | |
788 | { | |
d2d427b3 TM |
789 | if (val != ETH_P_8021Q && val != ETH_P_8021AD) |
790 | return -EPROTONOSUPPORT; | |
791 | ||
047831a9 | 792 | return __br_vlan_set_proto(br, htons(val)); |
204177f3 TM |
793 | } |
794 | ||
6dada9b1 NA |
795 | int br_vlan_set_stats(struct net_bridge *br, unsigned long val) |
796 | { | |
797 | switch (val) { | |
798 | case 0: | |
799 | case 1: | |
800 | br->vlan_stats_enabled = val; | |
801 | break; | |
802 | default: | |
803 | return -EINVAL; | |
804 | } | |
805 | ||
806 | return 0; | |
807 | } | |
808 | ||
77751ee8 | 809 | static bool vlan_default_pvid(struct net_bridge_vlan_group *vg, u16 vid) |
5be5a2df | 810 | { |
2594e906 NA |
811 | struct net_bridge_vlan *v; |
812 | ||
77751ee8 | 813 | if (vid != vg->pvid) |
2594e906 NA |
814 | return false; |
815 | ||
816 | v = br_vlan_lookup(&vg->vlan_hash, vid); | |
817 | if (v && br_vlan_should_use(v) && | |
818 | (v->flags & BRIDGE_VLAN_INFO_UNTAGGED)) | |
819 | return true; | |
820 | ||
821 | return false; | |
5be5a2df VY |
822 | } |
823 | ||
824 | static void br_vlan_disable_default_pvid(struct net_bridge *br) | |
825 | { | |
826 | struct net_bridge_port *p; | |
827 | u16 pvid = br->default_pvid; | |
828 | ||
829 | /* Disable default_pvid on all ports where it is still | |
830 | * configured. | |
831 | */ | |
907b1e6e | 832 | if (vlan_default_pvid(br_vlan_group(br), pvid)) |
5be5a2df VY |
833 | br_vlan_delete(br, pvid); |
834 | ||
835 | list_for_each_entry(p, &br->port_list, list) { | |
907b1e6e | 836 | if (vlan_default_pvid(nbp_vlan_group(p), pvid)) |
5be5a2df VY |
837 | nbp_vlan_delete(p, pvid); |
838 | } | |
839 | ||
840 | br->default_pvid = 0; | |
841 | } | |
842 | ||
0f963b75 | 843 | int __br_vlan_set_default_pvid(struct net_bridge *br, u16 pvid) |
5be5a2df | 844 | { |
2594e906 | 845 | const struct net_bridge_vlan *pvent; |
907b1e6e | 846 | struct net_bridge_vlan_group *vg; |
5be5a2df | 847 | struct net_bridge_port *p; |
f418af63 NA |
848 | unsigned long *changed; |
849 | bool vlchange; | |
5be5a2df VY |
850 | u16 old_pvid; |
851 | int err = 0; | |
5be5a2df | 852 | |
0f963b75 NA |
853 | if (!pvid) { |
854 | br_vlan_disable_default_pvid(br); | |
855 | return 0; | |
856 | } | |
857 | ||
5be5a2df VY |
858 | changed = kcalloc(BITS_TO_LONGS(BR_MAX_PORTS), sizeof(unsigned long), |
859 | GFP_KERNEL); | |
860 | if (!changed) | |
861 | return -ENOMEM; | |
862 | ||
863 | old_pvid = br->default_pvid; | |
864 | ||
865 | /* Update default_pvid config only if we do not conflict with | |
866 | * user configuration. | |
867 | */ | |
907b1e6e NA |
868 | vg = br_vlan_group(br); |
869 | pvent = br_vlan_find(vg, pvid); | |
870 | if ((!old_pvid || vlan_default_pvid(vg, old_pvid)) && | |
2594e906 | 871 | (!pvent || !br_vlan_should_use(pvent))) { |
5be5a2df VY |
872 | err = br_vlan_add(br, pvid, |
873 | BRIDGE_VLAN_INFO_PVID | | |
2594e906 | 874 | BRIDGE_VLAN_INFO_UNTAGGED | |
f418af63 NA |
875 | BRIDGE_VLAN_INFO_BRENTRY, |
876 | &vlchange); | |
5be5a2df VY |
877 | if (err) |
878 | goto out; | |
879 | br_vlan_delete(br, old_pvid); | |
880 | set_bit(0, changed); | |
881 | } | |
882 | ||
883 | list_for_each_entry(p, &br->port_list, list) { | |
884 | /* Update default_pvid config only if we do not conflict with | |
885 | * user configuration. | |
886 | */ | |
907b1e6e | 887 | vg = nbp_vlan_group(p); |
5be5a2df | 888 | if ((old_pvid && |
907b1e6e NA |
889 | !vlan_default_pvid(vg, old_pvid)) || |
890 | br_vlan_find(vg, pvid)) | |
5be5a2df VY |
891 | continue; |
892 | ||
893 | err = nbp_vlan_add(p, pvid, | |
894 | BRIDGE_VLAN_INFO_PVID | | |
f418af63 NA |
895 | BRIDGE_VLAN_INFO_UNTAGGED, |
896 | &vlchange); | |
5be5a2df VY |
897 | if (err) |
898 | goto err_port; | |
899 | nbp_vlan_delete(p, old_pvid); | |
900 | set_bit(p->port_no, changed); | |
901 | } | |
902 | ||
903 | br->default_pvid = pvid; | |
904 | ||
905 | out: | |
906 | kfree(changed); | |
907 | return err; | |
908 | ||
909 | err_port: | |
910 | list_for_each_entry_continue_reverse(p, &br->port_list, list) { | |
911 | if (!test_bit(p->port_no, changed)) | |
912 | continue; | |
913 | ||
914 | if (old_pvid) | |
915 | nbp_vlan_add(p, old_pvid, | |
916 | BRIDGE_VLAN_INFO_PVID | | |
f418af63 NA |
917 | BRIDGE_VLAN_INFO_UNTAGGED, |
918 | &vlchange); | |
5be5a2df VY |
919 | nbp_vlan_delete(p, pvid); |
920 | } | |
921 | ||
922 | if (test_bit(0, changed)) { | |
923 | if (old_pvid) | |
924 | br_vlan_add(br, old_pvid, | |
925 | BRIDGE_VLAN_INFO_PVID | | |
2594e906 | 926 | BRIDGE_VLAN_INFO_UNTAGGED | |
f418af63 NA |
927 | BRIDGE_VLAN_INFO_BRENTRY, |
928 | &vlchange); | |
5be5a2df VY |
929 | br_vlan_delete(br, pvid); |
930 | } | |
931 | goto out; | |
932 | } | |
933 | ||
96a20d9d VY |
934 | int br_vlan_set_default_pvid(struct net_bridge *br, unsigned long val) |
935 | { | |
936 | u16 pvid = val; | |
937 | int err = 0; | |
938 | ||
5be5a2df | 939 | if (val >= VLAN_VID_MASK) |
96a20d9d VY |
940 | return -EINVAL; |
941 | ||
96a20d9d | 942 | if (pvid == br->default_pvid) |
047831a9 | 943 | goto out; |
96a20d9d VY |
944 | |
945 | /* Only allow default pvid change when filtering is disabled */ | |
946 | if (br->vlan_enabled) { | |
947 | pr_info_once("Please disable vlan filtering to change default_pvid\n"); | |
948 | err = -EPERM; | |
047831a9 | 949 | goto out; |
96a20d9d | 950 | } |
0f963b75 | 951 | err = __br_vlan_set_default_pvid(br, pvid); |
047831a9 | 952 | out: |
96a20d9d VY |
953 | return err; |
954 | } | |
955 | ||
5be5a2df | 956 | int br_vlan_init(struct net_bridge *br) |
8580e211 | 957 | { |
907b1e6e | 958 | struct net_bridge_vlan_group *vg; |
2594e906 | 959 | int ret = -ENOMEM; |
f418af63 | 960 | bool changed; |
2594e906 | 961 | |
907b1e6e NA |
962 | vg = kzalloc(sizeof(*vg), GFP_KERNEL); |
963 | if (!vg) | |
2594e906 | 964 | goto out; |
907b1e6e | 965 | ret = rhashtable_init(&vg->vlan_hash, &br_vlan_rht_params); |
2594e906 NA |
966 | if (ret) |
967 | goto err_rhtbl; | |
efa5356b RP |
968 | ret = vlan_tunnel_init(vg); |
969 | if (ret) | |
970 | goto err_tunnel_init; | |
907b1e6e | 971 | INIT_LIST_HEAD(&vg->vlan_list); |
8580e211 | 972 | br->vlan_proto = htons(ETH_P_8021Q); |
96a20d9d | 973 | br->default_pvid = 1; |
907b1e6e | 974 | rcu_assign_pointer(br->vlgrp, vg); |
2594e906 NA |
975 | ret = br_vlan_add(br, 1, |
976 | BRIDGE_VLAN_INFO_PVID | BRIDGE_VLAN_INFO_UNTAGGED | | |
f418af63 | 977 | BRIDGE_VLAN_INFO_BRENTRY, &changed); |
2594e906 NA |
978 | if (ret) |
979 | goto err_vlan_add; | |
980 | ||
981 | out: | |
982 | return ret; | |
983 | ||
984 | err_vlan_add: | |
efa5356b RP |
985 | vlan_tunnel_deinit(vg); |
986 | err_tunnel_init: | |
907b1e6e | 987 | rhashtable_destroy(&vg->vlan_hash); |
2594e906 | 988 | err_rhtbl: |
907b1e6e | 989 | kfree(vg); |
2594e906 NA |
990 | |
991 | goto out; | |
992 | } | |
993 | ||
994 | int nbp_vlan_init(struct net_bridge_port *p) | |
995 | { | |
404cdbf0 ER |
996 | struct switchdev_attr attr = { |
997 | .orig_dev = p->br->dev, | |
998 | .id = SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING, | |
999 | .flags = SWITCHDEV_F_SKIP_EOPNOTSUPP, | |
1000 | .u.vlan_filtering = p->br->vlan_enabled, | |
1001 | }; | |
263344e6 | 1002 | struct net_bridge_vlan_group *vg; |
2594e906 NA |
1003 | int ret = -ENOMEM; |
1004 | ||
263344e6 NA |
1005 | vg = kzalloc(sizeof(struct net_bridge_vlan_group), GFP_KERNEL); |
1006 | if (!vg) | |
2594e906 NA |
1007 | goto out; |
1008 | ||
404cdbf0 ER |
1009 | ret = switchdev_port_attr_set(p->dev, &attr); |
1010 | if (ret && ret != -EOPNOTSUPP) | |
1011 | goto err_vlan_enabled; | |
1012 | ||
263344e6 | 1013 | ret = rhashtable_init(&vg->vlan_hash, &br_vlan_rht_params); |
2594e906 NA |
1014 | if (ret) |
1015 | goto err_rhtbl; | |
efa5356b RP |
1016 | ret = vlan_tunnel_init(vg); |
1017 | if (ret) | |
1018 | goto err_tunnel_init; | |
263344e6 | 1019 | INIT_LIST_HEAD(&vg->vlan_list); |
907b1e6e | 1020 | rcu_assign_pointer(p->vlgrp, vg); |
2594e906 | 1021 | if (p->br->default_pvid) { |
f418af63 NA |
1022 | bool changed; |
1023 | ||
2594e906 NA |
1024 | ret = nbp_vlan_add(p, p->br->default_pvid, |
1025 | BRIDGE_VLAN_INFO_PVID | | |
f418af63 NA |
1026 | BRIDGE_VLAN_INFO_UNTAGGED, |
1027 | &changed); | |
2594e906 NA |
1028 | if (ret) |
1029 | goto err_vlan_add; | |
1030 | } | |
1031 | out: | |
1032 | return ret; | |
1033 | ||
1034 | err_vlan_add: | |
07bc588f IS |
1035 | RCU_INIT_POINTER(p->vlgrp, NULL); |
1036 | synchronize_rcu(); | |
efa5356b | 1037 | vlan_tunnel_deinit(vg); |
efa5356b RP |
1038 | err_tunnel_init: |
1039 | rhashtable_destroy(&vg->vlan_hash); | |
2594e906 | 1040 | err_rhtbl: |
df2c4334 | 1041 | err_vlan_enabled: |
263344e6 | 1042 | kfree(vg); |
2594e906 NA |
1043 | |
1044 | goto out; | |
8580e211 TM |
1045 | } |
1046 | ||
8adff41c TM |
1047 | /* Must be protected by RTNL. |
1048 | * Must be called with vid in range from 1 to 4094 inclusive. | |
f418af63 | 1049 | * changed must be true only if the vlan was created or updated |
8adff41c | 1050 | */ |
f418af63 NA |
1051 | int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags, |
1052 | bool *changed) | |
243a2e63 | 1053 | { |
7fbac984 IS |
1054 | struct switchdev_obj_port_vlan v = { |
1055 | .obj.orig_dev = port->dev, | |
1056 | .obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN, | |
1057 | .flags = flags, | |
1058 | .vid_begin = vid, | |
1059 | .vid_end = vid, | |
1060 | }; | |
2594e906 NA |
1061 | struct net_bridge_vlan *vlan; |
1062 | int ret; | |
243a2e63 VY |
1063 | |
1064 | ASSERT_RTNL(); | |
1065 | ||
f418af63 | 1066 | *changed = false; |
907b1e6e | 1067 | vlan = br_vlan_find(nbp_vlan_group(port), vid); |
2594e906 | 1068 | if (vlan) { |
7fbac984 IS |
1069 | /* Pass the flags to the hardware bridge */ |
1070 | ret = switchdev_port_obj_add(port->dev, &v.obj); | |
1071 | if (ret && ret != -EOPNOTSUPP) | |
1072 | return ret; | |
f418af63 NA |
1073 | *changed = __vlan_add_flags(vlan, flags); |
1074 | ||
2594e906 | 1075 | return 0; |
243a2e63 VY |
1076 | } |
1077 | ||
2594e906 NA |
1078 | vlan = kzalloc(sizeof(*vlan), GFP_KERNEL); |
1079 | if (!vlan) | |
1080 | return -ENOMEM; | |
243a2e63 | 1081 | |
2594e906 NA |
1082 | vlan->vid = vid; |
1083 | vlan->port = port; | |
1084 | ret = __vlan_add(vlan, flags); | |
1085 | if (ret) | |
1086 | kfree(vlan); | |
f418af63 NA |
1087 | else |
1088 | *changed = true; | |
243a2e63 | 1089 | |
2594e906 | 1090 | return ret; |
243a2e63 VY |
1091 | } |
1092 | ||
8adff41c TM |
1093 | /* Must be protected by RTNL. |
1094 | * Must be called with vid in range from 1 to 4094 inclusive. | |
1095 | */ | |
243a2e63 VY |
1096 | int nbp_vlan_delete(struct net_bridge_port *port, u16 vid) |
1097 | { | |
2594e906 | 1098 | struct net_bridge_vlan *v; |
243a2e63 VY |
1099 | |
1100 | ASSERT_RTNL(); | |
1101 | ||
907b1e6e | 1102 | v = br_vlan_find(nbp_vlan_group(port), vid); |
2594e906 NA |
1103 | if (!v) |
1104 | return -ENOENT; | |
424bb9c9 | 1105 | br_fdb_find_delete_local(port->br, port, port->dev->dev_addr, vid); |
1ea2d020 | 1106 | br_fdb_delete_by_port(port->br, port, vid, 0); |
bc9a25d2 | 1107 | |
2594e906 | 1108 | return __vlan_del(v); |
243a2e63 VY |
1109 | } |
1110 | ||
1111 | void nbp_vlan_flush(struct net_bridge_port *port) | |
1112 | { | |
f409d0ed NA |
1113 | struct net_bridge_vlan_group *vg; |
1114 | ||
243a2e63 VY |
1115 | ASSERT_RTNL(); |
1116 | ||
f409d0ed NA |
1117 | vg = nbp_vlan_group(port); |
1118 | __vlan_flush(vg); | |
1119 | RCU_INIT_POINTER(port->vlgrp, NULL); | |
1120 | synchronize_rcu(); | |
1121 | __vlan_group_free(vg); | |
5be5a2df | 1122 | } |
a60c0903 NA |
1123 | |
1124 | void br_vlan_get_stats(const struct net_bridge_vlan *v, | |
1125 | struct br_vlan_stats *stats) | |
1126 | { | |
1127 | int i; | |
1128 | ||
1129 | memset(stats, 0, sizeof(*stats)); | |
1130 | for_each_possible_cpu(i) { | |
1131 | u64 rxpackets, rxbytes, txpackets, txbytes; | |
1132 | struct br_vlan_stats *cpu_stats; | |
1133 | unsigned int start; | |
1134 | ||
1135 | cpu_stats = per_cpu_ptr(v->stats, i); | |
1136 | do { | |
1137 | start = u64_stats_fetch_begin_irq(&cpu_stats->syncp); | |
1138 | rxpackets = cpu_stats->rx_packets; | |
1139 | rxbytes = cpu_stats->rx_bytes; | |
1140 | txbytes = cpu_stats->tx_bytes; | |
1141 | txpackets = cpu_stats->tx_packets; | |
1142 | } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start)); | |
1143 | ||
1144 | stats->rx_packets += rxpackets; | |
1145 | stats->rx_bytes += rxbytes; | |
1146 | stats->tx_bytes += txbytes; | |
1147 | stats->tx_packets += txpackets; | |
1148 | } | |
1149 | } |