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