1457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2243a2e63SVlad Yasevich #include <linux/kernel.h>
3243a2e63SVlad Yasevich #include <linux/netdevice.h>
4243a2e63SVlad Yasevich #include <linux/rtnetlink.h>
5243a2e63SVlad Yasevich #include <linux/slab.h>
67f109539SScott Feldman #include <net/switchdev.h>
7243a2e63SVlad Yasevich
8243a2e63SVlad Yasevich #include "br_private.h"
9efa5356bSRoopa Prabhu #include "br_private_tunnel.h"
10243a2e63SVlad Yasevich
1180900acdSMike Manning static void nbp_vlan_set_vlan_dev_state(struct net_bridge_port *p, u16 vid);
1280900acdSMike Manning
br_vlan_cmp(struct rhashtable_compare_arg * arg,const void * ptr)132594e906SNikolay Aleksandrov static inline int br_vlan_cmp(struct rhashtable_compare_arg *arg,
142594e906SNikolay Aleksandrov const void *ptr)
15552406c4SVlad Yasevich {
162594e906SNikolay Aleksandrov const struct net_bridge_vlan *vle = ptr;
172594e906SNikolay Aleksandrov u16 vid = *(u16 *)arg->key;
182594e906SNikolay Aleksandrov
192594e906SNikolay Aleksandrov return vle->vid != vid;
202594e906SNikolay Aleksandrov }
212594e906SNikolay Aleksandrov
222594e906SNikolay Aleksandrov static const struct rhashtable_params br_vlan_rht_params = {
232594e906SNikolay Aleksandrov .head_offset = offsetof(struct net_bridge_vlan, vnode),
242594e906SNikolay Aleksandrov .key_offset = offsetof(struct net_bridge_vlan, vid),
252594e906SNikolay Aleksandrov .key_len = sizeof(u16),
268af78b64SNikolay Aleksandrov .nelem_hint = 3,
272594e906SNikolay Aleksandrov .max_size = VLAN_N_VID,
282594e906SNikolay Aleksandrov .obj_cmpfn = br_vlan_cmp,
292594e906SNikolay Aleksandrov .automatic_shrinking = true,
302594e906SNikolay Aleksandrov };
312594e906SNikolay Aleksandrov
br_vlan_lookup(struct rhashtable * tbl,u16 vid)322594e906SNikolay Aleksandrov static struct net_bridge_vlan *br_vlan_lookup(struct rhashtable *tbl, u16 vid)
332594e906SNikolay Aleksandrov {
342594e906SNikolay Aleksandrov return rhashtable_lookup_fast(tbl, &vid, br_vlan_rht_params);
352594e906SNikolay Aleksandrov }
362594e906SNikolay Aleksandrov
__vlan_add_pvid(struct net_bridge_vlan_group * vg,const struct net_bridge_vlan * v)3727c5f74cSVladimir Oltean static void __vlan_add_pvid(struct net_bridge_vlan_group *vg,
38a580c76dSNikolay Aleksandrov const struct net_bridge_vlan *v)
392594e906SNikolay Aleksandrov {
40a580c76dSNikolay Aleksandrov if (vg->pvid == v->vid)
4127c5f74cSVladimir Oltean return;
42552406c4SVlad Yasevich
43552406c4SVlad Yasevich smp_wmb();
44a580c76dSNikolay Aleksandrov br_vlan_set_pvid_state(vg, v->state);
45a580c76dSNikolay Aleksandrov vg->pvid = v->vid;
46552406c4SVlad Yasevich }
47552406c4SVlad Yasevich
__vlan_delete_pvid(struct net_bridge_vlan_group * vg,u16 vid)4827c5f74cSVladimir Oltean static void __vlan_delete_pvid(struct net_bridge_vlan_group *vg, u16 vid)
49552406c4SVlad Yasevich {
5077751ee8SNikolay Aleksandrov if (vg->pvid != vid)
5127c5f74cSVladimir Oltean return;
52552406c4SVlad Yasevich
53552406c4SVlad Yasevich smp_wmb();
5477751ee8SNikolay Aleksandrov vg->pvid = 0;
55552406c4SVlad Yasevich }
56552406c4SVlad Yasevich
5727c5f74cSVladimir Oltean /* Update the BRIDGE_VLAN_INFO_PVID and BRIDGE_VLAN_INFO_UNTAGGED flags of @v.
5827c5f74cSVladimir Oltean * If @commit is false, return just whether the BRIDGE_VLAN_INFO_PVID and
5927c5f74cSVladimir Oltean * BRIDGE_VLAN_INFO_UNTAGGED bits of @flags would produce any change onto @v.
60cab2cd77SVladimir Oltean */
__vlan_flags_update(struct net_bridge_vlan * v,u16 flags,bool commit)6127c5f74cSVladimir Oltean static bool __vlan_flags_update(struct net_bridge_vlan *v, u16 flags,
6227c5f74cSVladimir Oltean bool commit)
6335e03f3aSVlad Yasevich {
6477751ee8SNikolay Aleksandrov struct net_bridge_vlan_group *vg;
6527c5f74cSVladimir Oltean bool change;
6677751ee8SNikolay Aleksandrov
672594e906SNikolay Aleksandrov if (br_vlan_is_master(v))
68907b1e6eSNikolay Aleksandrov vg = br_vlan_group(v->br);
69635126b7SVlad Yasevich else
70907b1e6eSNikolay Aleksandrov vg = nbp_vlan_group(v->port);
7177751ee8SNikolay Aleksandrov
7227c5f74cSVladimir Oltean /* check if anything would be changed on commit */
7327c5f74cSVladimir Oltean change = !!(flags & BRIDGE_VLAN_INFO_PVID) == !!(vg->pvid != v->vid) ||
7427c5f74cSVladimir Oltean ((flags ^ v->flags) & BRIDGE_VLAN_INFO_UNTAGGED);
7527c5f74cSVladimir Oltean
7627c5f74cSVladimir Oltean if (!commit)
7727c5f74cSVladimir Oltean goto out;
7827c5f74cSVladimir Oltean
7977751ee8SNikolay Aleksandrov if (flags & BRIDGE_VLAN_INFO_PVID)
8027c5f74cSVladimir Oltean __vlan_add_pvid(vg, v);
812594e906SNikolay Aleksandrov else
8227c5f74cSVladimir Oltean __vlan_delete_pvid(vg, v->vid);
8335e03f3aSVlad Yasevich
8435e03f3aSVlad Yasevich if (flags & BRIDGE_VLAN_INFO_UNTAGGED)
852594e906SNikolay Aleksandrov v->flags |= BRIDGE_VLAN_INFO_UNTAGGED;
86635126b7SVlad Yasevich else
872594e906SNikolay Aleksandrov v->flags &= ~BRIDGE_VLAN_INFO_UNTAGGED;
88f418af63SNikolay Aleksandrov
8927c5f74cSVladimir Oltean out:
9027c5f74cSVladimir Oltean return change;
9127c5f74cSVladimir Oltean }
9227c5f74cSVladimir Oltean
__vlan_flags_would_change(struct net_bridge_vlan * v,u16 flags)9327c5f74cSVladimir Oltean static bool __vlan_flags_would_change(struct net_bridge_vlan *v, u16 flags)
9427c5f74cSVladimir Oltean {
9527c5f74cSVladimir Oltean return __vlan_flags_update(v, flags, false);
9627c5f74cSVladimir Oltean }
9727c5f74cSVladimir Oltean
__vlan_flags_commit(struct net_bridge_vlan * v,u16 flags)9827c5f74cSVladimir Oltean static void __vlan_flags_commit(struct net_bridge_vlan *v, u16 flags)
9927c5f74cSVladimir Oltean {
10027c5f74cSVladimir Oltean __vlan_flags_update(v, flags, true);
10135e03f3aSVlad Yasevich }
10235e03f3aSVlad Yasevich
__vlan_vid_add(struct net_device * dev,struct net_bridge * br,struct net_bridge_vlan * v,u16 flags,struct netlink_ext_ack * extack)1037f109539SScott Feldman static int __vlan_vid_add(struct net_device *dev, struct net_bridge *br,
10427973793SIdo Schimmel struct net_bridge_vlan *v, u16 flags,
10527973793SIdo Schimmel struct netlink_ext_ack *extack)
1067f109539SScott Feldman {
1070944d6b5SJiri Pirko int err;
1087f109539SScott Feldman
1090944d6b5SJiri Pirko /* Try switchdev op first. In case it is not supported, fallback to
1100944d6b5SJiri Pirko * 8021q add.
1110944d6b5SJiri Pirko */
1128d23a54fSVladimir Oltean err = br_switchdev_port_vlan_add(dev, v->vid, flags, false, extack);
1137f109539SScott Feldman if (err == -EOPNOTSUPP)
11427973793SIdo Schimmel return vlan_vid_add(dev, br->vlan_proto, v->vid);
11527973793SIdo Schimmel v->priv_flags |= BR_VLFLAG_ADDED_BY_SWITCHDEV;
1167f109539SScott Feldman return err;
1177f109539SScott Feldman }
1187f109539SScott Feldman
__vlan_add_list(struct net_bridge_vlan * v)1192594e906SNikolay Aleksandrov static void __vlan_add_list(struct net_bridge_vlan *v)
120243a2e63SVlad Yasevich {
121907b1e6eSNikolay Aleksandrov struct net_bridge_vlan_group *vg;
1222594e906SNikolay Aleksandrov struct list_head *headp, *hpos;
1232594e906SNikolay Aleksandrov struct net_bridge_vlan *vent;
124243a2e63SVlad Yasevich
125907b1e6eSNikolay Aleksandrov if (br_vlan_is_master(v))
126907b1e6eSNikolay Aleksandrov vg = br_vlan_group(v->br);
127907b1e6eSNikolay Aleksandrov else
128907b1e6eSNikolay Aleksandrov vg = nbp_vlan_group(v->port);
129907b1e6eSNikolay Aleksandrov
130907b1e6eSNikolay Aleksandrov headp = &vg->vlan_list;
1312594e906SNikolay Aleksandrov list_for_each_prev(hpos, headp) {
1322594e906SNikolay Aleksandrov vent = list_entry(hpos, struct net_bridge_vlan, vlist);
133040c1257SColin Ian King if (v->vid >= vent->vid)
1342594e906SNikolay Aleksandrov break;
1352594e906SNikolay Aleksandrov }
136586c2b57SNikolay Aleksandrov list_add_rcu(&v->vlist, hpos);
137552406c4SVlad Yasevich }
138243a2e63SVlad Yasevich
__vlan_del_list(struct net_bridge_vlan * v)1392594e906SNikolay Aleksandrov static void __vlan_del_list(struct net_bridge_vlan *v)
1402594e906SNikolay Aleksandrov {
141586c2b57SNikolay Aleksandrov list_del_rcu(&v->vlist);
142243a2e63SVlad Yasevich }
143243a2e63SVlad Yasevich
__vlan_vid_del(struct net_device * dev,struct net_bridge * br,const struct net_bridge_vlan * v)144bf361ad3SVivien Didelot static int __vlan_vid_del(struct net_device *dev, struct net_bridge *br,
14527973793SIdo Schimmel const struct net_bridge_vlan *v)
1467f109539SScott Feldman {
1470944d6b5SJiri Pirko int err;
1487f109539SScott Feldman
1490944d6b5SJiri Pirko /* Try switchdev op first. In case it is not supported, fallback to
1500944d6b5SJiri Pirko * 8021q del.
1510944d6b5SJiri Pirko */
15227973793SIdo Schimmel err = br_switchdev_port_vlan_del(dev, v->vid);
15327973793SIdo Schimmel if (!(v->priv_flags & BR_VLFLAG_ADDED_BY_SWITCHDEV))
15427973793SIdo Schimmel vlan_vid_del(dev, br->vlan_proto, v->vid);
15527973793SIdo Schimmel return err == -EOPNOTSUPP ? 0 : err;
1567f109539SScott Feldman }
1577f109539SScott Feldman
1584bbd026cSRandy Dunlap /* Returns a master vlan, if it didn't exist it gets created. In all cases
159f8ed289fSNikolay Aleksandrov * a reference is taken to the master vlan before returning.
160f8ed289fSNikolay Aleksandrov */
161169327d5SPetr Machata static struct net_bridge_vlan *
br_vlan_get_master(struct net_bridge * br,u16 vid,struct netlink_ext_ack * extack)162169327d5SPetr Machata br_vlan_get_master(struct net_bridge *br, u16 vid,
163169327d5SPetr Machata struct netlink_ext_ack *extack)
164f8ed289fSNikolay Aleksandrov {
165907b1e6eSNikolay Aleksandrov struct net_bridge_vlan_group *vg;
166f8ed289fSNikolay Aleksandrov struct net_bridge_vlan *masterv;
167f8ed289fSNikolay Aleksandrov
168907b1e6eSNikolay Aleksandrov vg = br_vlan_group(br);
169907b1e6eSNikolay Aleksandrov masterv = br_vlan_find(vg, vid);
170f8ed289fSNikolay Aleksandrov if (!masterv) {
171f418af63SNikolay Aleksandrov bool changed;
172f418af63SNikolay Aleksandrov
173f8ed289fSNikolay Aleksandrov /* missing global ctx, create it now */
174169327d5SPetr Machata if (br_vlan_add(br, vid, 0, &changed, extack))
175f8ed289fSNikolay Aleksandrov return NULL;
176907b1e6eSNikolay Aleksandrov masterv = br_vlan_find(vg, vid);
177f8ed289fSNikolay Aleksandrov if (WARN_ON(!masterv))
178f8ed289fSNikolay Aleksandrov return NULL;
1790e5a82efSIdo Schimmel refcount_set(&masterv->refcnt, 1);
1800e5a82efSIdo Schimmel return masterv;
181f8ed289fSNikolay Aleksandrov }
18225127759SReshetova, Elena refcount_inc(&masterv->refcnt);
183f8ed289fSNikolay Aleksandrov
184f8ed289fSNikolay Aleksandrov return masterv;
185f8ed289fSNikolay Aleksandrov }
186f8ed289fSNikolay Aleksandrov
br_master_vlan_rcu_free(struct rcu_head * rcu)1876dada9b1SNikolay Aleksandrov static void br_master_vlan_rcu_free(struct rcu_head *rcu)
1886dada9b1SNikolay Aleksandrov {
1896dada9b1SNikolay Aleksandrov struct net_bridge_vlan *v;
1906dada9b1SNikolay Aleksandrov
1916dada9b1SNikolay Aleksandrov v = container_of(rcu, struct net_bridge_vlan, rcu);
1926dada9b1SNikolay Aleksandrov WARN_ON(!br_vlan_is_master(v));
1936dada9b1SNikolay Aleksandrov free_percpu(v->stats);
1946dada9b1SNikolay Aleksandrov v->stats = NULL;
1956dada9b1SNikolay Aleksandrov kfree(v);
1966dada9b1SNikolay Aleksandrov }
1976dada9b1SNikolay Aleksandrov
br_vlan_put_master(struct net_bridge_vlan * masterv)198f8ed289fSNikolay Aleksandrov static void br_vlan_put_master(struct net_bridge_vlan *masterv)
199f8ed289fSNikolay Aleksandrov {
200907b1e6eSNikolay Aleksandrov struct net_bridge_vlan_group *vg;
201907b1e6eSNikolay Aleksandrov
202f8ed289fSNikolay Aleksandrov if (!br_vlan_is_master(masterv))
203f8ed289fSNikolay Aleksandrov return;
204f8ed289fSNikolay Aleksandrov
205907b1e6eSNikolay Aleksandrov vg = br_vlan_group(masterv->br);
20625127759SReshetova, Elena if (refcount_dec_and_test(&masterv->refcnt)) {
207907b1e6eSNikolay Aleksandrov rhashtable_remove_fast(&vg->vlan_hash,
208f8ed289fSNikolay Aleksandrov &masterv->vnode, br_vlan_rht_params);
209f8ed289fSNikolay Aleksandrov __vlan_del_list(masterv);
2107b54aaafSNikolay Aleksandrov br_multicast_toggle_one_vlan(masterv, false);
211613d61dbSNikolay Aleksandrov br_multicast_ctx_deinit(&masterv->br_mcast_ctx);
2126dada9b1SNikolay Aleksandrov call_rcu(&masterv->rcu, br_master_vlan_rcu_free);
213f8ed289fSNikolay Aleksandrov }
214f8ed289fSNikolay Aleksandrov }
215f8ed289fSNikolay Aleksandrov
nbp_vlan_rcu_free(struct rcu_head * rcu)2169163a0fcSNikolay Aleksandrov static void nbp_vlan_rcu_free(struct rcu_head *rcu)
2179163a0fcSNikolay Aleksandrov {
2189163a0fcSNikolay Aleksandrov struct net_bridge_vlan *v;
2199163a0fcSNikolay Aleksandrov
2209163a0fcSNikolay Aleksandrov v = container_of(rcu, struct net_bridge_vlan, rcu);
2219163a0fcSNikolay Aleksandrov WARN_ON(br_vlan_is_master(v));
2229163a0fcSNikolay Aleksandrov /* if we had per-port stats configured then free them here */
2239d332e69SNikolay Aleksandrov if (v->priv_flags & BR_VLFLAG_PER_PORT_STATS)
2249163a0fcSNikolay Aleksandrov free_percpu(v->stats);
2259163a0fcSNikolay Aleksandrov v->stats = NULL;
2269163a0fcSNikolay Aleksandrov kfree(v);
2279163a0fcSNikolay Aleksandrov }
2289163a0fcSNikolay Aleksandrov
br_vlan_init_state(struct net_bridge_vlan * v)229ec7328b5STobias Waldekranz static void br_vlan_init_state(struct net_bridge_vlan *v)
230ec7328b5STobias Waldekranz {
231ec7328b5STobias Waldekranz struct net_bridge *br;
232ec7328b5STobias Waldekranz
233ec7328b5STobias Waldekranz if (br_vlan_is_master(v))
234ec7328b5STobias Waldekranz br = v->br;
235ec7328b5STobias Waldekranz else
236ec7328b5STobias Waldekranz br = v->port->br;
237ec7328b5STobias Waldekranz
238ec7328b5STobias Waldekranz if (br_opt_get(br, BROPT_MST_ENABLED)) {
239ec7328b5STobias Waldekranz br_mst_vlan_init_state(v);
240ec7328b5STobias Waldekranz return;
241ec7328b5STobias Waldekranz }
242ec7328b5STobias Waldekranz
243ec7328b5STobias Waldekranz v->state = BR_STATE_FORWARDING;
244ec7328b5STobias Waldekranz v->msti = 0;
245ec7328b5STobias Waldekranz }
246ec7328b5STobias Waldekranz
2472594e906SNikolay Aleksandrov /* This is the shared VLAN add function which works for both ports and bridge
2482594e906SNikolay Aleksandrov * devices. There are four possible calls to this function in terms of the
2492594e906SNikolay Aleksandrov * vlan entry type:
2502594e906SNikolay Aleksandrov * 1. vlan is being added on a port (no master flags, global entry exists)
251ddd611d3SIdo Schimmel * 2. vlan is being added on a bridge (both master and brentry flags)
2522594e906SNikolay Aleksandrov * 3. vlan is being added on a port, but a global entry didn't exist which
253ddd611d3SIdo Schimmel * is being created right now (master flag set, brentry flag unset), the
2542594e906SNikolay Aleksandrov * global entry is used for global per-vlan features, but not for filtering
255ddd611d3SIdo Schimmel * 4. same as 3 but with both master and brentry flags set so the entry
2562594e906SNikolay Aleksandrov * will be used for filtering in both the port and the bridge
2572594e906SNikolay Aleksandrov */
__vlan_add(struct net_bridge_vlan * v,u16 flags,struct netlink_ext_ack * extack)258169327d5SPetr Machata static int __vlan_add(struct net_bridge_vlan *v, u16 flags,
259169327d5SPetr Machata struct netlink_ext_ack *extack)
260243a2e63SVlad Yasevich {
2612594e906SNikolay Aleksandrov struct net_bridge_vlan *masterv = NULL;
2622594e906SNikolay Aleksandrov struct net_bridge_port *p = NULL;
2636be144f6SNikolay Aleksandrov struct net_bridge_vlan_group *vg;
2642594e906SNikolay Aleksandrov struct net_device *dev;
2652594e906SNikolay Aleksandrov struct net_bridge *br;
266bf361ad3SVivien Didelot int err;
267bf361ad3SVivien Didelot
2682594e906SNikolay Aleksandrov if (br_vlan_is_master(v)) {
2692594e906SNikolay Aleksandrov br = v->br;
2702594e906SNikolay Aleksandrov dev = br->dev;
271907b1e6eSNikolay Aleksandrov vg = br_vlan_group(br);
2722594e906SNikolay Aleksandrov } else {
2732594e906SNikolay Aleksandrov p = v->port;
2742594e906SNikolay Aleksandrov br = p->br;
2752594e906SNikolay Aleksandrov dev = p->dev;
276907b1e6eSNikolay Aleksandrov vg = nbp_vlan_group(p);
2772594e906SNikolay Aleksandrov }
2782594e906SNikolay Aleksandrov
2792594e906SNikolay Aleksandrov if (p) {
2802594e906SNikolay Aleksandrov /* Add VLAN to the device filter if it is supported.
2812594e906SNikolay Aleksandrov * This ensures tagged traffic enters the bridge when
2822594e906SNikolay Aleksandrov * promiscuous mode is disabled by br_manage_promisc().
2832594e906SNikolay Aleksandrov */
28427973793SIdo Schimmel err = __vlan_vid_add(dev, br, v, flags, extack);
285bf361ad3SVivien Didelot if (err)
2862594e906SNikolay Aleksandrov goto out;
2872594e906SNikolay Aleksandrov
2882594e906SNikolay Aleksandrov /* need to work on the master vlan too */
2892594e906SNikolay Aleksandrov if (flags & BRIDGE_VLAN_INFO_MASTER) {
290f418af63SNikolay Aleksandrov bool changed;
291f418af63SNikolay Aleksandrov
292f418af63SNikolay Aleksandrov err = br_vlan_add(br, v->vid,
293f418af63SNikolay Aleksandrov flags | BRIDGE_VLAN_INFO_BRENTRY,
294169327d5SPetr Machata &changed, extack);
2952594e906SNikolay Aleksandrov if (err)
2962594e906SNikolay Aleksandrov goto out_filt;
297f545923bSNikolay Aleksandrov
298f545923bSNikolay Aleksandrov if (changed)
299f545923bSNikolay Aleksandrov br_vlan_notify(br, NULL, v->vid, 0,
300f545923bSNikolay Aleksandrov RTM_NEWVLAN);
3012594e906SNikolay Aleksandrov }
3022594e906SNikolay Aleksandrov
303169327d5SPetr Machata masterv = br_vlan_get_master(br, v->vid, extack);
304ee4f52a8SZhang Changzhong if (!masterv) {
305ee4f52a8SZhang Changzhong err = -ENOMEM;
3062594e906SNikolay Aleksandrov goto out_filt;
307ee4f52a8SZhang Changzhong }
3082594e906SNikolay Aleksandrov v->brvlan = masterv;
3099163a0fcSNikolay Aleksandrov if (br_opt_get(br, BROPT_VLAN_STATS_PER_PORT)) {
310281cc284SHeiner Kallweit v->stats =
311281cc284SHeiner Kallweit netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
3129163a0fcSNikolay Aleksandrov if (!v->stats) {
3139163a0fcSNikolay Aleksandrov err = -ENOMEM;
3149163a0fcSNikolay Aleksandrov goto out_filt;
3159163a0fcSNikolay Aleksandrov }
3169d332e69SNikolay Aleksandrov v->priv_flags |= BR_VLFLAG_PER_PORT_STATS;
3179163a0fcSNikolay Aleksandrov } else {
3186dada9b1SNikolay Aleksandrov v->stats = masterv->stats;
3199163a0fcSNikolay Aleksandrov }
320613d61dbSNikolay Aleksandrov br_multicast_port_ctx_init(p, v, &v->port_mcast_ctx);
3219c86ce2cSPetr Machata } else {
3223116ad06SVladimir Oltean if (br_vlan_should_use(v)) {
3233116ad06SVladimir Oltean err = br_switchdev_port_vlan_add(dev, v->vid, flags,
3248d23a54fSVladimir Oltean false, extack);
3259c86ce2cSPetr Machata if (err && err != -EOPNOTSUPP)
3269c86ce2cSPetr Machata goto out;
3273116ad06SVladimir Oltean }
328613d61dbSNikolay Aleksandrov br_multicast_ctx_init(br, v, &v->br_mcast_ctx);
3297b54aaafSNikolay Aleksandrov v->priv_flags |= BR_VLFLAG_GLOBAL_MCAST_ENABLED;
3302594e906SNikolay Aleksandrov }
3312594e906SNikolay Aleksandrov
3326be144f6SNikolay Aleksandrov /* Add the dev mac and count the vlan only if it's usable */
3332594e906SNikolay Aleksandrov if (br_vlan_should_use(v)) {
334f6814fdcSVladimir Oltean err = br_fdb_add_local(br, p, dev->dev_addr, v->vid);
3352594e906SNikolay Aleksandrov if (err) {
3362594e906SNikolay Aleksandrov br_err(br, "failed insert local address into bridge forwarding table\n");
3372594e906SNikolay Aleksandrov goto out_filt;
3382594e906SNikolay Aleksandrov }
3396be144f6SNikolay Aleksandrov vg->num_vlans++;
3402594e906SNikolay Aleksandrov }
3412594e906SNikolay Aleksandrov
342a580c76dSNikolay Aleksandrov /* set the state before publishing */
343ec7328b5STobias Waldekranz br_vlan_init_state(v);
344a580c76dSNikolay Aleksandrov
3456be144f6SNikolay Aleksandrov err = rhashtable_lookup_insert_fast(&vg->vlan_hash, &v->vnode,
3466be144f6SNikolay Aleksandrov br_vlan_rht_params);
3472594e906SNikolay Aleksandrov if (err)
3482594e906SNikolay Aleksandrov goto out_fdb_insert;
3492594e906SNikolay Aleksandrov
3502594e906SNikolay Aleksandrov __vlan_add_list(v);
35127c5f74cSVladimir Oltean __vlan_flags_commit(v, flags);
3527b54aaafSNikolay Aleksandrov br_multicast_toggle_one_vlan(v, true);
35380900acdSMike Manning
35480900acdSMike Manning if (p)
35580900acdSMike Manning nbp_vlan_set_vlan_dev_state(p, v->vid);
3562594e906SNikolay Aleksandrov out:
3572594e906SNikolay Aleksandrov return err;
3582594e906SNikolay Aleksandrov
3592594e906SNikolay Aleksandrov out_fdb_insert:
3606be144f6SNikolay Aleksandrov if (br_vlan_should_use(v)) {
3616be144f6SNikolay Aleksandrov br_fdb_find_delete_local(br, p, dev->dev_addr, v->vid);
3626be144f6SNikolay Aleksandrov vg->num_vlans--;
3636be144f6SNikolay Aleksandrov }
3642594e906SNikolay Aleksandrov
3652594e906SNikolay Aleksandrov out_filt:
3662594e906SNikolay Aleksandrov if (p) {
36727973793SIdo Schimmel __vlan_vid_del(dev, br, v);
3682594e906SNikolay Aleksandrov if (masterv) {
3691a3aea25SLi RongQing if (v->stats && masterv->stats != v->stats)
3701a3aea25SLi RongQing free_percpu(v->stats);
3711a3aea25SLi RongQing v->stats = NULL;
3721a3aea25SLi RongQing
373f8ed289fSNikolay Aleksandrov br_vlan_put_master(masterv);
3742594e906SNikolay Aleksandrov v->brvlan = NULL;
3752594e906SNikolay Aleksandrov }
3769c86ce2cSPetr Machata } else {
3779c86ce2cSPetr Machata br_switchdev_port_vlan_del(dev, v->vid);
3782594e906SNikolay Aleksandrov }
3792594e906SNikolay Aleksandrov
3802594e906SNikolay Aleksandrov goto out;
3812594e906SNikolay Aleksandrov }
3822594e906SNikolay Aleksandrov
__vlan_del(struct net_bridge_vlan * v)3832594e906SNikolay Aleksandrov static int __vlan_del(struct net_bridge_vlan *v)
3842594e906SNikolay Aleksandrov {
3852594e906SNikolay Aleksandrov struct net_bridge_vlan *masterv = v;
38677751ee8SNikolay Aleksandrov struct net_bridge_vlan_group *vg;
3872594e906SNikolay Aleksandrov struct net_bridge_port *p = NULL;
3882594e906SNikolay Aleksandrov int err = 0;
3892594e906SNikolay Aleksandrov
3902594e906SNikolay Aleksandrov if (br_vlan_is_master(v)) {
391907b1e6eSNikolay Aleksandrov vg = br_vlan_group(v->br);
3922594e906SNikolay Aleksandrov } else {
3932594e906SNikolay Aleksandrov p = v->port;
394907b1e6eSNikolay Aleksandrov vg = nbp_vlan_group(v->port);
3952594e906SNikolay Aleksandrov masterv = v->brvlan;
3962594e906SNikolay Aleksandrov }
3972594e906SNikolay Aleksandrov
39877751ee8SNikolay Aleksandrov __vlan_delete_pvid(vg, v->vid);
3992594e906SNikolay Aleksandrov if (p) {
40027973793SIdo Schimmel err = __vlan_vid_del(p->dev, p->br, v);
4012594e906SNikolay Aleksandrov if (err)
4022594e906SNikolay Aleksandrov goto out;
4039c86ce2cSPetr Machata } else {
4049c86ce2cSPetr Machata err = br_switchdev_port_vlan_del(v->br->dev, v->vid);
4059c86ce2cSPetr Machata if (err && err != -EOPNOTSUPP)
4069c86ce2cSPetr Machata goto out;
4079c86ce2cSPetr Machata err = 0;
4082594e906SNikolay Aleksandrov }
4092594e906SNikolay Aleksandrov
4106be144f6SNikolay Aleksandrov if (br_vlan_should_use(v)) {
4112594e906SNikolay Aleksandrov v->flags &= ~BRIDGE_VLAN_INFO_BRENTRY;
4126be144f6SNikolay Aleksandrov vg->num_vlans--;
4132594e906SNikolay Aleksandrov }
4142594e906SNikolay Aleksandrov
4152594e906SNikolay Aleksandrov if (masterv != v) {
416efa5356bSRoopa Prabhu vlan_tunnel_info_del(vg, v);
41777751ee8SNikolay Aleksandrov rhashtable_remove_fast(&vg->vlan_hash, &v->vnode,
41877751ee8SNikolay Aleksandrov br_vlan_rht_params);
4192594e906SNikolay Aleksandrov __vlan_del_list(v);
42080900acdSMike Manning nbp_vlan_set_vlan_dev_state(p, v->vid);
4217b54aaafSNikolay Aleksandrov br_multicast_toggle_one_vlan(v, false);
422613d61dbSNikolay Aleksandrov br_multicast_port_ctx_deinit(&v->port_mcast_ctx);
4239163a0fcSNikolay Aleksandrov call_rcu(&v->rcu, nbp_vlan_rcu_free);
4242594e906SNikolay Aleksandrov }
4252594e906SNikolay Aleksandrov
426f8ed289fSNikolay Aleksandrov br_vlan_put_master(masterv);
4272594e906SNikolay Aleksandrov out:
428bf361ad3SVivien Didelot return err;
4298580e211SToshiaki Makita }
430243a2e63SVlad Yasevich
__vlan_group_free(struct net_bridge_vlan_group * vg)431f409d0edSNikolay Aleksandrov static void __vlan_group_free(struct net_bridge_vlan_group *vg)
432f409d0edSNikolay Aleksandrov {
433f409d0edSNikolay Aleksandrov WARN_ON(!list_empty(&vg->vlan_list));
434f409d0edSNikolay Aleksandrov rhashtable_destroy(&vg->vlan_hash);
435efa5356bSRoopa Prabhu vlan_tunnel_deinit(vg);
436f409d0edSNikolay Aleksandrov kfree(vg);
437f409d0edSNikolay Aleksandrov }
438f409d0edSNikolay Aleksandrov
__vlan_flush(const struct net_bridge * br,const struct net_bridge_port * p,struct net_bridge_vlan_group * vg)439f545923bSNikolay Aleksandrov static void __vlan_flush(const struct net_bridge *br,
440f545923bSNikolay Aleksandrov const struct net_bridge_port *p,
441f545923bSNikolay Aleksandrov struct net_bridge_vlan_group *vg)
442243a2e63SVlad Yasevich {
4432594e906SNikolay Aleksandrov struct net_bridge_vlan *vlan, *tmp;
444f545923bSNikolay Aleksandrov u16 v_start = 0, v_end = 0;
4455454f5c2SVladimir Oltean int err;
4462594e906SNikolay Aleksandrov
447f409d0edSNikolay Aleksandrov __vlan_delete_pvid(vg, vg->pvid);
448f545923bSNikolay Aleksandrov list_for_each_entry_safe(vlan, tmp, &vg->vlan_list, vlist) {
449f545923bSNikolay Aleksandrov /* take care of disjoint ranges */
450f545923bSNikolay Aleksandrov if (!v_start) {
451f545923bSNikolay Aleksandrov v_start = vlan->vid;
452f545923bSNikolay Aleksandrov } else if (vlan->vid - v_end != 1) {
453f545923bSNikolay Aleksandrov /* found range end, notify and start next one */
454f545923bSNikolay Aleksandrov br_vlan_notify(br, p, v_start, v_end, RTM_DELVLAN);
455f545923bSNikolay Aleksandrov v_start = vlan->vid;
456f545923bSNikolay Aleksandrov }
457f545923bSNikolay Aleksandrov v_end = vlan->vid;
458f545923bSNikolay Aleksandrov
4595454f5c2SVladimir Oltean err = __vlan_del(vlan);
4605454f5c2SVladimir Oltean if (err) {
4615454f5c2SVladimir Oltean br_err(br,
4625454f5c2SVladimir Oltean "port %u(%s) failed to delete vlan %d: %pe\n",
4635454f5c2SVladimir Oltean (unsigned int) p->port_no, p->dev->name,
4645454f5c2SVladimir Oltean vlan->vid, ERR_PTR(err));
4655454f5c2SVladimir Oltean }
466243a2e63SVlad Yasevich }
467243a2e63SVlad Yasevich
468f545923bSNikolay Aleksandrov /* notify about the last/whole vlan range */
469f545923bSNikolay Aleksandrov if (v_start)
470f545923bSNikolay Aleksandrov br_vlan_notify(br, p, v_start, v_end, RTM_DELVLAN);
471f545923bSNikolay Aleksandrov }
472f545923bSNikolay Aleksandrov
br_handle_vlan(struct net_bridge * br,const struct net_bridge_port * p,struct net_bridge_vlan_group * vg,struct sk_buff * skb)47378851988SVlad Yasevich struct sk_buff *br_handle_vlan(struct net_bridge *br,
47411538d03SRoopa Prabhu const struct net_bridge_port *p,
4752594e906SNikolay Aleksandrov struct net_bridge_vlan_group *vg,
476a37b85c9SVlad Yasevich struct sk_buff *skb)
477a37b85c9SVlad Yasevich {
478281cc284SHeiner Kallweit struct pcpu_sw_netstats *stats;
4792594e906SNikolay Aleksandrov struct net_bridge_vlan *v;
480a37b85c9SVlad Yasevich u16 vid;
481a37b85c9SVlad Yasevich
48220adfa1aSVlad Yasevich /* If this packet was not filtered at input, let it pass */
48320adfa1aSVlad Yasevich if (!BR_INPUT_SKB_CB(skb)->vlan_filtered)
48478851988SVlad Yasevich goto out;
48578851988SVlad Yasevich
4862594e906SNikolay Aleksandrov /* At this point, we know that the frame was filtered and contains
4872594e906SNikolay Aleksandrov * a valid vlan id. If the vlan id has untagged flag set,
4882594e906SNikolay Aleksandrov * send untagged; otherwise, send tagged.
4892594e906SNikolay Aleksandrov */
4902594e906SNikolay Aleksandrov br_vlan_get_tag(skb, &vid);
4912594e906SNikolay Aleksandrov v = br_vlan_find(vg, vid);
4922594e906SNikolay Aleksandrov /* Vlan entry must be configured at this point. The
493fc92f745SVlad Yasevich * only exception is the bridge is set in promisc mode and the
494fc92f745SVlad Yasevich * packet is destined for the bridge device. In this case
495fc92f745SVlad Yasevich * pass the packet as is.
496fc92f745SVlad Yasevich */
4972594e906SNikolay Aleksandrov if (!v || !br_vlan_should_use(v)) {
498fc92f745SVlad Yasevich if ((br->dev->flags & IFF_PROMISC) && skb->dev == br->dev) {
499fc92f745SVlad Yasevich goto out;
500fc92f745SVlad Yasevich } else {
501fc92f745SVlad Yasevich kfree_skb(skb);
502fc92f745SVlad Yasevich return NULL;
503fc92f745SVlad Yasevich }
504fc92f745SVlad Yasevich }
505ae75767eSNikolay Aleksandrov if (br_opt_get(br, BROPT_VLAN_STATS_ENABLED)) {
5066dada9b1SNikolay Aleksandrov stats = this_cpu_ptr(v->stats);
5076dada9b1SNikolay Aleksandrov u64_stats_update_begin(&stats->syncp);
5089962acefSEric Dumazet u64_stats_add(&stats->tx_bytes, skb->len);
5099962acefSEric Dumazet u64_stats_inc(&stats->tx_packets);
5106dada9b1SNikolay Aleksandrov u64_stats_update_end(&stats->syncp);
5116dada9b1SNikolay Aleksandrov }
5126dada9b1SNikolay Aleksandrov
51347211192STobias Waldekranz /* If the skb will be sent using forwarding offload, the assumption is
51447211192STobias Waldekranz * that the switchdev will inject the packet into hardware together
51547211192STobias Waldekranz * with the bridge VLAN, so that it can be forwarded according to that
51647211192STobias Waldekranz * VLAN. The switchdev should deal with popping the VLAN header in
51747211192STobias Waldekranz * hardware on each egress port as appropriate. So only strip the VLAN
51847211192STobias Waldekranz * header if forwarding offload is not being used.
51947211192STobias Waldekranz */
52047211192STobias Waldekranz if (v->flags & BRIDGE_VLAN_INFO_UNTAGGED &&
52147211192STobias Waldekranz !br_switchdev_frame_uses_tx_fwd_offload(skb))
5225978f8a9SMichał Mirosław __vlan_hwaccel_clear_tag(skb);
52311538d03SRoopa Prabhu
52411538d03SRoopa Prabhu if (p && (p->flags & BR_VLAN_TUNNEL) &&
52511538d03SRoopa Prabhu br_handle_egress_vlan_tunnel(skb, v)) {
52611538d03SRoopa Prabhu kfree_skb(skb);
52711538d03SRoopa Prabhu return NULL;
52811538d03SRoopa Prabhu }
52978851988SVlad Yasevich out:
53078851988SVlad Yasevich return skb;
53178851988SVlad Yasevich }
53278851988SVlad Yasevich
53378851988SVlad Yasevich /* Called under RCU */
__allowed_ingress(const struct net_bridge * br,struct net_bridge_vlan_group * vg,struct sk_buff * skb,u16 * vid,u8 * state,struct net_bridge_vlan ** vlan)5346dada9b1SNikolay Aleksandrov static bool __allowed_ingress(const struct net_bridge *br,
5356dada9b1SNikolay Aleksandrov struct net_bridge_vlan_group *vg,
536a580c76dSNikolay Aleksandrov struct sk_buff *skb, u16 *vid,
537f4b7002aSNikolay Aleksandrov u8 *state,
538f4b7002aSNikolay Aleksandrov struct net_bridge_vlan **vlan)
53978851988SVlad Yasevich {
540281cc284SHeiner Kallweit struct pcpu_sw_netstats *stats;
5416dada9b1SNikolay Aleksandrov struct net_bridge_vlan *v;
5428580e211SToshiaki Makita bool tagged;
543a37b85c9SVlad Yasevich
54420adfa1aSVlad Yasevich BR_INPUT_SKB_CB(skb)->vlan_filtered = true;
54512464bb8SToshiaki Makita /* If vlan tx offload is disabled on bridge device and frame was
54612464bb8SToshiaki Makita * sent from vlan device on the bridge device, it does not have
54712464bb8SToshiaki Makita * HW accelerated vlan tag.
54812464bb8SToshiaki Makita */
549df8a39deSJiri Pirko if (unlikely(!skb_vlan_tag_present(skb) &&
5506dada9b1SNikolay Aleksandrov skb->protocol == br->vlan_proto)) {
5510d5501c1SVlad Yasevich skb = skb_vlan_untag(skb);
55212464bb8SToshiaki Makita if (unlikely(!skb))
55312464bb8SToshiaki Makita return false;
55412464bb8SToshiaki Makita }
55512464bb8SToshiaki Makita
5568580e211SToshiaki Makita if (!br_vlan_get_tag(skb, vid)) {
5578580e211SToshiaki Makita /* Tagged frame */
5586dada9b1SNikolay Aleksandrov if (skb->vlan_proto != br->vlan_proto) {
5598580e211SToshiaki Makita /* Protocol-mismatch, empty out vlan_tci for new tag */
5608580e211SToshiaki Makita skb_push(skb, ETH_HLEN);
56162749e2cSJiri Pirko skb = vlan_insert_tag_set_proto(skb, skb->vlan_proto,
562df8a39deSJiri Pirko skb_vlan_tag_get(skb));
5638580e211SToshiaki Makita if (unlikely(!skb))
5648580e211SToshiaki Makita return false;
5658580e211SToshiaki Makita
5668580e211SToshiaki Makita skb_pull(skb, ETH_HLEN);
5678580e211SToshiaki Makita skb_reset_mac_len(skb);
5688580e211SToshiaki Makita *vid = 0;
5698580e211SToshiaki Makita tagged = false;
5708580e211SToshiaki Makita } else {
5718580e211SToshiaki Makita tagged = true;
5728580e211SToshiaki Makita }
5738580e211SToshiaki Makita } else {
5748580e211SToshiaki Makita /* Untagged frame */
5758580e211SToshiaki Makita tagged = false;
5768580e211SToshiaki Makita }
5778580e211SToshiaki Makita
578b90356ceSToshiaki Makita if (!*vid) {
57977751ee8SNikolay Aleksandrov u16 pvid = br_get_pvid(vg);
58077751ee8SNikolay Aleksandrov
581b90356ceSToshiaki Makita /* Frame had a tag with VID 0 or did not have a tag.
582b90356ceSToshiaki Makita * See if pvid is set on this port. That tells us which
583b90356ceSToshiaki Makita * vlan untagged or priority-tagged traffic belongs to.
58478851988SVlad Yasevich */
5853df6bf45SVlad Yasevich if (!pvid)
586eb707618SToshiaki Makita goto drop;
58778851988SVlad Yasevich
588b90356ceSToshiaki Makita /* PVID is set on this port. Any untagged or priority-tagged
589b90356ceSToshiaki Makita * ingress frame is considered to belong to this vlan.
59078851988SVlad Yasevich */
591dfb5fa32SToshiaki Makita *vid = pvid;
5928580e211SToshiaki Makita if (likely(!tagged))
593b90356ceSToshiaki Makita /* Untagged Frame. */
5946dada9b1SNikolay Aleksandrov __vlan_hwaccel_put_tag(skb, br->vlan_proto, pvid);
595b90356ceSToshiaki Makita else
596b90356ceSToshiaki Makita /* Priority-tagged Frame.
5975978f8a9SMichał Mirosław * At this point, we know that skb->vlan_tci VID
5985978f8a9SMichał Mirosław * field was 0.
599b90356ceSToshiaki Makita * We update only VID field and preserve PCP field.
600b90356ceSToshiaki Makita */
601b90356ceSToshiaki Makita skb->vlan_tci |= pvid;
602b90356ceSToshiaki Makita
603f4b7002aSNikolay Aleksandrov /* if snooping and stats are disabled we can avoid the lookup */
604f4b7002aSNikolay Aleksandrov if (!br_opt_get(br, BROPT_MCAST_VLAN_SNOOPING_ENABLED) &&
605f4b7002aSNikolay Aleksandrov !br_opt_get(br, BROPT_VLAN_STATS_ENABLED)) {
606a580c76dSNikolay Aleksandrov if (*state == BR_STATE_FORWARDING) {
607a580c76dSNikolay Aleksandrov *state = br_vlan_get_pvid_state(vg);
608fd20d973STim Yi if (!br_vlan_state_allowed(*state, true))
609fd20d973STim Yi goto drop;
61078851988SVlad Yasevich }
611fd20d973STim Yi return true;
612a580c76dSNikolay Aleksandrov }
613a580c76dSNikolay Aleksandrov }
61477751ee8SNikolay Aleksandrov v = br_vlan_find(vg, *vid);
6156dada9b1SNikolay Aleksandrov if (!v || !br_vlan_should_use(v))
6166dada9b1SNikolay Aleksandrov goto drop;
6176dada9b1SNikolay Aleksandrov
618a580c76dSNikolay Aleksandrov if (*state == BR_STATE_FORWARDING) {
619a580c76dSNikolay Aleksandrov *state = br_vlan_get_state(v);
620a580c76dSNikolay Aleksandrov if (!br_vlan_state_allowed(*state, true))
621a580c76dSNikolay Aleksandrov goto drop;
622a580c76dSNikolay Aleksandrov }
623a580c76dSNikolay Aleksandrov
624ae75767eSNikolay Aleksandrov if (br_opt_get(br, BROPT_VLAN_STATS_ENABLED)) {
6256dada9b1SNikolay Aleksandrov stats = this_cpu_ptr(v->stats);
6266dada9b1SNikolay Aleksandrov u64_stats_update_begin(&stats->syncp);
6279962acefSEric Dumazet u64_stats_add(&stats->rx_bytes, skb->len);
6289962acefSEric Dumazet u64_stats_inc(&stats->rx_packets);
6296dada9b1SNikolay Aleksandrov u64_stats_update_end(&stats->syncp);
6306dada9b1SNikolay Aleksandrov }
6316dada9b1SNikolay Aleksandrov
632f4b7002aSNikolay Aleksandrov *vlan = v;
633f4b7002aSNikolay Aleksandrov
634a37b85c9SVlad Yasevich return true;
6356dada9b1SNikolay Aleksandrov
636eb707618SToshiaki Makita drop:
637eb707618SToshiaki Makita kfree_skb(skb);
638a37b85c9SVlad Yasevich return false;
639a37b85c9SVlad Yasevich }
640a37b85c9SVlad Yasevich
br_allowed_ingress(const struct net_bridge * br,struct net_bridge_vlan_group * vg,struct sk_buff * skb,u16 * vid,u8 * state,struct net_bridge_vlan ** vlan)64177751ee8SNikolay Aleksandrov bool br_allowed_ingress(const struct net_bridge *br,
64277751ee8SNikolay Aleksandrov struct net_bridge_vlan_group *vg, struct sk_buff *skb,
643f4b7002aSNikolay Aleksandrov u16 *vid, u8 *state,
644f4b7002aSNikolay Aleksandrov struct net_bridge_vlan **vlan)
6452594e906SNikolay Aleksandrov {
6462594e906SNikolay Aleksandrov /* If VLAN filtering is disabled on the bridge, all packets are
6472594e906SNikolay Aleksandrov * permitted.
6482594e906SNikolay Aleksandrov */
649f4b7002aSNikolay Aleksandrov *vlan = NULL;
650ae75767eSNikolay Aleksandrov if (!br_opt_get(br, BROPT_VLAN_ENABLED)) {
6512594e906SNikolay Aleksandrov BR_INPUT_SKB_CB(skb)->vlan_filtered = false;
6522594e906SNikolay Aleksandrov return true;
6532594e906SNikolay Aleksandrov }
6542594e906SNikolay Aleksandrov
655f4b7002aSNikolay Aleksandrov return __allowed_ingress(br, vg, skb, vid, state, vlan);
6562594e906SNikolay Aleksandrov }
6572594e906SNikolay Aleksandrov
65885f46c6bSVlad Yasevich /* Called under RCU. */
br_allowed_egress(struct net_bridge_vlan_group * vg,const struct sk_buff * skb)6592594e906SNikolay Aleksandrov bool br_allowed_egress(struct net_bridge_vlan_group *vg,
66085f46c6bSVlad Yasevich const struct sk_buff *skb)
66185f46c6bSVlad Yasevich {
6622594e906SNikolay Aleksandrov const struct net_bridge_vlan *v;
66385f46c6bSVlad Yasevich u16 vid;
66485f46c6bSVlad Yasevich
66520adfa1aSVlad Yasevich /* If this packet was not filtered at input, let it pass */
66620adfa1aSVlad Yasevich if (!BR_INPUT_SKB_CB(skb)->vlan_filtered)
66785f46c6bSVlad Yasevich return true;
66885f46c6bSVlad Yasevich
66985f46c6bSVlad Yasevich br_vlan_get_tag(skb, &vid);
6702594e906SNikolay Aleksandrov v = br_vlan_find(vg, vid);
671a580c76dSNikolay Aleksandrov if (v && br_vlan_should_use(v) &&
672a580c76dSNikolay Aleksandrov br_vlan_state_allowed(br_vlan_get_state(v), false))
67385f46c6bSVlad Yasevich return true;
67485f46c6bSVlad Yasevich
67585f46c6bSVlad Yasevich return false;
67685f46c6bSVlad Yasevich }
67785f46c6bSVlad Yasevich
678e0d7968aSToshiaki Makita /* Called under RCU */
br_should_learn(struct net_bridge_port * p,struct sk_buff * skb,u16 * vid)679e0d7968aSToshiaki Makita bool br_should_learn(struct net_bridge_port *p, struct sk_buff *skb, u16 *vid)
680e0d7968aSToshiaki Makita {
681468e7944SNikolay Aleksandrov struct net_bridge_vlan_group *vg;
682e0d7968aSToshiaki Makita struct net_bridge *br = p->br;
683a580c76dSNikolay Aleksandrov struct net_bridge_vlan *v;
684e0d7968aSToshiaki Makita
68520adfa1aSVlad Yasevich /* If filtering was disabled at input, let it pass. */
686ae75767eSNikolay Aleksandrov if (!br_opt_get(br, BROPT_VLAN_ENABLED))
687e0d7968aSToshiaki Makita return true;
688e0d7968aSToshiaki Makita
689eca1e006SIdo Schimmel vg = nbp_vlan_group_rcu(p);
690468e7944SNikolay Aleksandrov if (!vg || !vg->num_vlans)
691e0d7968aSToshiaki Makita return false;
692e0d7968aSToshiaki Makita
6938580e211SToshiaki Makita if (!br_vlan_get_tag(skb, vid) && skb->vlan_proto != br->vlan_proto)
6948580e211SToshiaki Makita *vid = 0;
6958580e211SToshiaki Makita
696e0d7968aSToshiaki Makita if (!*vid) {
69777751ee8SNikolay Aleksandrov *vid = br_get_pvid(vg);
698a580c76dSNikolay Aleksandrov if (!*vid ||
699a580c76dSNikolay Aleksandrov !br_vlan_state_allowed(br_vlan_get_pvid_state(vg), true))
700e0d7968aSToshiaki Makita return false;
701e0d7968aSToshiaki Makita
702e0d7968aSToshiaki Makita return true;
703e0d7968aSToshiaki Makita }
704e0d7968aSToshiaki Makita
705a580c76dSNikolay Aleksandrov v = br_vlan_find(vg, *vid);
706a580c76dSNikolay Aleksandrov if (v && br_vlan_state_allowed(br_vlan_get_state(v), true))
707e0d7968aSToshiaki Makita return true;
708e0d7968aSToshiaki Makita
709e0d7968aSToshiaki Makita return false;
710e0d7968aSToshiaki Makita }
711e0d7968aSToshiaki Makita
br_vlan_add_existing(struct net_bridge * br,struct net_bridge_vlan_group * vg,struct net_bridge_vlan * vlan,u16 flags,bool * changed,struct netlink_ext_ack * extack)712dbd6dc75SPetr Machata static int br_vlan_add_existing(struct net_bridge *br,
713dbd6dc75SPetr Machata struct net_bridge_vlan_group *vg,
714dbd6dc75SPetr Machata struct net_bridge_vlan *vlan,
715169327d5SPetr Machata u16 flags, bool *changed,
716169327d5SPetr Machata struct netlink_ext_ack *extack)
717dbd6dc75SPetr Machata {
71827c5f74cSVladimir Oltean bool would_change = __vlan_flags_would_change(vlan, flags);
71927c5f74cSVladimir Oltean bool becomes_brentry = false;
720dbd6dc75SPetr Machata int err;
721dbd6dc75SPetr Machata
72227c5f74cSVladimir Oltean if (!br_vlan_is_brentry(vlan)) {
723b2bc58d4SVladimir Oltean /* Trying to change flags of non-existent bridge vlan */
72427c5f74cSVladimir Oltean if (!(flags & BRIDGE_VLAN_INFO_BRENTRY))
725b2bc58d4SVladimir Oltean return -EINVAL;
726b2bc58d4SVladimir Oltean
72727c5f74cSVladimir Oltean becomes_brentry = true;
72827c5f74cSVladimir Oltean }
72927c5f74cSVladimir Oltean
73027c5f74cSVladimir Oltean /* Master VLANs that aren't brentries weren't notified before,
73127c5f74cSVladimir Oltean * time to notify them now.
73227c5f74cSVladimir Oltean */
73327c5f74cSVladimir Oltean if (becomes_brentry || would_change) {
73427c5f74cSVladimir Oltean err = br_switchdev_port_vlan_add(br->dev, vlan->vid, flags,
7358d23a54fSVladimir Oltean would_change, extack);
7369c86ce2cSPetr Machata if (err && err != -EOPNOTSUPP)
7379c86ce2cSPetr Machata return err;
73827c5f74cSVladimir Oltean }
7399c86ce2cSPetr Machata
74027c5f74cSVladimir Oltean if (becomes_brentry) {
741dbd6dc75SPetr Machata /* It was only kept for port vlans, now make it real */
742f6814fdcSVladimir Oltean err = br_fdb_add_local(br, NULL, br->dev->dev_addr, vlan->vid);
743dbd6dc75SPetr Machata if (err) {
744dbd6dc75SPetr Machata br_err(br, "failed to insert local address into bridge forwarding table\n");
7459c86ce2cSPetr Machata goto err_fdb_insert;
746dbd6dc75SPetr Machata }
747dbd6dc75SPetr Machata
748dbd6dc75SPetr Machata refcount_inc(&vlan->refcnt);
749dbd6dc75SPetr Machata vlan->flags |= BRIDGE_VLAN_INFO_BRENTRY;
750dbd6dc75SPetr Machata vg->num_vlans++;
751dbd6dc75SPetr Machata *changed = true;
752b92dace3SNikolay Aleksandrov br_multicast_toggle_one_vlan(vlan, true);
753dbd6dc75SPetr Machata }
754dbd6dc75SPetr Machata
75527c5f74cSVladimir Oltean __vlan_flags_commit(vlan, flags);
75627c5f74cSVladimir Oltean if (would_change)
757dbd6dc75SPetr Machata *changed = true;
758dbd6dc75SPetr Machata
759dbd6dc75SPetr Machata return 0;
7609c86ce2cSPetr Machata
7619c86ce2cSPetr Machata err_fdb_insert:
7629c86ce2cSPetr Machata br_switchdev_port_vlan_del(br->dev, vlan->vid);
7639c86ce2cSPetr Machata return err;
764dbd6dc75SPetr Machata }
765dbd6dc75SPetr Machata
7668adff41cSToshiaki Makita /* Must be protected by RTNL.
7678adff41cSToshiaki Makita * Must be called with vid in range from 1 to 4094 inclusive.
768f418af63SNikolay Aleksandrov * changed must be true only if the vlan was created or updated
7698adff41cSToshiaki Makita */
br_vlan_add(struct net_bridge * br,u16 vid,u16 flags,bool * changed,struct netlink_ext_ack * extack)770169327d5SPetr Machata int br_vlan_add(struct net_bridge *br, u16 vid, u16 flags, bool *changed,
771169327d5SPetr Machata struct netlink_ext_ack *extack)
772243a2e63SVlad Yasevich {
773907b1e6eSNikolay Aleksandrov struct net_bridge_vlan_group *vg;
7742594e906SNikolay Aleksandrov struct net_bridge_vlan *vlan;
7752594e906SNikolay Aleksandrov int ret;
776243a2e63SVlad Yasevich
777243a2e63SVlad Yasevich ASSERT_RTNL();
778243a2e63SVlad Yasevich
779f418af63SNikolay Aleksandrov *changed = false;
780907b1e6eSNikolay Aleksandrov vg = br_vlan_group(br);
781907b1e6eSNikolay Aleksandrov vlan = br_vlan_find(vg, vid);
782dbd6dc75SPetr Machata if (vlan)
783169327d5SPetr Machata return br_vlan_add_existing(br, vg, vlan, flags, changed,
784169327d5SPetr Machata extack);
785243a2e63SVlad Yasevich
7862594e906SNikolay Aleksandrov vlan = kzalloc(sizeof(*vlan), GFP_KERNEL);
7872594e906SNikolay Aleksandrov if (!vlan)
788243a2e63SVlad Yasevich return -ENOMEM;
789243a2e63SVlad Yasevich
790281cc284SHeiner Kallweit vlan->stats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
7916dada9b1SNikolay Aleksandrov if (!vlan->stats) {
7926dada9b1SNikolay Aleksandrov kfree(vlan);
7936dada9b1SNikolay Aleksandrov return -ENOMEM;
7946dada9b1SNikolay Aleksandrov }
7952594e906SNikolay Aleksandrov vlan->vid = vid;
7962594e906SNikolay Aleksandrov vlan->flags = flags | BRIDGE_VLAN_INFO_MASTER;
7972594e906SNikolay Aleksandrov vlan->flags &= ~BRIDGE_VLAN_INFO_PVID;
7982594e906SNikolay Aleksandrov vlan->br = br;
7992594e906SNikolay Aleksandrov if (flags & BRIDGE_VLAN_INFO_BRENTRY)
80025127759SReshetova, Elena refcount_set(&vlan->refcnt, 1);
801169327d5SPetr Machata ret = __vlan_add(vlan, flags, extack);
8026dada9b1SNikolay Aleksandrov if (ret) {
8036dada9b1SNikolay Aleksandrov free_percpu(vlan->stats);
8042594e906SNikolay Aleksandrov kfree(vlan);
805f418af63SNikolay Aleksandrov } else {
806f418af63SNikolay Aleksandrov *changed = true;
8076dada9b1SNikolay Aleksandrov }
808243a2e63SVlad Yasevich
8092594e906SNikolay Aleksandrov return ret;
810243a2e63SVlad Yasevich }
811243a2e63SVlad Yasevich
8128adff41cSToshiaki Makita /* Must be protected by RTNL.
8138adff41cSToshiaki Makita * Must be called with vid in range from 1 to 4094 inclusive.
8148adff41cSToshiaki Makita */
br_vlan_delete(struct net_bridge * br,u16 vid)815243a2e63SVlad Yasevich int br_vlan_delete(struct net_bridge *br, u16 vid)
816243a2e63SVlad Yasevich {
817907b1e6eSNikolay Aleksandrov struct net_bridge_vlan_group *vg;
8182594e906SNikolay Aleksandrov struct net_bridge_vlan *v;
819243a2e63SVlad Yasevich
820243a2e63SVlad Yasevich ASSERT_RTNL();
821243a2e63SVlad Yasevich
822907b1e6eSNikolay Aleksandrov vg = br_vlan_group(br);
823907b1e6eSNikolay Aleksandrov v = br_vlan_find(vg, vid);
8242594e906SNikolay Aleksandrov if (!v || !br_vlan_is_brentry(v))
8252594e906SNikolay Aleksandrov return -ENOENT;
826243a2e63SVlad Yasevich
827424bb9c9SToshiaki Makita br_fdb_find_delete_local(br, NULL, br->dev->dev_addr, vid);
8283741873bSRoopa Prabhu br_fdb_delete_by_port(br, NULL, vid, 0);
829bc9a25d2SVlad Yasevich
830efa5356bSRoopa Prabhu vlan_tunnel_info_del(vg, v);
831efa5356bSRoopa Prabhu
8322594e906SNikolay Aleksandrov return __vlan_del(v);
833243a2e63SVlad Yasevich }
834243a2e63SVlad Yasevich
br_vlan_flush(struct net_bridge * br)835243a2e63SVlad Yasevich void br_vlan_flush(struct net_bridge *br)
836243a2e63SVlad Yasevich {
837f409d0edSNikolay Aleksandrov struct net_bridge_vlan_group *vg;
838f409d0edSNikolay Aleksandrov
839243a2e63SVlad Yasevich ASSERT_RTNL();
840243a2e63SVlad Yasevich
841f409d0edSNikolay Aleksandrov vg = br_vlan_group(br);
842f545923bSNikolay Aleksandrov __vlan_flush(br, NULL, vg);
843f409d0edSNikolay Aleksandrov RCU_INIT_POINTER(br->vlgrp, NULL);
844f409d0edSNikolay Aleksandrov synchronize_rcu();
845f409d0edSNikolay Aleksandrov __vlan_group_free(vg);
846243a2e63SVlad Yasevich }
847243a2e63SVlad Yasevich
br_vlan_find(struct net_bridge_vlan_group * vg,u16 vid)8482594e906SNikolay Aleksandrov struct net_bridge_vlan *br_vlan_find(struct net_bridge_vlan_group *vg, u16 vid)
8492b292fb4SToshiaki Makita {
8502594e906SNikolay Aleksandrov if (!vg)
8512594e906SNikolay Aleksandrov return NULL;
8522b292fb4SToshiaki Makita
8532594e906SNikolay Aleksandrov return br_vlan_lookup(&vg->vlan_hash, vid);
8542b292fb4SToshiaki Makita }
8552b292fb4SToshiaki Makita
856204177f3SToshiaki Makita /* Must be protected by RTNL. */
recalculate_group_addr(struct net_bridge * br)857204177f3SToshiaki Makita static void recalculate_group_addr(struct net_bridge *br)
858204177f3SToshiaki Makita {
859be3664a0SNikolay Aleksandrov if (br_opt_get(br, BROPT_GROUP_ADDR_SET))
860204177f3SToshiaki Makita return;
861204177f3SToshiaki Makita
862204177f3SToshiaki Makita spin_lock_bh(&br->lock);
863ae75767eSNikolay Aleksandrov if (!br_opt_get(br, BROPT_VLAN_ENABLED) ||
864ae75767eSNikolay Aleksandrov br->vlan_proto == htons(ETH_P_8021Q)) {
865204177f3SToshiaki Makita /* Bridge Group Address */
866204177f3SToshiaki Makita br->group_addr[5] = 0x00;
867204177f3SToshiaki Makita } else { /* vlan_enabled && ETH_P_8021AD */
868204177f3SToshiaki Makita /* Provider Bridge Group Address */
869204177f3SToshiaki Makita br->group_addr[5] = 0x08;
870204177f3SToshiaki Makita }
871204177f3SToshiaki Makita spin_unlock_bh(&br->lock);
872204177f3SToshiaki Makita }
873204177f3SToshiaki Makita
874204177f3SToshiaki Makita /* Must be protected by RTNL. */
br_recalculate_fwd_mask(struct net_bridge * br)875204177f3SToshiaki Makita void br_recalculate_fwd_mask(struct net_bridge *br)
876204177f3SToshiaki Makita {
877ae75767eSNikolay Aleksandrov if (!br_opt_get(br, BROPT_VLAN_ENABLED) ||
878ae75767eSNikolay Aleksandrov br->vlan_proto == htons(ETH_P_8021Q))
879204177f3SToshiaki Makita br->group_fwd_mask_required = BR_GROUPFWD_DEFAULT;
880204177f3SToshiaki Makita else /* vlan_enabled && ETH_P_8021AD */
881204177f3SToshiaki Makita br->group_fwd_mask_required = BR_GROUPFWD_8021AD &
882204177f3SToshiaki Makita ~(1u << br->group_addr[5]);
883204177f3SToshiaki Makita }
884204177f3SToshiaki Makita
br_vlan_filter_toggle(struct net_bridge * br,unsigned long val,struct netlink_ext_ack * extack)8859e781401SVladimir Oltean int br_vlan_filter_toggle(struct net_bridge *br, unsigned long val,
8869e781401SVladimir Oltean struct netlink_ext_ack *extack)
887243a2e63SVlad Yasevich {
8886b72a770SElad Raz struct switchdev_attr attr = {
8896b72a770SElad Raz .orig_dev = br->dev,
8906b72a770SElad Raz .id = SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING,
8916b72a770SElad Raz .flags = SWITCHDEV_F_SKIP_EOPNOTSUPP,
8926b72a770SElad Raz .u.vlan_filtering = val,
8936b72a770SElad Raz };
8946b72a770SElad Raz int err;
8956b72a770SElad Raz
896ae75767eSNikolay Aleksandrov if (br_opt_get(br, BROPT_VLAN_ENABLED) == !!val)
897a7854037SNikolay Aleksandrov return 0;
898243a2e63SVlad Yasevich
899ae75767eSNikolay Aleksandrov br_opt_toggle(br, BROPT_VLAN_ENABLED, !!val);
900f7cdb3ecSVladimir Oltean
901f7cdb3ecSVladimir Oltean err = switchdev_port_attr_set(br->dev, &attr, extack);
902f7cdb3ecSVladimir Oltean if (err && err != -EOPNOTSUPP) {
903f7cdb3ecSVladimir Oltean br_opt_toggle(br, BROPT_VLAN_ENABLED, !val);
904f7cdb3ecSVladimir Oltean return err;
905f7cdb3ecSVladimir Oltean }
906f7cdb3ecSVladimir Oltean
9072796d0c6SVlad Yasevich br_manage_promisc(br);
908204177f3SToshiaki Makita recalculate_group_addr(br);
909204177f3SToshiaki Makita br_recalculate_fwd_mask(br);
910f4b7002aSNikolay Aleksandrov if (!val && br_opt_get(br, BROPT_MCAST_VLAN_SNOOPING_ENABLED)) {
911f4b7002aSNikolay Aleksandrov br_info(br, "vlan filtering disabled, automatically disabling multicast vlan snooping\n");
912f4b7002aSNikolay Aleksandrov br_multicast_toggle_vlan_snooping(br, false, NULL);
913f4b7002aSNikolay Aleksandrov }
914243a2e63SVlad Yasevich
915a7854037SNikolay Aleksandrov return 0;
916a7854037SNikolay Aleksandrov }
917a7854037SNikolay Aleksandrov
br_vlan_enabled(const struct net_device * dev)9181f51445aSIdo Schimmel bool br_vlan_enabled(const struct net_device *dev)
9191f51445aSIdo Schimmel {
9201f51445aSIdo Schimmel struct net_bridge *br = netdev_priv(dev);
9211f51445aSIdo Schimmel
922ae75767eSNikolay Aleksandrov return br_opt_get(br, BROPT_VLAN_ENABLED);
9231f51445aSIdo Schimmel }
9241f51445aSIdo Schimmel EXPORT_SYMBOL_GPL(br_vlan_enabled);
9251f51445aSIdo Schimmel
br_vlan_get_proto(const struct net_device * dev,u16 * p_proto)92631aed46fSwenxu int br_vlan_get_proto(const struct net_device *dev, u16 *p_proto)
92731aed46fSwenxu {
92831aed46fSwenxu struct net_bridge *br = netdev_priv(dev);
92931aed46fSwenxu
93031aed46fSwenxu *p_proto = ntohs(br->vlan_proto);
93131aed46fSwenxu
93231aed46fSwenxu return 0;
93331aed46fSwenxu }
93431aed46fSwenxu EXPORT_SYMBOL_GPL(br_vlan_get_proto);
93531aed46fSwenxu
__br_vlan_set_proto(struct net_bridge * br,__be16 proto,struct netlink_ext_ack * extack)936dcbdf135SVladimir Oltean int __br_vlan_set_proto(struct net_bridge *br, __be16 proto,
937dcbdf135SVladimir Oltean struct netlink_ext_ack *extack)
938204177f3SToshiaki Makita {
93922ec19f3SDanielle Ratson struct switchdev_attr attr = {
94022ec19f3SDanielle Ratson .orig_dev = br->dev,
94122ec19f3SDanielle Ratson .id = SWITCHDEV_ATTR_ID_BRIDGE_VLAN_PROTOCOL,
94222ec19f3SDanielle Ratson .flags = SWITCHDEV_F_SKIP_EOPNOTSUPP,
94322ec19f3SDanielle Ratson .u.vlan_protocol = ntohs(proto),
94422ec19f3SDanielle Ratson };
945204177f3SToshiaki Makita int err = 0;
946204177f3SToshiaki Makita struct net_bridge_port *p;
9472594e906SNikolay Aleksandrov struct net_bridge_vlan *vlan;
948907b1e6eSNikolay Aleksandrov struct net_bridge_vlan_group *vg;
94922ec19f3SDanielle Ratson __be16 oldproto = br->vlan_proto;
950204177f3SToshiaki Makita
951204177f3SToshiaki Makita if (br->vlan_proto == proto)
952d2d427b3SToshiaki Makita return 0;
953204177f3SToshiaki Makita
954dcbdf135SVladimir Oltean err = switchdev_port_attr_set(br->dev, &attr, extack);
95522ec19f3SDanielle Ratson if (err && err != -EOPNOTSUPP)
95622ec19f3SDanielle Ratson return err;
95722ec19f3SDanielle Ratson
958204177f3SToshiaki Makita /* Add VLANs for the new proto to the device filter. */
959204177f3SToshiaki Makita list_for_each_entry(p, &br->port_list, list) {
960907b1e6eSNikolay Aleksandrov vg = nbp_vlan_group(p);
961907b1e6eSNikolay Aleksandrov list_for_each_entry(vlan, &vg->vlan_list, vlist) {
9629d45921eSIdo Schimmel if (vlan->priv_flags & BR_VLFLAG_ADDED_BY_SWITCHDEV)
9639d45921eSIdo Schimmel continue;
9642594e906SNikolay Aleksandrov err = vlan_vid_add(p->dev, proto, vlan->vid);
965204177f3SToshiaki Makita if (err)
966204177f3SToshiaki Makita goto err_filt;
967204177f3SToshiaki Makita }
968204177f3SToshiaki Makita }
969204177f3SToshiaki Makita
970204177f3SToshiaki Makita br->vlan_proto = proto;
971204177f3SToshiaki Makita
972204177f3SToshiaki Makita recalculate_group_addr(br);
973204177f3SToshiaki Makita br_recalculate_fwd_mask(br);
974204177f3SToshiaki Makita
975204177f3SToshiaki Makita /* Delete VLANs for the old proto from the device filter. */
976907b1e6eSNikolay Aleksandrov list_for_each_entry(p, &br->port_list, list) {
977907b1e6eSNikolay Aleksandrov vg = nbp_vlan_group(p);
9789d45921eSIdo Schimmel list_for_each_entry(vlan, &vg->vlan_list, vlist) {
9799d45921eSIdo Schimmel if (vlan->priv_flags & BR_VLFLAG_ADDED_BY_SWITCHDEV)
9809d45921eSIdo Schimmel continue;
9812594e906SNikolay Aleksandrov vlan_vid_del(p->dev, oldproto, vlan->vid);
982907b1e6eSNikolay Aleksandrov }
9839d45921eSIdo Schimmel }
984204177f3SToshiaki Makita
985d2d427b3SToshiaki Makita return 0;
986204177f3SToshiaki Makita
987204177f3SToshiaki Makita err_filt:
98822ec19f3SDanielle Ratson attr.u.vlan_protocol = ntohs(oldproto);
989dcbdf135SVladimir Oltean switchdev_port_attr_set(br->dev, &attr, NULL);
99022ec19f3SDanielle Ratson
9919d45921eSIdo Schimmel list_for_each_entry_continue_reverse(vlan, &vg->vlan_list, vlist) {
9929d45921eSIdo Schimmel if (vlan->priv_flags & BR_VLFLAG_ADDED_BY_SWITCHDEV)
9939d45921eSIdo Schimmel continue;
9942594e906SNikolay Aleksandrov vlan_vid_del(p->dev, proto, vlan->vid);
9959d45921eSIdo Schimmel }
996204177f3SToshiaki Makita
997907b1e6eSNikolay Aleksandrov list_for_each_entry_continue_reverse(p, &br->port_list, list) {
998907b1e6eSNikolay Aleksandrov vg = nbp_vlan_group(p);
9999d45921eSIdo Schimmel list_for_each_entry(vlan, &vg->vlan_list, vlist) {
10009d45921eSIdo Schimmel if (vlan->priv_flags & BR_VLFLAG_ADDED_BY_SWITCHDEV)
10019d45921eSIdo Schimmel continue;
10022594e906SNikolay Aleksandrov vlan_vid_del(p->dev, proto, vlan->vid);
1003907b1e6eSNikolay Aleksandrov }
10049d45921eSIdo Schimmel }
1005204177f3SToshiaki Makita
1006d2d427b3SToshiaki Makita return err;
1007d2d427b3SToshiaki Makita }
1008d2d427b3SToshiaki Makita
br_vlan_set_proto(struct net_bridge * br,unsigned long val,struct netlink_ext_ack * extack)10099e781401SVladimir Oltean int br_vlan_set_proto(struct net_bridge *br, unsigned long val,
10109e781401SVladimir Oltean struct netlink_ext_ack *extack)
1011d2d427b3SToshiaki Makita {
1012a98c0c47SMenglong Dong if (!eth_type_vlan(htons(val)))
1013d2d427b3SToshiaki Makita return -EPROTONOSUPPORT;
1014d2d427b3SToshiaki Makita
1015dcbdf135SVladimir Oltean return __br_vlan_set_proto(br, htons(val), extack);
1016204177f3SToshiaki Makita }
1017204177f3SToshiaki Makita
br_vlan_set_stats(struct net_bridge * br,unsigned long val)10186dada9b1SNikolay Aleksandrov int br_vlan_set_stats(struct net_bridge *br, unsigned long val)
10196dada9b1SNikolay Aleksandrov {
10206dada9b1SNikolay Aleksandrov switch (val) {
10216dada9b1SNikolay Aleksandrov case 0:
10226dada9b1SNikolay Aleksandrov case 1:
1023ae75767eSNikolay Aleksandrov br_opt_toggle(br, BROPT_VLAN_STATS_ENABLED, !!val);
10246dada9b1SNikolay Aleksandrov break;
10256dada9b1SNikolay Aleksandrov default:
10266dada9b1SNikolay Aleksandrov return -EINVAL;
10276dada9b1SNikolay Aleksandrov }
10286dada9b1SNikolay Aleksandrov
10296dada9b1SNikolay Aleksandrov return 0;
10306dada9b1SNikolay Aleksandrov }
10316dada9b1SNikolay Aleksandrov
br_vlan_set_stats_per_port(struct net_bridge * br,unsigned long val)10329163a0fcSNikolay Aleksandrov int br_vlan_set_stats_per_port(struct net_bridge *br, unsigned long val)
10339163a0fcSNikolay Aleksandrov {
10349163a0fcSNikolay Aleksandrov struct net_bridge_port *p;
10359163a0fcSNikolay Aleksandrov
10369163a0fcSNikolay Aleksandrov /* allow to change the option if there are no port vlans configured */
10379163a0fcSNikolay Aleksandrov list_for_each_entry(p, &br->port_list, list) {
10389163a0fcSNikolay Aleksandrov struct net_bridge_vlan_group *vg = nbp_vlan_group(p);
10399163a0fcSNikolay Aleksandrov
10409163a0fcSNikolay Aleksandrov if (vg->num_vlans)
10419163a0fcSNikolay Aleksandrov return -EBUSY;
10429163a0fcSNikolay Aleksandrov }
10439163a0fcSNikolay Aleksandrov
10449163a0fcSNikolay Aleksandrov switch (val) {
10459163a0fcSNikolay Aleksandrov case 0:
10469163a0fcSNikolay Aleksandrov case 1:
10479163a0fcSNikolay Aleksandrov br_opt_toggle(br, BROPT_VLAN_STATS_PER_PORT, !!val);
10489163a0fcSNikolay Aleksandrov break;
10499163a0fcSNikolay Aleksandrov default:
10509163a0fcSNikolay Aleksandrov return -EINVAL;
10519163a0fcSNikolay Aleksandrov }
10529163a0fcSNikolay Aleksandrov
10539163a0fcSNikolay Aleksandrov return 0;
10549163a0fcSNikolay Aleksandrov }
10559163a0fcSNikolay Aleksandrov
vlan_default_pvid(struct net_bridge_vlan_group * vg,u16 vid)105677751ee8SNikolay Aleksandrov static bool vlan_default_pvid(struct net_bridge_vlan_group *vg, u16 vid)
10575be5a2dfSVlad Yasevich {
10582594e906SNikolay Aleksandrov struct net_bridge_vlan *v;
10592594e906SNikolay Aleksandrov
106077751ee8SNikolay Aleksandrov if (vid != vg->pvid)
10612594e906SNikolay Aleksandrov return false;
10622594e906SNikolay Aleksandrov
10632594e906SNikolay Aleksandrov v = br_vlan_lookup(&vg->vlan_hash, vid);
10642594e906SNikolay Aleksandrov if (v && br_vlan_should_use(v) &&
10652594e906SNikolay Aleksandrov (v->flags & BRIDGE_VLAN_INFO_UNTAGGED))
10662594e906SNikolay Aleksandrov return true;
10672594e906SNikolay Aleksandrov
10682594e906SNikolay Aleksandrov return false;
10695be5a2dfSVlad Yasevich }
10705be5a2dfSVlad Yasevich
br_vlan_disable_default_pvid(struct net_bridge * br)10715be5a2dfSVlad Yasevich static void br_vlan_disable_default_pvid(struct net_bridge *br)
10725be5a2dfSVlad Yasevich {
10735be5a2dfSVlad Yasevich struct net_bridge_port *p;
10745be5a2dfSVlad Yasevich u16 pvid = br->default_pvid;
10755be5a2dfSVlad Yasevich
10765be5a2dfSVlad Yasevich /* Disable default_pvid on all ports where it is still
10775be5a2dfSVlad Yasevich * configured.
10785be5a2dfSVlad Yasevich */
1079f545923bSNikolay Aleksandrov if (vlan_default_pvid(br_vlan_group(br), pvid)) {
1080f545923bSNikolay Aleksandrov if (!br_vlan_delete(br, pvid))
1081f545923bSNikolay Aleksandrov br_vlan_notify(br, NULL, pvid, 0, RTM_DELVLAN);
1082f545923bSNikolay Aleksandrov }
10835be5a2dfSVlad Yasevich
10845be5a2dfSVlad Yasevich list_for_each_entry(p, &br->port_list, list) {
1085f545923bSNikolay Aleksandrov if (vlan_default_pvid(nbp_vlan_group(p), pvid) &&
1086f545923bSNikolay Aleksandrov !nbp_vlan_delete(p, pvid))
1087f545923bSNikolay Aleksandrov br_vlan_notify(br, p, pvid, 0, RTM_DELVLAN);
10885be5a2dfSVlad Yasevich }
10895be5a2dfSVlad Yasevich
10905be5a2dfSVlad Yasevich br->default_pvid = 0;
10915be5a2dfSVlad Yasevich }
10925be5a2dfSVlad Yasevich
__br_vlan_set_default_pvid(struct net_bridge * br,u16 pvid,struct netlink_ext_ack * extack)1093169327d5SPetr Machata int __br_vlan_set_default_pvid(struct net_bridge *br, u16 pvid,
1094169327d5SPetr Machata struct netlink_ext_ack *extack)
10955be5a2dfSVlad Yasevich {
10962594e906SNikolay Aleksandrov const struct net_bridge_vlan *pvent;
1097907b1e6eSNikolay Aleksandrov struct net_bridge_vlan_group *vg;
10985be5a2dfSVlad Yasevich struct net_bridge_port *p;
1099f418af63SNikolay Aleksandrov unsigned long *changed;
1100f418af63SNikolay Aleksandrov bool vlchange;
11015be5a2dfSVlad Yasevich u16 old_pvid;
11025be5a2dfSVlad Yasevich int err = 0;
11035be5a2dfSVlad Yasevich
11040f963b75SNikolay Aleksandrov if (!pvid) {
11050f963b75SNikolay Aleksandrov br_vlan_disable_default_pvid(br);
11060f963b75SNikolay Aleksandrov return 0;
11070f963b75SNikolay Aleksandrov }
11080f963b75SNikolay Aleksandrov
1109459479daSAndy Shevchenko changed = bitmap_zalloc(BR_MAX_PORTS, GFP_KERNEL);
11105be5a2dfSVlad Yasevich if (!changed)
11115be5a2dfSVlad Yasevich return -ENOMEM;
11125be5a2dfSVlad Yasevich
11135be5a2dfSVlad Yasevich old_pvid = br->default_pvid;
11145be5a2dfSVlad Yasevich
11155be5a2dfSVlad Yasevich /* Update default_pvid config only if we do not conflict with
11165be5a2dfSVlad Yasevich * user configuration.
11175be5a2dfSVlad Yasevich */
1118907b1e6eSNikolay Aleksandrov vg = br_vlan_group(br);
1119907b1e6eSNikolay Aleksandrov pvent = br_vlan_find(vg, pvid);
1120907b1e6eSNikolay Aleksandrov if ((!old_pvid || vlan_default_pvid(vg, old_pvid)) &&
11212594e906SNikolay Aleksandrov (!pvent || !br_vlan_should_use(pvent))) {
11225be5a2dfSVlad Yasevich err = br_vlan_add(br, pvid,
11235be5a2dfSVlad Yasevich BRIDGE_VLAN_INFO_PVID |
11242594e906SNikolay Aleksandrov BRIDGE_VLAN_INFO_UNTAGGED |
1125f418af63SNikolay Aleksandrov BRIDGE_VLAN_INFO_BRENTRY,
1126169327d5SPetr Machata &vlchange, extack);
11275be5a2dfSVlad Yasevich if (err)
11285be5a2dfSVlad Yasevich goto out;
1129f545923bSNikolay Aleksandrov
1130f545923bSNikolay Aleksandrov if (br_vlan_delete(br, old_pvid))
1131f545923bSNikolay Aleksandrov br_vlan_notify(br, NULL, old_pvid, 0, RTM_DELVLAN);
1132f545923bSNikolay Aleksandrov br_vlan_notify(br, NULL, pvid, 0, RTM_NEWVLAN);
1133442b03c3SXin Long __set_bit(0, changed);
11345be5a2dfSVlad Yasevich }
11355be5a2dfSVlad Yasevich
11365be5a2dfSVlad Yasevich list_for_each_entry(p, &br->port_list, list) {
11375be5a2dfSVlad Yasevich /* Update default_pvid config only if we do not conflict with
11385be5a2dfSVlad Yasevich * user configuration.
11395be5a2dfSVlad Yasevich */
1140907b1e6eSNikolay Aleksandrov vg = nbp_vlan_group(p);
11415be5a2dfSVlad Yasevich if ((old_pvid &&
1142907b1e6eSNikolay Aleksandrov !vlan_default_pvid(vg, old_pvid)) ||
1143907b1e6eSNikolay Aleksandrov br_vlan_find(vg, pvid))
11445be5a2dfSVlad Yasevich continue;
11455be5a2dfSVlad Yasevich
11465be5a2dfSVlad Yasevich err = nbp_vlan_add(p, pvid,
11475be5a2dfSVlad Yasevich BRIDGE_VLAN_INFO_PVID |
1148f418af63SNikolay Aleksandrov BRIDGE_VLAN_INFO_UNTAGGED,
1149169327d5SPetr Machata &vlchange, extack);
11505be5a2dfSVlad Yasevich if (err)
11515be5a2dfSVlad Yasevich goto err_port;
1152f545923bSNikolay Aleksandrov if (nbp_vlan_delete(p, old_pvid))
1153f545923bSNikolay Aleksandrov br_vlan_notify(br, p, old_pvid, 0, RTM_DELVLAN);
1154f545923bSNikolay Aleksandrov br_vlan_notify(p->br, p, pvid, 0, RTM_NEWVLAN);
1155442b03c3SXin Long __set_bit(p->port_no, changed);
11565be5a2dfSVlad Yasevich }
11575be5a2dfSVlad Yasevich
11585be5a2dfSVlad Yasevich br->default_pvid = pvid;
11595be5a2dfSVlad Yasevich
11605be5a2dfSVlad Yasevich out:
1161459479daSAndy Shevchenko bitmap_free(changed);
11625be5a2dfSVlad Yasevich return err;
11635be5a2dfSVlad Yasevich
11645be5a2dfSVlad Yasevich err_port:
11655be5a2dfSVlad Yasevich list_for_each_entry_continue_reverse(p, &br->port_list, list) {
11665be5a2dfSVlad Yasevich if (!test_bit(p->port_no, changed))
11675be5a2dfSVlad Yasevich continue;
11685be5a2dfSVlad Yasevich
1169f545923bSNikolay Aleksandrov if (old_pvid) {
11705be5a2dfSVlad Yasevich nbp_vlan_add(p, old_pvid,
11715be5a2dfSVlad Yasevich BRIDGE_VLAN_INFO_PVID |
1172f418af63SNikolay Aleksandrov BRIDGE_VLAN_INFO_UNTAGGED,
1173169327d5SPetr Machata &vlchange, NULL);
1174f545923bSNikolay Aleksandrov br_vlan_notify(p->br, p, old_pvid, 0, RTM_NEWVLAN);
1175f545923bSNikolay Aleksandrov }
11765be5a2dfSVlad Yasevich nbp_vlan_delete(p, pvid);
1177f545923bSNikolay Aleksandrov br_vlan_notify(br, p, pvid, 0, RTM_DELVLAN);
11785be5a2dfSVlad Yasevich }
11795be5a2dfSVlad Yasevich
11805be5a2dfSVlad Yasevich if (test_bit(0, changed)) {
1181f545923bSNikolay Aleksandrov if (old_pvid) {
11825be5a2dfSVlad Yasevich br_vlan_add(br, old_pvid,
11835be5a2dfSVlad Yasevich BRIDGE_VLAN_INFO_PVID |
11842594e906SNikolay Aleksandrov BRIDGE_VLAN_INFO_UNTAGGED |
1185f418af63SNikolay Aleksandrov BRIDGE_VLAN_INFO_BRENTRY,
1186169327d5SPetr Machata &vlchange, NULL);
1187f545923bSNikolay Aleksandrov br_vlan_notify(br, NULL, old_pvid, 0, RTM_NEWVLAN);
1188f545923bSNikolay Aleksandrov }
11895be5a2dfSVlad Yasevich br_vlan_delete(br, pvid);
1190f545923bSNikolay Aleksandrov br_vlan_notify(br, NULL, pvid, 0, RTM_DELVLAN);
11915be5a2dfSVlad Yasevich }
11925be5a2dfSVlad Yasevich goto out;
11935be5a2dfSVlad Yasevich }
11945be5a2dfSVlad Yasevich
br_vlan_set_default_pvid(struct net_bridge * br,unsigned long val,struct netlink_ext_ack * extack)11959e781401SVladimir Oltean int br_vlan_set_default_pvid(struct net_bridge *br, unsigned long val,
11969e781401SVladimir Oltean struct netlink_ext_ack *extack)
119796a20d9dSVlad Yasevich {
119896a20d9dSVlad Yasevich u16 pvid = val;
119996a20d9dSVlad Yasevich int err = 0;
120096a20d9dSVlad Yasevich
12015be5a2dfSVlad Yasevich if (val >= VLAN_VID_MASK)
120296a20d9dSVlad Yasevich return -EINVAL;
120396a20d9dSVlad Yasevich
120496a20d9dSVlad Yasevich if (pvid == br->default_pvid)
1205047831a9SXin Long goto out;
120696a20d9dSVlad Yasevich
120796a20d9dSVlad Yasevich /* Only allow default pvid change when filtering is disabled */
1208ae75767eSNikolay Aleksandrov if (br_opt_get(br, BROPT_VLAN_ENABLED)) {
120996a20d9dSVlad Yasevich pr_info_once("Please disable vlan filtering to change default_pvid\n");
121096a20d9dSVlad Yasevich err = -EPERM;
1211047831a9SXin Long goto out;
121296a20d9dSVlad Yasevich }
12139e781401SVladimir Oltean err = __br_vlan_set_default_pvid(br, pvid, extack);
1214047831a9SXin Long out:
121596a20d9dSVlad Yasevich return err;
121696a20d9dSVlad Yasevich }
121796a20d9dSVlad Yasevich
br_vlan_init(struct net_bridge * br)12185be5a2dfSVlad Yasevich int br_vlan_init(struct net_bridge *br)
12198580e211SToshiaki Makita {
1220907b1e6eSNikolay Aleksandrov struct net_bridge_vlan_group *vg;
12212594e906SNikolay Aleksandrov int ret = -ENOMEM;
12222594e906SNikolay Aleksandrov
1223907b1e6eSNikolay Aleksandrov vg = kzalloc(sizeof(*vg), GFP_KERNEL);
1224907b1e6eSNikolay Aleksandrov if (!vg)
12252594e906SNikolay Aleksandrov goto out;
1226907b1e6eSNikolay Aleksandrov ret = rhashtable_init(&vg->vlan_hash, &br_vlan_rht_params);
12272594e906SNikolay Aleksandrov if (ret)
12282594e906SNikolay Aleksandrov goto err_rhtbl;
1229efa5356bSRoopa Prabhu ret = vlan_tunnel_init(vg);
1230efa5356bSRoopa Prabhu if (ret)
1231efa5356bSRoopa Prabhu goto err_tunnel_init;
1232907b1e6eSNikolay Aleksandrov INIT_LIST_HEAD(&vg->vlan_list);
12338580e211SToshiaki Makita br->vlan_proto = htons(ETH_P_8021Q);
123496a20d9dSVlad Yasevich br->default_pvid = 1;
1235907b1e6eSNikolay Aleksandrov rcu_assign_pointer(br->vlgrp, vg);
12362594e906SNikolay Aleksandrov
12372594e906SNikolay Aleksandrov out:
12382594e906SNikolay Aleksandrov return ret;
12392594e906SNikolay Aleksandrov
1240efa5356bSRoopa Prabhu err_tunnel_init:
1241907b1e6eSNikolay Aleksandrov rhashtable_destroy(&vg->vlan_hash);
12422594e906SNikolay Aleksandrov err_rhtbl:
1243907b1e6eSNikolay Aleksandrov kfree(vg);
12442594e906SNikolay Aleksandrov
12452594e906SNikolay Aleksandrov goto out;
12462594e906SNikolay Aleksandrov }
12472594e906SNikolay Aleksandrov
nbp_vlan_init(struct net_bridge_port * p,struct netlink_ext_ack * extack)1248169327d5SPetr Machata int nbp_vlan_init(struct net_bridge_port *p, struct netlink_ext_ack *extack)
12492594e906SNikolay Aleksandrov {
1250404cdbf0SElad Raz struct switchdev_attr attr = {
1251404cdbf0SElad Raz .orig_dev = p->br->dev,
1252404cdbf0SElad Raz .id = SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING,
1253404cdbf0SElad Raz .flags = SWITCHDEV_F_SKIP_EOPNOTSUPP,
1254ae75767eSNikolay Aleksandrov .u.vlan_filtering = br_opt_get(p->br, BROPT_VLAN_ENABLED),
1255404cdbf0SElad Raz };
1256263344e6SNikolay Aleksandrov struct net_bridge_vlan_group *vg;
12572594e906SNikolay Aleksandrov int ret = -ENOMEM;
12582594e906SNikolay Aleksandrov
1259263344e6SNikolay Aleksandrov vg = kzalloc(sizeof(struct net_bridge_vlan_group), GFP_KERNEL);
1260263344e6SNikolay Aleksandrov if (!vg)
12612594e906SNikolay Aleksandrov goto out;
12622594e906SNikolay Aleksandrov
1263dcbdf135SVladimir Oltean ret = switchdev_port_attr_set(p->dev, &attr, extack);
1264404cdbf0SElad Raz if (ret && ret != -EOPNOTSUPP)
1265404cdbf0SElad Raz goto err_vlan_enabled;
1266404cdbf0SElad Raz
1267263344e6SNikolay Aleksandrov ret = rhashtable_init(&vg->vlan_hash, &br_vlan_rht_params);
12682594e906SNikolay Aleksandrov if (ret)
12692594e906SNikolay Aleksandrov goto err_rhtbl;
1270efa5356bSRoopa Prabhu ret = vlan_tunnel_init(vg);
1271efa5356bSRoopa Prabhu if (ret)
1272efa5356bSRoopa Prabhu goto err_tunnel_init;
1273263344e6SNikolay Aleksandrov INIT_LIST_HEAD(&vg->vlan_list);
1274907b1e6eSNikolay Aleksandrov rcu_assign_pointer(p->vlgrp, vg);
12752594e906SNikolay Aleksandrov if (p->br->default_pvid) {
1276f418af63SNikolay Aleksandrov bool changed;
1277f418af63SNikolay Aleksandrov
12782594e906SNikolay Aleksandrov ret = nbp_vlan_add(p, p->br->default_pvid,
12792594e906SNikolay Aleksandrov BRIDGE_VLAN_INFO_PVID |
1280f418af63SNikolay Aleksandrov BRIDGE_VLAN_INFO_UNTAGGED,
1281169327d5SPetr Machata &changed, extack);
12822594e906SNikolay Aleksandrov if (ret)
12832594e906SNikolay Aleksandrov goto err_vlan_add;
1284f545923bSNikolay Aleksandrov br_vlan_notify(p->br, p, p->br->default_pvid, 0, RTM_NEWVLAN);
12852594e906SNikolay Aleksandrov }
12862594e906SNikolay Aleksandrov out:
12872594e906SNikolay Aleksandrov return ret;
12882594e906SNikolay Aleksandrov
12892594e906SNikolay Aleksandrov err_vlan_add:
129007bc588fSIdo Schimmel RCU_INIT_POINTER(p->vlgrp, NULL);
129107bc588fSIdo Schimmel synchronize_rcu();
1292efa5356bSRoopa Prabhu vlan_tunnel_deinit(vg);
1293efa5356bSRoopa Prabhu err_tunnel_init:
1294efa5356bSRoopa Prabhu rhashtable_destroy(&vg->vlan_hash);
12952594e906SNikolay Aleksandrov err_rhtbl:
1296df2c4334SYotam Gigi err_vlan_enabled:
1297263344e6SNikolay Aleksandrov kfree(vg);
12982594e906SNikolay Aleksandrov
12992594e906SNikolay Aleksandrov goto out;
13008580e211SToshiaki Makita }
13018580e211SToshiaki Makita
13028adff41cSToshiaki Makita /* Must be protected by RTNL.
13038adff41cSToshiaki Makita * Must be called with vid in range from 1 to 4094 inclusive.
1304f418af63SNikolay Aleksandrov * changed must be true only if the vlan was created or updated
13058adff41cSToshiaki Makita */
nbp_vlan_add(struct net_bridge_port * port,u16 vid,u16 flags,bool * changed,struct netlink_ext_ack * extack)1306f418af63SNikolay Aleksandrov int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags,
1307169327d5SPetr Machata bool *changed, struct netlink_ext_ack *extack)
1308243a2e63SVlad Yasevich {
13092594e906SNikolay Aleksandrov struct net_bridge_vlan *vlan;
13102594e906SNikolay Aleksandrov int ret;
1311243a2e63SVlad Yasevich
1312243a2e63SVlad Yasevich ASSERT_RTNL();
1313243a2e63SVlad Yasevich
1314f418af63SNikolay Aleksandrov *changed = false;
1315907b1e6eSNikolay Aleksandrov vlan = br_vlan_find(nbp_vlan_group(port), vid);
13162594e906SNikolay Aleksandrov if (vlan) {
131727c5f74cSVladimir Oltean bool would_change = __vlan_flags_would_change(vlan, flags);
131827c5f74cSVladimir Oltean
131927c5f74cSVladimir Oltean if (would_change) {
13207fbac984SIdo Schimmel /* Pass the flags to the hardware bridge */
13218d23a54fSVladimir Oltean ret = br_switchdev_port_vlan_add(port->dev, vid, flags,
13228d23a54fSVladimir Oltean true, extack);
13237fbac984SIdo Schimmel if (ret && ret != -EOPNOTSUPP)
13247fbac984SIdo Schimmel return ret;
132527c5f74cSVladimir Oltean }
132627c5f74cSVladimir Oltean
132727c5f74cSVladimir Oltean __vlan_flags_commit(vlan, flags);
132827c5f74cSVladimir Oltean *changed = would_change;
1329f418af63SNikolay Aleksandrov
13302594e906SNikolay Aleksandrov return 0;
1331243a2e63SVlad Yasevich }
1332243a2e63SVlad Yasevich
13332594e906SNikolay Aleksandrov vlan = kzalloc(sizeof(*vlan), GFP_KERNEL);
13342594e906SNikolay Aleksandrov if (!vlan)
13352594e906SNikolay Aleksandrov return -ENOMEM;
1336243a2e63SVlad Yasevich
13372594e906SNikolay Aleksandrov vlan->vid = vid;
13382594e906SNikolay Aleksandrov vlan->port = port;
1339169327d5SPetr Machata ret = __vlan_add(vlan, flags, extack);
13402594e906SNikolay Aleksandrov if (ret)
13412594e906SNikolay Aleksandrov kfree(vlan);
1342f418af63SNikolay Aleksandrov else
1343f418af63SNikolay Aleksandrov *changed = true;
1344243a2e63SVlad Yasevich
13452594e906SNikolay Aleksandrov return ret;
1346243a2e63SVlad Yasevich }
1347243a2e63SVlad Yasevich
13488adff41cSToshiaki Makita /* Must be protected by RTNL.
13498adff41cSToshiaki Makita * Must be called with vid in range from 1 to 4094 inclusive.
13508adff41cSToshiaki Makita */
nbp_vlan_delete(struct net_bridge_port * port,u16 vid)1351243a2e63SVlad Yasevich int nbp_vlan_delete(struct net_bridge_port *port, u16 vid)
1352243a2e63SVlad Yasevich {
13532594e906SNikolay Aleksandrov struct net_bridge_vlan *v;
1354243a2e63SVlad Yasevich
1355243a2e63SVlad Yasevich ASSERT_RTNL();
1356243a2e63SVlad Yasevich
1357907b1e6eSNikolay Aleksandrov v = br_vlan_find(nbp_vlan_group(port), vid);
13582594e906SNikolay Aleksandrov if (!v)
13592594e906SNikolay Aleksandrov return -ENOENT;
1360424bb9c9SToshiaki Makita br_fdb_find_delete_local(port->br, port, port->dev->dev_addr, vid);
13611ea2d020SNikolay Aleksandrov br_fdb_delete_by_port(port->br, port, vid, 0);
1362bc9a25d2SVlad Yasevich
13632594e906SNikolay Aleksandrov return __vlan_del(v);
1364243a2e63SVlad Yasevich }
1365243a2e63SVlad Yasevich
nbp_vlan_flush(struct net_bridge_port * port)1366243a2e63SVlad Yasevich void nbp_vlan_flush(struct net_bridge_port *port)
1367243a2e63SVlad Yasevich {
1368f409d0edSNikolay Aleksandrov struct net_bridge_vlan_group *vg;
1369f409d0edSNikolay Aleksandrov
1370243a2e63SVlad Yasevich ASSERT_RTNL();
1371243a2e63SVlad Yasevich
1372f409d0edSNikolay Aleksandrov vg = nbp_vlan_group(port);
1373f545923bSNikolay Aleksandrov __vlan_flush(port->br, port, vg);
1374f409d0edSNikolay Aleksandrov RCU_INIT_POINTER(port->vlgrp, NULL);
1375f409d0edSNikolay Aleksandrov synchronize_rcu();
1376f409d0edSNikolay Aleksandrov __vlan_group_free(vg);
13775be5a2dfSVlad Yasevich }
1378a60c0903SNikolay Aleksandrov
br_vlan_get_stats(const struct net_bridge_vlan * v,struct pcpu_sw_netstats * stats)1379a60c0903SNikolay Aleksandrov void br_vlan_get_stats(const struct net_bridge_vlan *v,
1380281cc284SHeiner Kallweit struct pcpu_sw_netstats *stats)
1381a60c0903SNikolay Aleksandrov {
1382a60c0903SNikolay Aleksandrov int i;
1383a60c0903SNikolay Aleksandrov
1384a60c0903SNikolay Aleksandrov memset(stats, 0, sizeof(*stats));
1385a60c0903SNikolay Aleksandrov for_each_possible_cpu(i) {
1386a60c0903SNikolay Aleksandrov u64 rxpackets, rxbytes, txpackets, txbytes;
1387281cc284SHeiner Kallweit struct pcpu_sw_netstats *cpu_stats;
1388a60c0903SNikolay Aleksandrov unsigned int start;
1389a60c0903SNikolay Aleksandrov
1390a60c0903SNikolay Aleksandrov cpu_stats = per_cpu_ptr(v->stats, i);
1391a60c0903SNikolay Aleksandrov do {
1392d120d1a6SThomas Gleixner start = u64_stats_fetch_begin(&cpu_stats->syncp);
13939962acefSEric Dumazet rxpackets = u64_stats_read(&cpu_stats->rx_packets);
13949962acefSEric Dumazet rxbytes = u64_stats_read(&cpu_stats->rx_bytes);
13959962acefSEric Dumazet txbytes = u64_stats_read(&cpu_stats->tx_bytes);
13969962acefSEric Dumazet txpackets = u64_stats_read(&cpu_stats->tx_packets);
1397d120d1a6SThomas Gleixner } while (u64_stats_fetch_retry(&cpu_stats->syncp, start));
1398a60c0903SNikolay Aleksandrov
13999962acefSEric Dumazet u64_stats_add(&stats->rx_packets, rxpackets);
14009962acefSEric Dumazet u64_stats_add(&stats->rx_bytes, rxbytes);
14019962acefSEric Dumazet u64_stats_add(&stats->tx_bytes, txbytes);
14029962acefSEric Dumazet u64_stats_add(&stats->tx_packets, txpackets);
1403a60c0903SNikolay Aleksandrov }
1404a60c0903SNikolay Aleksandrov }
14054d4fd361SPetr Machata
br_vlan_get_pvid(const struct net_device * dev,u16 * p_pvid)140699f62a74SVladimir Oltean int br_vlan_get_pvid(const struct net_device *dev, u16 *p_pvid)
14074d4fd361SPetr Machata {
14084d4fd361SPetr Machata struct net_bridge_vlan_group *vg;
140999f62a74SVladimir Oltean struct net_bridge_port *p;
14104d4fd361SPetr Machata
141199f62a74SVladimir Oltean ASSERT_RTNL();
141299f62a74SVladimir Oltean p = br_port_get_check_rtnl(dev);
14135a6db04cSIdo Schimmel if (p)
14145a6db04cSIdo Schimmel vg = nbp_vlan_group(p);
14155a6db04cSIdo Schimmel else if (netif_is_bridge_master(dev))
14164d4fd361SPetr Machata vg = br_vlan_group(netdev_priv(dev));
14174d4fd361SPetr Machata else
14184d4fd361SPetr Machata return -EINVAL;
14194d4fd361SPetr Machata
14204d4fd361SPetr Machata *p_pvid = br_get_pvid(vg);
14214d4fd361SPetr Machata return 0;
14224d4fd361SPetr Machata }
14234d4fd361SPetr Machata EXPORT_SYMBOL_GPL(br_vlan_get_pvid);
14244d4fd361SPetr Machata
br_vlan_get_pvid_rcu(const struct net_device * dev,u16 * p_pvid)14257582f5b7SPablo Neira Ayuso int br_vlan_get_pvid_rcu(const struct net_device *dev, u16 *p_pvid)
14267582f5b7SPablo Neira Ayuso {
142799f62a74SVladimir Oltean struct net_bridge_vlan_group *vg;
142899f62a74SVladimir Oltean struct net_bridge_port *p;
142999f62a74SVladimir Oltean
143099f62a74SVladimir Oltean p = br_port_get_check_rcu(dev);
143199f62a74SVladimir Oltean if (p)
143299f62a74SVladimir Oltean vg = nbp_vlan_group_rcu(p);
143399f62a74SVladimir Oltean else if (netif_is_bridge_master(dev))
143499f62a74SVladimir Oltean vg = br_vlan_group_rcu(netdev_priv(dev));
143599f62a74SVladimir Oltean else
143699f62a74SVladimir Oltean return -EINVAL;
143799f62a74SVladimir Oltean
143899f62a74SVladimir Oltean *p_pvid = br_get_pvid(vg);
143999f62a74SVladimir Oltean return 0;
14407582f5b7SPablo Neira Ayuso }
14417582f5b7SPablo Neira Ayuso EXPORT_SYMBOL_GPL(br_vlan_get_pvid_rcu);
14427582f5b7SPablo Neira Ayuso
br_vlan_fill_forward_path_pvid(struct net_bridge * br,struct net_device_path_ctx * ctx,struct net_device_path * path)1443bcf2766bSFelix Fietkau void br_vlan_fill_forward_path_pvid(struct net_bridge *br,
1444bcf2766bSFelix Fietkau struct net_device_path_ctx *ctx,
1445bcf2766bSFelix Fietkau struct net_device_path *path)
1446bcf2766bSFelix Fietkau {
1447bcf2766bSFelix Fietkau struct net_bridge_vlan_group *vg;
1448bcf2766bSFelix Fietkau int idx = ctx->num_vlans - 1;
1449bcf2766bSFelix Fietkau u16 vid;
1450bcf2766bSFelix Fietkau
1451bcf2766bSFelix Fietkau path->bridge.vlan_mode = DEV_PATH_BR_VLAN_KEEP;
1452bcf2766bSFelix Fietkau
1453bcf2766bSFelix Fietkau if (!br_opt_get(br, BROPT_VLAN_ENABLED))
1454bcf2766bSFelix Fietkau return;
1455bcf2766bSFelix Fietkau
1456bcf2766bSFelix Fietkau vg = br_vlan_group(br);
1457bcf2766bSFelix Fietkau
1458bcf2766bSFelix Fietkau if (idx >= 0 &&
1459bcf2766bSFelix Fietkau ctx->vlan[idx].proto == br->vlan_proto) {
1460bcf2766bSFelix Fietkau vid = ctx->vlan[idx].id;
1461bcf2766bSFelix Fietkau } else {
1462bcf2766bSFelix Fietkau path->bridge.vlan_mode = DEV_PATH_BR_VLAN_TAG;
1463bcf2766bSFelix Fietkau vid = br_get_pvid(vg);
1464bcf2766bSFelix Fietkau }
1465bcf2766bSFelix Fietkau
1466bcf2766bSFelix Fietkau path->bridge.vlan_id = vid;
1467bcf2766bSFelix Fietkau path->bridge.vlan_proto = br->vlan_proto;
1468bcf2766bSFelix Fietkau }
1469bcf2766bSFelix Fietkau
br_vlan_fill_forward_path_mode(struct net_bridge * br,struct net_bridge_port * dst,struct net_device_path * path)1470bcf2766bSFelix Fietkau int br_vlan_fill_forward_path_mode(struct net_bridge *br,
1471bcf2766bSFelix Fietkau struct net_bridge_port *dst,
1472bcf2766bSFelix Fietkau struct net_device_path *path)
1473bcf2766bSFelix Fietkau {
1474bcf2766bSFelix Fietkau struct net_bridge_vlan_group *vg;
1475bcf2766bSFelix Fietkau struct net_bridge_vlan *v;
1476bcf2766bSFelix Fietkau
1477bcf2766bSFelix Fietkau if (!br_opt_get(br, BROPT_VLAN_ENABLED))
1478bcf2766bSFelix Fietkau return 0;
1479bcf2766bSFelix Fietkau
1480bcf2766bSFelix Fietkau vg = nbp_vlan_group_rcu(dst);
1481bcf2766bSFelix Fietkau v = br_vlan_find(vg, path->bridge.vlan_id);
1482bcf2766bSFelix Fietkau if (!v || !br_vlan_should_use(v))
1483bcf2766bSFelix Fietkau return -EINVAL;
1484bcf2766bSFelix Fietkau
1485bcf2766bSFelix Fietkau if (!(v->flags & BRIDGE_VLAN_INFO_UNTAGGED))
1486bcf2766bSFelix Fietkau return 0;
1487bcf2766bSFelix Fietkau
1488bcf2766bSFelix Fietkau if (path->bridge.vlan_mode == DEV_PATH_BR_VLAN_TAG)
1489bcf2766bSFelix Fietkau path->bridge.vlan_mode = DEV_PATH_BR_VLAN_KEEP;
149026267bf9SFelix Fietkau else if (v->priv_flags & BR_VLFLAG_ADDED_BY_SWITCHDEV)
149126267bf9SFelix Fietkau path->bridge.vlan_mode = DEV_PATH_BR_VLAN_UNTAG_HW;
1492bcf2766bSFelix Fietkau else
1493bcf2766bSFelix Fietkau path->bridge.vlan_mode = DEV_PATH_BR_VLAN_UNTAG;
1494bcf2766bSFelix Fietkau
1495bcf2766bSFelix Fietkau return 0;
1496bcf2766bSFelix Fietkau }
1497bcf2766bSFelix Fietkau
br_vlan_get_info(const struct net_device * dev,u16 vid,struct bridge_vlan_info * p_vinfo)14984d4fd361SPetr Machata int br_vlan_get_info(const struct net_device *dev, u16 vid,
14994d4fd361SPetr Machata struct bridge_vlan_info *p_vinfo)
15004d4fd361SPetr Machata {
15014d4fd361SPetr Machata struct net_bridge_vlan_group *vg;
15024d4fd361SPetr Machata struct net_bridge_vlan *v;
15034d4fd361SPetr Machata struct net_bridge_port *p;
15044d4fd361SPetr Machata
15054d4fd361SPetr Machata ASSERT_RTNL();
15064d4fd361SPetr Machata p = br_port_get_check_rtnl(dev);
15074d4fd361SPetr Machata if (p)
15084d4fd361SPetr Machata vg = nbp_vlan_group(p);
15092b18d79eSPetr Machata else if (netif_is_bridge_master(dev))
15102b18d79eSPetr Machata vg = br_vlan_group(netdev_priv(dev));
15114d4fd361SPetr Machata else
15124d4fd361SPetr Machata return -EINVAL;
15134d4fd361SPetr Machata
15144d4fd361SPetr Machata v = br_vlan_find(vg, vid);
15154d4fd361SPetr Machata if (!v)
15164d4fd361SPetr Machata return -ENOENT;
15174d4fd361SPetr Machata
15184d4fd361SPetr Machata p_vinfo->vid = vid;
15194d4fd361SPetr Machata p_vinfo->flags = v->flags;
1520f40d9b20SVladimir Oltean if (vid == br_get_pvid(vg))
1521f40d9b20SVladimir Oltean p_vinfo->flags |= BRIDGE_VLAN_INFO_PVID;
15224d4fd361SPetr Machata return 0;
15234d4fd361SPetr Machata }
15244d4fd361SPetr Machata EXPORT_SYMBOL_GPL(br_vlan_get_info);
15259c0ec2e7SMike Manning
br_vlan_get_info_rcu(const struct net_device * dev,u16 vid,struct bridge_vlan_info * p_vinfo)1526ee80dd2eSVladimir Oltean int br_vlan_get_info_rcu(const struct net_device *dev, u16 vid,
1527ee80dd2eSVladimir Oltean struct bridge_vlan_info *p_vinfo)
1528ee80dd2eSVladimir Oltean {
1529ee80dd2eSVladimir Oltean struct net_bridge_vlan_group *vg;
1530ee80dd2eSVladimir Oltean struct net_bridge_vlan *v;
1531ee80dd2eSVladimir Oltean struct net_bridge_port *p;
1532ee80dd2eSVladimir Oltean
1533ee80dd2eSVladimir Oltean p = br_port_get_check_rcu(dev);
1534ee80dd2eSVladimir Oltean if (p)
1535ee80dd2eSVladimir Oltean vg = nbp_vlan_group_rcu(p);
1536ee80dd2eSVladimir Oltean else if (netif_is_bridge_master(dev))
1537ee80dd2eSVladimir Oltean vg = br_vlan_group_rcu(netdev_priv(dev));
1538ee80dd2eSVladimir Oltean else
1539ee80dd2eSVladimir Oltean return -EINVAL;
1540ee80dd2eSVladimir Oltean
1541ee80dd2eSVladimir Oltean v = br_vlan_find(vg, vid);
1542ee80dd2eSVladimir Oltean if (!v)
1543ee80dd2eSVladimir Oltean return -ENOENT;
1544ee80dd2eSVladimir Oltean
1545ee80dd2eSVladimir Oltean p_vinfo->vid = vid;
1546ee80dd2eSVladimir Oltean p_vinfo->flags = v->flags;
1547ee80dd2eSVladimir Oltean if (vid == br_get_pvid(vg))
1548ee80dd2eSVladimir Oltean p_vinfo->flags |= BRIDGE_VLAN_INFO_PVID;
1549ee80dd2eSVladimir Oltean return 0;
1550ee80dd2eSVladimir Oltean }
1551ee80dd2eSVladimir Oltean EXPORT_SYMBOL_GPL(br_vlan_get_info_rcu);
1552ee80dd2eSVladimir Oltean
br_vlan_is_bind_vlan_dev(const struct net_device * dev)15539c0ec2e7SMike Manning static int br_vlan_is_bind_vlan_dev(const struct net_device *dev)
15549c0ec2e7SMike Manning {
15559c0ec2e7SMike Manning return is_vlan_dev(dev) &&
15569c0ec2e7SMike Manning !!(vlan_dev_priv(dev)->flags & VLAN_FLAG_BRIDGE_BINDING);
15579c0ec2e7SMike Manning }
15589c0ec2e7SMike Manning
br_vlan_is_bind_vlan_dev_fn(struct net_device * dev,__always_unused struct netdev_nested_priv * priv)15599c0ec2e7SMike Manning static int br_vlan_is_bind_vlan_dev_fn(struct net_device *dev,
1560eff74233STaehee Yoo __always_unused struct netdev_nested_priv *priv)
15619c0ec2e7SMike Manning {
15629c0ec2e7SMike Manning return br_vlan_is_bind_vlan_dev(dev);
15639c0ec2e7SMike Manning }
15649c0ec2e7SMike Manning
br_vlan_has_upper_bind_vlan_dev(struct net_device * dev)15659c0ec2e7SMike Manning static bool br_vlan_has_upper_bind_vlan_dev(struct net_device *dev)
15669c0ec2e7SMike Manning {
15679c0ec2e7SMike Manning int found;
15689c0ec2e7SMike Manning
15699c0ec2e7SMike Manning rcu_read_lock();
15709c0ec2e7SMike Manning found = netdev_walk_all_upper_dev_rcu(dev, br_vlan_is_bind_vlan_dev_fn,
15719c0ec2e7SMike Manning NULL);
15729c0ec2e7SMike Manning rcu_read_unlock();
15739c0ec2e7SMike Manning
15749c0ec2e7SMike Manning return !!found;
15759c0ec2e7SMike Manning }
15769c0ec2e7SMike Manning
15779c0ec2e7SMike Manning struct br_vlan_bind_walk_data {
15789c0ec2e7SMike Manning u16 vid;
15799c0ec2e7SMike Manning struct net_device *result;
15809c0ec2e7SMike Manning };
15819c0ec2e7SMike Manning
br_vlan_match_bind_vlan_dev_fn(struct net_device * dev,struct netdev_nested_priv * priv)15829c0ec2e7SMike Manning static int br_vlan_match_bind_vlan_dev_fn(struct net_device *dev,
1583eff74233STaehee Yoo struct netdev_nested_priv *priv)
15849c0ec2e7SMike Manning {
1585eff74233STaehee Yoo struct br_vlan_bind_walk_data *data = priv->data;
15869c0ec2e7SMike Manning int found = 0;
15879c0ec2e7SMike Manning
15889c0ec2e7SMike Manning if (br_vlan_is_bind_vlan_dev(dev) &&
15899c0ec2e7SMike Manning vlan_dev_priv(dev)->vlan_id == data->vid) {
15909c0ec2e7SMike Manning data->result = dev;
15919c0ec2e7SMike Manning found = 1;
15929c0ec2e7SMike Manning }
15939c0ec2e7SMike Manning
15949c0ec2e7SMike Manning return found;
15959c0ec2e7SMike Manning }
15969c0ec2e7SMike Manning
15979c0ec2e7SMike Manning static struct net_device *
br_vlan_get_upper_bind_vlan_dev(struct net_device * dev,u16 vid)15989c0ec2e7SMike Manning br_vlan_get_upper_bind_vlan_dev(struct net_device *dev, u16 vid)
15999c0ec2e7SMike Manning {
16009c0ec2e7SMike Manning struct br_vlan_bind_walk_data data = {
16019c0ec2e7SMike Manning .vid = vid,
16029c0ec2e7SMike Manning };
1603eff74233STaehee Yoo struct netdev_nested_priv priv = {
1604eff74233STaehee Yoo .data = (void *)&data,
1605eff74233STaehee Yoo };
16069c0ec2e7SMike Manning
16079c0ec2e7SMike Manning rcu_read_lock();
16089c0ec2e7SMike Manning netdev_walk_all_upper_dev_rcu(dev, br_vlan_match_bind_vlan_dev_fn,
1609eff74233STaehee Yoo &priv);
16109c0ec2e7SMike Manning rcu_read_unlock();
16119c0ec2e7SMike Manning
16129c0ec2e7SMike Manning return data.result;
16139c0ec2e7SMike Manning }
16149c0ec2e7SMike Manning
br_vlan_is_dev_up(const struct net_device * dev)16159c0ec2e7SMike Manning static bool br_vlan_is_dev_up(const struct net_device *dev)
16169c0ec2e7SMike Manning {
16179c0ec2e7SMike Manning return !!(dev->flags & IFF_UP) && netif_oper_up(dev);
16189c0ec2e7SMike Manning }
16199c0ec2e7SMike Manning
br_vlan_set_vlan_dev_state(const struct net_bridge * br,struct net_device * vlan_dev)16209c0ec2e7SMike Manning static void br_vlan_set_vlan_dev_state(const struct net_bridge *br,
16219c0ec2e7SMike Manning struct net_device *vlan_dev)
16229c0ec2e7SMike Manning {
16239c0ec2e7SMike Manning u16 vid = vlan_dev_priv(vlan_dev)->vlan_id;
16249c0ec2e7SMike Manning struct net_bridge_vlan_group *vg;
16259c0ec2e7SMike Manning struct net_bridge_port *p;
16269c0ec2e7SMike Manning bool has_carrier = false;
16279c0ec2e7SMike Manning
16288e1acd4fSMike Manning if (!netif_carrier_ok(br->dev)) {
16298e1acd4fSMike Manning netif_carrier_off(vlan_dev);
16308e1acd4fSMike Manning return;
16318e1acd4fSMike Manning }
16328e1acd4fSMike Manning
16339c0ec2e7SMike Manning list_for_each_entry(p, &br->port_list, list) {
16349c0ec2e7SMike Manning vg = nbp_vlan_group(p);
16359c0ec2e7SMike Manning if (br_vlan_find(vg, vid) && br_vlan_is_dev_up(p->dev)) {
16369c0ec2e7SMike Manning has_carrier = true;
16379c0ec2e7SMike Manning break;
16389c0ec2e7SMike Manning }
16399c0ec2e7SMike Manning }
16409c0ec2e7SMike Manning
16419c0ec2e7SMike Manning if (has_carrier)
16429c0ec2e7SMike Manning netif_carrier_on(vlan_dev);
16439c0ec2e7SMike Manning else
16449c0ec2e7SMike Manning netif_carrier_off(vlan_dev);
16459c0ec2e7SMike Manning }
16469c0ec2e7SMike Manning
br_vlan_set_all_vlan_dev_state(struct net_bridge_port * p)16479c0ec2e7SMike Manning static void br_vlan_set_all_vlan_dev_state(struct net_bridge_port *p)
16489c0ec2e7SMike Manning {
16499c0ec2e7SMike Manning struct net_bridge_vlan_group *vg = nbp_vlan_group(p);
16509c0ec2e7SMike Manning struct net_bridge_vlan *vlan;
16519c0ec2e7SMike Manning struct net_device *vlan_dev;
16529c0ec2e7SMike Manning
16539c0ec2e7SMike Manning list_for_each_entry(vlan, &vg->vlan_list, vlist) {
16549c0ec2e7SMike Manning vlan_dev = br_vlan_get_upper_bind_vlan_dev(p->br->dev,
16559c0ec2e7SMike Manning vlan->vid);
16569c0ec2e7SMike Manning if (vlan_dev) {
16578e1acd4fSMike Manning if (br_vlan_is_dev_up(p->dev)) {
16588e1acd4fSMike Manning if (netif_carrier_ok(p->br->dev))
16599c0ec2e7SMike Manning netif_carrier_on(vlan_dev);
16608e1acd4fSMike Manning } else {
16619c0ec2e7SMike Manning br_vlan_set_vlan_dev_state(p->br, vlan_dev);
16629c0ec2e7SMike Manning }
16639c0ec2e7SMike Manning }
16649c0ec2e7SMike Manning }
16658e1acd4fSMike Manning }
16669c0ec2e7SMike Manning
br_vlan_upper_change(struct net_device * dev,struct net_device * upper_dev,bool linking)16679c0ec2e7SMike Manning static void br_vlan_upper_change(struct net_device *dev,
16689c0ec2e7SMike Manning struct net_device *upper_dev,
16699c0ec2e7SMike Manning bool linking)
16709c0ec2e7SMike Manning {
16719c0ec2e7SMike Manning struct net_bridge *br = netdev_priv(dev);
16729c0ec2e7SMike Manning
16739c0ec2e7SMike Manning if (!br_vlan_is_bind_vlan_dev(upper_dev))
16749c0ec2e7SMike Manning return;
16759c0ec2e7SMike Manning
16769c0ec2e7SMike Manning if (linking) {
16779c0ec2e7SMike Manning br_vlan_set_vlan_dev_state(br, upper_dev);
16789c0ec2e7SMike Manning br_opt_toggle(br, BROPT_VLAN_BRIDGE_BINDING, true);
16799c0ec2e7SMike Manning } else {
16809c0ec2e7SMike Manning br_opt_toggle(br, BROPT_VLAN_BRIDGE_BINDING,
16819c0ec2e7SMike Manning br_vlan_has_upper_bind_vlan_dev(dev));
16829c0ec2e7SMike Manning }
16839c0ec2e7SMike Manning }
16849c0ec2e7SMike Manning
16858e1acd4fSMike Manning struct br_vlan_link_state_walk_data {
16868e1acd4fSMike Manning struct net_bridge *br;
16878e1acd4fSMike Manning };
16888e1acd4fSMike Manning
br_vlan_link_state_change_fn(struct net_device * vlan_dev,struct netdev_nested_priv * priv)16898e1acd4fSMike Manning static int br_vlan_link_state_change_fn(struct net_device *vlan_dev,
1690eff74233STaehee Yoo struct netdev_nested_priv *priv)
16918e1acd4fSMike Manning {
1692eff74233STaehee Yoo struct br_vlan_link_state_walk_data *data = priv->data;
16938e1acd4fSMike Manning
16948e1acd4fSMike Manning if (br_vlan_is_bind_vlan_dev(vlan_dev))
16958e1acd4fSMike Manning br_vlan_set_vlan_dev_state(data->br, vlan_dev);
16968e1acd4fSMike Manning
16978e1acd4fSMike Manning return 0;
16988e1acd4fSMike Manning }
16998e1acd4fSMike Manning
br_vlan_link_state_change(struct net_device * dev,struct net_bridge * br)17008e1acd4fSMike Manning static void br_vlan_link_state_change(struct net_device *dev,
17018e1acd4fSMike Manning struct net_bridge *br)
17028e1acd4fSMike Manning {
17038e1acd4fSMike Manning struct br_vlan_link_state_walk_data data = {
17048e1acd4fSMike Manning .br = br
17058e1acd4fSMike Manning };
1706eff74233STaehee Yoo struct netdev_nested_priv priv = {
1707eff74233STaehee Yoo .data = (void *)&data,
1708eff74233STaehee Yoo };
17098e1acd4fSMike Manning
17108e1acd4fSMike Manning rcu_read_lock();
17118e1acd4fSMike Manning netdev_walk_all_upper_dev_rcu(dev, br_vlan_link_state_change_fn,
1712eff74233STaehee Yoo &priv);
17138e1acd4fSMike Manning rcu_read_unlock();
17148e1acd4fSMike Manning }
17158e1acd4fSMike Manning
17169c0ec2e7SMike Manning /* Must be protected by RTNL. */
nbp_vlan_set_vlan_dev_state(struct net_bridge_port * p,u16 vid)171780900acdSMike Manning static void nbp_vlan_set_vlan_dev_state(struct net_bridge_port *p, u16 vid)
171880900acdSMike Manning {
171980900acdSMike Manning struct net_device *vlan_dev;
172080900acdSMike Manning
172180900acdSMike Manning if (!br_opt_get(p->br, BROPT_VLAN_BRIDGE_BINDING))
172280900acdSMike Manning return;
172380900acdSMike Manning
172480900acdSMike Manning vlan_dev = br_vlan_get_upper_bind_vlan_dev(p->br->dev, vid);
172580900acdSMike Manning if (vlan_dev)
172680900acdSMike Manning br_vlan_set_vlan_dev_state(p->br, vlan_dev);
172780900acdSMike Manning }
172880900acdSMike Manning
172980900acdSMike Manning /* Must be protected by RTNL. */
br_vlan_bridge_event(struct net_device * dev,unsigned long event,void * ptr)1730091adf9bSNikolay Aleksandrov int br_vlan_bridge_event(struct net_device *dev, unsigned long event, void *ptr)
17319c0ec2e7SMike Manning {
17329c0ec2e7SMike Manning struct netdev_notifier_changeupper_info *info;
1733091adf9bSNikolay Aleksandrov struct net_bridge *br = netdev_priv(dev);
1734f545923bSNikolay Aleksandrov int vlcmd = 0, ret = 0;
1735f545923bSNikolay Aleksandrov bool changed = false;
17369c0ec2e7SMike Manning
17379c0ec2e7SMike Manning switch (event) {
1738091adf9bSNikolay Aleksandrov case NETDEV_REGISTER:
1739091adf9bSNikolay Aleksandrov ret = br_vlan_add(br, br->default_pvid,
1740091adf9bSNikolay Aleksandrov BRIDGE_VLAN_INFO_PVID |
1741091adf9bSNikolay Aleksandrov BRIDGE_VLAN_INFO_UNTAGGED |
1742091adf9bSNikolay Aleksandrov BRIDGE_VLAN_INFO_BRENTRY, &changed, NULL);
1743f545923bSNikolay Aleksandrov vlcmd = RTM_NEWVLAN;
1744091adf9bSNikolay Aleksandrov break;
1745091adf9bSNikolay Aleksandrov case NETDEV_UNREGISTER:
1746f545923bSNikolay Aleksandrov changed = !br_vlan_delete(br, br->default_pvid);
1747f545923bSNikolay Aleksandrov vlcmd = RTM_DELVLAN;
1748091adf9bSNikolay Aleksandrov break;
17499c0ec2e7SMike Manning case NETDEV_CHANGEUPPER:
17509c0ec2e7SMike Manning info = ptr;
17519c0ec2e7SMike Manning br_vlan_upper_change(dev, info->upper_dev, info->linking);
17529c0ec2e7SMike Manning break;
17538e1acd4fSMike Manning
17548e1acd4fSMike Manning case NETDEV_CHANGE:
17558e1acd4fSMike Manning case NETDEV_UP:
17568e1acd4fSMike Manning if (!br_opt_get(br, BROPT_VLAN_BRIDGE_BINDING))
1757091adf9bSNikolay Aleksandrov break;
17588e1acd4fSMike Manning br_vlan_link_state_change(dev, br);
17598e1acd4fSMike Manning break;
17609c0ec2e7SMike Manning }
1761f545923bSNikolay Aleksandrov if (changed)
1762f545923bSNikolay Aleksandrov br_vlan_notify(br, NULL, br->default_pvid, 0, vlcmd);
1763091adf9bSNikolay Aleksandrov
1764091adf9bSNikolay Aleksandrov return ret;
17659c0ec2e7SMike Manning }
17669c0ec2e7SMike Manning
17679c0ec2e7SMike Manning /* Must be protected by RTNL. */
br_vlan_port_event(struct net_bridge_port * p,unsigned long event)17689c0ec2e7SMike Manning void br_vlan_port_event(struct net_bridge_port *p, unsigned long event)
17699c0ec2e7SMike Manning {
17709c0ec2e7SMike Manning if (!br_opt_get(p->br, BROPT_VLAN_BRIDGE_BINDING))
17719c0ec2e7SMike Manning return;
17729c0ec2e7SMike Manning
17739c0ec2e7SMike Manning switch (event) {
17749c0ec2e7SMike Manning case NETDEV_CHANGE:
17759c0ec2e7SMike Manning case NETDEV_DOWN:
17769c0ec2e7SMike Manning case NETDEV_UP:
17779c0ec2e7SMike Manning br_vlan_set_all_vlan_dev_state(p);
17789c0ec2e7SMike Manning break;
17799c0ec2e7SMike Manning }
17809c0ec2e7SMike Manning }
17818dcea187SNikolay Aleksandrov
br_vlan_stats_fill(struct sk_buff * skb,const struct net_bridge_vlan * v)178256d09976SNikolay Aleksandrov static bool br_vlan_stats_fill(struct sk_buff *skb,
178356d09976SNikolay Aleksandrov const struct net_bridge_vlan *v)
178456d09976SNikolay Aleksandrov {
1785281cc284SHeiner Kallweit struct pcpu_sw_netstats stats;
178656d09976SNikolay Aleksandrov struct nlattr *nest;
178756d09976SNikolay Aleksandrov
178856d09976SNikolay Aleksandrov nest = nla_nest_start(skb, BRIDGE_VLANDB_ENTRY_STATS);
178956d09976SNikolay Aleksandrov if (!nest)
179056d09976SNikolay Aleksandrov return false;
179156d09976SNikolay Aleksandrov
179256d09976SNikolay Aleksandrov br_vlan_get_stats(v, &stats);
17939962acefSEric Dumazet if (nla_put_u64_64bit(skb, BRIDGE_VLANDB_STATS_RX_BYTES,
17949962acefSEric Dumazet u64_stats_read(&stats.rx_bytes),
179556d09976SNikolay Aleksandrov BRIDGE_VLANDB_STATS_PAD) ||
179656d09976SNikolay Aleksandrov nla_put_u64_64bit(skb, BRIDGE_VLANDB_STATS_RX_PACKETS,
17979962acefSEric Dumazet u64_stats_read(&stats.rx_packets),
17989962acefSEric Dumazet BRIDGE_VLANDB_STATS_PAD) ||
17999962acefSEric Dumazet nla_put_u64_64bit(skb, BRIDGE_VLANDB_STATS_TX_BYTES,
18009962acefSEric Dumazet u64_stats_read(&stats.tx_bytes),
180156d09976SNikolay Aleksandrov BRIDGE_VLANDB_STATS_PAD) ||
180256d09976SNikolay Aleksandrov nla_put_u64_64bit(skb, BRIDGE_VLANDB_STATS_TX_PACKETS,
18039962acefSEric Dumazet u64_stats_read(&stats.tx_packets),
18049962acefSEric Dumazet BRIDGE_VLANDB_STATS_PAD))
180556d09976SNikolay Aleksandrov goto out_err;
180656d09976SNikolay Aleksandrov
180756d09976SNikolay Aleksandrov nla_nest_end(skb, nest);
180856d09976SNikolay Aleksandrov
180956d09976SNikolay Aleksandrov return true;
181056d09976SNikolay Aleksandrov
181156d09976SNikolay Aleksandrov out_err:
181256d09976SNikolay Aleksandrov nla_nest_cancel(skb, nest);
181356d09976SNikolay Aleksandrov return false;
181456d09976SNikolay Aleksandrov }
181556d09976SNikolay Aleksandrov
18167a53e718SNikolay Aleksandrov /* v_opts is used to dump the options which must be equal in the whole range */
br_vlan_fill_vids(struct sk_buff * skb,u16 vid,u16 vid_range,const struct net_bridge_vlan * v_opts,const struct net_bridge_port * p,u16 flags,bool dump_stats)18170ab55879SNikolay Aleksandrov static bool br_vlan_fill_vids(struct sk_buff *skb, u16 vid, u16 vid_range,
18187a53e718SNikolay Aleksandrov const struct net_bridge_vlan *v_opts,
1819a1aee20dSPetr Machata const struct net_bridge_port *p,
182056d09976SNikolay Aleksandrov u16 flags,
182156d09976SNikolay Aleksandrov bool dump_stats)
18228dcea187SNikolay Aleksandrov {
18238dcea187SNikolay Aleksandrov struct bridge_vlan_info info;
18248dcea187SNikolay Aleksandrov struct nlattr *nest;
18258dcea187SNikolay Aleksandrov
18268dcea187SNikolay Aleksandrov nest = nla_nest_start(skb, BRIDGE_VLANDB_ENTRY);
18278dcea187SNikolay Aleksandrov if (!nest)
18288dcea187SNikolay Aleksandrov return false;
18298dcea187SNikolay Aleksandrov
18308dcea187SNikolay Aleksandrov memset(&info, 0, sizeof(info));
18318dcea187SNikolay Aleksandrov info.vid = vid;
18328dcea187SNikolay Aleksandrov if (flags & BRIDGE_VLAN_INFO_UNTAGGED)
18338dcea187SNikolay Aleksandrov info.flags |= BRIDGE_VLAN_INFO_UNTAGGED;
18348dcea187SNikolay Aleksandrov if (flags & BRIDGE_VLAN_INFO_PVID)
18358dcea187SNikolay Aleksandrov info.flags |= BRIDGE_VLAN_INFO_PVID;
18368dcea187SNikolay Aleksandrov
18378dcea187SNikolay Aleksandrov if (nla_put(skb, BRIDGE_VLANDB_ENTRY_INFO, sizeof(info), &info))
18388dcea187SNikolay Aleksandrov goto out_err;
18398dcea187SNikolay Aleksandrov
18400ab55879SNikolay Aleksandrov if (vid_range && vid < vid_range &&
18410ab55879SNikolay Aleksandrov !(flags & BRIDGE_VLAN_INFO_PVID) &&
18420ab55879SNikolay Aleksandrov nla_put_u16(skb, BRIDGE_VLANDB_ENTRY_RANGE, vid_range))
18430ab55879SNikolay Aleksandrov goto out_err;
18440ab55879SNikolay Aleksandrov
184556d09976SNikolay Aleksandrov if (v_opts) {
1846a1aee20dSPetr Machata if (!br_vlan_opts_fill(skb, v_opts, p))
18477a53e718SNikolay Aleksandrov goto out_err;
18487a53e718SNikolay Aleksandrov
184956d09976SNikolay Aleksandrov if (dump_stats && !br_vlan_stats_fill(skb, v_opts))
185056d09976SNikolay Aleksandrov goto out_err;
185156d09976SNikolay Aleksandrov }
185256d09976SNikolay Aleksandrov
18538dcea187SNikolay Aleksandrov nla_nest_end(skb, nest);
18548dcea187SNikolay Aleksandrov
18558dcea187SNikolay Aleksandrov return true;
18568dcea187SNikolay Aleksandrov
18578dcea187SNikolay Aleksandrov out_err:
18588dcea187SNikolay Aleksandrov nla_nest_cancel(skb, nest);
18598dcea187SNikolay Aleksandrov return false;
18608dcea187SNikolay Aleksandrov }
18618dcea187SNikolay Aleksandrov
rtnl_vlan_nlmsg_size(void)1862cf5bddb9SNikolay Aleksandrov static size_t rtnl_vlan_nlmsg_size(void)
1863cf5bddb9SNikolay Aleksandrov {
1864cf5bddb9SNikolay Aleksandrov return NLMSG_ALIGN(sizeof(struct br_vlan_msg))
1865cf5bddb9SNikolay Aleksandrov + nla_total_size(0) /* BRIDGE_VLANDB_ENTRY */
1866cf5bddb9SNikolay Aleksandrov + nla_total_size(sizeof(u16)) /* BRIDGE_VLANDB_ENTRY_RANGE */
18677a53e718SNikolay Aleksandrov + nla_total_size(sizeof(struct bridge_vlan_info)) /* BRIDGE_VLANDB_ENTRY_INFO */
18687a53e718SNikolay Aleksandrov + br_vlan_opts_nl_size(); /* bridge vlan options */
1869cf5bddb9SNikolay Aleksandrov }
1870cf5bddb9SNikolay Aleksandrov
br_vlan_notify(const struct net_bridge * br,const struct net_bridge_port * p,u16 vid,u16 vid_range,int cmd)1871cf5bddb9SNikolay Aleksandrov void br_vlan_notify(const struct net_bridge *br,
1872cf5bddb9SNikolay Aleksandrov const struct net_bridge_port *p,
1873cf5bddb9SNikolay Aleksandrov u16 vid, u16 vid_range,
1874cf5bddb9SNikolay Aleksandrov int cmd)
1875cf5bddb9SNikolay Aleksandrov {
1876cf5bddb9SNikolay Aleksandrov struct net_bridge_vlan_group *vg;
18777a53e718SNikolay Aleksandrov struct net_bridge_vlan *v = NULL;
1878cf5bddb9SNikolay Aleksandrov struct br_vlan_msg *bvm;
1879cf5bddb9SNikolay Aleksandrov struct nlmsghdr *nlh;
1880cf5bddb9SNikolay Aleksandrov struct sk_buff *skb;
1881cf5bddb9SNikolay Aleksandrov int err = -ENOBUFS;
1882cf5bddb9SNikolay Aleksandrov struct net *net;
1883cf5bddb9SNikolay Aleksandrov u16 flags = 0;
1884cf5bddb9SNikolay Aleksandrov int ifindex;
1885cf5bddb9SNikolay Aleksandrov
1886cf5bddb9SNikolay Aleksandrov /* right now notifications are done only with rtnl held */
1887cf5bddb9SNikolay Aleksandrov ASSERT_RTNL();
1888cf5bddb9SNikolay Aleksandrov
1889cf5bddb9SNikolay Aleksandrov if (p) {
1890cf5bddb9SNikolay Aleksandrov ifindex = p->dev->ifindex;
1891cf5bddb9SNikolay Aleksandrov vg = nbp_vlan_group(p);
1892cf5bddb9SNikolay Aleksandrov net = dev_net(p->dev);
1893cf5bddb9SNikolay Aleksandrov } else {
1894cf5bddb9SNikolay Aleksandrov ifindex = br->dev->ifindex;
1895cf5bddb9SNikolay Aleksandrov vg = br_vlan_group(br);
1896cf5bddb9SNikolay Aleksandrov net = dev_net(br->dev);
1897cf5bddb9SNikolay Aleksandrov }
1898cf5bddb9SNikolay Aleksandrov
1899cf5bddb9SNikolay Aleksandrov skb = nlmsg_new(rtnl_vlan_nlmsg_size(), GFP_KERNEL);
1900cf5bddb9SNikolay Aleksandrov if (!skb)
1901cf5bddb9SNikolay Aleksandrov goto out_err;
1902cf5bddb9SNikolay Aleksandrov
1903cf5bddb9SNikolay Aleksandrov err = -EMSGSIZE;
1904cf5bddb9SNikolay Aleksandrov nlh = nlmsg_put(skb, 0, 0, cmd, sizeof(*bvm), 0);
1905cf5bddb9SNikolay Aleksandrov if (!nlh)
1906cf5bddb9SNikolay Aleksandrov goto out_err;
1907cf5bddb9SNikolay Aleksandrov bvm = nlmsg_data(nlh);
1908cf5bddb9SNikolay Aleksandrov memset(bvm, 0, sizeof(*bvm));
1909cf5bddb9SNikolay Aleksandrov bvm->family = AF_BRIDGE;
1910cf5bddb9SNikolay Aleksandrov bvm->ifindex = ifindex;
1911cf5bddb9SNikolay Aleksandrov
1912cf5bddb9SNikolay Aleksandrov switch (cmd) {
1913cf5bddb9SNikolay Aleksandrov case RTM_NEWVLAN:
1914cf5bddb9SNikolay Aleksandrov /* need to find the vlan due to flags/options */
1915cf5bddb9SNikolay Aleksandrov v = br_vlan_find(vg, vid);
1916cf5bddb9SNikolay Aleksandrov if (!v || !br_vlan_should_use(v))
1917cf5bddb9SNikolay Aleksandrov goto out_kfree;
1918cf5bddb9SNikolay Aleksandrov
1919cf5bddb9SNikolay Aleksandrov flags = v->flags;
1920cf5bddb9SNikolay Aleksandrov if (br_get_pvid(vg) == v->vid)
1921cf5bddb9SNikolay Aleksandrov flags |= BRIDGE_VLAN_INFO_PVID;
1922cf5bddb9SNikolay Aleksandrov break;
1923cf5bddb9SNikolay Aleksandrov case RTM_DELVLAN:
1924cf5bddb9SNikolay Aleksandrov break;
1925cf5bddb9SNikolay Aleksandrov default:
1926cf5bddb9SNikolay Aleksandrov goto out_kfree;
1927cf5bddb9SNikolay Aleksandrov }
1928cf5bddb9SNikolay Aleksandrov
1929a1aee20dSPetr Machata if (!br_vlan_fill_vids(skb, vid, vid_range, v, p, flags, false))
1930cf5bddb9SNikolay Aleksandrov goto out_err;
1931cf5bddb9SNikolay Aleksandrov
1932cf5bddb9SNikolay Aleksandrov nlmsg_end(skb, nlh);
1933cf5bddb9SNikolay Aleksandrov rtnl_notify(skb, net, 0, RTNLGRP_BRVLAN, NULL, GFP_KERNEL);
1934cf5bddb9SNikolay Aleksandrov return;
1935cf5bddb9SNikolay Aleksandrov
1936cf5bddb9SNikolay Aleksandrov out_err:
1937cf5bddb9SNikolay Aleksandrov rtnl_set_sk_err(net, RTNLGRP_BRVLAN, err);
1938cf5bddb9SNikolay Aleksandrov out_kfree:
1939cf5bddb9SNikolay Aleksandrov kfree_skb(skb);
1940cf5bddb9SNikolay Aleksandrov }
1941cf5bddb9SNikolay Aleksandrov
19420ab55879SNikolay Aleksandrov /* check if v_curr can enter a range ending in range_end */
br_vlan_can_enter_range(const struct net_bridge_vlan * v_curr,const struct net_bridge_vlan * range_end)1943a5d29ae2SNikolay Aleksandrov bool br_vlan_can_enter_range(const struct net_bridge_vlan *v_curr,
19440ab55879SNikolay Aleksandrov const struct net_bridge_vlan *range_end)
19450ab55879SNikolay Aleksandrov {
19460ab55879SNikolay Aleksandrov return v_curr->vid - range_end->vid == 1 &&
19477a53e718SNikolay Aleksandrov range_end->flags == v_curr->flags &&
194899f7c5e0SNikolay Aleksandrov br_vlan_opts_eq_range(v_curr, range_end);
19490ab55879SNikolay Aleksandrov }
19500ab55879SNikolay Aleksandrov
br_vlan_dump_dev(const struct net_device * dev,struct sk_buff * skb,struct netlink_callback * cb,u32 dump_flags)19518dcea187SNikolay Aleksandrov static int br_vlan_dump_dev(const struct net_device *dev,
19528dcea187SNikolay Aleksandrov struct sk_buff *skb,
195356d09976SNikolay Aleksandrov struct netlink_callback *cb,
195456d09976SNikolay Aleksandrov u32 dump_flags)
19558dcea187SNikolay Aleksandrov {
19560ab55879SNikolay Aleksandrov struct net_bridge_vlan *v, *range_start = NULL, *range_end = NULL;
1957743a53d9SNikolay Aleksandrov bool dump_global = !!(dump_flags & BRIDGE_VLANDB_DUMPF_GLOBAL);
195856d09976SNikolay Aleksandrov bool dump_stats = !!(dump_flags & BRIDGE_VLANDB_DUMPF_STATS);
19598dcea187SNikolay Aleksandrov struct net_bridge_vlan_group *vg;
19608dcea187SNikolay Aleksandrov int idx = 0, s_idx = cb->args[1];
19618dcea187SNikolay Aleksandrov struct nlmsghdr *nlh = NULL;
19628dcea187SNikolay Aleksandrov struct net_bridge_port *p;
19638dcea187SNikolay Aleksandrov struct br_vlan_msg *bvm;
19648dcea187SNikolay Aleksandrov struct net_bridge *br;
19658dcea187SNikolay Aleksandrov int err = 0;
19668dcea187SNikolay Aleksandrov u16 pvid;
19678dcea187SNikolay Aleksandrov
19688dcea187SNikolay Aleksandrov if (!netif_is_bridge_master(dev) && !netif_is_bridge_port(dev))
19698dcea187SNikolay Aleksandrov return -EINVAL;
19708dcea187SNikolay Aleksandrov
19718dcea187SNikolay Aleksandrov if (netif_is_bridge_master(dev)) {
19728dcea187SNikolay Aleksandrov br = netdev_priv(dev);
19738dcea187SNikolay Aleksandrov vg = br_vlan_group_rcu(br);
19748dcea187SNikolay Aleksandrov p = NULL;
19758dcea187SNikolay Aleksandrov } else {
1976743a53d9SNikolay Aleksandrov /* global options are dumped only for bridge devices */
1977743a53d9SNikolay Aleksandrov if (dump_global)
1978743a53d9SNikolay Aleksandrov return 0;
1979743a53d9SNikolay Aleksandrov
19808dcea187SNikolay Aleksandrov p = br_port_get_rcu(dev);
19818dcea187SNikolay Aleksandrov if (WARN_ON(!p))
19828dcea187SNikolay Aleksandrov return -EINVAL;
19838dcea187SNikolay Aleksandrov vg = nbp_vlan_group_rcu(p);
19848dcea187SNikolay Aleksandrov br = p->br;
19858dcea187SNikolay Aleksandrov }
19868dcea187SNikolay Aleksandrov
19878dcea187SNikolay Aleksandrov if (!vg)
19888dcea187SNikolay Aleksandrov return 0;
19898dcea187SNikolay Aleksandrov
19908dcea187SNikolay Aleksandrov nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
19918dcea187SNikolay Aleksandrov RTM_NEWVLAN, sizeof(*bvm), NLM_F_MULTI);
19928dcea187SNikolay Aleksandrov if (!nlh)
19938dcea187SNikolay Aleksandrov return -EMSGSIZE;
19948dcea187SNikolay Aleksandrov bvm = nlmsg_data(nlh);
19958dcea187SNikolay Aleksandrov memset(bvm, 0, sizeof(*bvm));
19968dcea187SNikolay Aleksandrov bvm->family = PF_BRIDGE;
19978dcea187SNikolay Aleksandrov bvm->ifindex = dev->ifindex;
19988dcea187SNikolay Aleksandrov pvid = br_get_pvid(vg);
19998dcea187SNikolay Aleksandrov
20000ab55879SNikolay Aleksandrov /* idx must stay at range's beginning until it is filled in */
20018dcea187SNikolay Aleksandrov list_for_each_entry_rcu(v, &vg->vlan_list, vlist) {
2002743a53d9SNikolay Aleksandrov if (!dump_global && !br_vlan_should_use(v))
20038dcea187SNikolay Aleksandrov continue;
20040ab55879SNikolay Aleksandrov if (idx < s_idx) {
20050ab55879SNikolay Aleksandrov idx++;
20060ab55879SNikolay Aleksandrov continue;
20070ab55879SNikolay Aleksandrov }
20080ab55879SNikolay Aleksandrov
20090ab55879SNikolay Aleksandrov if (!range_start) {
20100ab55879SNikolay Aleksandrov range_start = v;
20110ab55879SNikolay Aleksandrov range_end = v;
20120ab55879SNikolay Aleksandrov continue;
20130ab55879SNikolay Aleksandrov }
20140ab55879SNikolay Aleksandrov
2015743a53d9SNikolay Aleksandrov if (dump_global) {
2016743a53d9SNikolay Aleksandrov if (br_vlan_global_opts_can_enter_range(v, range_end))
20176c4110d9SNikolay Aleksandrov goto update_end;
2018743a53d9SNikolay Aleksandrov if (!br_vlan_global_opts_fill(skb, range_start->vid,
2019743a53d9SNikolay Aleksandrov range_end->vid,
2020743a53d9SNikolay Aleksandrov range_start)) {
2021743a53d9SNikolay Aleksandrov err = -EMSGSIZE;
2022743a53d9SNikolay Aleksandrov break;
2023743a53d9SNikolay Aleksandrov }
2024743a53d9SNikolay Aleksandrov /* advance number of filled vlans */
2025743a53d9SNikolay Aleksandrov idx += range_end->vid - range_start->vid + 1;
2026743a53d9SNikolay Aleksandrov
2027743a53d9SNikolay Aleksandrov range_start = v;
2028743a53d9SNikolay Aleksandrov } else if (dump_stats || v->vid == pvid ||
202956d09976SNikolay Aleksandrov !br_vlan_can_enter_range(v, range_end)) {
203056d09976SNikolay Aleksandrov u16 vlan_flags = br_vlan_flags(range_start, pvid);
20310ab55879SNikolay Aleksandrov
20320ab55879SNikolay Aleksandrov if (!br_vlan_fill_vids(skb, range_start->vid,
20337a53e718SNikolay Aleksandrov range_end->vid, range_start,
2034a1aee20dSPetr Machata p, vlan_flags, dump_stats)) {
20358dcea187SNikolay Aleksandrov err = -EMSGSIZE;
20368dcea187SNikolay Aleksandrov break;
20378dcea187SNikolay Aleksandrov }
20380ab55879SNikolay Aleksandrov /* advance number of filled vlans */
20390ab55879SNikolay Aleksandrov idx += range_end->vid - range_start->vid + 1;
20400ab55879SNikolay Aleksandrov
20410ab55879SNikolay Aleksandrov range_start = v;
20428dcea187SNikolay Aleksandrov }
20436c4110d9SNikolay Aleksandrov update_end:
20440ab55879SNikolay Aleksandrov range_end = v;
20450ab55879SNikolay Aleksandrov }
20460ab55879SNikolay Aleksandrov
20470ab55879SNikolay Aleksandrov /* err will be 0 and range_start will be set in 3 cases here:
20480ab55879SNikolay Aleksandrov * - first vlan (range_start == range_end)
20490ab55879SNikolay Aleksandrov * - last vlan (range_start == range_end, not in range)
20500ab55879SNikolay Aleksandrov * - last vlan range (range_start != range_end, in range)
20510ab55879SNikolay Aleksandrov */
2052743a53d9SNikolay Aleksandrov if (!err && range_start) {
2053743a53d9SNikolay Aleksandrov if (dump_global &&
2054743a53d9SNikolay Aleksandrov !br_vlan_global_opts_fill(skb, range_start->vid,
2055743a53d9SNikolay Aleksandrov range_end->vid, range_start))
2056743a53d9SNikolay Aleksandrov err = -EMSGSIZE;
2057743a53d9SNikolay Aleksandrov else if (!dump_global &&
2058743a53d9SNikolay Aleksandrov !br_vlan_fill_vids(skb, range_start->vid,
2059743a53d9SNikolay Aleksandrov range_end->vid, range_start,
2060a1aee20dSPetr Machata p, br_vlan_flags(range_start, pvid),
206156d09976SNikolay Aleksandrov dump_stats))
20620ab55879SNikolay Aleksandrov err = -EMSGSIZE;
2063743a53d9SNikolay Aleksandrov }
20640ab55879SNikolay Aleksandrov
20650ab55879SNikolay Aleksandrov cb->args[1] = err ? idx : 0;
20660ab55879SNikolay Aleksandrov
20678dcea187SNikolay Aleksandrov nlmsg_end(skb, nlh);
20688dcea187SNikolay Aleksandrov
20698dcea187SNikolay Aleksandrov return err;
20708dcea187SNikolay Aleksandrov }
20718dcea187SNikolay Aleksandrov
207256d09976SNikolay Aleksandrov static const struct nla_policy br_vlan_db_dump_pol[BRIDGE_VLANDB_DUMP_MAX + 1] = {
207356d09976SNikolay Aleksandrov [BRIDGE_VLANDB_DUMP_FLAGS] = { .type = NLA_U32 },
207456d09976SNikolay Aleksandrov };
207556d09976SNikolay Aleksandrov
br_vlan_rtm_dump(struct sk_buff * skb,struct netlink_callback * cb)20768dcea187SNikolay Aleksandrov static int br_vlan_rtm_dump(struct sk_buff *skb, struct netlink_callback *cb)
20778dcea187SNikolay Aleksandrov {
207856d09976SNikolay Aleksandrov struct nlattr *dtb[BRIDGE_VLANDB_DUMP_MAX + 1];
20798dcea187SNikolay Aleksandrov int idx = 0, err = 0, s_idx = cb->args[0];
20808dcea187SNikolay Aleksandrov struct net *net = sock_net(skb->sk);
20818dcea187SNikolay Aleksandrov struct br_vlan_msg *bvm;
20828dcea187SNikolay Aleksandrov struct net_device *dev;
208356d09976SNikolay Aleksandrov u32 dump_flags = 0;
20848dcea187SNikolay Aleksandrov
208556d09976SNikolay Aleksandrov err = nlmsg_parse(cb->nlh, sizeof(*bvm), dtb, BRIDGE_VLANDB_DUMP_MAX,
208656d09976SNikolay Aleksandrov br_vlan_db_dump_pol, cb->extack);
20878dcea187SNikolay Aleksandrov if (err < 0)
20888dcea187SNikolay Aleksandrov return err;
20898dcea187SNikolay Aleksandrov
20908dcea187SNikolay Aleksandrov bvm = nlmsg_data(cb->nlh);
209156d09976SNikolay Aleksandrov if (dtb[BRIDGE_VLANDB_DUMP_FLAGS])
209256d09976SNikolay Aleksandrov dump_flags = nla_get_u32(dtb[BRIDGE_VLANDB_DUMP_FLAGS]);
20938dcea187SNikolay Aleksandrov
20948dcea187SNikolay Aleksandrov rcu_read_lock();
20958dcea187SNikolay Aleksandrov if (bvm->ifindex) {
20968dcea187SNikolay Aleksandrov dev = dev_get_by_index_rcu(net, bvm->ifindex);
20978dcea187SNikolay Aleksandrov if (!dev) {
20988dcea187SNikolay Aleksandrov err = -ENODEV;
20998dcea187SNikolay Aleksandrov goto out_err;
21008dcea187SNikolay Aleksandrov }
210156d09976SNikolay Aleksandrov err = br_vlan_dump_dev(dev, skb, cb, dump_flags);
2102dcb2c5c6SNikolay Aleksandrov /* if the dump completed without an error we return 0 here */
2103dcb2c5c6SNikolay Aleksandrov if (err != -EMSGSIZE)
21048dcea187SNikolay Aleksandrov goto out_err;
21058dcea187SNikolay Aleksandrov } else {
21068dcea187SNikolay Aleksandrov for_each_netdev_rcu(net, dev) {
21078dcea187SNikolay Aleksandrov if (idx < s_idx)
21088dcea187SNikolay Aleksandrov goto skip;
21098dcea187SNikolay Aleksandrov
211056d09976SNikolay Aleksandrov err = br_vlan_dump_dev(dev, skb, cb, dump_flags);
21118dcea187SNikolay Aleksandrov if (err == -EMSGSIZE)
21128dcea187SNikolay Aleksandrov break;
21138dcea187SNikolay Aleksandrov skip:
21148dcea187SNikolay Aleksandrov idx++;
21158dcea187SNikolay Aleksandrov }
21168dcea187SNikolay Aleksandrov }
21178dcea187SNikolay Aleksandrov cb->args[0] = idx;
21188dcea187SNikolay Aleksandrov rcu_read_unlock();
21198dcea187SNikolay Aleksandrov
21208dcea187SNikolay Aleksandrov return skb->len;
21218dcea187SNikolay Aleksandrov
21228dcea187SNikolay Aleksandrov out_err:
21238dcea187SNikolay Aleksandrov rcu_read_unlock();
21248dcea187SNikolay Aleksandrov
21258dcea187SNikolay Aleksandrov return err;
21268dcea187SNikolay Aleksandrov }
21278dcea187SNikolay Aleksandrov
2128f26b2965SNikolay Aleksandrov static const struct nla_policy br_vlan_db_policy[BRIDGE_VLANDB_ENTRY_MAX + 1] = {
21298140860cSJohannes Berg [BRIDGE_VLANDB_ENTRY_INFO] =
21308140860cSJohannes Berg NLA_POLICY_EXACT_LEN(sizeof(struct bridge_vlan_info)),
21310ab55879SNikolay Aleksandrov [BRIDGE_VLANDB_ENTRY_RANGE] = { .type = NLA_U16 },
2132a580c76dSNikolay Aleksandrov [BRIDGE_VLANDB_ENTRY_STATE] = { .type = NLA_U8 },
2133fa388f29SNikolay Aleksandrov [BRIDGE_VLANDB_ENTRY_TUNNEL_INFO] = { .type = NLA_NESTED },
21342796d846SNikolay Aleksandrov [BRIDGE_VLANDB_ENTRY_MCAST_ROUTER] = { .type = NLA_U8 },
2135a1aee20dSPetr Machata [BRIDGE_VLANDB_ENTRY_MCAST_N_GROUPS] = { .type = NLA_REJECT },
2136a1aee20dSPetr Machata [BRIDGE_VLANDB_ENTRY_MCAST_MAX_GROUPS] = { .type = NLA_U32 },
213783f6d600SIdo Schimmel [BRIDGE_VLANDB_ENTRY_NEIGH_SUPPRESS] = NLA_POLICY_MAX(NLA_U8, 1),
2138f26b2965SNikolay Aleksandrov };
2139f26b2965SNikolay Aleksandrov
br_vlan_rtm_process_one(struct net_device * dev,const struct nlattr * attr,int cmd,struct netlink_ext_ack * extack)2140f26b2965SNikolay Aleksandrov static int br_vlan_rtm_process_one(struct net_device *dev,
2141f26b2965SNikolay Aleksandrov const struct nlattr *attr,
2142f26b2965SNikolay Aleksandrov int cmd, struct netlink_ext_ack *extack)
2143f26b2965SNikolay Aleksandrov {
21440ab55879SNikolay Aleksandrov struct bridge_vlan_info *vinfo, vrange_end, *vinfo_last = NULL;
2145f26b2965SNikolay Aleksandrov struct nlattr *tb[BRIDGE_VLANDB_ENTRY_MAX + 1];
2146a5d29ae2SNikolay Aleksandrov bool changed = false, skip_processing = false;
2147f26b2965SNikolay Aleksandrov struct net_bridge_vlan_group *vg;
2148f26b2965SNikolay Aleksandrov struct net_bridge_port *p = NULL;
2149f26b2965SNikolay Aleksandrov int err = 0, cmdmap = 0;
2150f26b2965SNikolay Aleksandrov struct net_bridge *br;
2151f26b2965SNikolay Aleksandrov
2152f26b2965SNikolay Aleksandrov if (netif_is_bridge_master(dev)) {
2153f26b2965SNikolay Aleksandrov br = netdev_priv(dev);
2154f26b2965SNikolay Aleksandrov vg = br_vlan_group(br);
2155f26b2965SNikolay Aleksandrov } else {
2156f26b2965SNikolay Aleksandrov p = br_port_get_rtnl(dev);
2157f26b2965SNikolay Aleksandrov if (WARN_ON(!p))
2158f26b2965SNikolay Aleksandrov return -ENODEV;
2159f26b2965SNikolay Aleksandrov br = p->br;
2160f26b2965SNikolay Aleksandrov vg = nbp_vlan_group(p);
2161f26b2965SNikolay Aleksandrov }
2162f26b2965SNikolay Aleksandrov
2163f26b2965SNikolay Aleksandrov if (WARN_ON(!vg))
2164f26b2965SNikolay Aleksandrov return -ENODEV;
2165f26b2965SNikolay Aleksandrov
2166f26b2965SNikolay Aleksandrov err = nla_parse_nested(tb, BRIDGE_VLANDB_ENTRY_MAX, attr,
2167f26b2965SNikolay Aleksandrov br_vlan_db_policy, extack);
2168f26b2965SNikolay Aleksandrov if (err)
2169f26b2965SNikolay Aleksandrov return err;
2170f26b2965SNikolay Aleksandrov
2171f26b2965SNikolay Aleksandrov if (!tb[BRIDGE_VLANDB_ENTRY_INFO]) {
2172f26b2965SNikolay Aleksandrov NL_SET_ERR_MSG_MOD(extack, "Missing vlan entry info");
2173f26b2965SNikolay Aleksandrov return -EINVAL;
2174f26b2965SNikolay Aleksandrov }
21750ab55879SNikolay Aleksandrov memset(&vrange_end, 0, sizeof(vrange_end));
2176f26b2965SNikolay Aleksandrov
2177f26b2965SNikolay Aleksandrov vinfo = nla_data(tb[BRIDGE_VLANDB_ENTRY_INFO]);
2178f26b2965SNikolay Aleksandrov if (vinfo->flags & (BRIDGE_VLAN_INFO_RANGE_BEGIN |
2179f26b2965SNikolay Aleksandrov BRIDGE_VLAN_INFO_RANGE_END)) {
2180f26b2965SNikolay Aleksandrov NL_SET_ERR_MSG_MOD(extack, "Old-style vlan ranges are not allowed when using RTM vlan calls");
2181f26b2965SNikolay Aleksandrov return -EINVAL;
2182f26b2965SNikolay Aleksandrov }
2183f26b2965SNikolay Aleksandrov if (!br_vlan_valid_id(vinfo->vid, extack))
2184f26b2965SNikolay Aleksandrov return -EINVAL;
2185f26b2965SNikolay Aleksandrov
21860ab55879SNikolay Aleksandrov if (tb[BRIDGE_VLANDB_ENTRY_RANGE]) {
21870ab55879SNikolay Aleksandrov vrange_end.vid = nla_get_u16(tb[BRIDGE_VLANDB_ENTRY_RANGE]);
21880ab55879SNikolay Aleksandrov /* validate user-provided flags without RANGE_BEGIN */
21890ab55879SNikolay Aleksandrov vrange_end.flags = BRIDGE_VLAN_INFO_RANGE_END | vinfo->flags;
21900ab55879SNikolay Aleksandrov vinfo->flags |= BRIDGE_VLAN_INFO_RANGE_BEGIN;
21910ab55879SNikolay Aleksandrov
21920ab55879SNikolay Aleksandrov /* vinfo_last is the range start, vinfo the range end */
21930ab55879SNikolay Aleksandrov vinfo_last = vinfo;
21940ab55879SNikolay Aleksandrov vinfo = &vrange_end;
21950ab55879SNikolay Aleksandrov
21960ab55879SNikolay Aleksandrov if (!br_vlan_valid_id(vinfo->vid, extack) ||
21970ab55879SNikolay Aleksandrov !br_vlan_valid_range(vinfo, vinfo_last, extack))
21980ab55879SNikolay Aleksandrov return -EINVAL;
21990ab55879SNikolay Aleksandrov }
22000ab55879SNikolay Aleksandrov
2201f26b2965SNikolay Aleksandrov switch (cmd) {
2202f26b2965SNikolay Aleksandrov case RTM_NEWVLAN:
2203f26b2965SNikolay Aleksandrov cmdmap = RTM_SETLINK;
2204a5d29ae2SNikolay Aleksandrov skip_processing = !!(vinfo->flags & BRIDGE_VLAN_INFO_ONLY_OPTS);
2205f26b2965SNikolay Aleksandrov break;
2206adb3ce9bSNikolay Aleksandrov case RTM_DELVLAN:
2207adb3ce9bSNikolay Aleksandrov cmdmap = RTM_DELLINK;
2208adb3ce9bSNikolay Aleksandrov break;
2209f26b2965SNikolay Aleksandrov }
2210f26b2965SNikolay Aleksandrov
2211a5d29ae2SNikolay Aleksandrov if (!skip_processing) {
2212a5d29ae2SNikolay Aleksandrov struct bridge_vlan_info *tmp_last = vinfo_last;
2213a5d29ae2SNikolay Aleksandrov
2214a5d29ae2SNikolay Aleksandrov /* br_process_vlan_info may overwrite vinfo_last */
2215a5d29ae2SNikolay Aleksandrov err = br_process_vlan_info(br, p, cmdmap, vinfo, &tmp_last,
2216a5d29ae2SNikolay Aleksandrov &changed, extack);
2217a5d29ae2SNikolay Aleksandrov
2218a5d29ae2SNikolay Aleksandrov /* notify first if anything changed */
2219f26b2965SNikolay Aleksandrov if (changed)
2220f26b2965SNikolay Aleksandrov br_ifinfo_notify(cmdmap, br, p);
2221f26b2965SNikolay Aleksandrov
2222a5d29ae2SNikolay Aleksandrov if (err)
2223a5d29ae2SNikolay Aleksandrov return err;
2224a5d29ae2SNikolay Aleksandrov }
2225a5d29ae2SNikolay Aleksandrov
2226a5d29ae2SNikolay Aleksandrov /* deal with options */
2227a5d29ae2SNikolay Aleksandrov if (cmd == RTM_NEWVLAN) {
2228a5d29ae2SNikolay Aleksandrov struct net_bridge_vlan *range_start, *range_end;
2229a5d29ae2SNikolay Aleksandrov
2230a5d29ae2SNikolay Aleksandrov if (vinfo_last) {
2231a5d29ae2SNikolay Aleksandrov range_start = br_vlan_find(vg, vinfo_last->vid);
2232a5d29ae2SNikolay Aleksandrov range_end = br_vlan_find(vg, vinfo->vid);
2233a5d29ae2SNikolay Aleksandrov } else {
2234a5d29ae2SNikolay Aleksandrov range_start = br_vlan_find(vg, vinfo->vid);
2235a5d29ae2SNikolay Aleksandrov range_end = range_start;
2236a5d29ae2SNikolay Aleksandrov }
2237a5d29ae2SNikolay Aleksandrov
2238a5d29ae2SNikolay Aleksandrov err = br_vlan_process_options(br, p, range_start, range_end,
2239a5d29ae2SNikolay Aleksandrov tb, extack);
2240a5d29ae2SNikolay Aleksandrov }
2241a5d29ae2SNikolay Aleksandrov
2242f26b2965SNikolay Aleksandrov return err;
2243f26b2965SNikolay Aleksandrov }
2244f26b2965SNikolay Aleksandrov
br_vlan_rtm_process(struct sk_buff * skb,struct nlmsghdr * nlh,struct netlink_ext_ack * extack)2245f26b2965SNikolay Aleksandrov static int br_vlan_rtm_process(struct sk_buff *skb, struct nlmsghdr *nlh,
2246f26b2965SNikolay Aleksandrov struct netlink_ext_ack *extack)
2247f26b2965SNikolay Aleksandrov {
2248f26b2965SNikolay Aleksandrov struct net *net = sock_net(skb->sk);
2249f26b2965SNikolay Aleksandrov struct br_vlan_msg *bvm;
2250f26b2965SNikolay Aleksandrov struct net_device *dev;
2251f26b2965SNikolay Aleksandrov struct nlattr *attr;
2252f26b2965SNikolay Aleksandrov int err, vlans = 0;
2253f26b2965SNikolay Aleksandrov int rem;
2254f26b2965SNikolay Aleksandrov
2255f26b2965SNikolay Aleksandrov /* this should validate the header and check for remaining bytes */
2256f26b2965SNikolay Aleksandrov err = nlmsg_parse(nlh, sizeof(*bvm), NULL, BRIDGE_VLANDB_MAX, NULL,
2257f26b2965SNikolay Aleksandrov extack);
2258f26b2965SNikolay Aleksandrov if (err < 0)
2259f26b2965SNikolay Aleksandrov return err;
2260f26b2965SNikolay Aleksandrov
2261f26b2965SNikolay Aleksandrov bvm = nlmsg_data(nlh);
2262f26b2965SNikolay Aleksandrov dev = __dev_get_by_index(net, bvm->ifindex);
2263f26b2965SNikolay Aleksandrov if (!dev)
2264f26b2965SNikolay Aleksandrov return -ENODEV;
2265f26b2965SNikolay Aleksandrov
2266f26b2965SNikolay Aleksandrov if (!netif_is_bridge_master(dev) && !netif_is_bridge_port(dev)) {
2267f26b2965SNikolay Aleksandrov NL_SET_ERR_MSG_MOD(extack, "The device is not a valid bridge or bridge port");
2268f26b2965SNikolay Aleksandrov return -EINVAL;
2269f26b2965SNikolay Aleksandrov }
2270f26b2965SNikolay Aleksandrov
2271f26b2965SNikolay Aleksandrov nlmsg_for_each_attr(attr, nlh, sizeof(*bvm), rem) {
227247ecd2dbSNikolay Aleksandrov switch (nla_type(attr)) {
227347ecd2dbSNikolay Aleksandrov case BRIDGE_VLANDB_ENTRY:
227447ecd2dbSNikolay Aleksandrov err = br_vlan_rtm_process_one(dev, attr,
227547ecd2dbSNikolay Aleksandrov nlh->nlmsg_type,
227647ecd2dbSNikolay Aleksandrov extack);
227747ecd2dbSNikolay Aleksandrov break;
227847ecd2dbSNikolay Aleksandrov case BRIDGE_VLANDB_GLOBAL_OPTIONS:
227947ecd2dbSNikolay Aleksandrov err = br_vlan_rtm_process_global_options(dev, attr,
228047ecd2dbSNikolay Aleksandrov nlh->nlmsg_type,
228147ecd2dbSNikolay Aleksandrov extack);
228247ecd2dbSNikolay Aleksandrov break;
228347ecd2dbSNikolay Aleksandrov default:
2284f26b2965SNikolay Aleksandrov continue;
228547ecd2dbSNikolay Aleksandrov }
2286f26b2965SNikolay Aleksandrov
2287f26b2965SNikolay Aleksandrov vlans++;
2288f26b2965SNikolay Aleksandrov if (err)
2289f26b2965SNikolay Aleksandrov break;
2290f26b2965SNikolay Aleksandrov }
2291f26b2965SNikolay Aleksandrov if (!vlans) {
2292f26b2965SNikolay Aleksandrov NL_SET_ERR_MSG_MOD(extack, "No vlans found to process");
2293f26b2965SNikolay Aleksandrov err = -EINVAL;
2294f26b2965SNikolay Aleksandrov }
2295f26b2965SNikolay Aleksandrov
2296f26b2965SNikolay Aleksandrov return err;
2297f26b2965SNikolay Aleksandrov }
2298f26b2965SNikolay Aleksandrov
2299*60bfd345SKuniyuki Iwashima static const struct rtnl_msg_handler br_vlan_rtnl_msg_handlers[] = {
2300*60bfd345SKuniyuki Iwashima {THIS_MODULE, PF_BRIDGE, RTM_NEWVLAN, br_vlan_rtm_process, NULL, 0},
2301*60bfd345SKuniyuki Iwashima {THIS_MODULE, PF_BRIDGE, RTM_DELVLAN, br_vlan_rtm_process, NULL, 0},
2302*60bfd345SKuniyuki Iwashima {THIS_MODULE, PF_BRIDGE, RTM_GETVLAN, NULL, br_vlan_rtm_dump, 0},
2303*60bfd345SKuniyuki Iwashima };
2304*60bfd345SKuniyuki Iwashima
br_vlan_rtnl_init(void)2305*60bfd345SKuniyuki Iwashima int br_vlan_rtnl_init(void)
23068dcea187SNikolay Aleksandrov {
2307*60bfd345SKuniyuki Iwashima return rtnl_register_many(br_vlan_rtnl_msg_handlers);
23088dcea187SNikolay Aleksandrov }
23098dcea187SNikolay Aleksandrov
br_vlan_rtnl_uninit(void)23108dcea187SNikolay Aleksandrov void br_vlan_rtnl_uninit(void)
23118dcea187SNikolay Aleksandrov {
2312*60bfd345SKuniyuki Iwashima rtnl_unregister_many(br_vlan_rtnl_msg_handlers);
23138dcea187SNikolay Aleksandrov }
2314