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 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 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 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 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 */ 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 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 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 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 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 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 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 * 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 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 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 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 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 */ 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 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 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 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 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 */ 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 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. */ 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 */ 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 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 */ 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 */ 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 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 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. */ 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. */ 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 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 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 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 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 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 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 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 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 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 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 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 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 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 */ 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 */ 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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. */ 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. */ 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. */ 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 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 */ 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, 1819*a1aee20dSPetr 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) { 1846*a1aee20dSPetr 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 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 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 1929*a1aee20dSPetr 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 */ 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 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, 2034*a1aee20dSPetr 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, 2060*a1aee20dSPetr 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 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 }, 2135*a1aee20dSPetr Machata [BRIDGE_VLANDB_ENTRY_MCAST_N_GROUPS] = { .type = NLA_REJECT }, 2136*a1aee20dSPetr Machata [BRIDGE_VLANDB_ENTRY_MCAST_MAX_GROUPS] = { .type = NLA_U32 }, 2137f26b2965SNikolay Aleksandrov }; 2138f26b2965SNikolay Aleksandrov 2139f26b2965SNikolay Aleksandrov static int br_vlan_rtm_process_one(struct net_device *dev, 2140f26b2965SNikolay Aleksandrov const struct nlattr *attr, 2141f26b2965SNikolay Aleksandrov int cmd, struct netlink_ext_ack *extack) 2142f26b2965SNikolay Aleksandrov { 21430ab55879SNikolay Aleksandrov struct bridge_vlan_info *vinfo, vrange_end, *vinfo_last = NULL; 2144f26b2965SNikolay Aleksandrov struct nlattr *tb[BRIDGE_VLANDB_ENTRY_MAX + 1]; 2145a5d29ae2SNikolay Aleksandrov bool changed = false, skip_processing = false; 2146f26b2965SNikolay Aleksandrov struct net_bridge_vlan_group *vg; 2147f26b2965SNikolay Aleksandrov struct net_bridge_port *p = NULL; 2148f26b2965SNikolay Aleksandrov int err = 0, cmdmap = 0; 2149f26b2965SNikolay Aleksandrov struct net_bridge *br; 2150f26b2965SNikolay Aleksandrov 2151f26b2965SNikolay Aleksandrov if (netif_is_bridge_master(dev)) { 2152f26b2965SNikolay Aleksandrov br = netdev_priv(dev); 2153f26b2965SNikolay Aleksandrov vg = br_vlan_group(br); 2154f26b2965SNikolay Aleksandrov } else { 2155f26b2965SNikolay Aleksandrov p = br_port_get_rtnl(dev); 2156f26b2965SNikolay Aleksandrov if (WARN_ON(!p)) 2157f26b2965SNikolay Aleksandrov return -ENODEV; 2158f26b2965SNikolay Aleksandrov br = p->br; 2159f26b2965SNikolay Aleksandrov vg = nbp_vlan_group(p); 2160f26b2965SNikolay Aleksandrov } 2161f26b2965SNikolay Aleksandrov 2162f26b2965SNikolay Aleksandrov if (WARN_ON(!vg)) 2163f26b2965SNikolay Aleksandrov return -ENODEV; 2164f26b2965SNikolay Aleksandrov 2165f26b2965SNikolay Aleksandrov err = nla_parse_nested(tb, BRIDGE_VLANDB_ENTRY_MAX, attr, 2166f26b2965SNikolay Aleksandrov br_vlan_db_policy, extack); 2167f26b2965SNikolay Aleksandrov if (err) 2168f26b2965SNikolay Aleksandrov return err; 2169f26b2965SNikolay Aleksandrov 2170f26b2965SNikolay Aleksandrov if (!tb[BRIDGE_VLANDB_ENTRY_INFO]) { 2171f26b2965SNikolay Aleksandrov NL_SET_ERR_MSG_MOD(extack, "Missing vlan entry info"); 2172f26b2965SNikolay Aleksandrov return -EINVAL; 2173f26b2965SNikolay Aleksandrov } 21740ab55879SNikolay Aleksandrov memset(&vrange_end, 0, sizeof(vrange_end)); 2175f26b2965SNikolay Aleksandrov 2176f26b2965SNikolay Aleksandrov vinfo = nla_data(tb[BRIDGE_VLANDB_ENTRY_INFO]); 2177f26b2965SNikolay Aleksandrov if (vinfo->flags & (BRIDGE_VLAN_INFO_RANGE_BEGIN | 2178f26b2965SNikolay Aleksandrov BRIDGE_VLAN_INFO_RANGE_END)) { 2179f26b2965SNikolay Aleksandrov NL_SET_ERR_MSG_MOD(extack, "Old-style vlan ranges are not allowed when using RTM vlan calls"); 2180f26b2965SNikolay Aleksandrov return -EINVAL; 2181f26b2965SNikolay Aleksandrov } 2182f26b2965SNikolay Aleksandrov if (!br_vlan_valid_id(vinfo->vid, extack)) 2183f26b2965SNikolay Aleksandrov return -EINVAL; 2184f26b2965SNikolay Aleksandrov 21850ab55879SNikolay Aleksandrov if (tb[BRIDGE_VLANDB_ENTRY_RANGE]) { 21860ab55879SNikolay Aleksandrov vrange_end.vid = nla_get_u16(tb[BRIDGE_VLANDB_ENTRY_RANGE]); 21870ab55879SNikolay Aleksandrov /* validate user-provided flags without RANGE_BEGIN */ 21880ab55879SNikolay Aleksandrov vrange_end.flags = BRIDGE_VLAN_INFO_RANGE_END | vinfo->flags; 21890ab55879SNikolay Aleksandrov vinfo->flags |= BRIDGE_VLAN_INFO_RANGE_BEGIN; 21900ab55879SNikolay Aleksandrov 21910ab55879SNikolay Aleksandrov /* vinfo_last is the range start, vinfo the range end */ 21920ab55879SNikolay Aleksandrov vinfo_last = vinfo; 21930ab55879SNikolay Aleksandrov vinfo = &vrange_end; 21940ab55879SNikolay Aleksandrov 21950ab55879SNikolay Aleksandrov if (!br_vlan_valid_id(vinfo->vid, extack) || 21960ab55879SNikolay Aleksandrov !br_vlan_valid_range(vinfo, vinfo_last, extack)) 21970ab55879SNikolay Aleksandrov return -EINVAL; 21980ab55879SNikolay Aleksandrov } 21990ab55879SNikolay Aleksandrov 2200f26b2965SNikolay Aleksandrov switch (cmd) { 2201f26b2965SNikolay Aleksandrov case RTM_NEWVLAN: 2202f26b2965SNikolay Aleksandrov cmdmap = RTM_SETLINK; 2203a5d29ae2SNikolay Aleksandrov skip_processing = !!(vinfo->flags & BRIDGE_VLAN_INFO_ONLY_OPTS); 2204f26b2965SNikolay Aleksandrov break; 2205adb3ce9bSNikolay Aleksandrov case RTM_DELVLAN: 2206adb3ce9bSNikolay Aleksandrov cmdmap = RTM_DELLINK; 2207adb3ce9bSNikolay Aleksandrov break; 2208f26b2965SNikolay Aleksandrov } 2209f26b2965SNikolay Aleksandrov 2210a5d29ae2SNikolay Aleksandrov if (!skip_processing) { 2211a5d29ae2SNikolay Aleksandrov struct bridge_vlan_info *tmp_last = vinfo_last; 2212a5d29ae2SNikolay Aleksandrov 2213a5d29ae2SNikolay Aleksandrov /* br_process_vlan_info may overwrite vinfo_last */ 2214a5d29ae2SNikolay Aleksandrov err = br_process_vlan_info(br, p, cmdmap, vinfo, &tmp_last, 2215a5d29ae2SNikolay Aleksandrov &changed, extack); 2216a5d29ae2SNikolay Aleksandrov 2217a5d29ae2SNikolay Aleksandrov /* notify first if anything changed */ 2218f26b2965SNikolay Aleksandrov if (changed) 2219f26b2965SNikolay Aleksandrov br_ifinfo_notify(cmdmap, br, p); 2220f26b2965SNikolay Aleksandrov 2221a5d29ae2SNikolay Aleksandrov if (err) 2222a5d29ae2SNikolay Aleksandrov return err; 2223a5d29ae2SNikolay Aleksandrov } 2224a5d29ae2SNikolay Aleksandrov 2225a5d29ae2SNikolay Aleksandrov /* deal with options */ 2226a5d29ae2SNikolay Aleksandrov if (cmd == RTM_NEWVLAN) { 2227a5d29ae2SNikolay Aleksandrov struct net_bridge_vlan *range_start, *range_end; 2228a5d29ae2SNikolay Aleksandrov 2229a5d29ae2SNikolay Aleksandrov if (vinfo_last) { 2230a5d29ae2SNikolay Aleksandrov range_start = br_vlan_find(vg, vinfo_last->vid); 2231a5d29ae2SNikolay Aleksandrov range_end = br_vlan_find(vg, vinfo->vid); 2232a5d29ae2SNikolay Aleksandrov } else { 2233a5d29ae2SNikolay Aleksandrov range_start = br_vlan_find(vg, vinfo->vid); 2234a5d29ae2SNikolay Aleksandrov range_end = range_start; 2235a5d29ae2SNikolay Aleksandrov } 2236a5d29ae2SNikolay Aleksandrov 2237a5d29ae2SNikolay Aleksandrov err = br_vlan_process_options(br, p, range_start, range_end, 2238a5d29ae2SNikolay Aleksandrov tb, extack); 2239a5d29ae2SNikolay Aleksandrov } 2240a5d29ae2SNikolay Aleksandrov 2241f26b2965SNikolay Aleksandrov return err; 2242f26b2965SNikolay Aleksandrov } 2243f26b2965SNikolay Aleksandrov 2244f26b2965SNikolay Aleksandrov static int br_vlan_rtm_process(struct sk_buff *skb, struct nlmsghdr *nlh, 2245f26b2965SNikolay Aleksandrov struct netlink_ext_ack *extack) 2246f26b2965SNikolay Aleksandrov { 2247f26b2965SNikolay Aleksandrov struct net *net = sock_net(skb->sk); 2248f26b2965SNikolay Aleksandrov struct br_vlan_msg *bvm; 2249f26b2965SNikolay Aleksandrov struct net_device *dev; 2250f26b2965SNikolay Aleksandrov struct nlattr *attr; 2251f26b2965SNikolay Aleksandrov int err, vlans = 0; 2252f26b2965SNikolay Aleksandrov int rem; 2253f26b2965SNikolay Aleksandrov 2254f26b2965SNikolay Aleksandrov /* this should validate the header and check for remaining bytes */ 2255f26b2965SNikolay Aleksandrov err = nlmsg_parse(nlh, sizeof(*bvm), NULL, BRIDGE_VLANDB_MAX, NULL, 2256f26b2965SNikolay Aleksandrov extack); 2257f26b2965SNikolay Aleksandrov if (err < 0) 2258f26b2965SNikolay Aleksandrov return err; 2259f26b2965SNikolay Aleksandrov 2260f26b2965SNikolay Aleksandrov bvm = nlmsg_data(nlh); 2261f26b2965SNikolay Aleksandrov dev = __dev_get_by_index(net, bvm->ifindex); 2262f26b2965SNikolay Aleksandrov if (!dev) 2263f26b2965SNikolay Aleksandrov return -ENODEV; 2264f26b2965SNikolay Aleksandrov 2265f26b2965SNikolay Aleksandrov if (!netif_is_bridge_master(dev) && !netif_is_bridge_port(dev)) { 2266f26b2965SNikolay Aleksandrov NL_SET_ERR_MSG_MOD(extack, "The device is not a valid bridge or bridge port"); 2267f26b2965SNikolay Aleksandrov return -EINVAL; 2268f26b2965SNikolay Aleksandrov } 2269f26b2965SNikolay Aleksandrov 2270f26b2965SNikolay Aleksandrov nlmsg_for_each_attr(attr, nlh, sizeof(*bvm), rem) { 227147ecd2dbSNikolay Aleksandrov switch (nla_type(attr)) { 227247ecd2dbSNikolay Aleksandrov case BRIDGE_VLANDB_ENTRY: 227347ecd2dbSNikolay Aleksandrov err = br_vlan_rtm_process_one(dev, attr, 227447ecd2dbSNikolay Aleksandrov nlh->nlmsg_type, 227547ecd2dbSNikolay Aleksandrov extack); 227647ecd2dbSNikolay Aleksandrov break; 227747ecd2dbSNikolay Aleksandrov case BRIDGE_VLANDB_GLOBAL_OPTIONS: 227847ecd2dbSNikolay Aleksandrov err = br_vlan_rtm_process_global_options(dev, attr, 227947ecd2dbSNikolay Aleksandrov nlh->nlmsg_type, 228047ecd2dbSNikolay Aleksandrov extack); 228147ecd2dbSNikolay Aleksandrov break; 228247ecd2dbSNikolay Aleksandrov default: 2283f26b2965SNikolay Aleksandrov continue; 228447ecd2dbSNikolay Aleksandrov } 2285f26b2965SNikolay Aleksandrov 2286f26b2965SNikolay Aleksandrov vlans++; 2287f26b2965SNikolay Aleksandrov if (err) 2288f26b2965SNikolay Aleksandrov break; 2289f26b2965SNikolay Aleksandrov } 2290f26b2965SNikolay Aleksandrov if (!vlans) { 2291f26b2965SNikolay Aleksandrov NL_SET_ERR_MSG_MOD(extack, "No vlans found to process"); 2292f26b2965SNikolay Aleksandrov err = -EINVAL; 2293f26b2965SNikolay Aleksandrov } 2294f26b2965SNikolay Aleksandrov 2295f26b2965SNikolay Aleksandrov return err; 2296f26b2965SNikolay Aleksandrov } 2297f26b2965SNikolay Aleksandrov 22988dcea187SNikolay Aleksandrov void br_vlan_rtnl_init(void) 22998dcea187SNikolay Aleksandrov { 23008dcea187SNikolay Aleksandrov rtnl_register_module(THIS_MODULE, PF_BRIDGE, RTM_GETVLAN, NULL, 23018dcea187SNikolay Aleksandrov br_vlan_rtm_dump, 0); 2302f26b2965SNikolay Aleksandrov rtnl_register_module(THIS_MODULE, PF_BRIDGE, RTM_NEWVLAN, 2303f26b2965SNikolay Aleksandrov br_vlan_rtm_process, NULL, 0); 2304adb3ce9bSNikolay Aleksandrov rtnl_register_module(THIS_MODULE, PF_BRIDGE, RTM_DELVLAN, 2305adb3ce9bSNikolay Aleksandrov br_vlan_rtm_process, NULL, 0); 23068dcea187SNikolay Aleksandrov } 23078dcea187SNikolay Aleksandrov 23088dcea187SNikolay Aleksandrov void br_vlan_rtnl_uninit(void) 23098dcea187SNikolay Aleksandrov { 23108dcea187SNikolay Aleksandrov rtnl_unregister(PF_BRIDGE, RTM_GETVLAN); 2311f26b2965SNikolay Aleksandrov rtnl_unregister(PF_BRIDGE, RTM_NEWVLAN); 2312adb3ce9bSNikolay Aleksandrov rtnl_unregister(PF_BRIDGE, RTM_DELVLAN); 23138dcea187SNikolay Aleksandrov } 2314