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