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 37a580c76dSNikolay Aleksandrov static bool __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) 41f418af63SNikolay Aleksandrov return false; 42552406c4SVlad Yasevich 43552406c4SVlad Yasevich smp_wmb(); 44a580c76dSNikolay Aleksandrov br_vlan_set_pvid_state(vg, v->state); 45a580c76dSNikolay Aleksandrov vg->pvid = v->vid; 46f418af63SNikolay Aleksandrov 47f418af63SNikolay Aleksandrov return true; 48552406c4SVlad Yasevich } 49552406c4SVlad Yasevich 50f418af63SNikolay Aleksandrov static bool __vlan_delete_pvid(struct net_bridge_vlan_group *vg, u16 vid) 51552406c4SVlad Yasevich { 5277751ee8SNikolay Aleksandrov if (vg->pvid != vid) 53f418af63SNikolay Aleksandrov return false; 54552406c4SVlad Yasevich 55552406c4SVlad Yasevich smp_wmb(); 5677751ee8SNikolay Aleksandrov vg->pvid = 0; 57f418af63SNikolay Aleksandrov 58f418af63SNikolay Aleksandrov return true; 59552406c4SVlad Yasevich } 60552406c4SVlad Yasevich 61f418af63SNikolay Aleksandrov /* return true if anything changed, false otherwise */ 62f418af63SNikolay Aleksandrov static bool __vlan_add_flags(struct net_bridge_vlan *v, u16 flags) 6335e03f3aSVlad Yasevich { 6477751ee8SNikolay Aleksandrov struct net_bridge_vlan_group *vg; 65f418af63SNikolay Aleksandrov u16 old_flags = v->flags; 66f418af63SNikolay Aleksandrov bool ret; 6777751ee8SNikolay Aleksandrov 682594e906SNikolay Aleksandrov if (br_vlan_is_master(v)) 69907b1e6eSNikolay Aleksandrov vg = br_vlan_group(v->br); 70635126b7SVlad Yasevich else 71907b1e6eSNikolay Aleksandrov vg = nbp_vlan_group(v->port); 7277751ee8SNikolay Aleksandrov 7377751ee8SNikolay Aleksandrov if (flags & BRIDGE_VLAN_INFO_PVID) 74a580c76dSNikolay Aleksandrov ret = __vlan_add_pvid(vg, v); 752594e906SNikolay Aleksandrov else 76f418af63SNikolay Aleksandrov ret = __vlan_delete_pvid(vg, v->vid); 7735e03f3aSVlad Yasevich 7835e03f3aSVlad Yasevich if (flags & BRIDGE_VLAN_INFO_UNTAGGED) 792594e906SNikolay Aleksandrov v->flags |= BRIDGE_VLAN_INFO_UNTAGGED; 80635126b7SVlad Yasevich else 812594e906SNikolay Aleksandrov v->flags &= ~BRIDGE_VLAN_INFO_UNTAGGED; 82f418af63SNikolay Aleksandrov 83f418af63SNikolay Aleksandrov return ret || !!(old_flags ^ v->flags); 8435e03f3aSVlad Yasevich } 8535e03f3aSVlad Yasevich 867f109539SScott Feldman static int __vlan_vid_add(struct net_device *dev, struct net_bridge *br, 8727973793SIdo Schimmel struct net_bridge_vlan *v, u16 flags, 8827973793SIdo Schimmel struct netlink_ext_ack *extack) 897f109539SScott Feldman { 900944d6b5SJiri Pirko int err; 917f109539SScott Feldman 920944d6b5SJiri Pirko /* Try switchdev op first. In case it is not supported, fallback to 930944d6b5SJiri Pirko * 8021q add. 940944d6b5SJiri Pirko */ 9527973793SIdo Schimmel err = br_switchdev_port_vlan_add(dev, v->vid, flags, extack); 967f109539SScott Feldman if (err == -EOPNOTSUPP) 9727973793SIdo Schimmel return vlan_vid_add(dev, br->vlan_proto, v->vid); 9827973793SIdo Schimmel v->priv_flags |= BR_VLFLAG_ADDED_BY_SWITCHDEV; 997f109539SScott Feldman return err; 1007f109539SScott Feldman } 1017f109539SScott Feldman 1022594e906SNikolay Aleksandrov static void __vlan_add_list(struct net_bridge_vlan *v) 103243a2e63SVlad Yasevich { 104907b1e6eSNikolay Aleksandrov struct net_bridge_vlan_group *vg; 1052594e906SNikolay Aleksandrov struct list_head *headp, *hpos; 1062594e906SNikolay Aleksandrov struct net_bridge_vlan *vent; 107243a2e63SVlad Yasevich 108907b1e6eSNikolay Aleksandrov if (br_vlan_is_master(v)) 109907b1e6eSNikolay Aleksandrov vg = br_vlan_group(v->br); 110907b1e6eSNikolay Aleksandrov else 111907b1e6eSNikolay Aleksandrov vg = nbp_vlan_group(v->port); 112907b1e6eSNikolay Aleksandrov 113907b1e6eSNikolay Aleksandrov headp = &vg->vlan_list; 1142594e906SNikolay Aleksandrov list_for_each_prev(hpos, headp) { 1152594e906SNikolay Aleksandrov vent = list_entry(hpos, struct net_bridge_vlan, vlist); 116040c1257SColin Ian King if (v->vid >= vent->vid) 1172594e906SNikolay Aleksandrov break; 1182594e906SNikolay Aleksandrov } 119586c2b57SNikolay Aleksandrov list_add_rcu(&v->vlist, hpos); 120552406c4SVlad Yasevich } 121243a2e63SVlad Yasevich 1222594e906SNikolay Aleksandrov static void __vlan_del_list(struct net_bridge_vlan *v) 1232594e906SNikolay Aleksandrov { 124586c2b57SNikolay Aleksandrov list_del_rcu(&v->vlist); 125243a2e63SVlad Yasevich } 126243a2e63SVlad Yasevich 127bf361ad3SVivien Didelot static int __vlan_vid_del(struct net_device *dev, struct net_bridge *br, 12827973793SIdo Schimmel const struct net_bridge_vlan *v) 1297f109539SScott Feldman { 1300944d6b5SJiri Pirko int err; 1317f109539SScott Feldman 1320944d6b5SJiri Pirko /* Try switchdev op first. In case it is not supported, fallback to 1330944d6b5SJiri Pirko * 8021q del. 1340944d6b5SJiri Pirko */ 13527973793SIdo Schimmel err = br_switchdev_port_vlan_del(dev, v->vid); 13627973793SIdo Schimmel if (!(v->priv_flags & BR_VLFLAG_ADDED_BY_SWITCHDEV)) 13727973793SIdo Schimmel vlan_vid_del(dev, br->vlan_proto, v->vid); 13827973793SIdo Schimmel return err == -EOPNOTSUPP ? 0 : err; 1397f109539SScott Feldman } 1407f109539SScott Feldman 1414bbd026cSRandy Dunlap /* Returns a master vlan, if it didn't exist it gets created. In all cases 142f8ed289fSNikolay Aleksandrov * a reference is taken to the master vlan before returning. 143f8ed289fSNikolay Aleksandrov */ 144169327d5SPetr Machata static struct net_bridge_vlan * 145169327d5SPetr Machata br_vlan_get_master(struct net_bridge *br, u16 vid, 146169327d5SPetr Machata struct netlink_ext_ack *extack) 147f8ed289fSNikolay Aleksandrov { 148907b1e6eSNikolay Aleksandrov struct net_bridge_vlan_group *vg; 149f8ed289fSNikolay Aleksandrov struct net_bridge_vlan *masterv; 150f8ed289fSNikolay Aleksandrov 151907b1e6eSNikolay Aleksandrov vg = br_vlan_group(br); 152907b1e6eSNikolay Aleksandrov masterv = br_vlan_find(vg, vid); 153f8ed289fSNikolay Aleksandrov if (!masterv) { 154f418af63SNikolay Aleksandrov bool changed; 155f418af63SNikolay Aleksandrov 156f8ed289fSNikolay Aleksandrov /* missing global ctx, create it now */ 157169327d5SPetr Machata if (br_vlan_add(br, vid, 0, &changed, extack)) 158f8ed289fSNikolay Aleksandrov return NULL; 159907b1e6eSNikolay Aleksandrov masterv = br_vlan_find(vg, vid); 160f8ed289fSNikolay Aleksandrov if (WARN_ON(!masterv)) 161f8ed289fSNikolay Aleksandrov return NULL; 1620e5a82efSIdo Schimmel refcount_set(&masterv->refcnt, 1); 1630e5a82efSIdo Schimmel return masterv; 164f8ed289fSNikolay Aleksandrov } 16525127759SReshetova, Elena refcount_inc(&masterv->refcnt); 166f8ed289fSNikolay Aleksandrov 167f8ed289fSNikolay Aleksandrov return masterv; 168f8ed289fSNikolay Aleksandrov } 169f8ed289fSNikolay Aleksandrov 1706dada9b1SNikolay Aleksandrov static void br_master_vlan_rcu_free(struct rcu_head *rcu) 1716dada9b1SNikolay Aleksandrov { 1726dada9b1SNikolay Aleksandrov struct net_bridge_vlan *v; 1736dada9b1SNikolay Aleksandrov 1746dada9b1SNikolay Aleksandrov v = container_of(rcu, struct net_bridge_vlan, rcu); 1756dada9b1SNikolay Aleksandrov WARN_ON(!br_vlan_is_master(v)); 1766dada9b1SNikolay Aleksandrov free_percpu(v->stats); 1776dada9b1SNikolay Aleksandrov v->stats = NULL; 1786dada9b1SNikolay Aleksandrov kfree(v); 1796dada9b1SNikolay Aleksandrov } 1806dada9b1SNikolay Aleksandrov 181f8ed289fSNikolay Aleksandrov static void br_vlan_put_master(struct net_bridge_vlan *masterv) 182f8ed289fSNikolay Aleksandrov { 183907b1e6eSNikolay Aleksandrov struct net_bridge_vlan_group *vg; 184907b1e6eSNikolay Aleksandrov 185f8ed289fSNikolay Aleksandrov if (!br_vlan_is_master(masterv)) 186f8ed289fSNikolay Aleksandrov return; 187f8ed289fSNikolay Aleksandrov 188907b1e6eSNikolay Aleksandrov vg = br_vlan_group(masterv->br); 18925127759SReshetova, Elena if (refcount_dec_and_test(&masterv->refcnt)) { 190907b1e6eSNikolay Aleksandrov rhashtable_remove_fast(&vg->vlan_hash, 191f8ed289fSNikolay Aleksandrov &masterv->vnode, br_vlan_rht_params); 192f8ed289fSNikolay Aleksandrov __vlan_del_list(masterv); 1937b54aaafSNikolay Aleksandrov br_multicast_toggle_one_vlan(masterv, false); 194613d61dbSNikolay Aleksandrov br_multicast_ctx_deinit(&masterv->br_mcast_ctx); 1956dada9b1SNikolay Aleksandrov call_rcu(&masterv->rcu, br_master_vlan_rcu_free); 196f8ed289fSNikolay Aleksandrov } 197f8ed289fSNikolay Aleksandrov } 198f8ed289fSNikolay Aleksandrov 1999163a0fcSNikolay Aleksandrov static void nbp_vlan_rcu_free(struct rcu_head *rcu) 2009163a0fcSNikolay Aleksandrov { 2019163a0fcSNikolay Aleksandrov struct net_bridge_vlan *v; 2029163a0fcSNikolay Aleksandrov 2039163a0fcSNikolay Aleksandrov v = container_of(rcu, struct net_bridge_vlan, rcu); 2049163a0fcSNikolay Aleksandrov WARN_ON(br_vlan_is_master(v)); 2059163a0fcSNikolay Aleksandrov /* if we had per-port stats configured then free them here */ 2069d332e69SNikolay Aleksandrov if (v->priv_flags & BR_VLFLAG_PER_PORT_STATS) 2079163a0fcSNikolay Aleksandrov free_percpu(v->stats); 2089163a0fcSNikolay Aleksandrov v->stats = NULL; 2099163a0fcSNikolay Aleksandrov kfree(v); 2109163a0fcSNikolay Aleksandrov } 2119163a0fcSNikolay Aleksandrov 2122594e906SNikolay Aleksandrov /* This is the shared VLAN add function which works for both ports and bridge 2132594e906SNikolay Aleksandrov * devices. There are four possible calls to this function in terms of the 2142594e906SNikolay Aleksandrov * vlan entry type: 2152594e906SNikolay Aleksandrov * 1. vlan is being added on a port (no master flags, global entry exists) 216ddd611d3SIdo Schimmel * 2. vlan is being added on a bridge (both master and brentry flags) 2172594e906SNikolay Aleksandrov * 3. vlan is being added on a port, but a global entry didn't exist which 218ddd611d3SIdo Schimmel * is being created right now (master flag set, brentry flag unset), the 2192594e906SNikolay Aleksandrov * global entry is used for global per-vlan features, but not for filtering 220ddd611d3SIdo Schimmel * 4. same as 3 but with both master and brentry flags set so the entry 2212594e906SNikolay Aleksandrov * will be used for filtering in both the port and the bridge 2222594e906SNikolay Aleksandrov */ 223169327d5SPetr Machata static int __vlan_add(struct net_bridge_vlan *v, u16 flags, 224169327d5SPetr Machata struct netlink_ext_ack *extack) 225243a2e63SVlad Yasevich { 2262594e906SNikolay Aleksandrov struct net_bridge_vlan *masterv = NULL; 2272594e906SNikolay Aleksandrov struct net_bridge_port *p = NULL; 2286be144f6SNikolay Aleksandrov struct net_bridge_vlan_group *vg; 2292594e906SNikolay Aleksandrov struct net_device *dev; 2302594e906SNikolay Aleksandrov struct net_bridge *br; 231bf361ad3SVivien Didelot int err; 232bf361ad3SVivien Didelot 2332594e906SNikolay Aleksandrov if (br_vlan_is_master(v)) { 2342594e906SNikolay Aleksandrov br = v->br; 2352594e906SNikolay Aleksandrov dev = br->dev; 236907b1e6eSNikolay Aleksandrov vg = br_vlan_group(br); 2372594e906SNikolay Aleksandrov } else { 2382594e906SNikolay Aleksandrov p = v->port; 2392594e906SNikolay Aleksandrov br = p->br; 2402594e906SNikolay Aleksandrov dev = p->dev; 241907b1e6eSNikolay Aleksandrov vg = nbp_vlan_group(p); 2422594e906SNikolay Aleksandrov } 2432594e906SNikolay Aleksandrov 2442594e906SNikolay Aleksandrov if (p) { 2452594e906SNikolay Aleksandrov /* Add VLAN to the device filter if it is supported. 2462594e906SNikolay Aleksandrov * This ensures tagged traffic enters the bridge when 2472594e906SNikolay Aleksandrov * promiscuous mode is disabled by br_manage_promisc(). 2482594e906SNikolay Aleksandrov */ 24927973793SIdo Schimmel err = __vlan_vid_add(dev, br, v, flags, extack); 250bf361ad3SVivien Didelot if (err) 2512594e906SNikolay Aleksandrov goto out; 2522594e906SNikolay Aleksandrov 2532594e906SNikolay Aleksandrov /* need to work on the master vlan too */ 2542594e906SNikolay Aleksandrov if (flags & BRIDGE_VLAN_INFO_MASTER) { 255f418af63SNikolay Aleksandrov bool changed; 256f418af63SNikolay Aleksandrov 257f418af63SNikolay Aleksandrov err = br_vlan_add(br, v->vid, 258f418af63SNikolay Aleksandrov flags | BRIDGE_VLAN_INFO_BRENTRY, 259169327d5SPetr Machata &changed, extack); 2602594e906SNikolay Aleksandrov if (err) 2612594e906SNikolay Aleksandrov goto out_filt; 262f545923bSNikolay Aleksandrov 263f545923bSNikolay Aleksandrov if (changed) 264f545923bSNikolay Aleksandrov br_vlan_notify(br, NULL, v->vid, 0, 265f545923bSNikolay Aleksandrov RTM_NEWVLAN); 2662594e906SNikolay Aleksandrov } 2672594e906SNikolay Aleksandrov 268169327d5SPetr Machata masterv = br_vlan_get_master(br, v->vid, extack); 269ee4f52a8SZhang Changzhong if (!masterv) { 270ee4f52a8SZhang Changzhong err = -ENOMEM; 2712594e906SNikolay Aleksandrov goto out_filt; 272ee4f52a8SZhang Changzhong } 2732594e906SNikolay Aleksandrov v->brvlan = masterv; 2749163a0fcSNikolay Aleksandrov if (br_opt_get(br, BROPT_VLAN_STATS_PER_PORT)) { 275281cc284SHeiner Kallweit v->stats = 276281cc284SHeiner Kallweit netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); 2779163a0fcSNikolay Aleksandrov if (!v->stats) { 2789163a0fcSNikolay Aleksandrov err = -ENOMEM; 2799163a0fcSNikolay Aleksandrov goto out_filt; 2809163a0fcSNikolay Aleksandrov } 2819d332e69SNikolay Aleksandrov v->priv_flags |= BR_VLFLAG_PER_PORT_STATS; 2829163a0fcSNikolay Aleksandrov } else { 2836dada9b1SNikolay Aleksandrov v->stats = masterv->stats; 2849163a0fcSNikolay Aleksandrov } 285613d61dbSNikolay Aleksandrov br_multicast_port_ctx_init(p, v, &v->port_mcast_ctx); 2869c86ce2cSPetr Machata } else { 287169327d5SPetr Machata err = br_switchdev_port_vlan_add(dev, v->vid, flags, extack); 2889c86ce2cSPetr Machata if (err && err != -EOPNOTSUPP) 2899c86ce2cSPetr Machata goto out; 290613d61dbSNikolay Aleksandrov br_multicast_ctx_init(br, v, &v->br_mcast_ctx); 2917b54aaafSNikolay Aleksandrov v->priv_flags |= BR_VLFLAG_GLOBAL_MCAST_ENABLED; 2922594e906SNikolay Aleksandrov } 2932594e906SNikolay Aleksandrov 2946be144f6SNikolay Aleksandrov /* Add the dev mac and count the vlan only if it's usable */ 2952594e906SNikolay Aleksandrov if (br_vlan_should_use(v)) { 2962594e906SNikolay Aleksandrov err = br_fdb_insert(br, p, dev->dev_addr, v->vid); 2972594e906SNikolay Aleksandrov if (err) { 2982594e906SNikolay Aleksandrov br_err(br, "failed insert local address into bridge forwarding table\n"); 2992594e906SNikolay Aleksandrov goto out_filt; 3002594e906SNikolay Aleksandrov } 3016be144f6SNikolay Aleksandrov vg->num_vlans++; 3022594e906SNikolay Aleksandrov } 3032594e906SNikolay Aleksandrov 304a580c76dSNikolay Aleksandrov /* set the state before publishing */ 305a580c76dSNikolay Aleksandrov v->state = BR_STATE_FORWARDING; 306a580c76dSNikolay Aleksandrov 3076be144f6SNikolay Aleksandrov err = rhashtable_lookup_insert_fast(&vg->vlan_hash, &v->vnode, 3086be144f6SNikolay Aleksandrov br_vlan_rht_params); 3092594e906SNikolay Aleksandrov if (err) 3102594e906SNikolay Aleksandrov goto out_fdb_insert; 3112594e906SNikolay Aleksandrov 3122594e906SNikolay Aleksandrov __vlan_add_list(v); 3132594e906SNikolay Aleksandrov __vlan_add_flags(v, flags); 3147b54aaafSNikolay Aleksandrov br_multicast_toggle_one_vlan(v, true); 31580900acdSMike Manning 31680900acdSMike Manning if (p) 31780900acdSMike Manning nbp_vlan_set_vlan_dev_state(p, v->vid); 3182594e906SNikolay Aleksandrov out: 3192594e906SNikolay Aleksandrov return err; 3202594e906SNikolay Aleksandrov 3212594e906SNikolay Aleksandrov out_fdb_insert: 3226be144f6SNikolay Aleksandrov if (br_vlan_should_use(v)) { 3236be144f6SNikolay Aleksandrov br_fdb_find_delete_local(br, p, dev->dev_addr, v->vid); 3246be144f6SNikolay Aleksandrov vg->num_vlans--; 3256be144f6SNikolay Aleksandrov } 3262594e906SNikolay Aleksandrov 3272594e906SNikolay Aleksandrov out_filt: 3282594e906SNikolay Aleksandrov if (p) { 32927973793SIdo Schimmel __vlan_vid_del(dev, br, v); 3302594e906SNikolay Aleksandrov if (masterv) { 3311a3aea25SLi RongQing if (v->stats && masterv->stats != v->stats) 3321a3aea25SLi RongQing free_percpu(v->stats); 3331a3aea25SLi RongQing v->stats = NULL; 3341a3aea25SLi RongQing 335f8ed289fSNikolay Aleksandrov br_vlan_put_master(masterv); 3362594e906SNikolay Aleksandrov v->brvlan = NULL; 3372594e906SNikolay Aleksandrov } 3389c86ce2cSPetr Machata } else { 3399c86ce2cSPetr Machata br_switchdev_port_vlan_del(dev, v->vid); 3402594e906SNikolay Aleksandrov } 3412594e906SNikolay Aleksandrov 3422594e906SNikolay Aleksandrov goto out; 3432594e906SNikolay Aleksandrov } 3442594e906SNikolay Aleksandrov 3452594e906SNikolay Aleksandrov static int __vlan_del(struct net_bridge_vlan *v) 3462594e906SNikolay Aleksandrov { 3472594e906SNikolay Aleksandrov struct net_bridge_vlan *masterv = v; 34877751ee8SNikolay Aleksandrov struct net_bridge_vlan_group *vg; 3492594e906SNikolay Aleksandrov struct net_bridge_port *p = NULL; 3502594e906SNikolay Aleksandrov int err = 0; 3512594e906SNikolay Aleksandrov 3522594e906SNikolay Aleksandrov if (br_vlan_is_master(v)) { 353907b1e6eSNikolay Aleksandrov vg = br_vlan_group(v->br); 3542594e906SNikolay Aleksandrov } else { 3552594e906SNikolay Aleksandrov p = v->port; 356907b1e6eSNikolay Aleksandrov vg = nbp_vlan_group(v->port); 3572594e906SNikolay Aleksandrov masterv = v->brvlan; 3582594e906SNikolay Aleksandrov } 3592594e906SNikolay Aleksandrov 36077751ee8SNikolay Aleksandrov __vlan_delete_pvid(vg, v->vid); 3612594e906SNikolay Aleksandrov if (p) { 36227973793SIdo Schimmel err = __vlan_vid_del(p->dev, p->br, v); 3632594e906SNikolay Aleksandrov if (err) 3642594e906SNikolay Aleksandrov goto out; 3659c86ce2cSPetr Machata } else { 3669c86ce2cSPetr Machata err = br_switchdev_port_vlan_del(v->br->dev, v->vid); 3679c86ce2cSPetr Machata if (err && err != -EOPNOTSUPP) 3689c86ce2cSPetr Machata goto out; 3699c86ce2cSPetr Machata err = 0; 3702594e906SNikolay Aleksandrov } 3712594e906SNikolay Aleksandrov 3726be144f6SNikolay Aleksandrov if (br_vlan_should_use(v)) { 3732594e906SNikolay Aleksandrov v->flags &= ~BRIDGE_VLAN_INFO_BRENTRY; 3746be144f6SNikolay Aleksandrov vg->num_vlans--; 3752594e906SNikolay Aleksandrov } 3762594e906SNikolay Aleksandrov 3772594e906SNikolay Aleksandrov if (masterv != v) { 378efa5356bSRoopa Prabhu vlan_tunnel_info_del(vg, v); 37977751ee8SNikolay Aleksandrov rhashtable_remove_fast(&vg->vlan_hash, &v->vnode, 38077751ee8SNikolay Aleksandrov br_vlan_rht_params); 3812594e906SNikolay Aleksandrov __vlan_del_list(v); 38280900acdSMike Manning nbp_vlan_set_vlan_dev_state(p, v->vid); 3837b54aaafSNikolay Aleksandrov br_multicast_toggle_one_vlan(v, false); 384613d61dbSNikolay Aleksandrov br_multicast_port_ctx_deinit(&v->port_mcast_ctx); 3859163a0fcSNikolay Aleksandrov call_rcu(&v->rcu, nbp_vlan_rcu_free); 3862594e906SNikolay Aleksandrov } 3872594e906SNikolay Aleksandrov 388f8ed289fSNikolay Aleksandrov br_vlan_put_master(masterv); 3892594e906SNikolay Aleksandrov out: 390bf361ad3SVivien Didelot return err; 3918580e211SToshiaki Makita } 392243a2e63SVlad Yasevich 393f409d0edSNikolay Aleksandrov static void __vlan_group_free(struct net_bridge_vlan_group *vg) 394f409d0edSNikolay Aleksandrov { 395f409d0edSNikolay Aleksandrov WARN_ON(!list_empty(&vg->vlan_list)); 396f409d0edSNikolay Aleksandrov rhashtable_destroy(&vg->vlan_hash); 397efa5356bSRoopa Prabhu vlan_tunnel_deinit(vg); 398f409d0edSNikolay Aleksandrov kfree(vg); 399f409d0edSNikolay Aleksandrov } 400f409d0edSNikolay Aleksandrov 401f545923bSNikolay Aleksandrov static void __vlan_flush(const struct net_bridge *br, 402f545923bSNikolay Aleksandrov const struct net_bridge_port *p, 403f545923bSNikolay Aleksandrov struct net_bridge_vlan_group *vg) 404243a2e63SVlad Yasevich { 4052594e906SNikolay Aleksandrov struct net_bridge_vlan *vlan, *tmp; 406f545923bSNikolay Aleksandrov u16 v_start = 0, v_end = 0; 4072594e906SNikolay Aleksandrov 408f409d0edSNikolay Aleksandrov __vlan_delete_pvid(vg, vg->pvid); 409f545923bSNikolay Aleksandrov list_for_each_entry_safe(vlan, tmp, &vg->vlan_list, vlist) { 410f545923bSNikolay Aleksandrov /* take care of disjoint ranges */ 411f545923bSNikolay Aleksandrov if (!v_start) { 412f545923bSNikolay Aleksandrov v_start = vlan->vid; 413f545923bSNikolay Aleksandrov } else if (vlan->vid - v_end != 1) { 414f545923bSNikolay Aleksandrov /* found range end, notify and start next one */ 415f545923bSNikolay Aleksandrov br_vlan_notify(br, p, v_start, v_end, RTM_DELVLAN); 416f545923bSNikolay Aleksandrov v_start = vlan->vid; 417f545923bSNikolay Aleksandrov } 418f545923bSNikolay Aleksandrov v_end = vlan->vid; 419f545923bSNikolay Aleksandrov 4202594e906SNikolay Aleksandrov __vlan_del(vlan); 421243a2e63SVlad Yasevich } 422243a2e63SVlad Yasevich 423f545923bSNikolay Aleksandrov /* notify about the last/whole vlan range */ 424f545923bSNikolay Aleksandrov if (v_start) 425f545923bSNikolay Aleksandrov br_vlan_notify(br, p, v_start, v_end, RTM_DELVLAN); 426f545923bSNikolay Aleksandrov } 427f545923bSNikolay Aleksandrov 42878851988SVlad Yasevich struct sk_buff *br_handle_vlan(struct net_bridge *br, 42911538d03SRoopa Prabhu const struct net_bridge_port *p, 4302594e906SNikolay Aleksandrov struct net_bridge_vlan_group *vg, 431a37b85c9SVlad Yasevich struct sk_buff *skb) 432a37b85c9SVlad Yasevich { 433281cc284SHeiner Kallweit struct pcpu_sw_netstats *stats; 4342594e906SNikolay Aleksandrov struct net_bridge_vlan *v; 435a37b85c9SVlad Yasevich u16 vid; 436a37b85c9SVlad Yasevich 43720adfa1aSVlad Yasevich /* If this packet was not filtered at input, let it pass */ 43820adfa1aSVlad Yasevich if (!BR_INPUT_SKB_CB(skb)->vlan_filtered) 43978851988SVlad Yasevich goto out; 44078851988SVlad Yasevich 4412594e906SNikolay Aleksandrov /* At this point, we know that the frame was filtered and contains 4422594e906SNikolay Aleksandrov * a valid vlan id. If the vlan id has untagged flag set, 4432594e906SNikolay Aleksandrov * send untagged; otherwise, send tagged. 4442594e906SNikolay Aleksandrov */ 4452594e906SNikolay Aleksandrov br_vlan_get_tag(skb, &vid); 4462594e906SNikolay Aleksandrov v = br_vlan_find(vg, vid); 4472594e906SNikolay Aleksandrov /* Vlan entry must be configured at this point. The 448fc92f745SVlad Yasevich * only exception is the bridge is set in promisc mode and the 449fc92f745SVlad Yasevich * packet is destined for the bridge device. In this case 450fc92f745SVlad Yasevich * pass the packet as is. 451fc92f745SVlad Yasevich */ 4522594e906SNikolay Aleksandrov if (!v || !br_vlan_should_use(v)) { 453fc92f745SVlad Yasevich if ((br->dev->flags & IFF_PROMISC) && skb->dev == br->dev) { 454fc92f745SVlad Yasevich goto out; 455fc92f745SVlad Yasevich } else { 456fc92f745SVlad Yasevich kfree_skb(skb); 457fc92f745SVlad Yasevich return NULL; 458fc92f745SVlad Yasevich } 459fc92f745SVlad Yasevich } 460ae75767eSNikolay Aleksandrov if (br_opt_get(br, BROPT_VLAN_STATS_ENABLED)) { 4616dada9b1SNikolay Aleksandrov stats = this_cpu_ptr(v->stats); 4626dada9b1SNikolay Aleksandrov u64_stats_update_begin(&stats->syncp); 4636dada9b1SNikolay Aleksandrov stats->tx_bytes += skb->len; 4646dada9b1SNikolay Aleksandrov stats->tx_packets++; 4656dada9b1SNikolay Aleksandrov u64_stats_update_end(&stats->syncp); 4666dada9b1SNikolay Aleksandrov } 4676dada9b1SNikolay Aleksandrov 468*47211192STobias Waldekranz /* If the skb will be sent using forwarding offload, the assumption is 469*47211192STobias Waldekranz * that the switchdev will inject the packet into hardware together 470*47211192STobias Waldekranz * with the bridge VLAN, so that it can be forwarded according to that 471*47211192STobias Waldekranz * VLAN. The switchdev should deal with popping the VLAN header in 472*47211192STobias Waldekranz * hardware on each egress port as appropriate. So only strip the VLAN 473*47211192STobias Waldekranz * header if forwarding offload is not being used. 474*47211192STobias Waldekranz */ 475*47211192STobias Waldekranz if (v->flags & BRIDGE_VLAN_INFO_UNTAGGED && 476*47211192STobias Waldekranz !br_switchdev_frame_uses_tx_fwd_offload(skb)) 4775978f8a9SMichał Mirosław __vlan_hwaccel_clear_tag(skb); 47811538d03SRoopa Prabhu 47911538d03SRoopa Prabhu if (p && (p->flags & BR_VLAN_TUNNEL) && 48011538d03SRoopa Prabhu br_handle_egress_vlan_tunnel(skb, v)) { 48111538d03SRoopa Prabhu kfree_skb(skb); 48211538d03SRoopa Prabhu return NULL; 48311538d03SRoopa Prabhu } 48478851988SVlad Yasevich out: 48578851988SVlad Yasevich return skb; 48678851988SVlad Yasevich } 48778851988SVlad Yasevich 48878851988SVlad Yasevich /* Called under RCU */ 4896dada9b1SNikolay Aleksandrov static bool __allowed_ingress(const struct net_bridge *br, 4906dada9b1SNikolay Aleksandrov struct net_bridge_vlan_group *vg, 491a580c76dSNikolay Aleksandrov struct sk_buff *skb, u16 *vid, 492f4b7002aSNikolay Aleksandrov u8 *state, 493f4b7002aSNikolay Aleksandrov struct net_bridge_vlan **vlan) 49478851988SVlad Yasevich { 495281cc284SHeiner Kallweit struct pcpu_sw_netstats *stats; 4966dada9b1SNikolay Aleksandrov struct net_bridge_vlan *v; 4978580e211SToshiaki Makita bool tagged; 498a37b85c9SVlad Yasevich 49920adfa1aSVlad Yasevich BR_INPUT_SKB_CB(skb)->vlan_filtered = true; 50012464bb8SToshiaki Makita /* If vlan tx offload is disabled on bridge device and frame was 50112464bb8SToshiaki Makita * sent from vlan device on the bridge device, it does not have 50212464bb8SToshiaki Makita * HW accelerated vlan tag. 50312464bb8SToshiaki Makita */ 504df8a39deSJiri Pirko if (unlikely(!skb_vlan_tag_present(skb) && 5056dada9b1SNikolay Aleksandrov skb->protocol == br->vlan_proto)) { 5060d5501c1SVlad Yasevich skb = skb_vlan_untag(skb); 50712464bb8SToshiaki Makita if (unlikely(!skb)) 50812464bb8SToshiaki Makita return false; 50912464bb8SToshiaki Makita } 51012464bb8SToshiaki Makita 5118580e211SToshiaki Makita if (!br_vlan_get_tag(skb, vid)) { 5128580e211SToshiaki Makita /* Tagged frame */ 5136dada9b1SNikolay Aleksandrov if (skb->vlan_proto != br->vlan_proto) { 5148580e211SToshiaki Makita /* Protocol-mismatch, empty out vlan_tci for new tag */ 5158580e211SToshiaki Makita skb_push(skb, ETH_HLEN); 51662749e2cSJiri Pirko skb = vlan_insert_tag_set_proto(skb, skb->vlan_proto, 517df8a39deSJiri Pirko skb_vlan_tag_get(skb)); 5188580e211SToshiaki Makita if (unlikely(!skb)) 5198580e211SToshiaki Makita return false; 5208580e211SToshiaki Makita 5218580e211SToshiaki Makita skb_pull(skb, ETH_HLEN); 5228580e211SToshiaki Makita skb_reset_mac_len(skb); 5238580e211SToshiaki Makita *vid = 0; 5248580e211SToshiaki Makita tagged = false; 5258580e211SToshiaki Makita } else { 5268580e211SToshiaki Makita tagged = true; 5278580e211SToshiaki Makita } 5288580e211SToshiaki Makita } else { 5298580e211SToshiaki Makita /* Untagged frame */ 5308580e211SToshiaki Makita tagged = false; 5318580e211SToshiaki Makita } 5328580e211SToshiaki Makita 533b90356ceSToshiaki Makita if (!*vid) { 53477751ee8SNikolay Aleksandrov u16 pvid = br_get_pvid(vg); 53577751ee8SNikolay Aleksandrov 536b90356ceSToshiaki Makita /* Frame had a tag with VID 0 or did not have a tag. 537b90356ceSToshiaki Makita * See if pvid is set on this port. That tells us which 538b90356ceSToshiaki Makita * vlan untagged or priority-tagged traffic belongs to. 53978851988SVlad Yasevich */ 5403df6bf45SVlad Yasevich if (!pvid) 541eb707618SToshiaki Makita goto drop; 54278851988SVlad Yasevich 543b90356ceSToshiaki Makita /* PVID is set on this port. Any untagged or priority-tagged 544b90356ceSToshiaki Makita * ingress frame is considered to belong to this vlan. 54578851988SVlad Yasevich */ 546dfb5fa32SToshiaki Makita *vid = pvid; 5478580e211SToshiaki Makita if (likely(!tagged)) 548b90356ceSToshiaki Makita /* Untagged Frame. */ 5496dada9b1SNikolay Aleksandrov __vlan_hwaccel_put_tag(skb, br->vlan_proto, pvid); 550b90356ceSToshiaki Makita else 551b90356ceSToshiaki Makita /* Priority-tagged Frame. 5525978f8a9SMichał Mirosław * At this point, we know that skb->vlan_tci VID 5535978f8a9SMichał Mirosław * field was 0. 554b90356ceSToshiaki Makita * We update only VID field and preserve PCP field. 555b90356ceSToshiaki Makita */ 556b90356ceSToshiaki Makita skb->vlan_tci |= pvid; 557b90356ceSToshiaki Makita 558f4b7002aSNikolay Aleksandrov /* if snooping and stats are disabled we can avoid the lookup */ 559f4b7002aSNikolay Aleksandrov if (!br_opt_get(br, BROPT_MCAST_VLAN_SNOOPING_ENABLED) && 560f4b7002aSNikolay Aleksandrov !br_opt_get(br, BROPT_VLAN_STATS_ENABLED)) { 561a580c76dSNikolay Aleksandrov if (*state == BR_STATE_FORWARDING) { 562a580c76dSNikolay Aleksandrov *state = br_vlan_get_pvid_state(vg); 563a580c76dSNikolay Aleksandrov return br_vlan_state_allowed(*state, true); 564a580c76dSNikolay Aleksandrov } else { 56578851988SVlad Yasevich return true; 56678851988SVlad Yasevich } 567a580c76dSNikolay Aleksandrov } 568a580c76dSNikolay Aleksandrov } 56977751ee8SNikolay Aleksandrov v = br_vlan_find(vg, *vid); 5706dada9b1SNikolay Aleksandrov if (!v || !br_vlan_should_use(v)) 5716dada9b1SNikolay Aleksandrov goto drop; 5726dada9b1SNikolay Aleksandrov 573a580c76dSNikolay Aleksandrov if (*state == BR_STATE_FORWARDING) { 574a580c76dSNikolay Aleksandrov *state = br_vlan_get_state(v); 575a580c76dSNikolay Aleksandrov if (!br_vlan_state_allowed(*state, true)) 576a580c76dSNikolay Aleksandrov goto drop; 577a580c76dSNikolay Aleksandrov } 578a580c76dSNikolay Aleksandrov 579ae75767eSNikolay Aleksandrov if (br_opt_get(br, BROPT_VLAN_STATS_ENABLED)) { 5806dada9b1SNikolay Aleksandrov stats = this_cpu_ptr(v->stats); 5816dada9b1SNikolay Aleksandrov u64_stats_update_begin(&stats->syncp); 5826dada9b1SNikolay Aleksandrov stats->rx_bytes += skb->len; 5836dada9b1SNikolay Aleksandrov stats->rx_packets++; 5846dada9b1SNikolay Aleksandrov u64_stats_update_end(&stats->syncp); 5856dada9b1SNikolay Aleksandrov } 5866dada9b1SNikolay Aleksandrov 587f4b7002aSNikolay Aleksandrov *vlan = v; 588f4b7002aSNikolay Aleksandrov 589a37b85c9SVlad Yasevich return true; 5906dada9b1SNikolay Aleksandrov 591eb707618SToshiaki Makita drop: 592eb707618SToshiaki Makita kfree_skb(skb); 593a37b85c9SVlad Yasevich return false; 594a37b85c9SVlad Yasevich } 595a37b85c9SVlad Yasevich 59677751ee8SNikolay Aleksandrov bool br_allowed_ingress(const struct net_bridge *br, 59777751ee8SNikolay Aleksandrov struct net_bridge_vlan_group *vg, struct sk_buff *skb, 598f4b7002aSNikolay Aleksandrov u16 *vid, u8 *state, 599f4b7002aSNikolay Aleksandrov struct net_bridge_vlan **vlan) 6002594e906SNikolay Aleksandrov { 6012594e906SNikolay Aleksandrov /* If VLAN filtering is disabled on the bridge, all packets are 6022594e906SNikolay Aleksandrov * permitted. 6032594e906SNikolay Aleksandrov */ 604f4b7002aSNikolay Aleksandrov *vlan = NULL; 605ae75767eSNikolay Aleksandrov if (!br_opt_get(br, BROPT_VLAN_ENABLED)) { 6062594e906SNikolay Aleksandrov BR_INPUT_SKB_CB(skb)->vlan_filtered = false; 6072594e906SNikolay Aleksandrov return true; 6082594e906SNikolay Aleksandrov } 6092594e906SNikolay Aleksandrov 610f4b7002aSNikolay Aleksandrov return __allowed_ingress(br, vg, skb, vid, state, vlan); 6112594e906SNikolay Aleksandrov } 6122594e906SNikolay Aleksandrov 61385f46c6bSVlad Yasevich /* Called under RCU. */ 6142594e906SNikolay Aleksandrov bool br_allowed_egress(struct net_bridge_vlan_group *vg, 61585f46c6bSVlad Yasevich const struct sk_buff *skb) 61685f46c6bSVlad Yasevich { 6172594e906SNikolay Aleksandrov const struct net_bridge_vlan *v; 61885f46c6bSVlad Yasevich u16 vid; 61985f46c6bSVlad Yasevich 62020adfa1aSVlad Yasevich /* If this packet was not filtered at input, let it pass */ 62120adfa1aSVlad Yasevich if (!BR_INPUT_SKB_CB(skb)->vlan_filtered) 62285f46c6bSVlad Yasevich return true; 62385f46c6bSVlad Yasevich 62485f46c6bSVlad Yasevich br_vlan_get_tag(skb, &vid); 6252594e906SNikolay Aleksandrov v = br_vlan_find(vg, vid); 626a580c76dSNikolay Aleksandrov if (v && br_vlan_should_use(v) && 627a580c76dSNikolay Aleksandrov br_vlan_state_allowed(br_vlan_get_state(v), false)) 62885f46c6bSVlad Yasevich return true; 62985f46c6bSVlad Yasevich 63085f46c6bSVlad Yasevich return false; 63185f46c6bSVlad Yasevich } 63285f46c6bSVlad Yasevich 633e0d7968aSToshiaki Makita /* Called under RCU */ 634e0d7968aSToshiaki Makita bool br_should_learn(struct net_bridge_port *p, struct sk_buff *skb, u16 *vid) 635e0d7968aSToshiaki Makita { 636468e7944SNikolay Aleksandrov struct net_bridge_vlan_group *vg; 637e0d7968aSToshiaki Makita struct net_bridge *br = p->br; 638a580c76dSNikolay Aleksandrov struct net_bridge_vlan *v; 639e0d7968aSToshiaki Makita 64020adfa1aSVlad Yasevich /* If filtering was disabled at input, let it pass. */ 641ae75767eSNikolay Aleksandrov if (!br_opt_get(br, BROPT_VLAN_ENABLED)) 642e0d7968aSToshiaki Makita return true; 643e0d7968aSToshiaki Makita 644eca1e006SIdo Schimmel vg = nbp_vlan_group_rcu(p); 645468e7944SNikolay Aleksandrov if (!vg || !vg->num_vlans) 646e0d7968aSToshiaki Makita return false; 647e0d7968aSToshiaki Makita 6488580e211SToshiaki Makita if (!br_vlan_get_tag(skb, vid) && skb->vlan_proto != br->vlan_proto) 6498580e211SToshiaki Makita *vid = 0; 6508580e211SToshiaki Makita 651e0d7968aSToshiaki Makita if (!*vid) { 65277751ee8SNikolay Aleksandrov *vid = br_get_pvid(vg); 653a580c76dSNikolay Aleksandrov if (!*vid || 654a580c76dSNikolay Aleksandrov !br_vlan_state_allowed(br_vlan_get_pvid_state(vg), true)) 655e0d7968aSToshiaki Makita return false; 656e0d7968aSToshiaki Makita 657e0d7968aSToshiaki Makita return true; 658e0d7968aSToshiaki Makita } 659e0d7968aSToshiaki Makita 660a580c76dSNikolay Aleksandrov v = br_vlan_find(vg, *vid); 661a580c76dSNikolay Aleksandrov if (v && br_vlan_state_allowed(br_vlan_get_state(v), true)) 662e0d7968aSToshiaki Makita return true; 663e0d7968aSToshiaki Makita 664e0d7968aSToshiaki Makita return false; 665e0d7968aSToshiaki Makita } 666e0d7968aSToshiaki Makita 667dbd6dc75SPetr Machata static int br_vlan_add_existing(struct net_bridge *br, 668dbd6dc75SPetr Machata struct net_bridge_vlan_group *vg, 669dbd6dc75SPetr Machata struct net_bridge_vlan *vlan, 670169327d5SPetr Machata u16 flags, bool *changed, 671169327d5SPetr Machata struct netlink_ext_ack *extack) 672dbd6dc75SPetr Machata { 673dbd6dc75SPetr Machata int err; 674dbd6dc75SPetr Machata 675169327d5SPetr Machata err = br_switchdev_port_vlan_add(br->dev, vlan->vid, flags, extack); 6769c86ce2cSPetr Machata if (err && err != -EOPNOTSUPP) 6779c86ce2cSPetr Machata return err; 6789c86ce2cSPetr Machata 679dbd6dc75SPetr Machata if (!br_vlan_is_brentry(vlan)) { 680dbd6dc75SPetr Machata /* Trying to change flags of non-existent bridge vlan */ 6819c86ce2cSPetr Machata if (!(flags & BRIDGE_VLAN_INFO_BRENTRY)) { 6829c86ce2cSPetr Machata err = -EINVAL; 6839c86ce2cSPetr Machata goto err_flags; 6849c86ce2cSPetr Machata } 685dbd6dc75SPetr Machata /* It was only kept for port vlans, now make it real */ 686dbd6dc75SPetr Machata err = br_fdb_insert(br, NULL, br->dev->dev_addr, 687dbd6dc75SPetr Machata vlan->vid); 688dbd6dc75SPetr Machata if (err) { 689dbd6dc75SPetr Machata br_err(br, "failed to insert local address into bridge forwarding table\n"); 6909c86ce2cSPetr Machata goto err_fdb_insert; 691dbd6dc75SPetr Machata } 692dbd6dc75SPetr Machata 693dbd6dc75SPetr Machata refcount_inc(&vlan->refcnt); 694dbd6dc75SPetr Machata vlan->flags |= BRIDGE_VLAN_INFO_BRENTRY; 695dbd6dc75SPetr Machata vg->num_vlans++; 696dbd6dc75SPetr Machata *changed = true; 697dbd6dc75SPetr Machata } 698dbd6dc75SPetr Machata 699dbd6dc75SPetr Machata if (__vlan_add_flags(vlan, flags)) 700dbd6dc75SPetr Machata *changed = true; 701dbd6dc75SPetr Machata 702dbd6dc75SPetr Machata return 0; 7039c86ce2cSPetr Machata 7049c86ce2cSPetr Machata err_fdb_insert: 7059c86ce2cSPetr Machata err_flags: 7069c86ce2cSPetr Machata br_switchdev_port_vlan_del(br->dev, vlan->vid); 7079c86ce2cSPetr Machata return err; 708dbd6dc75SPetr Machata } 709dbd6dc75SPetr Machata 7108adff41cSToshiaki Makita /* Must be protected by RTNL. 7118adff41cSToshiaki Makita * Must be called with vid in range from 1 to 4094 inclusive. 712f418af63SNikolay Aleksandrov * changed must be true only if the vlan was created or updated 7138adff41cSToshiaki Makita */ 714169327d5SPetr Machata int br_vlan_add(struct net_bridge *br, u16 vid, u16 flags, bool *changed, 715169327d5SPetr Machata struct netlink_ext_ack *extack) 716243a2e63SVlad Yasevich { 717907b1e6eSNikolay Aleksandrov struct net_bridge_vlan_group *vg; 7182594e906SNikolay Aleksandrov struct net_bridge_vlan *vlan; 7192594e906SNikolay Aleksandrov int ret; 720243a2e63SVlad Yasevich 721243a2e63SVlad Yasevich ASSERT_RTNL(); 722243a2e63SVlad Yasevich 723f418af63SNikolay Aleksandrov *changed = false; 724907b1e6eSNikolay Aleksandrov vg = br_vlan_group(br); 725907b1e6eSNikolay Aleksandrov vlan = br_vlan_find(vg, vid); 726dbd6dc75SPetr Machata if (vlan) 727169327d5SPetr Machata return br_vlan_add_existing(br, vg, vlan, flags, changed, 728169327d5SPetr Machata extack); 729243a2e63SVlad Yasevich 7302594e906SNikolay Aleksandrov vlan = kzalloc(sizeof(*vlan), GFP_KERNEL); 7312594e906SNikolay Aleksandrov if (!vlan) 732243a2e63SVlad Yasevich return -ENOMEM; 733243a2e63SVlad Yasevich 734281cc284SHeiner Kallweit vlan->stats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); 7356dada9b1SNikolay Aleksandrov if (!vlan->stats) { 7366dada9b1SNikolay Aleksandrov kfree(vlan); 7376dada9b1SNikolay Aleksandrov return -ENOMEM; 7386dada9b1SNikolay Aleksandrov } 7392594e906SNikolay Aleksandrov vlan->vid = vid; 7402594e906SNikolay Aleksandrov vlan->flags = flags | BRIDGE_VLAN_INFO_MASTER; 7412594e906SNikolay Aleksandrov vlan->flags &= ~BRIDGE_VLAN_INFO_PVID; 7422594e906SNikolay Aleksandrov vlan->br = br; 7432594e906SNikolay Aleksandrov if (flags & BRIDGE_VLAN_INFO_BRENTRY) 74425127759SReshetova, Elena refcount_set(&vlan->refcnt, 1); 745169327d5SPetr Machata ret = __vlan_add(vlan, flags, extack); 7466dada9b1SNikolay Aleksandrov if (ret) { 7476dada9b1SNikolay Aleksandrov free_percpu(vlan->stats); 7482594e906SNikolay Aleksandrov kfree(vlan); 749f418af63SNikolay Aleksandrov } else { 750f418af63SNikolay Aleksandrov *changed = true; 7516dada9b1SNikolay Aleksandrov } 752243a2e63SVlad Yasevich 7532594e906SNikolay Aleksandrov return ret; 754243a2e63SVlad Yasevich } 755243a2e63SVlad Yasevich 7568adff41cSToshiaki Makita /* Must be protected by RTNL. 7578adff41cSToshiaki Makita * Must be called with vid in range from 1 to 4094 inclusive. 7588adff41cSToshiaki Makita */ 759243a2e63SVlad Yasevich int br_vlan_delete(struct net_bridge *br, u16 vid) 760243a2e63SVlad Yasevich { 761907b1e6eSNikolay Aleksandrov struct net_bridge_vlan_group *vg; 7622594e906SNikolay Aleksandrov struct net_bridge_vlan *v; 763243a2e63SVlad Yasevich 764243a2e63SVlad Yasevich ASSERT_RTNL(); 765243a2e63SVlad Yasevich 766907b1e6eSNikolay Aleksandrov vg = br_vlan_group(br); 767907b1e6eSNikolay Aleksandrov v = br_vlan_find(vg, vid); 7682594e906SNikolay Aleksandrov if (!v || !br_vlan_is_brentry(v)) 7692594e906SNikolay Aleksandrov return -ENOENT; 770243a2e63SVlad Yasevich 771424bb9c9SToshiaki Makita br_fdb_find_delete_local(br, NULL, br->dev->dev_addr, vid); 7723741873bSRoopa Prabhu br_fdb_delete_by_port(br, NULL, vid, 0); 773bc9a25d2SVlad Yasevich 774efa5356bSRoopa Prabhu vlan_tunnel_info_del(vg, v); 775efa5356bSRoopa Prabhu 7762594e906SNikolay Aleksandrov return __vlan_del(v); 777243a2e63SVlad Yasevich } 778243a2e63SVlad Yasevich 779243a2e63SVlad Yasevich void br_vlan_flush(struct net_bridge *br) 780243a2e63SVlad Yasevich { 781f409d0edSNikolay Aleksandrov struct net_bridge_vlan_group *vg; 782f409d0edSNikolay Aleksandrov 783243a2e63SVlad Yasevich ASSERT_RTNL(); 784243a2e63SVlad Yasevich 785f409d0edSNikolay Aleksandrov vg = br_vlan_group(br); 786f545923bSNikolay Aleksandrov __vlan_flush(br, NULL, vg); 787f409d0edSNikolay Aleksandrov RCU_INIT_POINTER(br->vlgrp, NULL); 788f409d0edSNikolay Aleksandrov synchronize_rcu(); 789f409d0edSNikolay Aleksandrov __vlan_group_free(vg); 790243a2e63SVlad Yasevich } 791243a2e63SVlad Yasevich 7922594e906SNikolay Aleksandrov struct net_bridge_vlan *br_vlan_find(struct net_bridge_vlan_group *vg, u16 vid) 7932b292fb4SToshiaki Makita { 7942594e906SNikolay Aleksandrov if (!vg) 7952594e906SNikolay Aleksandrov return NULL; 7962b292fb4SToshiaki Makita 7972594e906SNikolay Aleksandrov return br_vlan_lookup(&vg->vlan_hash, vid); 7982b292fb4SToshiaki Makita } 7992b292fb4SToshiaki Makita 800204177f3SToshiaki Makita /* Must be protected by RTNL. */ 801204177f3SToshiaki Makita static void recalculate_group_addr(struct net_bridge *br) 802204177f3SToshiaki Makita { 803be3664a0SNikolay Aleksandrov if (br_opt_get(br, BROPT_GROUP_ADDR_SET)) 804204177f3SToshiaki Makita return; 805204177f3SToshiaki Makita 806204177f3SToshiaki Makita spin_lock_bh(&br->lock); 807ae75767eSNikolay Aleksandrov if (!br_opt_get(br, BROPT_VLAN_ENABLED) || 808ae75767eSNikolay Aleksandrov br->vlan_proto == htons(ETH_P_8021Q)) { 809204177f3SToshiaki Makita /* Bridge Group Address */ 810204177f3SToshiaki Makita br->group_addr[5] = 0x00; 811204177f3SToshiaki Makita } else { /* vlan_enabled && ETH_P_8021AD */ 812204177f3SToshiaki Makita /* Provider Bridge Group Address */ 813204177f3SToshiaki Makita br->group_addr[5] = 0x08; 814204177f3SToshiaki Makita } 815204177f3SToshiaki Makita spin_unlock_bh(&br->lock); 816204177f3SToshiaki Makita } 817204177f3SToshiaki Makita 818204177f3SToshiaki Makita /* Must be protected by RTNL. */ 819204177f3SToshiaki Makita void br_recalculate_fwd_mask(struct net_bridge *br) 820204177f3SToshiaki Makita { 821ae75767eSNikolay Aleksandrov if (!br_opt_get(br, BROPT_VLAN_ENABLED) || 822ae75767eSNikolay Aleksandrov br->vlan_proto == htons(ETH_P_8021Q)) 823204177f3SToshiaki Makita br->group_fwd_mask_required = BR_GROUPFWD_DEFAULT; 824204177f3SToshiaki Makita else /* vlan_enabled && ETH_P_8021AD */ 825204177f3SToshiaki Makita br->group_fwd_mask_required = BR_GROUPFWD_8021AD & 826204177f3SToshiaki Makita ~(1u << br->group_addr[5]); 827204177f3SToshiaki Makita } 828204177f3SToshiaki Makita 8299e781401SVladimir Oltean int br_vlan_filter_toggle(struct net_bridge *br, unsigned long val, 8309e781401SVladimir Oltean struct netlink_ext_ack *extack) 831243a2e63SVlad Yasevich { 8326b72a770SElad Raz struct switchdev_attr attr = { 8336b72a770SElad Raz .orig_dev = br->dev, 8346b72a770SElad Raz .id = SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING, 8356b72a770SElad Raz .flags = SWITCHDEV_F_SKIP_EOPNOTSUPP, 8366b72a770SElad Raz .u.vlan_filtering = val, 8376b72a770SElad Raz }; 8386b72a770SElad Raz int err; 8396b72a770SElad Raz 840ae75767eSNikolay Aleksandrov if (br_opt_get(br, BROPT_VLAN_ENABLED) == !!val) 841a7854037SNikolay Aleksandrov return 0; 842243a2e63SVlad Yasevich 843dcbdf135SVladimir Oltean err = switchdev_port_attr_set(br->dev, &attr, extack); 8446b72a770SElad Raz if (err && err != -EOPNOTSUPP) 8456b72a770SElad Raz return err; 8466b72a770SElad Raz 847ae75767eSNikolay Aleksandrov br_opt_toggle(br, BROPT_VLAN_ENABLED, !!val); 8482796d0c6SVlad Yasevich br_manage_promisc(br); 849204177f3SToshiaki Makita recalculate_group_addr(br); 850204177f3SToshiaki Makita br_recalculate_fwd_mask(br); 851f4b7002aSNikolay Aleksandrov if (!val && br_opt_get(br, BROPT_MCAST_VLAN_SNOOPING_ENABLED)) { 852f4b7002aSNikolay Aleksandrov br_info(br, "vlan filtering disabled, automatically disabling multicast vlan snooping\n"); 853f4b7002aSNikolay Aleksandrov br_multicast_toggle_vlan_snooping(br, false, NULL); 854f4b7002aSNikolay Aleksandrov } 855243a2e63SVlad Yasevich 856a7854037SNikolay Aleksandrov return 0; 857a7854037SNikolay Aleksandrov } 858a7854037SNikolay Aleksandrov 8591f51445aSIdo Schimmel bool br_vlan_enabled(const struct net_device *dev) 8601f51445aSIdo Schimmel { 8611f51445aSIdo Schimmel struct net_bridge *br = netdev_priv(dev); 8621f51445aSIdo Schimmel 863ae75767eSNikolay Aleksandrov return br_opt_get(br, BROPT_VLAN_ENABLED); 8641f51445aSIdo Schimmel } 8651f51445aSIdo Schimmel EXPORT_SYMBOL_GPL(br_vlan_enabled); 8661f51445aSIdo Schimmel 86731aed46fSwenxu int br_vlan_get_proto(const struct net_device *dev, u16 *p_proto) 86831aed46fSwenxu { 86931aed46fSwenxu struct net_bridge *br = netdev_priv(dev); 87031aed46fSwenxu 87131aed46fSwenxu *p_proto = ntohs(br->vlan_proto); 87231aed46fSwenxu 87331aed46fSwenxu return 0; 87431aed46fSwenxu } 87531aed46fSwenxu EXPORT_SYMBOL_GPL(br_vlan_get_proto); 87631aed46fSwenxu 877dcbdf135SVladimir Oltean int __br_vlan_set_proto(struct net_bridge *br, __be16 proto, 878dcbdf135SVladimir Oltean struct netlink_ext_ack *extack) 879204177f3SToshiaki Makita { 88022ec19f3SDanielle Ratson struct switchdev_attr attr = { 88122ec19f3SDanielle Ratson .orig_dev = br->dev, 88222ec19f3SDanielle Ratson .id = SWITCHDEV_ATTR_ID_BRIDGE_VLAN_PROTOCOL, 88322ec19f3SDanielle Ratson .flags = SWITCHDEV_F_SKIP_EOPNOTSUPP, 88422ec19f3SDanielle Ratson .u.vlan_protocol = ntohs(proto), 88522ec19f3SDanielle Ratson }; 886204177f3SToshiaki Makita int err = 0; 887204177f3SToshiaki Makita struct net_bridge_port *p; 8882594e906SNikolay Aleksandrov struct net_bridge_vlan *vlan; 889907b1e6eSNikolay Aleksandrov struct net_bridge_vlan_group *vg; 89022ec19f3SDanielle Ratson __be16 oldproto = br->vlan_proto; 891204177f3SToshiaki Makita 892204177f3SToshiaki Makita if (br->vlan_proto == proto) 893d2d427b3SToshiaki Makita return 0; 894204177f3SToshiaki Makita 895dcbdf135SVladimir Oltean err = switchdev_port_attr_set(br->dev, &attr, extack); 89622ec19f3SDanielle Ratson if (err && err != -EOPNOTSUPP) 89722ec19f3SDanielle Ratson return err; 89822ec19f3SDanielle Ratson 899204177f3SToshiaki Makita /* Add VLANs for the new proto to the device filter. */ 900204177f3SToshiaki Makita list_for_each_entry(p, &br->port_list, list) { 901907b1e6eSNikolay Aleksandrov vg = nbp_vlan_group(p); 902907b1e6eSNikolay Aleksandrov list_for_each_entry(vlan, &vg->vlan_list, vlist) { 9032594e906SNikolay Aleksandrov err = vlan_vid_add(p->dev, proto, vlan->vid); 904204177f3SToshiaki Makita if (err) 905204177f3SToshiaki Makita goto err_filt; 906204177f3SToshiaki Makita } 907204177f3SToshiaki Makita } 908204177f3SToshiaki Makita 909204177f3SToshiaki Makita br->vlan_proto = proto; 910204177f3SToshiaki Makita 911204177f3SToshiaki Makita recalculate_group_addr(br); 912204177f3SToshiaki Makita br_recalculate_fwd_mask(br); 913204177f3SToshiaki Makita 914204177f3SToshiaki Makita /* Delete VLANs for the old proto from the device filter. */ 915907b1e6eSNikolay Aleksandrov list_for_each_entry(p, &br->port_list, list) { 916907b1e6eSNikolay Aleksandrov vg = nbp_vlan_group(p); 917907b1e6eSNikolay Aleksandrov list_for_each_entry(vlan, &vg->vlan_list, vlist) 9182594e906SNikolay Aleksandrov vlan_vid_del(p->dev, oldproto, vlan->vid); 919907b1e6eSNikolay Aleksandrov } 920204177f3SToshiaki Makita 921d2d427b3SToshiaki Makita return 0; 922204177f3SToshiaki Makita 923204177f3SToshiaki Makita err_filt: 92422ec19f3SDanielle Ratson attr.u.vlan_protocol = ntohs(oldproto); 925dcbdf135SVladimir Oltean switchdev_port_attr_set(br->dev, &attr, NULL); 92622ec19f3SDanielle Ratson 927907b1e6eSNikolay Aleksandrov list_for_each_entry_continue_reverse(vlan, &vg->vlan_list, vlist) 9282594e906SNikolay Aleksandrov vlan_vid_del(p->dev, proto, vlan->vid); 929204177f3SToshiaki Makita 930907b1e6eSNikolay Aleksandrov list_for_each_entry_continue_reverse(p, &br->port_list, list) { 931907b1e6eSNikolay Aleksandrov vg = nbp_vlan_group(p); 932907b1e6eSNikolay Aleksandrov list_for_each_entry(vlan, &vg->vlan_list, vlist) 9332594e906SNikolay Aleksandrov vlan_vid_del(p->dev, proto, vlan->vid); 934907b1e6eSNikolay Aleksandrov } 935204177f3SToshiaki Makita 936d2d427b3SToshiaki Makita return err; 937d2d427b3SToshiaki Makita } 938d2d427b3SToshiaki Makita 9399e781401SVladimir Oltean int br_vlan_set_proto(struct net_bridge *br, unsigned long val, 9409e781401SVladimir Oltean struct netlink_ext_ack *extack) 941d2d427b3SToshiaki Makita { 942a98c0c47SMenglong Dong if (!eth_type_vlan(htons(val))) 943d2d427b3SToshiaki Makita return -EPROTONOSUPPORT; 944d2d427b3SToshiaki Makita 945dcbdf135SVladimir Oltean return __br_vlan_set_proto(br, htons(val), extack); 946204177f3SToshiaki Makita } 947204177f3SToshiaki Makita 9486dada9b1SNikolay Aleksandrov int br_vlan_set_stats(struct net_bridge *br, unsigned long val) 9496dada9b1SNikolay Aleksandrov { 9506dada9b1SNikolay Aleksandrov switch (val) { 9516dada9b1SNikolay Aleksandrov case 0: 9526dada9b1SNikolay Aleksandrov case 1: 953ae75767eSNikolay Aleksandrov br_opt_toggle(br, BROPT_VLAN_STATS_ENABLED, !!val); 9546dada9b1SNikolay Aleksandrov break; 9556dada9b1SNikolay Aleksandrov default: 9566dada9b1SNikolay Aleksandrov return -EINVAL; 9576dada9b1SNikolay Aleksandrov } 9586dada9b1SNikolay Aleksandrov 9596dada9b1SNikolay Aleksandrov return 0; 9606dada9b1SNikolay Aleksandrov } 9616dada9b1SNikolay Aleksandrov 9629163a0fcSNikolay Aleksandrov int br_vlan_set_stats_per_port(struct net_bridge *br, unsigned long val) 9639163a0fcSNikolay Aleksandrov { 9649163a0fcSNikolay Aleksandrov struct net_bridge_port *p; 9659163a0fcSNikolay Aleksandrov 9669163a0fcSNikolay Aleksandrov /* allow to change the option if there are no port vlans configured */ 9679163a0fcSNikolay Aleksandrov list_for_each_entry(p, &br->port_list, list) { 9689163a0fcSNikolay Aleksandrov struct net_bridge_vlan_group *vg = nbp_vlan_group(p); 9699163a0fcSNikolay Aleksandrov 9709163a0fcSNikolay Aleksandrov if (vg->num_vlans) 9719163a0fcSNikolay Aleksandrov return -EBUSY; 9729163a0fcSNikolay Aleksandrov } 9739163a0fcSNikolay Aleksandrov 9749163a0fcSNikolay Aleksandrov switch (val) { 9759163a0fcSNikolay Aleksandrov case 0: 9769163a0fcSNikolay Aleksandrov case 1: 9779163a0fcSNikolay Aleksandrov br_opt_toggle(br, BROPT_VLAN_STATS_PER_PORT, !!val); 9789163a0fcSNikolay Aleksandrov break; 9799163a0fcSNikolay Aleksandrov default: 9809163a0fcSNikolay Aleksandrov return -EINVAL; 9819163a0fcSNikolay Aleksandrov } 9829163a0fcSNikolay Aleksandrov 9839163a0fcSNikolay Aleksandrov return 0; 9849163a0fcSNikolay Aleksandrov } 9859163a0fcSNikolay Aleksandrov 98677751ee8SNikolay Aleksandrov static bool vlan_default_pvid(struct net_bridge_vlan_group *vg, u16 vid) 9875be5a2dfSVlad Yasevich { 9882594e906SNikolay Aleksandrov struct net_bridge_vlan *v; 9892594e906SNikolay Aleksandrov 99077751ee8SNikolay Aleksandrov if (vid != vg->pvid) 9912594e906SNikolay Aleksandrov return false; 9922594e906SNikolay Aleksandrov 9932594e906SNikolay Aleksandrov v = br_vlan_lookup(&vg->vlan_hash, vid); 9942594e906SNikolay Aleksandrov if (v && br_vlan_should_use(v) && 9952594e906SNikolay Aleksandrov (v->flags & BRIDGE_VLAN_INFO_UNTAGGED)) 9962594e906SNikolay Aleksandrov return true; 9972594e906SNikolay Aleksandrov 9982594e906SNikolay Aleksandrov return false; 9995be5a2dfSVlad Yasevich } 10005be5a2dfSVlad Yasevich 10015be5a2dfSVlad Yasevich static void br_vlan_disable_default_pvid(struct net_bridge *br) 10025be5a2dfSVlad Yasevich { 10035be5a2dfSVlad Yasevich struct net_bridge_port *p; 10045be5a2dfSVlad Yasevich u16 pvid = br->default_pvid; 10055be5a2dfSVlad Yasevich 10065be5a2dfSVlad Yasevich /* Disable default_pvid on all ports where it is still 10075be5a2dfSVlad Yasevich * configured. 10085be5a2dfSVlad Yasevich */ 1009f545923bSNikolay Aleksandrov if (vlan_default_pvid(br_vlan_group(br), pvid)) { 1010f545923bSNikolay Aleksandrov if (!br_vlan_delete(br, pvid)) 1011f545923bSNikolay Aleksandrov br_vlan_notify(br, NULL, pvid, 0, RTM_DELVLAN); 1012f545923bSNikolay Aleksandrov } 10135be5a2dfSVlad Yasevich 10145be5a2dfSVlad Yasevich list_for_each_entry(p, &br->port_list, list) { 1015f545923bSNikolay Aleksandrov if (vlan_default_pvid(nbp_vlan_group(p), pvid) && 1016f545923bSNikolay Aleksandrov !nbp_vlan_delete(p, pvid)) 1017f545923bSNikolay Aleksandrov br_vlan_notify(br, p, pvid, 0, RTM_DELVLAN); 10185be5a2dfSVlad Yasevich } 10195be5a2dfSVlad Yasevich 10205be5a2dfSVlad Yasevich br->default_pvid = 0; 10215be5a2dfSVlad Yasevich } 10225be5a2dfSVlad Yasevich 1023169327d5SPetr Machata int __br_vlan_set_default_pvid(struct net_bridge *br, u16 pvid, 1024169327d5SPetr Machata struct netlink_ext_ack *extack) 10255be5a2dfSVlad Yasevich { 10262594e906SNikolay Aleksandrov const struct net_bridge_vlan *pvent; 1027907b1e6eSNikolay Aleksandrov struct net_bridge_vlan_group *vg; 10285be5a2dfSVlad Yasevich struct net_bridge_port *p; 1029f418af63SNikolay Aleksandrov unsigned long *changed; 1030f418af63SNikolay Aleksandrov bool vlchange; 10315be5a2dfSVlad Yasevich u16 old_pvid; 10325be5a2dfSVlad Yasevich int err = 0; 10335be5a2dfSVlad Yasevich 10340f963b75SNikolay Aleksandrov if (!pvid) { 10350f963b75SNikolay Aleksandrov br_vlan_disable_default_pvid(br); 10360f963b75SNikolay Aleksandrov return 0; 10370f963b75SNikolay Aleksandrov } 10380f963b75SNikolay Aleksandrov 1039459479daSAndy Shevchenko changed = bitmap_zalloc(BR_MAX_PORTS, GFP_KERNEL); 10405be5a2dfSVlad Yasevich if (!changed) 10415be5a2dfSVlad Yasevich return -ENOMEM; 10425be5a2dfSVlad Yasevich 10435be5a2dfSVlad Yasevich old_pvid = br->default_pvid; 10445be5a2dfSVlad Yasevich 10455be5a2dfSVlad Yasevich /* Update default_pvid config only if we do not conflict with 10465be5a2dfSVlad Yasevich * user configuration. 10475be5a2dfSVlad Yasevich */ 1048907b1e6eSNikolay Aleksandrov vg = br_vlan_group(br); 1049907b1e6eSNikolay Aleksandrov pvent = br_vlan_find(vg, pvid); 1050907b1e6eSNikolay Aleksandrov if ((!old_pvid || vlan_default_pvid(vg, old_pvid)) && 10512594e906SNikolay Aleksandrov (!pvent || !br_vlan_should_use(pvent))) { 10525be5a2dfSVlad Yasevich err = br_vlan_add(br, pvid, 10535be5a2dfSVlad Yasevich BRIDGE_VLAN_INFO_PVID | 10542594e906SNikolay Aleksandrov BRIDGE_VLAN_INFO_UNTAGGED | 1055f418af63SNikolay Aleksandrov BRIDGE_VLAN_INFO_BRENTRY, 1056169327d5SPetr Machata &vlchange, extack); 10575be5a2dfSVlad Yasevich if (err) 10585be5a2dfSVlad Yasevich goto out; 1059f545923bSNikolay Aleksandrov 1060f545923bSNikolay Aleksandrov if (br_vlan_delete(br, old_pvid)) 1061f545923bSNikolay Aleksandrov br_vlan_notify(br, NULL, old_pvid, 0, RTM_DELVLAN); 1062f545923bSNikolay Aleksandrov br_vlan_notify(br, NULL, pvid, 0, RTM_NEWVLAN); 10635be5a2dfSVlad Yasevich set_bit(0, changed); 10645be5a2dfSVlad Yasevich } 10655be5a2dfSVlad Yasevich 10665be5a2dfSVlad Yasevich list_for_each_entry(p, &br->port_list, list) { 10675be5a2dfSVlad Yasevich /* Update default_pvid config only if we do not conflict with 10685be5a2dfSVlad Yasevich * user configuration. 10695be5a2dfSVlad Yasevich */ 1070907b1e6eSNikolay Aleksandrov vg = nbp_vlan_group(p); 10715be5a2dfSVlad Yasevich if ((old_pvid && 1072907b1e6eSNikolay Aleksandrov !vlan_default_pvid(vg, old_pvid)) || 1073907b1e6eSNikolay Aleksandrov br_vlan_find(vg, pvid)) 10745be5a2dfSVlad Yasevich continue; 10755be5a2dfSVlad Yasevich 10765be5a2dfSVlad Yasevich err = nbp_vlan_add(p, pvid, 10775be5a2dfSVlad Yasevich BRIDGE_VLAN_INFO_PVID | 1078f418af63SNikolay Aleksandrov BRIDGE_VLAN_INFO_UNTAGGED, 1079169327d5SPetr Machata &vlchange, extack); 10805be5a2dfSVlad Yasevich if (err) 10815be5a2dfSVlad Yasevich goto err_port; 1082f545923bSNikolay Aleksandrov if (nbp_vlan_delete(p, old_pvid)) 1083f545923bSNikolay Aleksandrov br_vlan_notify(br, p, old_pvid, 0, RTM_DELVLAN); 1084f545923bSNikolay Aleksandrov br_vlan_notify(p->br, p, pvid, 0, RTM_NEWVLAN); 10855be5a2dfSVlad Yasevich set_bit(p->port_no, changed); 10865be5a2dfSVlad Yasevich } 10875be5a2dfSVlad Yasevich 10885be5a2dfSVlad Yasevich br->default_pvid = pvid; 10895be5a2dfSVlad Yasevich 10905be5a2dfSVlad Yasevich out: 1091459479daSAndy Shevchenko bitmap_free(changed); 10925be5a2dfSVlad Yasevich return err; 10935be5a2dfSVlad Yasevich 10945be5a2dfSVlad Yasevich err_port: 10955be5a2dfSVlad Yasevich list_for_each_entry_continue_reverse(p, &br->port_list, list) { 10965be5a2dfSVlad Yasevich if (!test_bit(p->port_no, changed)) 10975be5a2dfSVlad Yasevich continue; 10985be5a2dfSVlad Yasevich 1099f545923bSNikolay Aleksandrov if (old_pvid) { 11005be5a2dfSVlad Yasevich nbp_vlan_add(p, old_pvid, 11015be5a2dfSVlad Yasevich BRIDGE_VLAN_INFO_PVID | 1102f418af63SNikolay Aleksandrov BRIDGE_VLAN_INFO_UNTAGGED, 1103169327d5SPetr Machata &vlchange, NULL); 1104f545923bSNikolay Aleksandrov br_vlan_notify(p->br, p, old_pvid, 0, RTM_NEWVLAN); 1105f545923bSNikolay Aleksandrov } 11065be5a2dfSVlad Yasevich nbp_vlan_delete(p, pvid); 1107f545923bSNikolay Aleksandrov br_vlan_notify(br, p, pvid, 0, RTM_DELVLAN); 11085be5a2dfSVlad Yasevich } 11095be5a2dfSVlad Yasevich 11105be5a2dfSVlad Yasevich if (test_bit(0, changed)) { 1111f545923bSNikolay Aleksandrov if (old_pvid) { 11125be5a2dfSVlad Yasevich br_vlan_add(br, old_pvid, 11135be5a2dfSVlad Yasevich BRIDGE_VLAN_INFO_PVID | 11142594e906SNikolay Aleksandrov BRIDGE_VLAN_INFO_UNTAGGED | 1115f418af63SNikolay Aleksandrov BRIDGE_VLAN_INFO_BRENTRY, 1116169327d5SPetr Machata &vlchange, NULL); 1117f545923bSNikolay Aleksandrov br_vlan_notify(br, NULL, old_pvid, 0, RTM_NEWVLAN); 1118f545923bSNikolay Aleksandrov } 11195be5a2dfSVlad Yasevich br_vlan_delete(br, pvid); 1120f545923bSNikolay Aleksandrov br_vlan_notify(br, NULL, pvid, 0, RTM_DELVLAN); 11215be5a2dfSVlad Yasevich } 11225be5a2dfSVlad Yasevich goto out; 11235be5a2dfSVlad Yasevich } 11245be5a2dfSVlad Yasevich 11259e781401SVladimir Oltean int br_vlan_set_default_pvid(struct net_bridge *br, unsigned long val, 11269e781401SVladimir Oltean struct netlink_ext_ack *extack) 112796a20d9dSVlad Yasevich { 112896a20d9dSVlad Yasevich u16 pvid = val; 112996a20d9dSVlad Yasevich int err = 0; 113096a20d9dSVlad Yasevich 11315be5a2dfSVlad Yasevich if (val >= VLAN_VID_MASK) 113296a20d9dSVlad Yasevich return -EINVAL; 113396a20d9dSVlad Yasevich 113496a20d9dSVlad Yasevich if (pvid == br->default_pvid) 1135047831a9SXin Long goto out; 113696a20d9dSVlad Yasevich 113796a20d9dSVlad Yasevich /* Only allow default pvid change when filtering is disabled */ 1138ae75767eSNikolay Aleksandrov if (br_opt_get(br, BROPT_VLAN_ENABLED)) { 113996a20d9dSVlad Yasevich pr_info_once("Please disable vlan filtering to change default_pvid\n"); 114096a20d9dSVlad Yasevich err = -EPERM; 1141047831a9SXin Long goto out; 114296a20d9dSVlad Yasevich } 11439e781401SVladimir Oltean err = __br_vlan_set_default_pvid(br, pvid, extack); 1144047831a9SXin Long out: 114596a20d9dSVlad Yasevich return err; 114696a20d9dSVlad Yasevich } 114796a20d9dSVlad Yasevich 11485be5a2dfSVlad Yasevich int br_vlan_init(struct net_bridge *br) 11498580e211SToshiaki Makita { 1150907b1e6eSNikolay Aleksandrov struct net_bridge_vlan_group *vg; 11512594e906SNikolay Aleksandrov int ret = -ENOMEM; 11522594e906SNikolay Aleksandrov 1153907b1e6eSNikolay Aleksandrov vg = kzalloc(sizeof(*vg), GFP_KERNEL); 1154907b1e6eSNikolay Aleksandrov if (!vg) 11552594e906SNikolay Aleksandrov goto out; 1156907b1e6eSNikolay Aleksandrov ret = rhashtable_init(&vg->vlan_hash, &br_vlan_rht_params); 11572594e906SNikolay Aleksandrov if (ret) 11582594e906SNikolay Aleksandrov goto err_rhtbl; 1159efa5356bSRoopa Prabhu ret = vlan_tunnel_init(vg); 1160efa5356bSRoopa Prabhu if (ret) 1161efa5356bSRoopa Prabhu goto err_tunnel_init; 1162907b1e6eSNikolay Aleksandrov INIT_LIST_HEAD(&vg->vlan_list); 11638580e211SToshiaki Makita br->vlan_proto = htons(ETH_P_8021Q); 116496a20d9dSVlad Yasevich br->default_pvid = 1; 1165907b1e6eSNikolay Aleksandrov rcu_assign_pointer(br->vlgrp, vg); 11662594e906SNikolay Aleksandrov 11672594e906SNikolay Aleksandrov out: 11682594e906SNikolay Aleksandrov return ret; 11692594e906SNikolay Aleksandrov 1170efa5356bSRoopa Prabhu err_tunnel_init: 1171907b1e6eSNikolay Aleksandrov rhashtable_destroy(&vg->vlan_hash); 11722594e906SNikolay Aleksandrov err_rhtbl: 1173907b1e6eSNikolay Aleksandrov kfree(vg); 11742594e906SNikolay Aleksandrov 11752594e906SNikolay Aleksandrov goto out; 11762594e906SNikolay Aleksandrov } 11772594e906SNikolay Aleksandrov 1178169327d5SPetr Machata int nbp_vlan_init(struct net_bridge_port *p, struct netlink_ext_ack *extack) 11792594e906SNikolay Aleksandrov { 1180404cdbf0SElad Raz struct switchdev_attr attr = { 1181404cdbf0SElad Raz .orig_dev = p->br->dev, 1182404cdbf0SElad Raz .id = SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING, 1183404cdbf0SElad Raz .flags = SWITCHDEV_F_SKIP_EOPNOTSUPP, 1184ae75767eSNikolay Aleksandrov .u.vlan_filtering = br_opt_get(p->br, BROPT_VLAN_ENABLED), 1185404cdbf0SElad Raz }; 1186263344e6SNikolay Aleksandrov struct net_bridge_vlan_group *vg; 11872594e906SNikolay Aleksandrov int ret = -ENOMEM; 11882594e906SNikolay Aleksandrov 1189263344e6SNikolay Aleksandrov vg = kzalloc(sizeof(struct net_bridge_vlan_group), GFP_KERNEL); 1190263344e6SNikolay Aleksandrov if (!vg) 11912594e906SNikolay Aleksandrov goto out; 11922594e906SNikolay Aleksandrov 1193dcbdf135SVladimir Oltean ret = switchdev_port_attr_set(p->dev, &attr, extack); 1194404cdbf0SElad Raz if (ret && ret != -EOPNOTSUPP) 1195404cdbf0SElad Raz goto err_vlan_enabled; 1196404cdbf0SElad Raz 1197263344e6SNikolay Aleksandrov ret = rhashtable_init(&vg->vlan_hash, &br_vlan_rht_params); 11982594e906SNikolay Aleksandrov if (ret) 11992594e906SNikolay Aleksandrov goto err_rhtbl; 1200efa5356bSRoopa Prabhu ret = vlan_tunnel_init(vg); 1201efa5356bSRoopa Prabhu if (ret) 1202efa5356bSRoopa Prabhu goto err_tunnel_init; 1203263344e6SNikolay Aleksandrov INIT_LIST_HEAD(&vg->vlan_list); 1204907b1e6eSNikolay Aleksandrov rcu_assign_pointer(p->vlgrp, vg); 12052594e906SNikolay Aleksandrov if (p->br->default_pvid) { 1206f418af63SNikolay Aleksandrov bool changed; 1207f418af63SNikolay Aleksandrov 12082594e906SNikolay Aleksandrov ret = nbp_vlan_add(p, p->br->default_pvid, 12092594e906SNikolay Aleksandrov BRIDGE_VLAN_INFO_PVID | 1210f418af63SNikolay Aleksandrov BRIDGE_VLAN_INFO_UNTAGGED, 1211169327d5SPetr Machata &changed, extack); 12122594e906SNikolay Aleksandrov if (ret) 12132594e906SNikolay Aleksandrov goto err_vlan_add; 1214f545923bSNikolay Aleksandrov br_vlan_notify(p->br, p, p->br->default_pvid, 0, RTM_NEWVLAN); 12152594e906SNikolay Aleksandrov } 12162594e906SNikolay Aleksandrov out: 12172594e906SNikolay Aleksandrov return ret; 12182594e906SNikolay Aleksandrov 12192594e906SNikolay Aleksandrov err_vlan_add: 122007bc588fSIdo Schimmel RCU_INIT_POINTER(p->vlgrp, NULL); 122107bc588fSIdo Schimmel synchronize_rcu(); 1222efa5356bSRoopa Prabhu vlan_tunnel_deinit(vg); 1223efa5356bSRoopa Prabhu err_tunnel_init: 1224efa5356bSRoopa Prabhu rhashtable_destroy(&vg->vlan_hash); 12252594e906SNikolay Aleksandrov err_rhtbl: 1226df2c4334SYotam Gigi err_vlan_enabled: 1227263344e6SNikolay Aleksandrov kfree(vg); 12282594e906SNikolay Aleksandrov 12292594e906SNikolay Aleksandrov goto out; 12308580e211SToshiaki Makita } 12318580e211SToshiaki Makita 12328adff41cSToshiaki Makita /* Must be protected by RTNL. 12338adff41cSToshiaki Makita * Must be called with vid in range from 1 to 4094 inclusive. 1234f418af63SNikolay Aleksandrov * changed must be true only if the vlan was created or updated 12358adff41cSToshiaki Makita */ 1236f418af63SNikolay Aleksandrov int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags, 1237169327d5SPetr Machata bool *changed, struct netlink_ext_ack *extack) 1238243a2e63SVlad Yasevich { 12392594e906SNikolay Aleksandrov struct net_bridge_vlan *vlan; 12402594e906SNikolay Aleksandrov int ret; 1241243a2e63SVlad Yasevich 1242243a2e63SVlad Yasevich ASSERT_RTNL(); 1243243a2e63SVlad Yasevich 1244f418af63SNikolay Aleksandrov *changed = false; 1245907b1e6eSNikolay Aleksandrov vlan = br_vlan_find(nbp_vlan_group(port), vid); 12462594e906SNikolay Aleksandrov if (vlan) { 12477fbac984SIdo Schimmel /* Pass the flags to the hardware bridge */ 1248169327d5SPetr Machata ret = br_switchdev_port_vlan_add(port->dev, vid, flags, extack); 12497fbac984SIdo Schimmel if (ret && ret != -EOPNOTSUPP) 12507fbac984SIdo Schimmel return ret; 1251f418af63SNikolay Aleksandrov *changed = __vlan_add_flags(vlan, flags); 1252f418af63SNikolay Aleksandrov 12532594e906SNikolay Aleksandrov return 0; 1254243a2e63SVlad Yasevich } 1255243a2e63SVlad Yasevich 12562594e906SNikolay Aleksandrov vlan = kzalloc(sizeof(*vlan), GFP_KERNEL); 12572594e906SNikolay Aleksandrov if (!vlan) 12582594e906SNikolay Aleksandrov return -ENOMEM; 1259243a2e63SVlad Yasevich 12602594e906SNikolay Aleksandrov vlan->vid = vid; 12612594e906SNikolay Aleksandrov vlan->port = port; 1262169327d5SPetr Machata ret = __vlan_add(vlan, flags, extack); 12632594e906SNikolay Aleksandrov if (ret) 12642594e906SNikolay Aleksandrov kfree(vlan); 1265f418af63SNikolay Aleksandrov else 1266f418af63SNikolay Aleksandrov *changed = true; 1267243a2e63SVlad Yasevich 12682594e906SNikolay Aleksandrov return ret; 1269243a2e63SVlad Yasevich } 1270243a2e63SVlad Yasevich 12718adff41cSToshiaki Makita /* Must be protected by RTNL. 12728adff41cSToshiaki Makita * Must be called with vid in range from 1 to 4094 inclusive. 12738adff41cSToshiaki Makita */ 1274243a2e63SVlad Yasevich int nbp_vlan_delete(struct net_bridge_port *port, u16 vid) 1275243a2e63SVlad Yasevich { 12762594e906SNikolay Aleksandrov struct net_bridge_vlan *v; 1277243a2e63SVlad Yasevich 1278243a2e63SVlad Yasevich ASSERT_RTNL(); 1279243a2e63SVlad Yasevich 1280907b1e6eSNikolay Aleksandrov v = br_vlan_find(nbp_vlan_group(port), vid); 12812594e906SNikolay Aleksandrov if (!v) 12822594e906SNikolay Aleksandrov return -ENOENT; 1283424bb9c9SToshiaki Makita br_fdb_find_delete_local(port->br, port, port->dev->dev_addr, vid); 12841ea2d020SNikolay Aleksandrov br_fdb_delete_by_port(port->br, port, vid, 0); 1285bc9a25d2SVlad Yasevich 12862594e906SNikolay Aleksandrov return __vlan_del(v); 1287243a2e63SVlad Yasevich } 1288243a2e63SVlad Yasevich 1289243a2e63SVlad Yasevich void nbp_vlan_flush(struct net_bridge_port *port) 1290243a2e63SVlad Yasevich { 1291f409d0edSNikolay Aleksandrov struct net_bridge_vlan_group *vg; 1292f409d0edSNikolay Aleksandrov 1293243a2e63SVlad Yasevich ASSERT_RTNL(); 1294243a2e63SVlad Yasevich 1295f409d0edSNikolay Aleksandrov vg = nbp_vlan_group(port); 1296f545923bSNikolay Aleksandrov __vlan_flush(port->br, port, vg); 1297f409d0edSNikolay Aleksandrov RCU_INIT_POINTER(port->vlgrp, NULL); 1298f409d0edSNikolay Aleksandrov synchronize_rcu(); 1299f409d0edSNikolay Aleksandrov __vlan_group_free(vg); 13005be5a2dfSVlad Yasevich } 1301a60c0903SNikolay Aleksandrov 1302a60c0903SNikolay Aleksandrov void br_vlan_get_stats(const struct net_bridge_vlan *v, 1303281cc284SHeiner Kallweit struct pcpu_sw_netstats *stats) 1304a60c0903SNikolay Aleksandrov { 1305a60c0903SNikolay Aleksandrov int i; 1306a60c0903SNikolay Aleksandrov 1307a60c0903SNikolay Aleksandrov memset(stats, 0, sizeof(*stats)); 1308a60c0903SNikolay Aleksandrov for_each_possible_cpu(i) { 1309a60c0903SNikolay Aleksandrov u64 rxpackets, rxbytes, txpackets, txbytes; 1310281cc284SHeiner Kallweit struct pcpu_sw_netstats *cpu_stats; 1311a60c0903SNikolay Aleksandrov unsigned int start; 1312a60c0903SNikolay Aleksandrov 1313a60c0903SNikolay Aleksandrov cpu_stats = per_cpu_ptr(v->stats, i); 1314a60c0903SNikolay Aleksandrov do { 1315a60c0903SNikolay Aleksandrov start = u64_stats_fetch_begin_irq(&cpu_stats->syncp); 1316a60c0903SNikolay Aleksandrov rxpackets = cpu_stats->rx_packets; 1317a60c0903SNikolay Aleksandrov rxbytes = cpu_stats->rx_bytes; 1318a60c0903SNikolay Aleksandrov txbytes = cpu_stats->tx_bytes; 1319a60c0903SNikolay Aleksandrov txpackets = cpu_stats->tx_packets; 1320a60c0903SNikolay Aleksandrov } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start)); 1321a60c0903SNikolay Aleksandrov 1322a60c0903SNikolay Aleksandrov stats->rx_packets += rxpackets; 1323a60c0903SNikolay Aleksandrov stats->rx_bytes += rxbytes; 1324a60c0903SNikolay Aleksandrov stats->tx_bytes += txbytes; 1325a60c0903SNikolay Aleksandrov stats->tx_packets += txpackets; 1326a60c0903SNikolay Aleksandrov } 1327a60c0903SNikolay Aleksandrov } 13284d4fd361SPetr Machata 132999f62a74SVladimir Oltean int br_vlan_get_pvid(const struct net_device *dev, u16 *p_pvid) 13304d4fd361SPetr Machata { 13314d4fd361SPetr Machata struct net_bridge_vlan_group *vg; 133299f62a74SVladimir Oltean struct net_bridge_port *p; 13334d4fd361SPetr Machata 133499f62a74SVladimir Oltean ASSERT_RTNL(); 133599f62a74SVladimir Oltean p = br_port_get_check_rtnl(dev); 13365a6db04cSIdo Schimmel if (p) 13375a6db04cSIdo Schimmel vg = nbp_vlan_group(p); 13385a6db04cSIdo Schimmel else if (netif_is_bridge_master(dev)) 13394d4fd361SPetr Machata vg = br_vlan_group(netdev_priv(dev)); 13404d4fd361SPetr Machata else 13414d4fd361SPetr Machata return -EINVAL; 13424d4fd361SPetr Machata 13434d4fd361SPetr Machata *p_pvid = br_get_pvid(vg); 13444d4fd361SPetr Machata return 0; 13454d4fd361SPetr Machata } 13464d4fd361SPetr Machata EXPORT_SYMBOL_GPL(br_vlan_get_pvid); 13474d4fd361SPetr Machata 13487582f5b7SPablo Neira Ayuso int br_vlan_get_pvid_rcu(const struct net_device *dev, u16 *p_pvid) 13497582f5b7SPablo Neira Ayuso { 135099f62a74SVladimir Oltean struct net_bridge_vlan_group *vg; 135199f62a74SVladimir Oltean struct net_bridge_port *p; 135299f62a74SVladimir Oltean 135399f62a74SVladimir Oltean p = br_port_get_check_rcu(dev); 135499f62a74SVladimir Oltean if (p) 135599f62a74SVladimir Oltean vg = nbp_vlan_group_rcu(p); 135699f62a74SVladimir Oltean else if (netif_is_bridge_master(dev)) 135799f62a74SVladimir Oltean vg = br_vlan_group_rcu(netdev_priv(dev)); 135899f62a74SVladimir Oltean else 135999f62a74SVladimir Oltean return -EINVAL; 136099f62a74SVladimir Oltean 136199f62a74SVladimir Oltean *p_pvid = br_get_pvid(vg); 136299f62a74SVladimir Oltean return 0; 13637582f5b7SPablo Neira Ayuso } 13647582f5b7SPablo Neira Ayuso EXPORT_SYMBOL_GPL(br_vlan_get_pvid_rcu); 13657582f5b7SPablo Neira Ayuso 1366bcf2766bSFelix Fietkau void br_vlan_fill_forward_path_pvid(struct net_bridge *br, 1367bcf2766bSFelix Fietkau struct net_device_path_ctx *ctx, 1368bcf2766bSFelix Fietkau struct net_device_path *path) 1369bcf2766bSFelix Fietkau { 1370bcf2766bSFelix Fietkau struct net_bridge_vlan_group *vg; 1371bcf2766bSFelix Fietkau int idx = ctx->num_vlans - 1; 1372bcf2766bSFelix Fietkau u16 vid; 1373bcf2766bSFelix Fietkau 1374bcf2766bSFelix Fietkau path->bridge.vlan_mode = DEV_PATH_BR_VLAN_KEEP; 1375bcf2766bSFelix Fietkau 1376bcf2766bSFelix Fietkau if (!br_opt_get(br, BROPT_VLAN_ENABLED)) 1377bcf2766bSFelix Fietkau return; 1378bcf2766bSFelix Fietkau 1379bcf2766bSFelix Fietkau vg = br_vlan_group(br); 1380bcf2766bSFelix Fietkau 1381bcf2766bSFelix Fietkau if (idx >= 0 && 1382bcf2766bSFelix Fietkau ctx->vlan[idx].proto == br->vlan_proto) { 1383bcf2766bSFelix Fietkau vid = ctx->vlan[idx].id; 1384bcf2766bSFelix Fietkau } else { 1385bcf2766bSFelix Fietkau path->bridge.vlan_mode = DEV_PATH_BR_VLAN_TAG; 1386bcf2766bSFelix Fietkau vid = br_get_pvid(vg); 1387bcf2766bSFelix Fietkau } 1388bcf2766bSFelix Fietkau 1389bcf2766bSFelix Fietkau path->bridge.vlan_id = vid; 1390bcf2766bSFelix Fietkau path->bridge.vlan_proto = br->vlan_proto; 1391bcf2766bSFelix Fietkau } 1392bcf2766bSFelix Fietkau 1393bcf2766bSFelix Fietkau int br_vlan_fill_forward_path_mode(struct net_bridge *br, 1394bcf2766bSFelix Fietkau struct net_bridge_port *dst, 1395bcf2766bSFelix Fietkau struct net_device_path *path) 1396bcf2766bSFelix Fietkau { 1397bcf2766bSFelix Fietkau struct net_bridge_vlan_group *vg; 1398bcf2766bSFelix Fietkau struct net_bridge_vlan *v; 1399bcf2766bSFelix Fietkau 1400bcf2766bSFelix Fietkau if (!br_opt_get(br, BROPT_VLAN_ENABLED)) 1401bcf2766bSFelix Fietkau return 0; 1402bcf2766bSFelix Fietkau 1403bcf2766bSFelix Fietkau vg = nbp_vlan_group_rcu(dst); 1404bcf2766bSFelix Fietkau v = br_vlan_find(vg, path->bridge.vlan_id); 1405bcf2766bSFelix Fietkau if (!v || !br_vlan_should_use(v)) 1406bcf2766bSFelix Fietkau return -EINVAL; 1407bcf2766bSFelix Fietkau 1408bcf2766bSFelix Fietkau if (!(v->flags & BRIDGE_VLAN_INFO_UNTAGGED)) 1409bcf2766bSFelix Fietkau return 0; 1410bcf2766bSFelix Fietkau 1411bcf2766bSFelix Fietkau if (path->bridge.vlan_mode == DEV_PATH_BR_VLAN_TAG) 1412bcf2766bSFelix Fietkau path->bridge.vlan_mode = DEV_PATH_BR_VLAN_KEEP; 141326267bf9SFelix Fietkau else if (v->priv_flags & BR_VLFLAG_ADDED_BY_SWITCHDEV) 141426267bf9SFelix Fietkau path->bridge.vlan_mode = DEV_PATH_BR_VLAN_UNTAG_HW; 1415bcf2766bSFelix Fietkau else 1416bcf2766bSFelix Fietkau path->bridge.vlan_mode = DEV_PATH_BR_VLAN_UNTAG; 1417bcf2766bSFelix Fietkau 1418bcf2766bSFelix Fietkau return 0; 1419bcf2766bSFelix Fietkau } 1420bcf2766bSFelix Fietkau 14214d4fd361SPetr Machata int br_vlan_get_info(const struct net_device *dev, u16 vid, 14224d4fd361SPetr Machata struct bridge_vlan_info *p_vinfo) 14234d4fd361SPetr Machata { 14244d4fd361SPetr Machata struct net_bridge_vlan_group *vg; 14254d4fd361SPetr Machata struct net_bridge_vlan *v; 14264d4fd361SPetr Machata struct net_bridge_port *p; 14274d4fd361SPetr Machata 14284d4fd361SPetr Machata ASSERT_RTNL(); 14294d4fd361SPetr Machata p = br_port_get_check_rtnl(dev); 14304d4fd361SPetr Machata if (p) 14314d4fd361SPetr Machata vg = nbp_vlan_group(p); 14322b18d79eSPetr Machata else if (netif_is_bridge_master(dev)) 14332b18d79eSPetr Machata vg = br_vlan_group(netdev_priv(dev)); 14344d4fd361SPetr Machata else 14354d4fd361SPetr Machata return -EINVAL; 14364d4fd361SPetr Machata 14374d4fd361SPetr Machata v = br_vlan_find(vg, vid); 14384d4fd361SPetr Machata if (!v) 14394d4fd361SPetr Machata return -ENOENT; 14404d4fd361SPetr Machata 14414d4fd361SPetr Machata p_vinfo->vid = vid; 14424d4fd361SPetr Machata p_vinfo->flags = v->flags; 1443f40d9b20SVladimir Oltean if (vid == br_get_pvid(vg)) 1444f40d9b20SVladimir Oltean p_vinfo->flags |= BRIDGE_VLAN_INFO_PVID; 14454d4fd361SPetr Machata return 0; 14464d4fd361SPetr Machata } 14474d4fd361SPetr Machata EXPORT_SYMBOL_GPL(br_vlan_get_info); 14489c0ec2e7SMike Manning 14499c0ec2e7SMike Manning static int br_vlan_is_bind_vlan_dev(const struct net_device *dev) 14509c0ec2e7SMike Manning { 14519c0ec2e7SMike Manning return is_vlan_dev(dev) && 14529c0ec2e7SMike Manning !!(vlan_dev_priv(dev)->flags & VLAN_FLAG_BRIDGE_BINDING); 14539c0ec2e7SMike Manning } 14549c0ec2e7SMike Manning 14559c0ec2e7SMike Manning static int br_vlan_is_bind_vlan_dev_fn(struct net_device *dev, 1456eff74233STaehee Yoo __always_unused struct netdev_nested_priv *priv) 14579c0ec2e7SMike Manning { 14589c0ec2e7SMike Manning return br_vlan_is_bind_vlan_dev(dev); 14599c0ec2e7SMike Manning } 14609c0ec2e7SMike Manning 14619c0ec2e7SMike Manning static bool br_vlan_has_upper_bind_vlan_dev(struct net_device *dev) 14629c0ec2e7SMike Manning { 14639c0ec2e7SMike Manning int found; 14649c0ec2e7SMike Manning 14659c0ec2e7SMike Manning rcu_read_lock(); 14669c0ec2e7SMike Manning found = netdev_walk_all_upper_dev_rcu(dev, br_vlan_is_bind_vlan_dev_fn, 14679c0ec2e7SMike Manning NULL); 14689c0ec2e7SMike Manning rcu_read_unlock(); 14699c0ec2e7SMike Manning 14709c0ec2e7SMike Manning return !!found; 14719c0ec2e7SMike Manning } 14729c0ec2e7SMike Manning 14739c0ec2e7SMike Manning struct br_vlan_bind_walk_data { 14749c0ec2e7SMike Manning u16 vid; 14759c0ec2e7SMike Manning struct net_device *result; 14769c0ec2e7SMike Manning }; 14779c0ec2e7SMike Manning 14789c0ec2e7SMike Manning static int br_vlan_match_bind_vlan_dev_fn(struct net_device *dev, 1479eff74233STaehee Yoo struct netdev_nested_priv *priv) 14809c0ec2e7SMike Manning { 1481eff74233STaehee Yoo struct br_vlan_bind_walk_data *data = priv->data; 14829c0ec2e7SMike Manning int found = 0; 14839c0ec2e7SMike Manning 14849c0ec2e7SMike Manning if (br_vlan_is_bind_vlan_dev(dev) && 14859c0ec2e7SMike Manning vlan_dev_priv(dev)->vlan_id == data->vid) { 14869c0ec2e7SMike Manning data->result = dev; 14879c0ec2e7SMike Manning found = 1; 14889c0ec2e7SMike Manning } 14899c0ec2e7SMike Manning 14909c0ec2e7SMike Manning return found; 14919c0ec2e7SMike Manning } 14929c0ec2e7SMike Manning 14939c0ec2e7SMike Manning static struct net_device * 14949c0ec2e7SMike Manning br_vlan_get_upper_bind_vlan_dev(struct net_device *dev, u16 vid) 14959c0ec2e7SMike Manning { 14969c0ec2e7SMike Manning struct br_vlan_bind_walk_data data = { 14979c0ec2e7SMike Manning .vid = vid, 14989c0ec2e7SMike Manning }; 1499eff74233STaehee Yoo struct netdev_nested_priv priv = { 1500eff74233STaehee Yoo .data = (void *)&data, 1501eff74233STaehee Yoo }; 15029c0ec2e7SMike Manning 15039c0ec2e7SMike Manning rcu_read_lock(); 15049c0ec2e7SMike Manning netdev_walk_all_upper_dev_rcu(dev, br_vlan_match_bind_vlan_dev_fn, 1505eff74233STaehee Yoo &priv); 15069c0ec2e7SMike Manning rcu_read_unlock(); 15079c0ec2e7SMike Manning 15089c0ec2e7SMike Manning return data.result; 15099c0ec2e7SMike Manning } 15109c0ec2e7SMike Manning 15119c0ec2e7SMike Manning static bool br_vlan_is_dev_up(const struct net_device *dev) 15129c0ec2e7SMike Manning { 15139c0ec2e7SMike Manning return !!(dev->flags & IFF_UP) && netif_oper_up(dev); 15149c0ec2e7SMike Manning } 15159c0ec2e7SMike Manning 15169c0ec2e7SMike Manning static void br_vlan_set_vlan_dev_state(const struct net_bridge *br, 15179c0ec2e7SMike Manning struct net_device *vlan_dev) 15189c0ec2e7SMike Manning { 15199c0ec2e7SMike Manning u16 vid = vlan_dev_priv(vlan_dev)->vlan_id; 15209c0ec2e7SMike Manning struct net_bridge_vlan_group *vg; 15219c0ec2e7SMike Manning struct net_bridge_port *p; 15229c0ec2e7SMike Manning bool has_carrier = false; 15239c0ec2e7SMike Manning 15248e1acd4fSMike Manning if (!netif_carrier_ok(br->dev)) { 15258e1acd4fSMike Manning netif_carrier_off(vlan_dev); 15268e1acd4fSMike Manning return; 15278e1acd4fSMike Manning } 15288e1acd4fSMike Manning 15299c0ec2e7SMike Manning list_for_each_entry(p, &br->port_list, list) { 15309c0ec2e7SMike Manning vg = nbp_vlan_group(p); 15319c0ec2e7SMike Manning if (br_vlan_find(vg, vid) && br_vlan_is_dev_up(p->dev)) { 15329c0ec2e7SMike Manning has_carrier = true; 15339c0ec2e7SMike Manning break; 15349c0ec2e7SMike Manning } 15359c0ec2e7SMike Manning } 15369c0ec2e7SMike Manning 15379c0ec2e7SMike Manning if (has_carrier) 15389c0ec2e7SMike Manning netif_carrier_on(vlan_dev); 15399c0ec2e7SMike Manning else 15409c0ec2e7SMike Manning netif_carrier_off(vlan_dev); 15419c0ec2e7SMike Manning } 15429c0ec2e7SMike Manning 15439c0ec2e7SMike Manning static void br_vlan_set_all_vlan_dev_state(struct net_bridge_port *p) 15449c0ec2e7SMike Manning { 15459c0ec2e7SMike Manning struct net_bridge_vlan_group *vg = nbp_vlan_group(p); 15469c0ec2e7SMike Manning struct net_bridge_vlan *vlan; 15479c0ec2e7SMike Manning struct net_device *vlan_dev; 15489c0ec2e7SMike Manning 15499c0ec2e7SMike Manning list_for_each_entry(vlan, &vg->vlan_list, vlist) { 15509c0ec2e7SMike Manning vlan_dev = br_vlan_get_upper_bind_vlan_dev(p->br->dev, 15519c0ec2e7SMike Manning vlan->vid); 15529c0ec2e7SMike Manning if (vlan_dev) { 15538e1acd4fSMike Manning if (br_vlan_is_dev_up(p->dev)) { 15548e1acd4fSMike Manning if (netif_carrier_ok(p->br->dev)) 15559c0ec2e7SMike Manning netif_carrier_on(vlan_dev); 15568e1acd4fSMike Manning } else { 15579c0ec2e7SMike Manning br_vlan_set_vlan_dev_state(p->br, vlan_dev); 15589c0ec2e7SMike Manning } 15599c0ec2e7SMike Manning } 15609c0ec2e7SMike Manning } 15618e1acd4fSMike Manning } 15629c0ec2e7SMike Manning 15639c0ec2e7SMike Manning static void br_vlan_upper_change(struct net_device *dev, 15649c0ec2e7SMike Manning struct net_device *upper_dev, 15659c0ec2e7SMike Manning bool linking) 15669c0ec2e7SMike Manning { 15679c0ec2e7SMike Manning struct net_bridge *br = netdev_priv(dev); 15689c0ec2e7SMike Manning 15699c0ec2e7SMike Manning if (!br_vlan_is_bind_vlan_dev(upper_dev)) 15709c0ec2e7SMike Manning return; 15719c0ec2e7SMike Manning 15729c0ec2e7SMike Manning if (linking) { 15739c0ec2e7SMike Manning br_vlan_set_vlan_dev_state(br, upper_dev); 15749c0ec2e7SMike Manning br_opt_toggle(br, BROPT_VLAN_BRIDGE_BINDING, true); 15759c0ec2e7SMike Manning } else { 15769c0ec2e7SMike Manning br_opt_toggle(br, BROPT_VLAN_BRIDGE_BINDING, 15779c0ec2e7SMike Manning br_vlan_has_upper_bind_vlan_dev(dev)); 15789c0ec2e7SMike Manning } 15799c0ec2e7SMike Manning } 15809c0ec2e7SMike Manning 15818e1acd4fSMike Manning struct br_vlan_link_state_walk_data { 15828e1acd4fSMike Manning struct net_bridge *br; 15838e1acd4fSMike Manning }; 15848e1acd4fSMike Manning 15858e1acd4fSMike Manning static int br_vlan_link_state_change_fn(struct net_device *vlan_dev, 1586eff74233STaehee Yoo struct netdev_nested_priv *priv) 15878e1acd4fSMike Manning { 1588eff74233STaehee Yoo struct br_vlan_link_state_walk_data *data = priv->data; 15898e1acd4fSMike Manning 15908e1acd4fSMike Manning if (br_vlan_is_bind_vlan_dev(vlan_dev)) 15918e1acd4fSMike Manning br_vlan_set_vlan_dev_state(data->br, vlan_dev); 15928e1acd4fSMike Manning 15938e1acd4fSMike Manning return 0; 15948e1acd4fSMike Manning } 15958e1acd4fSMike Manning 15968e1acd4fSMike Manning static void br_vlan_link_state_change(struct net_device *dev, 15978e1acd4fSMike Manning struct net_bridge *br) 15988e1acd4fSMike Manning { 15998e1acd4fSMike Manning struct br_vlan_link_state_walk_data data = { 16008e1acd4fSMike Manning .br = br 16018e1acd4fSMike Manning }; 1602eff74233STaehee Yoo struct netdev_nested_priv priv = { 1603eff74233STaehee Yoo .data = (void *)&data, 1604eff74233STaehee Yoo }; 16058e1acd4fSMike Manning 16068e1acd4fSMike Manning rcu_read_lock(); 16078e1acd4fSMike Manning netdev_walk_all_upper_dev_rcu(dev, br_vlan_link_state_change_fn, 1608eff74233STaehee Yoo &priv); 16098e1acd4fSMike Manning rcu_read_unlock(); 16108e1acd4fSMike Manning } 16118e1acd4fSMike Manning 16129c0ec2e7SMike Manning /* Must be protected by RTNL. */ 161380900acdSMike Manning static void nbp_vlan_set_vlan_dev_state(struct net_bridge_port *p, u16 vid) 161480900acdSMike Manning { 161580900acdSMike Manning struct net_device *vlan_dev; 161680900acdSMike Manning 161780900acdSMike Manning if (!br_opt_get(p->br, BROPT_VLAN_BRIDGE_BINDING)) 161880900acdSMike Manning return; 161980900acdSMike Manning 162080900acdSMike Manning vlan_dev = br_vlan_get_upper_bind_vlan_dev(p->br->dev, vid); 162180900acdSMike Manning if (vlan_dev) 162280900acdSMike Manning br_vlan_set_vlan_dev_state(p->br, vlan_dev); 162380900acdSMike Manning } 162480900acdSMike Manning 162580900acdSMike Manning /* Must be protected by RTNL. */ 1626091adf9bSNikolay Aleksandrov int br_vlan_bridge_event(struct net_device *dev, unsigned long event, void *ptr) 16279c0ec2e7SMike Manning { 16289c0ec2e7SMike Manning struct netdev_notifier_changeupper_info *info; 1629091adf9bSNikolay Aleksandrov struct net_bridge *br = netdev_priv(dev); 1630f545923bSNikolay Aleksandrov int vlcmd = 0, ret = 0; 1631f545923bSNikolay Aleksandrov bool changed = false; 16329c0ec2e7SMike Manning 16339c0ec2e7SMike Manning switch (event) { 1634091adf9bSNikolay Aleksandrov case NETDEV_REGISTER: 1635091adf9bSNikolay Aleksandrov ret = br_vlan_add(br, br->default_pvid, 1636091adf9bSNikolay Aleksandrov BRIDGE_VLAN_INFO_PVID | 1637091adf9bSNikolay Aleksandrov BRIDGE_VLAN_INFO_UNTAGGED | 1638091adf9bSNikolay Aleksandrov BRIDGE_VLAN_INFO_BRENTRY, &changed, NULL); 1639f545923bSNikolay Aleksandrov vlcmd = RTM_NEWVLAN; 1640091adf9bSNikolay Aleksandrov break; 1641091adf9bSNikolay Aleksandrov case NETDEV_UNREGISTER: 1642f545923bSNikolay Aleksandrov changed = !br_vlan_delete(br, br->default_pvid); 1643f545923bSNikolay Aleksandrov vlcmd = RTM_DELVLAN; 1644091adf9bSNikolay Aleksandrov break; 16459c0ec2e7SMike Manning case NETDEV_CHANGEUPPER: 16469c0ec2e7SMike Manning info = ptr; 16479c0ec2e7SMike Manning br_vlan_upper_change(dev, info->upper_dev, info->linking); 16489c0ec2e7SMike Manning break; 16498e1acd4fSMike Manning 16508e1acd4fSMike Manning case NETDEV_CHANGE: 16518e1acd4fSMike Manning case NETDEV_UP: 16528e1acd4fSMike Manning if (!br_opt_get(br, BROPT_VLAN_BRIDGE_BINDING)) 1653091adf9bSNikolay Aleksandrov break; 16548e1acd4fSMike Manning br_vlan_link_state_change(dev, br); 16558e1acd4fSMike Manning break; 16569c0ec2e7SMike Manning } 1657f545923bSNikolay Aleksandrov if (changed) 1658f545923bSNikolay Aleksandrov br_vlan_notify(br, NULL, br->default_pvid, 0, vlcmd); 1659091adf9bSNikolay Aleksandrov 1660091adf9bSNikolay Aleksandrov return ret; 16619c0ec2e7SMike Manning } 16629c0ec2e7SMike Manning 16639c0ec2e7SMike Manning /* Must be protected by RTNL. */ 16649c0ec2e7SMike Manning void br_vlan_port_event(struct net_bridge_port *p, unsigned long event) 16659c0ec2e7SMike Manning { 16669c0ec2e7SMike Manning if (!br_opt_get(p->br, BROPT_VLAN_BRIDGE_BINDING)) 16679c0ec2e7SMike Manning return; 16689c0ec2e7SMike Manning 16699c0ec2e7SMike Manning switch (event) { 16709c0ec2e7SMike Manning case NETDEV_CHANGE: 16719c0ec2e7SMike Manning case NETDEV_DOWN: 16729c0ec2e7SMike Manning case NETDEV_UP: 16739c0ec2e7SMike Manning br_vlan_set_all_vlan_dev_state(p); 16749c0ec2e7SMike Manning break; 16759c0ec2e7SMike Manning } 16769c0ec2e7SMike Manning } 16778dcea187SNikolay Aleksandrov 167856d09976SNikolay Aleksandrov static bool br_vlan_stats_fill(struct sk_buff *skb, 167956d09976SNikolay Aleksandrov const struct net_bridge_vlan *v) 168056d09976SNikolay Aleksandrov { 1681281cc284SHeiner Kallweit struct pcpu_sw_netstats stats; 168256d09976SNikolay Aleksandrov struct nlattr *nest; 168356d09976SNikolay Aleksandrov 168456d09976SNikolay Aleksandrov nest = nla_nest_start(skb, BRIDGE_VLANDB_ENTRY_STATS); 168556d09976SNikolay Aleksandrov if (!nest) 168656d09976SNikolay Aleksandrov return false; 168756d09976SNikolay Aleksandrov 168856d09976SNikolay Aleksandrov br_vlan_get_stats(v, &stats); 168956d09976SNikolay Aleksandrov if (nla_put_u64_64bit(skb, BRIDGE_VLANDB_STATS_RX_BYTES, stats.rx_bytes, 169056d09976SNikolay Aleksandrov BRIDGE_VLANDB_STATS_PAD) || 169156d09976SNikolay Aleksandrov nla_put_u64_64bit(skb, BRIDGE_VLANDB_STATS_RX_PACKETS, 169256d09976SNikolay Aleksandrov stats.rx_packets, BRIDGE_VLANDB_STATS_PAD) || 169356d09976SNikolay Aleksandrov nla_put_u64_64bit(skb, BRIDGE_VLANDB_STATS_TX_BYTES, stats.tx_bytes, 169456d09976SNikolay Aleksandrov BRIDGE_VLANDB_STATS_PAD) || 169556d09976SNikolay Aleksandrov nla_put_u64_64bit(skb, BRIDGE_VLANDB_STATS_TX_PACKETS, 169656d09976SNikolay Aleksandrov stats.tx_packets, BRIDGE_VLANDB_STATS_PAD)) 169756d09976SNikolay Aleksandrov goto out_err; 169856d09976SNikolay Aleksandrov 169956d09976SNikolay Aleksandrov nla_nest_end(skb, nest); 170056d09976SNikolay Aleksandrov 170156d09976SNikolay Aleksandrov return true; 170256d09976SNikolay Aleksandrov 170356d09976SNikolay Aleksandrov out_err: 170456d09976SNikolay Aleksandrov nla_nest_cancel(skb, nest); 170556d09976SNikolay Aleksandrov return false; 170656d09976SNikolay Aleksandrov } 170756d09976SNikolay Aleksandrov 17087a53e718SNikolay Aleksandrov /* v_opts is used to dump the options which must be equal in the whole range */ 17090ab55879SNikolay Aleksandrov static bool br_vlan_fill_vids(struct sk_buff *skb, u16 vid, u16 vid_range, 17107a53e718SNikolay Aleksandrov const struct net_bridge_vlan *v_opts, 171156d09976SNikolay Aleksandrov u16 flags, 171256d09976SNikolay Aleksandrov bool dump_stats) 17138dcea187SNikolay Aleksandrov { 17148dcea187SNikolay Aleksandrov struct bridge_vlan_info info; 17158dcea187SNikolay Aleksandrov struct nlattr *nest; 17168dcea187SNikolay Aleksandrov 17178dcea187SNikolay Aleksandrov nest = nla_nest_start(skb, BRIDGE_VLANDB_ENTRY); 17188dcea187SNikolay Aleksandrov if (!nest) 17198dcea187SNikolay Aleksandrov return false; 17208dcea187SNikolay Aleksandrov 17218dcea187SNikolay Aleksandrov memset(&info, 0, sizeof(info)); 17228dcea187SNikolay Aleksandrov info.vid = vid; 17238dcea187SNikolay Aleksandrov if (flags & BRIDGE_VLAN_INFO_UNTAGGED) 17248dcea187SNikolay Aleksandrov info.flags |= BRIDGE_VLAN_INFO_UNTAGGED; 17258dcea187SNikolay Aleksandrov if (flags & BRIDGE_VLAN_INFO_PVID) 17268dcea187SNikolay Aleksandrov info.flags |= BRIDGE_VLAN_INFO_PVID; 17278dcea187SNikolay Aleksandrov 17288dcea187SNikolay Aleksandrov if (nla_put(skb, BRIDGE_VLANDB_ENTRY_INFO, sizeof(info), &info)) 17298dcea187SNikolay Aleksandrov goto out_err; 17308dcea187SNikolay Aleksandrov 17310ab55879SNikolay Aleksandrov if (vid_range && vid < vid_range && 17320ab55879SNikolay Aleksandrov !(flags & BRIDGE_VLAN_INFO_PVID) && 17330ab55879SNikolay Aleksandrov nla_put_u16(skb, BRIDGE_VLANDB_ENTRY_RANGE, vid_range)) 17340ab55879SNikolay Aleksandrov goto out_err; 17350ab55879SNikolay Aleksandrov 173656d09976SNikolay Aleksandrov if (v_opts) { 173756d09976SNikolay Aleksandrov if (!br_vlan_opts_fill(skb, v_opts)) 17387a53e718SNikolay Aleksandrov goto out_err; 17397a53e718SNikolay Aleksandrov 174056d09976SNikolay Aleksandrov if (dump_stats && !br_vlan_stats_fill(skb, v_opts)) 174156d09976SNikolay Aleksandrov goto out_err; 174256d09976SNikolay Aleksandrov } 174356d09976SNikolay Aleksandrov 17448dcea187SNikolay Aleksandrov nla_nest_end(skb, nest); 17458dcea187SNikolay Aleksandrov 17468dcea187SNikolay Aleksandrov return true; 17478dcea187SNikolay Aleksandrov 17488dcea187SNikolay Aleksandrov out_err: 17498dcea187SNikolay Aleksandrov nla_nest_cancel(skb, nest); 17508dcea187SNikolay Aleksandrov return false; 17518dcea187SNikolay Aleksandrov } 17528dcea187SNikolay Aleksandrov 1753cf5bddb9SNikolay Aleksandrov static size_t rtnl_vlan_nlmsg_size(void) 1754cf5bddb9SNikolay Aleksandrov { 1755cf5bddb9SNikolay Aleksandrov return NLMSG_ALIGN(sizeof(struct br_vlan_msg)) 1756cf5bddb9SNikolay Aleksandrov + nla_total_size(0) /* BRIDGE_VLANDB_ENTRY */ 1757cf5bddb9SNikolay Aleksandrov + nla_total_size(sizeof(u16)) /* BRIDGE_VLANDB_ENTRY_RANGE */ 17587a53e718SNikolay Aleksandrov + nla_total_size(sizeof(struct bridge_vlan_info)) /* BRIDGE_VLANDB_ENTRY_INFO */ 17597a53e718SNikolay Aleksandrov + br_vlan_opts_nl_size(); /* bridge vlan options */ 1760cf5bddb9SNikolay Aleksandrov } 1761cf5bddb9SNikolay Aleksandrov 1762cf5bddb9SNikolay Aleksandrov void br_vlan_notify(const struct net_bridge *br, 1763cf5bddb9SNikolay Aleksandrov const struct net_bridge_port *p, 1764cf5bddb9SNikolay Aleksandrov u16 vid, u16 vid_range, 1765cf5bddb9SNikolay Aleksandrov int cmd) 1766cf5bddb9SNikolay Aleksandrov { 1767cf5bddb9SNikolay Aleksandrov struct net_bridge_vlan_group *vg; 17687a53e718SNikolay Aleksandrov struct net_bridge_vlan *v = NULL; 1769cf5bddb9SNikolay Aleksandrov struct br_vlan_msg *bvm; 1770cf5bddb9SNikolay Aleksandrov struct nlmsghdr *nlh; 1771cf5bddb9SNikolay Aleksandrov struct sk_buff *skb; 1772cf5bddb9SNikolay Aleksandrov int err = -ENOBUFS; 1773cf5bddb9SNikolay Aleksandrov struct net *net; 1774cf5bddb9SNikolay Aleksandrov u16 flags = 0; 1775cf5bddb9SNikolay Aleksandrov int ifindex; 1776cf5bddb9SNikolay Aleksandrov 1777cf5bddb9SNikolay Aleksandrov /* right now notifications are done only with rtnl held */ 1778cf5bddb9SNikolay Aleksandrov ASSERT_RTNL(); 1779cf5bddb9SNikolay Aleksandrov 1780cf5bddb9SNikolay Aleksandrov if (p) { 1781cf5bddb9SNikolay Aleksandrov ifindex = p->dev->ifindex; 1782cf5bddb9SNikolay Aleksandrov vg = nbp_vlan_group(p); 1783cf5bddb9SNikolay Aleksandrov net = dev_net(p->dev); 1784cf5bddb9SNikolay Aleksandrov } else { 1785cf5bddb9SNikolay Aleksandrov ifindex = br->dev->ifindex; 1786cf5bddb9SNikolay Aleksandrov vg = br_vlan_group(br); 1787cf5bddb9SNikolay Aleksandrov net = dev_net(br->dev); 1788cf5bddb9SNikolay Aleksandrov } 1789cf5bddb9SNikolay Aleksandrov 1790cf5bddb9SNikolay Aleksandrov skb = nlmsg_new(rtnl_vlan_nlmsg_size(), GFP_KERNEL); 1791cf5bddb9SNikolay Aleksandrov if (!skb) 1792cf5bddb9SNikolay Aleksandrov goto out_err; 1793cf5bddb9SNikolay Aleksandrov 1794cf5bddb9SNikolay Aleksandrov err = -EMSGSIZE; 1795cf5bddb9SNikolay Aleksandrov nlh = nlmsg_put(skb, 0, 0, cmd, sizeof(*bvm), 0); 1796cf5bddb9SNikolay Aleksandrov if (!nlh) 1797cf5bddb9SNikolay Aleksandrov goto out_err; 1798cf5bddb9SNikolay Aleksandrov bvm = nlmsg_data(nlh); 1799cf5bddb9SNikolay Aleksandrov memset(bvm, 0, sizeof(*bvm)); 1800cf5bddb9SNikolay Aleksandrov bvm->family = AF_BRIDGE; 1801cf5bddb9SNikolay Aleksandrov bvm->ifindex = ifindex; 1802cf5bddb9SNikolay Aleksandrov 1803cf5bddb9SNikolay Aleksandrov switch (cmd) { 1804cf5bddb9SNikolay Aleksandrov case RTM_NEWVLAN: 1805cf5bddb9SNikolay Aleksandrov /* need to find the vlan due to flags/options */ 1806cf5bddb9SNikolay Aleksandrov v = br_vlan_find(vg, vid); 1807cf5bddb9SNikolay Aleksandrov if (!v || !br_vlan_should_use(v)) 1808cf5bddb9SNikolay Aleksandrov goto out_kfree; 1809cf5bddb9SNikolay Aleksandrov 1810cf5bddb9SNikolay Aleksandrov flags = v->flags; 1811cf5bddb9SNikolay Aleksandrov if (br_get_pvid(vg) == v->vid) 1812cf5bddb9SNikolay Aleksandrov flags |= BRIDGE_VLAN_INFO_PVID; 1813cf5bddb9SNikolay Aleksandrov break; 1814cf5bddb9SNikolay Aleksandrov case RTM_DELVLAN: 1815cf5bddb9SNikolay Aleksandrov break; 1816cf5bddb9SNikolay Aleksandrov default: 1817cf5bddb9SNikolay Aleksandrov goto out_kfree; 1818cf5bddb9SNikolay Aleksandrov } 1819cf5bddb9SNikolay Aleksandrov 182056d09976SNikolay Aleksandrov if (!br_vlan_fill_vids(skb, vid, vid_range, v, flags, false)) 1821cf5bddb9SNikolay Aleksandrov goto out_err; 1822cf5bddb9SNikolay Aleksandrov 1823cf5bddb9SNikolay Aleksandrov nlmsg_end(skb, nlh); 1824cf5bddb9SNikolay Aleksandrov rtnl_notify(skb, net, 0, RTNLGRP_BRVLAN, NULL, GFP_KERNEL); 1825cf5bddb9SNikolay Aleksandrov return; 1826cf5bddb9SNikolay Aleksandrov 1827cf5bddb9SNikolay Aleksandrov out_err: 1828cf5bddb9SNikolay Aleksandrov rtnl_set_sk_err(net, RTNLGRP_BRVLAN, err); 1829cf5bddb9SNikolay Aleksandrov out_kfree: 1830cf5bddb9SNikolay Aleksandrov kfree_skb(skb); 1831cf5bddb9SNikolay Aleksandrov } 1832cf5bddb9SNikolay Aleksandrov 183322f67cdfSVladimir Oltean static int br_vlan_replay_one(struct notifier_block *nb, 183422f67cdfSVladimir Oltean struct net_device *dev, 183522f67cdfSVladimir Oltean struct switchdev_obj_port_vlan *vlan, 18367e8c1858SVladimir Oltean const void *ctx, unsigned long action, 18377e8c1858SVladimir Oltean struct netlink_ext_ack *extack) 183822f67cdfSVladimir Oltean { 183922f67cdfSVladimir Oltean struct switchdev_notifier_port_obj_info obj_info = { 184022f67cdfSVladimir Oltean .info = { 184122f67cdfSVladimir Oltean .dev = dev, 184222f67cdfSVladimir Oltean .extack = extack, 18430d2cfbd4SVladimir Oltean .ctx = ctx, 184422f67cdfSVladimir Oltean }, 184522f67cdfSVladimir Oltean .obj = &vlan->obj, 184622f67cdfSVladimir Oltean }; 184722f67cdfSVladimir Oltean int err; 184822f67cdfSVladimir Oltean 18497e8c1858SVladimir Oltean err = nb->notifier_call(nb, action, &obj_info); 185022f67cdfSVladimir Oltean return notifier_to_errno(err); 185122f67cdfSVladimir Oltean } 185222f67cdfSVladimir Oltean 185322f67cdfSVladimir Oltean int br_vlan_replay(struct net_device *br_dev, struct net_device *dev, 18547e8c1858SVladimir Oltean const void *ctx, bool adding, struct notifier_block *nb, 18550d2cfbd4SVladimir Oltean struct netlink_ext_ack *extack) 185622f67cdfSVladimir Oltean { 185722f67cdfSVladimir Oltean struct net_bridge_vlan_group *vg; 185822f67cdfSVladimir Oltean struct net_bridge_vlan *v; 185922f67cdfSVladimir Oltean struct net_bridge_port *p; 186022f67cdfSVladimir Oltean struct net_bridge *br; 18617e8c1858SVladimir Oltean unsigned long action; 186222f67cdfSVladimir Oltean int err = 0; 186322f67cdfSVladimir Oltean u16 pvid; 186422f67cdfSVladimir Oltean 186522f67cdfSVladimir Oltean ASSERT_RTNL(); 186622f67cdfSVladimir Oltean 18677105b50bSVladimir Oltean if (!nb) 18687105b50bSVladimir Oltean return 0; 18697105b50bSVladimir Oltean 187022f67cdfSVladimir Oltean if (!netif_is_bridge_master(br_dev)) 187122f67cdfSVladimir Oltean return -EINVAL; 187222f67cdfSVladimir Oltean 187322f67cdfSVladimir Oltean if (!netif_is_bridge_master(dev) && !netif_is_bridge_port(dev)) 187422f67cdfSVladimir Oltean return -EINVAL; 187522f67cdfSVladimir Oltean 187622f67cdfSVladimir Oltean if (netif_is_bridge_master(dev)) { 187722f67cdfSVladimir Oltean br = netdev_priv(dev); 187822f67cdfSVladimir Oltean vg = br_vlan_group(br); 187922f67cdfSVladimir Oltean p = NULL; 188022f67cdfSVladimir Oltean } else { 188122f67cdfSVladimir Oltean p = br_port_get_rtnl(dev); 188222f67cdfSVladimir Oltean if (WARN_ON(!p)) 188322f67cdfSVladimir Oltean return -EINVAL; 188422f67cdfSVladimir Oltean vg = nbp_vlan_group(p); 188522f67cdfSVladimir Oltean br = p->br; 188622f67cdfSVladimir Oltean } 188722f67cdfSVladimir Oltean 188822f67cdfSVladimir Oltean if (!vg) 188922f67cdfSVladimir Oltean return 0; 189022f67cdfSVladimir Oltean 18917e8c1858SVladimir Oltean if (adding) 18927e8c1858SVladimir Oltean action = SWITCHDEV_PORT_OBJ_ADD; 18937e8c1858SVladimir Oltean else 18947e8c1858SVladimir Oltean action = SWITCHDEV_PORT_OBJ_DEL; 18957e8c1858SVladimir Oltean 189622f67cdfSVladimir Oltean pvid = br_get_pvid(vg); 189722f67cdfSVladimir Oltean 189822f67cdfSVladimir Oltean list_for_each_entry(v, &vg->vlan_list, vlist) { 189922f67cdfSVladimir Oltean struct switchdev_obj_port_vlan vlan = { 190022f67cdfSVladimir Oltean .obj.orig_dev = dev, 190122f67cdfSVladimir Oltean .obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN, 190222f67cdfSVladimir Oltean .flags = br_vlan_flags(v, pvid), 190322f67cdfSVladimir Oltean .vid = v->vid, 190422f67cdfSVladimir Oltean }; 190522f67cdfSVladimir Oltean 190622f67cdfSVladimir Oltean if (!br_vlan_should_use(v)) 190722f67cdfSVladimir Oltean continue; 190822f67cdfSVladimir Oltean 19097e8c1858SVladimir Oltean err = br_vlan_replay_one(nb, dev, &vlan, ctx, action, extack); 191022f67cdfSVladimir Oltean if (err) 191122f67cdfSVladimir Oltean return err; 191222f67cdfSVladimir Oltean } 191322f67cdfSVladimir Oltean 191422f67cdfSVladimir Oltean return err; 191522f67cdfSVladimir Oltean } 191622f67cdfSVladimir Oltean 19170ab55879SNikolay Aleksandrov /* check if v_curr can enter a range ending in range_end */ 1918a5d29ae2SNikolay Aleksandrov bool br_vlan_can_enter_range(const struct net_bridge_vlan *v_curr, 19190ab55879SNikolay Aleksandrov const struct net_bridge_vlan *range_end) 19200ab55879SNikolay Aleksandrov { 19210ab55879SNikolay Aleksandrov return v_curr->vid - range_end->vid == 1 && 19227a53e718SNikolay Aleksandrov range_end->flags == v_curr->flags && 192399f7c5e0SNikolay Aleksandrov br_vlan_opts_eq_range(v_curr, range_end); 19240ab55879SNikolay Aleksandrov } 19250ab55879SNikolay Aleksandrov 19268dcea187SNikolay Aleksandrov static int br_vlan_dump_dev(const struct net_device *dev, 19278dcea187SNikolay Aleksandrov struct sk_buff *skb, 192856d09976SNikolay Aleksandrov struct netlink_callback *cb, 192956d09976SNikolay Aleksandrov u32 dump_flags) 19308dcea187SNikolay Aleksandrov { 19310ab55879SNikolay Aleksandrov struct net_bridge_vlan *v, *range_start = NULL, *range_end = NULL; 1932743a53d9SNikolay Aleksandrov bool dump_global = !!(dump_flags & BRIDGE_VLANDB_DUMPF_GLOBAL); 193356d09976SNikolay Aleksandrov bool dump_stats = !!(dump_flags & BRIDGE_VLANDB_DUMPF_STATS); 19348dcea187SNikolay Aleksandrov struct net_bridge_vlan_group *vg; 19358dcea187SNikolay Aleksandrov int idx = 0, s_idx = cb->args[1]; 19368dcea187SNikolay Aleksandrov struct nlmsghdr *nlh = NULL; 19378dcea187SNikolay Aleksandrov struct net_bridge_port *p; 19388dcea187SNikolay Aleksandrov struct br_vlan_msg *bvm; 19398dcea187SNikolay Aleksandrov struct net_bridge *br; 19408dcea187SNikolay Aleksandrov int err = 0; 19418dcea187SNikolay Aleksandrov u16 pvid; 19428dcea187SNikolay Aleksandrov 19438dcea187SNikolay Aleksandrov if (!netif_is_bridge_master(dev) && !netif_is_bridge_port(dev)) 19448dcea187SNikolay Aleksandrov return -EINVAL; 19458dcea187SNikolay Aleksandrov 19468dcea187SNikolay Aleksandrov if (netif_is_bridge_master(dev)) { 19478dcea187SNikolay Aleksandrov br = netdev_priv(dev); 19488dcea187SNikolay Aleksandrov vg = br_vlan_group_rcu(br); 19498dcea187SNikolay Aleksandrov p = NULL; 19508dcea187SNikolay Aleksandrov } else { 1951743a53d9SNikolay Aleksandrov /* global options are dumped only for bridge devices */ 1952743a53d9SNikolay Aleksandrov if (dump_global) 1953743a53d9SNikolay Aleksandrov return 0; 1954743a53d9SNikolay Aleksandrov 19558dcea187SNikolay Aleksandrov p = br_port_get_rcu(dev); 19568dcea187SNikolay Aleksandrov if (WARN_ON(!p)) 19578dcea187SNikolay Aleksandrov return -EINVAL; 19588dcea187SNikolay Aleksandrov vg = nbp_vlan_group_rcu(p); 19598dcea187SNikolay Aleksandrov br = p->br; 19608dcea187SNikolay Aleksandrov } 19618dcea187SNikolay Aleksandrov 19628dcea187SNikolay Aleksandrov if (!vg) 19638dcea187SNikolay Aleksandrov return 0; 19648dcea187SNikolay Aleksandrov 19658dcea187SNikolay Aleksandrov nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, 19668dcea187SNikolay Aleksandrov RTM_NEWVLAN, sizeof(*bvm), NLM_F_MULTI); 19678dcea187SNikolay Aleksandrov if (!nlh) 19688dcea187SNikolay Aleksandrov return -EMSGSIZE; 19698dcea187SNikolay Aleksandrov bvm = nlmsg_data(nlh); 19708dcea187SNikolay Aleksandrov memset(bvm, 0, sizeof(*bvm)); 19718dcea187SNikolay Aleksandrov bvm->family = PF_BRIDGE; 19728dcea187SNikolay Aleksandrov bvm->ifindex = dev->ifindex; 19738dcea187SNikolay Aleksandrov pvid = br_get_pvid(vg); 19748dcea187SNikolay Aleksandrov 19750ab55879SNikolay Aleksandrov /* idx must stay at range's beginning until it is filled in */ 19768dcea187SNikolay Aleksandrov list_for_each_entry_rcu(v, &vg->vlan_list, vlist) { 1977743a53d9SNikolay Aleksandrov if (!dump_global && !br_vlan_should_use(v)) 19788dcea187SNikolay Aleksandrov continue; 19790ab55879SNikolay Aleksandrov if (idx < s_idx) { 19800ab55879SNikolay Aleksandrov idx++; 19810ab55879SNikolay Aleksandrov continue; 19820ab55879SNikolay Aleksandrov } 19830ab55879SNikolay Aleksandrov 19840ab55879SNikolay Aleksandrov if (!range_start) { 19850ab55879SNikolay Aleksandrov range_start = v; 19860ab55879SNikolay Aleksandrov range_end = v; 19870ab55879SNikolay Aleksandrov continue; 19880ab55879SNikolay Aleksandrov } 19890ab55879SNikolay Aleksandrov 1990743a53d9SNikolay Aleksandrov if (dump_global) { 1991743a53d9SNikolay Aleksandrov if (br_vlan_global_opts_can_enter_range(v, range_end)) 1992743a53d9SNikolay Aleksandrov continue; 1993743a53d9SNikolay Aleksandrov if (!br_vlan_global_opts_fill(skb, range_start->vid, 1994743a53d9SNikolay Aleksandrov range_end->vid, 1995743a53d9SNikolay Aleksandrov range_start)) { 1996743a53d9SNikolay Aleksandrov err = -EMSGSIZE; 1997743a53d9SNikolay Aleksandrov break; 1998743a53d9SNikolay Aleksandrov } 1999743a53d9SNikolay Aleksandrov /* advance number of filled vlans */ 2000743a53d9SNikolay Aleksandrov idx += range_end->vid - range_start->vid + 1; 2001743a53d9SNikolay Aleksandrov 2002743a53d9SNikolay Aleksandrov range_start = v; 2003743a53d9SNikolay Aleksandrov } else if (dump_stats || v->vid == pvid || 200456d09976SNikolay Aleksandrov !br_vlan_can_enter_range(v, range_end)) { 200556d09976SNikolay Aleksandrov u16 vlan_flags = br_vlan_flags(range_start, pvid); 20060ab55879SNikolay Aleksandrov 20070ab55879SNikolay Aleksandrov if (!br_vlan_fill_vids(skb, range_start->vid, 20087a53e718SNikolay Aleksandrov range_end->vid, range_start, 200956d09976SNikolay Aleksandrov vlan_flags, dump_stats)) { 20108dcea187SNikolay Aleksandrov err = -EMSGSIZE; 20118dcea187SNikolay Aleksandrov break; 20128dcea187SNikolay Aleksandrov } 20130ab55879SNikolay Aleksandrov /* advance number of filled vlans */ 20140ab55879SNikolay Aleksandrov idx += range_end->vid - range_start->vid + 1; 20150ab55879SNikolay Aleksandrov 20160ab55879SNikolay Aleksandrov range_start = v; 20178dcea187SNikolay Aleksandrov } 20180ab55879SNikolay Aleksandrov range_end = v; 20190ab55879SNikolay Aleksandrov } 20200ab55879SNikolay Aleksandrov 20210ab55879SNikolay Aleksandrov /* err will be 0 and range_start will be set in 3 cases here: 20220ab55879SNikolay Aleksandrov * - first vlan (range_start == range_end) 20230ab55879SNikolay Aleksandrov * - last vlan (range_start == range_end, not in range) 20240ab55879SNikolay Aleksandrov * - last vlan range (range_start != range_end, in range) 20250ab55879SNikolay Aleksandrov */ 2026743a53d9SNikolay Aleksandrov if (!err && range_start) { 2027743a53d9SNikolay Aleksandrov if (dump_global && 2028743a53d9SNikolay Aleksandrov !br_vlan_global_opts_fill(skb, range_start->vid, 2029743a53d9SNikolay Aleksandrov range_end->vid, range_start)) 2030743a53d9SNikolay Aleksandrov err = -EMSGSIZE; 2031743a53d9SNikolay Aleksandrov else if (!dump_global && 2032743a53d9SNikolay Aleksandrov !br_vlan_fill_vids(skb, range_start->vid, 2033743a53d9SNikolay Aleksandrov range_end->vid, range_start, 2034743a53d9SNikolay Aleksandrov br_vlan_flags(range_start, pvid), 203556d09976SNikolay Aleksandrov dump_stats)) 20360ab55879SNikolay Aleksandrov err = -EMSGSIZE; 2037743a53d9SNikolay Aleksandrov } 20380ab55879SNikolay Aleksandrov 20390ab55879SNikolay Aleksandrov cb->args[1] = err ? idx : 0; 20400ab55879SNikolay Aleksandrov 20418dcea187SNikolay Aleksandrov nlmsg_end(skb, nlh); 20428dcea187SNikolay Aleksandrov 20438dcea187SNikolay Aleksandrov return err; 20448dcea187SNikolay Aleksandrov } 20458dcea187SNikolay Aleksandrov 204656d09976SNikolay Aleksandrov static const struct nla_policy br_vlan_db_dump_pol[BRIDGE_VLANDB_DUMP_MAX + 1] = { 204756d09976SNikolay Aleksandrov [BRIDGE_VLANDB_DUMP_FLAGS] = { .type = NLA_U32 }, 204856d09976SNikolay Aleksandrov }; 204956d09976SNikolay Aleksandrov 20508dcea187SNikolay Aleksandrov static int br_vlan_rtm_dump(struct sk_buff *skb, struct netlink_callback *cb) 20518dcea187SNikolay Aleksandrov { 205256d09976SNikolay Aleksandrov struct nlattr *dtb[BRIDGE_VLANDB_DUMP_MAX + 1]; 20538dcea187SNikolay Aleksandrov int idx = 0, err = 0, s_idx = cb->args[0]; 20548dcea187SNikolay Aleksandrov struct net *net = sock_net(skb->sk); 20558dcea187SNikolay Aleksandrov struct br_vlan_msg *bvm; 20568dcea187SNikolay Aleksandrov struct net_device *dev; 205756d09976SNikolay Aleksandrov u32 dump_flags = 0; 20588dcea187SNikolay Aleksandrov 205956d09976SNikolay Aleksandrov err = nlmsg_parse(cb->nlh, sizeof(*bvm), dtb, BRIDGE_VLANDB_DUMP_MAX, 206056d09976SNikolay Aleksandrov br_vlan_db_dump_pol, cb->extack); 20618dcea187SNikolay Aleksandrov if (err < 0) 20628dcea187SNikolay Aleksandrov return err; 20638dcea187SNikolay Aleksandrov 20648dcea187SNikolay Aleksandrov bvm = nlmsg_data(cb->nlh); 206556d09976SNikolay Aleksandrov if (dtb[BRIDGE_VLANDB_DUMP_FLAGS]) 206656d09976SNikolay Aleksandrov dump_flags = nla_get_u32(dtb[BRIDGE_VLANDB_DUMP_FLAGS]); 20678dcea187SNikolay Aleksandrov 20688dcea187SNikolay Aleksandrov rcu_read_lock(); 20698dcea187SNikolay Aleksandrov if (bvm->ifindex) { 20708dcea187SNikolay Aleksandrov dev = dev_get_by_index_rcu(net, bvm->ifindex); 20718dcea187SNikolay Aleksandrov if (!dev) { 20728dcea187SNikolay Aleksandrov err = -ENODEV; 20738dcea187SNikolay Aleksandrov goto out_err; 20748dcea187SNikolay Aleksandrov } 207556d09976SNikolay Aleksandrov err = br_vlan_dump_dev(dev, skb, cb, dump_flags); 20768dcea187SNikolay Aleksandrov if (err && err != -EMSGSIZE) 20778dcea187SNikolay Aleksandrov goto out_err; 20788dcea187SNikolay Aleksandrov } else { 20798dcea187SNikolay Aleksandrov for_each_netdev_rcu(net, dev) { 20808dcea187SNikolay Aleksandrov if (idx < s_idx) 20818dcea187SNikolay Aleksandrov goto skip; 20828dcea187SNikolay Aleksandrov 208356d09976SNikolay Aleksandrov err = br_vlan_dump_dev(dev, skb, cb, dump_flags); 20848dcea187SNikolay Aleksandrov if (err == -EMSGSIZE) 20858dcea187SNikolay Aleksandrov break; 20868dcea187SNikolay Aleksandrov skip: 20878dcea187SNikolay Aleksandrov idx++; 20888dcea187SNikolay Aleksandrov } 20898dcea187SNikolay Aleksandrov } 20908dcea187SNikolay Aleksandrov cb->args[0] = idx; 20918dcea187SNikolay Aleksandrov rcu_read_unlock(); 20928dcea187SNikolay Aleksandrov 20938dcea187SNikolay Aleksandrov return skb->len; 20948dcea187SNikolay Aleksandrov 20958dcea187SNikolay Aleksandrov out_err: 20968dcea187SNikolay Aleksandrov rcu_read_unlock(); 20978dcea187SNikolay Aleksandrov 20988dcea187SNikolay Aleksandrov return err; 20998dcea187SNikolay Aleksandrov } 21008dcea187SNikolay Aleksandrov 2101f26b2965SNikolay Aleksandrov static const struct nla_policy br_vlan_db_policy[BRIDGE_VLANDB_ENTRY_MAX + 1] = { 21028140860cSJohannes Berg [BRIDGE_VLANDB_ENTRY_INFO] = 21038140860cSJohannes Berg NLA_POLICY_EXACT_LEN(sizeof(struct bridge_vlan_info)), 21040ab55879SNikolay Aleksandrov [BRIDGE_VLANDB_ENTRY_RANGE] = { .type = NLA_U16 }, 2105a580c76dSNikolay Aleksandrov [BRIDGE_VLANDB_ENTRY_STATE] = { .type = NLA_U8 }, 2106fa388f29SNikolay Aleksandrov [BRIDGE_VLANDB_ENTRY_TUNNEL_INFO] = { .type = NLA_NESTED }, 2107f26b2965SNikolay Aleksandrov }; 2108f26b2965SNikolay Aleksandrov 2109f26b2965SNikolay Aleksandrov static int br_vlan_rtm_process_one(struct net_device *dev, 2110f26b2965SNikolay Aleksandrov const struct nlattr *attr, 2111f26b2965SNikolay Aleksandrov int cmd, struct netlink_ext_ack *extack) 2112f26b2965SNikolay Aleksandrov { 21130ab55879SNikolay Aleksandrov struct bridge_vlan_info *vinfo, vrange_end, *vinfo_last = NULL; 2114f26b2965SNikolay Aleksandrov struct nlattr *tb[BRIDGE_VLANDB_ENTRY_MAX + 1]; 2115a5d29ae2SNikolay Aleksandrov bool changed = false, skip_processing = false; 2116f26b2965SNikolay Aleksandrov struct net_bridge_vlan_group *vg; 2117f26b2965SNikolay Aleksandrov struct net_bridge_port *p = NULL; 2118f26b2965SNikolay Aleksandrov int err = 0, cmdmap = 0; 2119f26b2965SNikolay Aleksandrov struct net_bridge *br; 2120f26b2965SNikolay Aleksandrov 2121f26b2965SNikolay Aleksandrov if (netif_is_bridge_master(dev)) { 2122f26b2965SNikolay Aleksandrov br = netdev_priv(dev); 2123f26b2965SNikolay Aleksandrov vg = br_vlan_group(br); 2124f26b2965SNikolay Aleksandrov } else { 2125f26b2965SNikolay Aleksandrov p = br_port_get_rtnl(dev); 2126f26b2965SNikolay Aleksandrov if (WARN_ON(!p)) 2127f26b2965SNikolay Aleksandrov return -ENODEV; 2128f26b2965SNikolay Aleksandrov br = p->br; 2129f26b2965SNikolay Aleksandrov vg = nbp_vlan_group(p); 2130f26b2965SNikolay Aleksandrov } 2131f26b2965SNikolay Aleksandrov 2132f26b2965SNikolay Aleksandrov if (WARN_ON(!vg)) 2133f26b2965SNikolay Aleksandrov return -ENODEV; 2134f26b2965SNikolay Aleksandrov 2135f26b2965SNikolay Aleksandrov err = nla_parse_nested(tb, BRIDGE_VLANDB_ENTRY_MAX, attr, 2136f26b2965SNikolay Aleksandrov br_vlan_db_policy, extack); 2137f26b2965SNikolay Aleksandrov if (err) 2138f26b2965SNikolay Aleksandrov return err; 2139f26b2965SNikolay Aleksandrov 2140f26b2965SNikolay Aleksandrov if (!tb[BRIDGE_VLANDB_ENTRY_INFO]) { 2141f26b2965SNikolay Aleksandrov NL_SET_ERR_MSG_MOD(extack, "Missing vlan entry info"); 2142f26b2965SNikolay Aleksandrov return -EINVAL; 2143f26b2965SNikolay Aleksandrov } 21440ab55879SNikolay Aleksandrov memset(&vrange_end, 0, sizeof(vrange_end)); 2145f26b2965SNikolay Aleksandrov 2146f26b2965SNikolay Aleksandrov vinfo = nla_data(tb[BRIDGE_VLANDB_ENTRY_INFO]); 2147f26b2965SNikolay Aleksandrov if (vinfo->flags & (BRIDGE_VLAN_INFO_RANGE_BEGIN | 2148f26b2965SNikolay Aleksandrov BRIDGE_VLAN_INFO_RANGE_END)) { 2149f26b2965SNikolay Aleksandrov NL_SET_ERR_MSG_MOD(extack, "Old-style vlan ranges are not allowed when using RTM vlan calls"); 2150f26b2965SNikolay Aleksandrov return -EINVAL; 2151f26b2965SNikolay Aleksandrov } 2152f26b2965SNikolay Aleksandrov if (!br_vlan_valid_id(vinfo->vid, extack)) 2153f26b2965SNikolay Aleksandrov return -EINVAL; 2154f26b2965SNikolay Aleksandrov 21550ab55879SNikolay Aleksandrov if (tb[BRIDGE_VLANDB_ENTRY_RANGE]) { 21560ab55879SNikolay Aleksandrov vrange_end.vid = nla_get_u16(tb[BRIDGE_VLANDB_ENTRY_RANGE]); 21570ab55879SNikolay Aleksandrov /* validate user-provided flags without RANGE_BEGIN */ 21580ab55879SNikolay Aleksandrov vrange_end.flags = BRIDGE_VLAN_INFO_RANGE_END | vinfo->flags; 21590ab55879SNikolay Aleksandrov vinfo->flags |= BRIDGE_VLAN_INFO_RANGE_BEGIN; 21600ab55879SNikolay Aleksandrov 21610ab55879SNikolay Aleksandrov /* vinfo_last is the range start, vinfo the range end */ 21620ab55879SNikolay Aleksandrov vinfo_last = vinfo; 21630ab55879SNikolay Aleksandrov vinfo = &vrange_end; 21640ab55879SNikolay Aleksandrov 21650ab55879SNikolay Aleksandrov if (!br_vlan_valid_id(vinfo->vid, extack) || 21660ab55879SNikolay Aleksandrov !br_vlan_valid_range(vinfo, vinfo_last, extack)) 21670ab55879SNikolay Aleksandrov return -EINVAL; 21680ab55879SNikolay Aleksandrov } 21690ab55879SNikolay Aleksandrov 2170f26b2965SNikolay Aleksandrov switch (cmd) { 2171f26b2965SNikolay Aleksandrov case RTM_NEWVLAN: 2172f26b2965SNikolay Aleksandrov cmdmap = RTM_SETLINK; 2173a5d29ae2SNikolay Aleksandrov skip_processing = !!(vinfo->flags & BRIDGE_VLAN_INFO_ONLY_OPTS); 2174f26b2965SNikolay Aleksandrov break; 2175adb3ce9bSNikolay Aleksandrov case RTM_DELVLAN: 2176adb3ce9bSNikolay Aleksandrov cmdmap = RTM_DELLINK; 2177adb3ce9bSNikolay Aleksandrov break; 2178f26b2965SNikolay Aleksandrov } 2179f26b2965SNikolay Aleksandrov 2180a5d29ae2SNikolay Aleksandrov if (!skip_processing) { 2181a5d29ae2SNikolay Aleksandrov struct bridge_vlan_info *tmp_last = vinfo_last; 2182a5d29ae2SNikolay Aleksandrov 2183a5d29ae2SNikolay Aleksandrov /* br_process_vlan_info may overwrite vinfo_last */ 2184a5d29ae2SNikolay Aleksandrov err = br_process_vlan_info(br, p, cmdmap, vinfo, &tmp_last, 2185a5d29ae2SNikolay Aleksandrov &changed, extack); 2186a5d29ae2SNikolay Aleksandrov 2187a5d29ae2SNikolay Aleksandrov /* notify first if anything changed */ 2188f26b2965SNikolay Aleksandrov if (changed) 2189f26b2965SNikolay Aleksandrov br_ifinfo_notify(cmdmap, br, p); 2190f26b2965SNikolay Aleksandrov 2191a5d29ae2SNikolay Aleksandrov if (err) 2192a5d29ae2SNikolay Aleksandrov return err; 2193a5d29ae2SNikolay Aleksandrov } 2194a5d29ae2SNikolay Aleksandrov 2195a5d29ae2SNikolay Aleksandrov /* deal with options */ 2196a5d29ae2SNikolay Aleksandrov if (cmd == RTM_NEWVLAN) { 2197a5d29ae2SNikolay Aleksandrov struct net_bridge_vlan *range_start, *range_end; 2198a5d29ae2SNikolay Aleksandrov 2199a5d29ae2SNikolay Aleksandrov if (vinfo_last) { 2200a5d29ae2SNikolay Aleksandrov range_start = br_vlan_find(vg, vinfo_last->vid); 2201a5d29ae2SNikolay Aleksandrov range_end = br_vlan_find(vg, vinfo->vid); 2202a5d29ae2SNikolay Aleksandrov } else { 2203a5d29ae2SNikolay Aleksandrov range_start = br_vlan_find(vg, vinfo->vid); 2204a5d29ae2SNikolay Aleksandrov range_end = range_start; 2205a5d29ae2SNikolay Aleksandrov } 2206a5d29ae2SNikolay Aleksandrov 2207a5d29ae2SNikolay Aleksandrov err = br_vlan_process_options(br, p, range_start, range_end, 2208a5d29ae2SNikolay Aleksandrov tb, extack); 2209a5d29ae2SNikolay Aleksandrov } 2210a5d29ae2SNikolay Aleksandrov 2211f26b2965SNikolay Aleksandrov return err; 2212f26b2965SNikolay Aleksandrov } 2213f26b2965SNikolay Aleksandrov 2214f26b2965SNikolay Aleksandrov static int br_vlan_rtm_process(struct sk_buff *skb, struct nlmsghdr *nlh, 2215f26b2965SNikolay Aleksandrov struct netlink_ext_ack *extack) 2216f26b2965SNikolay Aleksandrov { 2217f26b2965SNikolay Aleksandrov struct net *net = sock_net(skb->sk); 2218f26b2965SNikolay Aleksandrov struct br_vlan_msg *bvm; 2219f26b2965SNikolay Aleksandrov struct net_device *dev; 2220f26b2965SNikolay Aleksandrov struct nlattr *attr; 2221f26b2965SNikolay Aleksandrov int err, vlans = 0; 2222f26b2965SNikolay Aleksandrov int rem; 2223f26b2965SNikolay Aleksandrov 2224f26b2965SNikolay Aleksandrov /* this should validate the header and check for remaining bytes */ 2225f26b2965SNikolay Aleksandrov err = nlmsg_parse(nlh, sizeof(*bvm), NULL, BRIDGE_VLANDB_MAX, NULL, 2226f26b2965SNikolay Aleksandrov extack); 2227f26b2965SNikolay Aleksandrov if (err < 0) 2228f26b2965SNikolay Aleksandrov return err; 2229f26b2965SNikolay Aleksandrov 2230f26b2965SNikolay Aleksandrov bvm = nlmsg_data(nlh); 2231f26b2965SNikolay Aleksandrov dev = __dev_get_by_index(net, bvm->ifindex); 2232f26b2965SNikolay Aleksandrov if (!dev) 2233f26b2965SNikolay Aleksandrov return -ENODEV; 2234f26b2965SNikolay Aleksandrov 2235f26b2965SNikolay Aleksandrov if (!netif_is_bridge_master(dev) && !netif_is_bridge_port(dev)) { 2236f26b2965SNikolay Aleksandrov NL_SET_ERR_MSG_MOD(extack, "The device is not a valid bridge or bridge port"); 2237f26b2965SNikolay Aleksandrov return -EINVAL; 2238f26b2965SNikolay Aleksandrov } 2239f26b2965SNikolay Aleksandrov 2240f26b2965SNikolay Aleksandrov nlmsg_for_each_attr(attr, nlh, sizeof(*bvm), rem) { 224147ecd2dbSNikolay Aleksandrov switch (nla_type(attr)) { 224247ecd2dbSNikolay Aleksandrov case BRIDGE_VLANDB_ENTRY: 224347ecd2dbSNikolay Aleksandrov err = br_vlan_rtm_process_one(dev, attr, 224447ecd2dbSNikolay Aleksandrov nlh->nlmsg_type, 224547ecd2dbSNikolay Aleksandrov extack); 224647ecd2dbSNikolay Aleksandrov break; 224747ecd2dbSNikolay Aleksandrov case BRIDGE_VLANDB_GLOBAL_OPTIONS: 224847ecd2dbSNikolay Aleksandrov err = br_vlan_rtm_process_global_options(dev, attr, 224947ecd2dbSNikolay Aleksandrov nlh->nlmsg_type, 225047ecd2dbSNikolay Aleksandrov extack); 225147ecd2dbSNikolay Aleksandrov break; 225247ecd2dbSNikolay Aleksandrov default: 2253f26b2965SNikolay Aleksandrov continue; 225447ecd2dbSNikolay Aleksandrov } 2255f26b2965SNikolay Aleksandrov 2256f26b2965SNikolay Aleksandrov vlans++; 2257f26b2965SNikolay Aleksandrov if (err) 2258f26b2965SNikolay Aleksandrov break; 2259f26b2965SNikolay Aleksandrov } 2260f26b2965SNikolay Aleksandrov if (!vlans) { 2261f26b2965SNikolay Aleksandrov NL_SET_ERR_MSG_MOD(extack, "No vlans found to process"); 2262f26b2965SNikolay Aleksandrov err = -EINVAL; 2263f26b2965SNikolay Aleksandrov } 2264f26b2965SNikolay Aleksandrov 2265f26b2965SNikolay Aleksandrov return err; 2266f26b2965SNikolay Aleksandrov } 2267f26b2965SNikolay Aleksandrov 22688dcea187SNikolay Aleksandrov void br_vlan_rtnl_init(void) 22698dcea187SNikolay Aleksandrov { 22708dcea187SNikolay Aleksandrov rtnl_register_module(THIS_MODULE, PF_BRIDGE, RTM_GETVLAN, NULL, 22718dcea187SNikolay Aleksandrov br_vlan_rtm_dump, 0); 2272f26b2965SNikolay Aleksandrov rtnl_register_module(THIS_MODULE, PF_BRIDGE, RTM_NEWVLAN, 2273f26b2965SNikolay Aleksandrov br_vlan_rtm_process, NULL, 0); 2274adb3ce9bSNikolay Aleksandrov rtnl_register_module(THIS_MODULE, PF_BRIDGE, RTM_DELVLAN, 2275adb3ce9bSNikolay Aleksandrov br_vlan_rtm_process, NULL, 0); 22768dcea187SNikolay Aleksandrov } 22778dcea187SNikolay Aleksandrov 22788dcea187SNikolay Aleksandrov void br_vlan_rtnl_uninit(void) 22798dcea187SNikolay Aleksandrov { 22808dcea187SNikolay Aleksandrov rtnl_unregister(PF_BRIDGE, RTM_GETVLAN); 2281f26b2965SNikolay Aleksandrov rtnl_unregister(PF_BRIDGE, RTM_NEWVLAN); 2282adb3ce9bSNikolay Aleksandrov rtnl_unregister(PF_BRIDGE, RTM_DELVLAN); 22838dcea187SNikolay Aleksandrov } 2284