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 37f418af63SNikolay Aleksandrov static bool __vlan_add_pvid(struct net_bridge_vlan_group *vg, u16 vid) 382594e906SNikolay Aleksandrov { 3977751ee8SNikolay Aleksandrov if (vg->pvid == vid) 40f418af63SNikolay Aleksandrov return false; 41552406c4SVlad Yasevich 42552406c4SVlad Yasevich smp_wmb(); 4377751ee8SNikolay Aleksandrov vg->pvid = vid; 44f418af63SNikolay Aleksandrov 45f418af63SNikolay Aleksandrov return true; 46552406c4SVlad Yasevich } 47552406c4SVlad Yasevich 48f418af63SNikolay Aleksandrov static bool __vlan_delete_pvid(struct net_bridge_vlan_group *vg, u16 vid) 49552406c4SVlad Yasevich { 5077751ee8SNikolay Aleksandrov if (vg->pvid != vid) 51f418af63SNikolay Aleksandrov return false; 52552406c4SVlad Yasevich 53552406c4SVlad Yasevich smp_wmb(); 5477751ee8SNikolay Aleksandrov vg->pvid = 0; 55f418af63SNikolay Aleksandrov 56f418af63SNikolay Aleksandrov return true; 57552406c4SVlad Yasevich } 58552406c4SVlad Yasevich 59f418af63SNikolay Aleksandrov /* return true if anything changed, false otherwise */ 60f418af63SNikolay Aleksandrov static bool __vlan_add_flags(struct net_bridge_vlan *v, u16 flags) 6135e03f3aSVlad Yasevich { 6277751ee8SNikolay Aleksandrov struct net_bridge_vlan_group *vg; 63f418af63SNikolay Aleksandrov u16 old_flags = v->flags; 64f418af63SNikolay Aleksandrov bool ret; 6577751ee8SNikolay Aleksandrov 662594e906SNikolay Aleksandrov if (br_vlan_is_master(v)) 67907b1e6eSNikolay Aleksandrov vg = br_vlan_group(v->br); 68635126b7SVlad Yasevich else 69907b1e6eSNikolay Aleksandrov vg = nbp_vlan_group(v->port); 7077751ee8SNikolay Aleksandrov 7177751ee8SNikolay Aleksandrov if (flags & BRIDGE_VLAN_INFO_PVID) 72f418af63SNikolay Aleksandrov ret = __vlan_add_pvid(vg, v->vid); 732594e906SNikolay Aleksandrov else 74f418af63SNikolay Aleksandrov ret = __vlan_delete_pvid(vg, v->vid); 7535e03f3aSVlad Yasevich 7635e03f3aSVlad Yasevich if (flags & BRIDGE_VLAN_INFO_UNTAGGED) 772594e906SNikolay Aleksandrov v->flags |= BRIDGE_VLAN_INFO_UNTAGGED; 78635126b7SVlad Yasevich else 792594e906SNikolay Aleksandrov v->flags &= ~BRIDGE_VLAN_INFO_UNTAGGED; 80f418af63SNikolay Aleksandrov 81f418af63SNikolay Aleksandrov return ret || !!(old_flags ^ v->flags); 8235e03f3aSVlad Yasevich } 8335e03f3aSVlad Yasevich 847f109539SScott Feldman static int __vlan_vid_add(struct net_device *dev, struct net_bridge *br, 8527973793SIdo Schimmel struct net_bridge_vlan *v, u16 flags, 8627973793SIdo Schimmel struct netlink_ext_ack *extack) 877f109539SScott Feldman { 880944d6b5SJiri Pirko int err; 897f109539SScott Feldman 900944d6b5SJiri Pirko /* Try switchdev op first. In case it is not supported, fallback to 910944d6b5SJiri Pirko * 8021q add. 920944d6b5SJiri Pirko */ 9327973793SIdo Schimmel err = br_switchdev_port_vlan_add(dev, v->vid, flags, extack); 947f109539SScott Feldman if (err == -EOPNOTSUPP) 9527973793SIdo Schimmel return vlan_vid_add(dev, br->vlan_proto, v->vid); 9627973793SIdo Schimmel v->priv_flags |= BR_VLFLAG_ADDED_BY_SWITCHDEV; 977f109539SScott Feldman return err; 987f109539SScott Feldman } 997f109539SScott Feldman 1002594e906SNikolay Aleksandrov static void __vlan_add_list(struct net_bridge_vlan *v) 101243a2e63SVlad Yasevich { 102907b1e6eSNikolay Aleksandrov struct net_bridge_vlan_group *vg; 1032594e906SNikolay Aleksandrov struct list_head *headp, *hpos; 1042594e906SNikolay Aleksandrov struct net_bridge_vlan *vent; 105243a2e63SVlad Yasevich 106907b1e6eSNikolay Aleksandrov if (br_vlan_is_master(v)) 107907b1e6eSNikolay Aleksandrov vg = br_vlan_group(v->br); 108907b1e6eSNikolay Aleksandrov else 109907b1e6eSNikolay Aleksandrov vg = nbp_vlan_group(v->port); 110907b1e6eSNikolay Aleksandrov 111907b1e6eSNikolay Aleksandrov headp = &vg->vlan_list; 1122594e906SNikolay Aleksandrov list_for_each_prev(hpos, headp) { 1132594e906SNikolay Aleksandrov vent = list_entry(hpos, struct net_bridge_vlan, vlist); 1142594e906SNikolay Aleksandrov if (v->vid < vent->vid) 1152594e906SNikolay Aleksandrov continue; 1162594e906SNikolay Aleksandrov else 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 141f8ed289fSNikolay Aleksandrov /* Returns a master vlan, if it didn't exist it gets created. In all cases a 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); 1936dada9b1SNikolay Aleksandrov call_rcu(&masterv->rcu, br_master_vlan_rcu_free); 194f8ed289fSNikolay Aleksandrov } 195f8ed289fSNikolay Aleksandrov } 196f8ed289fSNikolay Aleksandrov 1979163a0fcSNikolay Aleksandrov static void nbp_vlan_rcu_free(struct rcu_head *rcu) 1989163a0fcSNikolay Aleksandrov { 1999163a0fcSNikolay Aleksandrov struct net_bridge_vlan *v; 2009163a0fcSNikolay Aleksandrov 2019163a0fcSNikolay Aleksandrov v = container_of(rcu, struct net_bridge_vlan, rcu); 2029163a0fcSNikolay Aleksandrov WARN_ON(br_vlan_is_master(v)); 2039163a0fcSNikolay Aleksandrov /* if we had per-port stats configured then free them here */ 2049d332e69SNikolay Aleksandrov if (v->priv_flags & BR_VLFLAG_PER_PORT_STATS) 2059163a0fcSNikolay Aleksandrov free_percpu(v->stats); 2069163a0fcSNikolay Aleksandrov v->stats = NULL; 2079163a0fcSNikolay Aleksandrov kfree(v); 2089163a0fcSNikolay Aleksandrov } 2099163a0fcSNikolay Aleksandrov 2102594e906SNikolay Aleksandrov /* This is the shared VLAN add function which works for both ports and bridge 2112594e906SNikolay Aleksandrov * devices. There are four possible calls to this function in terms of the 2122594e906SNikolay Aleksandrov * vlan entry type: 2132594e906SNikolay Aleksandrov * 1. vlan is being added on a port (no master flags, global entry exists) 214ddd611d3SIdo Schimmel * 2. vlan is being added on a bridge (both master and brentry flags) 2152594e906SNikolay Aleksandrov * 3. vlan is being added on a port, but a global entry didn't exist which 216ddd611d3SIdo Schimmel * is being created right now (master flag set, brentry flag unset), the 2172594e906SNikolay Aleksandrov * global entry is used for global per-vlan features, but not for filtering 218ddd611d3SIdo Schimmel * 4. same as 3 but with both master and brentry flags set so the entry 2192594e906SNikolay Aleksandrov * will be used for filtering in both the port and the bridge 2202594e906SNikolay Aleksandrov */ 221169327d5SPetr Machata static int __vlan_add(struct net_bridge_vlan *v, u16 flags, 222169327d5SPetr Machata struct netlink_ext_ack *extack) 223243a2e63SVlad Yasevich { 2242594e906SNikolay Aleksandrov struct net_bridge_vlan *masterv = NULL; 2252594e906SNikolay Aleksandrov struct net_bridge_port *p = NULL; 2266be144f6SNikolay Aleksandrov struct net_bridge_vlan_group *vg; 2272594e906SNikolay Aleksandrov struct net_device *dev; 2282594e906SNikolay Aleksandrov struct net_bridge *br; 229bf361ad3SVivien Didelot int err; 230bf361ad3SVivien Didelot 2312594e906SNikolay Aleksandrov if (br_vlan_is_master(v)) { 2322594e906SNikolay Aleksandrov br = v->br; 2332594e906SNikolay Aleksandrov dev = br->dev; 234907b1e6eSNikolay Aleksandrov vg = br_vlan_group(br); 2352594e906SNikolay Aleksandrov } else { 2362594e906SNikolay Aleksandrov p = v->port; 2372594e906SNikolay Aleksandrov br = p->br; 2382594e906SNikolay Aleksandrov dev = p->dev; 239907b1e6eSNikolay Aleksandrov vg = nbp_vlan_group(p); 2402594e906SNikolay Aleksandrov } 2412594e906SNikolay Aleksandrov 2422594e906SNikolay Aleksandrov if (p) { 2432594e906SNikolay Aleksandrov /* Add VLAN to the device filter if it is supported. 2442594e906SNikolay Aleksandrov * This ensures tagged traffic enters the bridge when 2452594e906SNikolay Aleksandrov * promiscuous mode is disabled by br_manage_promisc(). 2462594e906SNikolay Aleksandrov */ 24727973793SIdo Schimmel err = __vlan_vid_add(dev, br, v, flags, extack); 248bf361ad3SVivien Didelot if (err) 2492594e906SNikolay Aleksandrov goto out; 2502594e906SNikolay Aleksandrov 2512594e906SNikolay Aleksandrov /* need to work on the master vlan too */ 2522594e906SNikolay Aleksandrov if (flags & BRIDGE_VLAN_INFO_MASTER) { 253f418af63SNikolay Aleksandrov bool changed; 254f418af63SNikolay Aleksandrov 255f418af63SNikolay Aleksandrov err = br_vlan_add(br, v->vid, 256f418af63SNikolay Aleksandrov flags | BRIDGE_VLAN_INFO_BRENTRY, 257169327d5SPetr Machata &changed, extack); 2582594e906SNikolay Aleksandrov if (err) 2592594e906SNikolay Aleksandrov goto out_filt; 260f545923bSNikolay Aleksandrov 261f545923bSNikolay Aleksandrov if (changed) 262f545923bSNikolay Aleksandrov br_vlan_notify(br, NULL, v->vid, 0, 263f545923bSNikolay Aleksandrov RTM_NEWVLAN); 2642594e906SNikolay Aleksandrov } 2652594e906SNikolay Aleksandrov 266169327d5SPetr Machata masterv = br_vlan_get_master(br, v->vid, extack); 267f8ed289fSNikolay Aleksandrov if (!masterv) 2682594e906SNikolay Aleksandrov goto out_filt; 2692594e906SNikolay Aleksandrov v->brvlan = masterv; 2709163a0fcSNikolay Aleksandrov if (br_opt_get(br, BROPT_VLAN_STATS_PER_PORT)) { 2719163a0fcSNikolay Aleksandrov v->stats = netdev_alloc_pcpu_stats(struct br_vlan_stats); 2729163a0fcSNikolay Aleksandrov if (!v->stats) { 2739163a0fcSNikolay Aleksandrov err = -ENOMEM; 2749163a0fcSNikolay Aleksandrov goto out_filt; 2759163a0fcSNikolay Aleksandrov } 2769d332e69SNikolay Aleksandrov v->priv_flags |= BR_VLFLAG_PER_PORT_STATS; 2779163a0fcSNikolay Aleksandrov } else { 2786dada9b1SNikolay Aleksandrov v->stats = masterv->stats; 2799163a0fcSNikolay Aleksandrov } 2809c86ce2cSPetr Machata } else { 281169327d5SPetr Machata err = br_switchdev_port_vlan_add(dev, v->vid, flags, extack); 2829c86ce2cSPetr Machata if (err && err != -EOPNOTSUPP) 2839c86ce2cSPetr Machata goto out; 2842594e906SNikolay Aleksandrov } 2852594e906SNikolay Aleksandrov 2866be144f6SNikolay Aleksandrov /* Add the dev mac and count the vlan only if it's usable */ 2872594e906SNikolay Aleksandrov if (br_vlan_should_use(v)) { 2882594e906SNikolay Aleksandrov err = br_fdb_insert(br, p, dev->dev_addr, v->vid); 2892594e906SNikolay Aleksandrov if (err) { 2902594e906SNikolay Aleksandrov br_err(br, "failed insert local address into bridge forwarding table\n"); 2912594e906SNikolay Aleksandrov goto out_filt; 2922594e906SNikolay Aleksandrov } 2936be144f6SNikolay Aleksandrov vg->num_vlans++; 2942594e906SNikolay Aleksandrov } 2952594e906SNikolay Aleksandrov 2966be144f6SNikolay Aleksandrov err = rhashtable_lookup_insert_fast(&vg->vlan_hash, &v->vnode, 2976be144f6SNikolay Aleksandrov br_vlan_rht_params); 2982594e906SNikolay Aleksandrov if (err) 2992594e906SNikolay Aleksandrov goto out_fdb_insert; 3002594e906SNikolay Aleksandrov 3012594e906SNikolay Aleksandrov __vlan_add_list(v); 3022594e906SNikolay Aleksandrov __vlan_add_flags(v, flags); 30380900acdSMike Manning 30480900acdSMike Manning if (p) 30580900acdSMike Manning nbp_vlan_set_vlan_dev_state(p, v->vid); 3062594e906SNikolay Aleksandrov out: 3072594e906SNikolay Aleksandrov return err; 3082594e906SNikolay Aleksandrov 3092594e906SNikolay Aleksandrov out_fdb_insert: 3106be144f6SNikolay Aleksandrov if (br_vlan_should_use(v)) { 3116be144f6SNikolay Aleksandrov br_fdb_find_delete_local(br, p, dev->dev_addr, v->vid); 3126be144f6SNikolay Aleksandrov vg->num_vlans--; 3136be144f6SNikolay Aleksandrov } 3142594e906SNikolay Aleksandrov 3152594e906SNikolay Aleksandrov out_filt: 3162594e906SNikolay Aleksandrov if (p) { 31727973793SIdo Schimmel __vlan_vid_del(dev, br, v); 3182594e906SNikolay Aleksandrov if (masterv) { 3191a3aea25SLi RongQing if (v->stats && masterv->stats != v->stats) 3201a3aea25SLi RongQing free_percpu(v->stats); 3211a3aea25SLi RongQing v->stats = NULL; 3221a3aea25SLi RongQing 323f8ed289fSNikolay Aleksandrov br_vlan_put_master(masterv); 3242594e906SNikolay Aleksandrov v->brvlan = NULL; 3252594e906SNikolay Aleksandrov } 3269c86ce2cSPetr Machata } else { 3279c86ce2cSPetr Machata br_switchdev_port_vlan_del(dev, v->vid); 3282594e906SNikolay Aleksandrov } 3292594e906SNikolay Aleksandrov 3302594e906SNikolay Aleksandrov goto out; 3312594e906SNikolay Aleksandrov } 3322594e906SNikolay Aleksandrov 3332594e906SNikolay Aleksandrov static int __vlan_del(struct net_bridge_vlan *v) 3342594e906SNikolay Aleksandrov { 3352594e906SNikolay Aleksandrov struct net_bridge_vlan *masterv = v; 33677751ee8SNikolay Aleksandrov struct net_bridge_vlan_group *vg; 3372594e906SNikolay Aleksandrov struct net_bridge_port *p = NULL; 3382594e906SNikolay Aleksandrov int err = 0; 3392594e906SNikolay Aleksandrov 3402594e906SNikolay Aleksandrov if (br_vlan_is_master(v)) { 341907b1e6eSNikolay Aleksandrov vg = br_vlan_group(v->br); 3422594e906SNikolay Aleksandrov } else { 3432594e906SNikolay Aleksandrov p = v->port; 344907b1e6eSNikolay Aleksandrov vg = nbp_vlan_group(v->port); 3452594e906SNikolay Aleksandrov masterv = v->brvlan; 3462594e906SNikolay Aleksandrov } 3472594e906SNikolay Aleksandrov 34877751ee8SNikolay Aleksandrov __vlan_delete_pvid(vg, v->vid); 3492594e906SNikolay Aleksandrov if (p) { 35027973793SIdo Schimmel err = __vlan_vid_del(p->dev, p->br, v); 3512594e906SNikolay Aleksandrov if (err) 3522594e906SNikolay Aleksandrov goto out; 3539c86ce2cSPetr Machata } else { 3549c86ce2cSPetr Machata err = br_switchdev_port_vlan_del(v->br->dev, v->vid); 3559c86ce2cSPetr Machata if (err && err != -EOPNOTSUPP) 3569c86ce2cSPetr Machata goto out; 3579c86ce2cSPetr Machata err = 0; 3582594e906SNikolay Aleksandrov } 3592594e906SNikolay Aleksandrov 3606be144f6SNikolay Aleksandrov if (br_vlan_should_use(v)) { 3612594e906SNikolay Aleksandrov v->flags &= ~BRIDGE_VLAN_INFO_BRENTRY; 3626be144f6SNikolay Aleksandrov vg->num_vlans--; 3632594e906SNikolay Aleksandrov } 3642594e906SNikolay Aleksandrov 3652594e906SNikolay Aleksandrov if (masterv != v) { 366efa5356bSRoopa Prabhu vlan_tunnel_info_del(vg, v); 36777751ee8SNikolay Aleksandrov rhashtable_remove_fast(&vg->vlan_hash, &v->vnode, 36877751ee8SNikolay Aleksandrov br_vlan_rht_params); 3692594e906SNikolay Aleksandrov __vlan_del_list(v); 37080900acdSMike Manning nbp_vlan_set_vlan_dev_state(p, v->vid); 3719163a0fcSNikolay Aleksandrov call_rcu(&v->rcu, nbp_vlan_rcu_free); 3722594e906SNikolay Aleksandrov } 3732594e906SNikolay Aleksandrov 374f8ed289fSNikolay Aleksandrov br_vlan_put_master(masterv); 3752594e906SNikolay Aleksandrov out: 376bf361ad3SVivien Didelot return err; 3778580e211SToshiaki Makita } 378243a2e63SVlad Yasevich 379f409d0edSNikolay Aleksandrov static void __vlan_group_free(struct net_bridge_vlan_group *vg) 380f409d0edSNikolay Aleksandrov { 381f409d0edSNikolay Aleksandrov WARN_ON(!list_empty(&vg->vlan_list)); 382f409d0edSNikolay Aleksandrov rhashtable_destroy(&vg->vlan_hash); 383efa5356bSRoopa Prabhu vlan_tunnel_deinit(vg); 384f409d0edSNikolay Aleksandrov kfree(vg); 385f409d0edSNikolay Aleksandrov } 386f409d0edSNikolay Aleksandrov 387f545923bSNikolay Aleksandrov static void __vlan_flush(const struct net_bridge *br, 388f545923bSNikolay Aleksandrov const struct net_bridge_port *p, 389f545923bSNikolay Aleksandrov struct net_bridge_vlan_group *vg) 390243a2e63SVlad Yasevich { 3912594e906SNikolay Aleksandrov struct net_bridge_vlan *vlan, *tmp; 392f545923bSNikolay Aleksandrov u16 v_start = 0, v_end = 0; 3932594e906SNikolay Aleksandrov 394f409d0edSNikolay Aleksandrov __vlan_delete_pvid(vg, vg->pvid); 395f545923bSNikolay Aleksandrov list_for_each_entry_safe(vlan, tmp, &vg->vlan_list, vlist) { 396f545923bSNikolay Aleksandrov /* take care of disjoint ranges */ 397f545923bSNikolay Aleksandrov if (!v_start) { 398f545923bSNikolay Aleksandrov v_start = vlan->vid; 399f545923bSNikolay Aleksandrov } else if (vlan->vid - v_end != 1) { 400f545923bSNikolay Aleksandrov /* found range end, notify and start next one */ 401f545923bSNikolay Aleksandrov br_vlan_notify(br, p, v_start, v_end, RTM_DELVLAN); 402f545923bSNikolay Aleksandrov v_start = vlan->vid; 403f545923bSNikolay Aleksandrov } 404f545923bSNikolay Aleksandrov v_end = vlan->vid; 405f545923bSNikolay Aleksandrov 4062594e906SNikolay Aleksandrov __vlan_del(vlan); 407243a2e63SVlad Yasevich } 408243a2e63SVlad Yasevich 409f545923bSNikolay Aleksandrov /* notify about the last/whole vlan range */ 410f545923bSNikolay Aleksandrov if (v_start) 411f545923bSNikolay Aleksandrov br_vlan_notify(br, p, v_start, v_end, RTM_DELVLAN); 412f545923bSNikolay Aleksandrov } 413f545923bSNikolay Aleksandrov 41478851988SVlad Yasevich struct sk_buff *br_handle_vlan(struct net_bridge *br, 41511538d03SRoopa Prabhu const struct net_bridge_port *p, 4162594e906SNikolay Aleksandrov struct net_bridge_vlan_group *vg, 417a37b85c9SVlad Yasevich struct sk_buff *skb) 418a37b85c9SVlad Yasevich { 4196dada9b1SNikolay Aleksandrov struct br_vlan_stats *stats; 4202594e906SNikolay Aleksandrov struct net_bridge_vlan *v; 421a37b85c9SVlad Yasevich u16 vid; 422a37b85c9SVlad Yasevich 42320adfa1aSVlad Yasevich /* If this packet was not filtered at input, let it pass */ 42420adfa1aSVlad Yasevich if (!BR_INPUT_SKB_CB(skb)->vlan_filtered) 42578851988SVlad Yasevich goto out; 42678851988SVlad Yasevich 4272594e906SNikolay Aleksandrov /* At this point, we know that the frame was filtered and contains 4282594e906SNikolay Aleksandrov * a valid vlan id. If the vlan id has untagged flag set, 4292594e906SNikolay Aleksandrov * send untagged; otherwise, send tagged. 4302594e906SNikolay Aleksandrov */ 4312594e906SNikolay Aleksandrov br_vlan_get_tag(skb, &vid); 4322594e906SNikolay Aleksandrov v = br_vlan_find(vg, vid); 4332594e906SNikolay Aleksandrov /* Vlan entry must be configured at this point. The 434fc92f745SVlad Yasevich * only exception is the bridge is set in promisc mode and the 435fc92f745SVlad Yasevich * packet is destined for the bridge device. In this case 436fc92f745SVlad Yasevich * pass the packet as is. 437fc92f745SVlad Yasevich */ 4382594e906SNikolay Aleksandrov if (!v || !br_vlan_should_use(v)) { 439fc92f745SVlad Yasevich if ((br->dev->flags & IFF_PROMISC) && skb->dev == br->dev) { 440fc92f745SVlad Yasevich goto out; 441fc92f745SVlad Yasevich } else { 442fc92f745SVlad Yasevich kfree_skb(skb); 443fc92f745SVlad Yasevich return NULL; 444fc92f745SVlad Yasevich } 445fc92f745SVlad Yasevich } 446ae75767eSNikolay Aleksandrov if (br_opt_get(br, BROPT_VLAN_STATS_ENABLED)) { 4476dada9b1SNikolay Aleksandrov stats = this_cpu_ptr(v->stats); 4486dada9b1SNikolay Aleksandrov u64_stats_update_begin(&stats->syncp); 4496dada9b1SNikolay Aleksandrov stats->tx_bytes += skb->len; 4506dada9b1SNikolay Aleksandrov stats->tx_packets++; 4516dada9b1SNikolay Aleksandrov u64_stats_update_end(&stats->syncp); 4526dada9b1SNikolay Aleksandrov } 4536dada9b1SNikolay Aleksandrov 4542594e906SNikolay Aleksandrov if (v->flags & BRIDGE_VLAN_INFO_UNTAGGED) 4555978f8a9SMichał Mirosław __vlan_hwaccel_clear_tag(skb); 45611538d03SRoopa Prabhu 45711538d03SRoopa Prabhu if (p && (p->flags & BR_VLAN_TUNNEL) && 45811538d03SRoopa Prabhu br_handle_egress_vlan_tunnel(skb, v)) { 45911538d03SRoopa Prabhu kfree_skb(skb); 46011538d03SRoopa Prabhu return NULL; 46111538d03SRoopa Prabhu } 46278851988SVlad Yasevich out: 46378851988SVlad Yasevich return skb; 46478851988SVlad Yasevich } 46578851988SVlad Yasevich 46678851988SVlad Yasevich /* Called under RCU */ 4676dada9b1SNikolay Aleksandrov static bool __allowed_ingress(const struct net_bridge *br, 4686dada9b1SNikolay Aleksandrov struct net_bridge_vlan_group *vg, 46978851988SVlad Yasevich struct sk_buff *skb, u16 *vid) 47078851988SVlad Yasevich { 4716dada9b1SNikolay Aleksandrov struct br_vlan_stats *stats; 4726dada9b1SNikolay Aleksandrov struct net_bridge_vlan *v; 4738580e211SToshiaki Makita bool tagged; 474a37b85c9SVlad Yasevich 47520adfa1aSVlad Yasevich BR_INPUT_SKB_CB(skb)->vlan_filtered = true; 47612464bb8SToshiaki Makita /* If vlan tx offload is disabled on bridge device and frame was 47712464bb8SToshiaki Makita * sent from vlan device on the bridge device, it does not have 47812464bb8SToshiaki Makita * HW accelerated vlan tag. 47912464bb8SToshiaki Makita */ 480df8a39deSJiri Pirko if (unlikely(!skb_vlan_tag_present(skb) && 4816dada9b1SNikolay Aleksandrov skb->protocol == br->vlan_proto)) { 4820d5501c1SVlad Yasevich skb = skb_vlan_untag(skb); 48312464bb8SToshiaki Makita if (unlikely(!skb)) 48412464bb8SToshiaki Makita return false; 48512464bb8SToshiaki Makita } 48612464bb8SToshiaki Makita 4878580e211SToshiaki Makita if (!br_vlan_get_tag(skb, vid)) { 4888580e211SToshiaki Makita /* Tagged frame */ 4896dada9b1SNikolay Aleksandrov if (skb->vlan_proto != br->vlan_proto) { 4908580e211SToshiaki Makita /* Protocol-mismatch, empty out vlan_tci for new tag */ 4918580e211SToshiaki Makita skb_push(skb, ETH_HLEN); 49262749e2cSJiri Pirko skb = vlan_insert_tag_set_proto(skb, skb->vlan_proto, 493df8a39deSJiri Pirko skb_vlan_tag_get(skb)); 4948580e211SToshiaki Makita if (unlikely(!skb)) 4958580e211SToshiaki Makita return false; 4968580e211SToshiaki Makita 4978580e211SToshiaki Makita skb_pull(skb, ETH_HLEN); 4988580e211SToshiaki Makita skb_reset_mac_len(skb); 4998580e211SToshiaki Makita *vid = 0; 5008580e211SToshiaki Makita tagged = false; 5018580e211SToshiaki Makita } else { 5028580e211SToshiaki Makita tagged = true; 5038580e211SToshiaki Makita } 5048580e211SToshiaki Makita } else { 5058580e211SToshiaki Makita /* Untagged frame */ 5068580e211SToshiaki Makita tagged = false; 5078580e211SToshiaki Makita } 5088580e211SToshiaki Makita 509b90356ceSToshiaki Makita if (!*vid) { 51077751ee8SNikolay Aleksandrov u16 pvid = br_get_pvid(vg); 51177751ee8SNikolay Aleksandrov 512b90356ceSToshiaki Makita /* Frame had a tag with VID 0 or did not have a tag. 513b90356ceSToshiaki Makita * See if pvid is set on this port. That tells us which 514b90356ceSToshiaki Makita * vlan untagged or priority-tagged traffic belongs to. 51578851988SVlad Yasevich */ 5163df6bf45SVlad Yasevich if (!pvid) 517eb707618SToshiaki Makita goto drop; 51878851988SVlad Yasevich 519b90356ceSToshiaki Makita /* PVID is set on this port. Any untagged or priority-tagged 520b90356ceSToshiaki Makita * ingress frame is considered to belong to this vlan. 52178851988SVlad Yasevich */ 522dfb5fa32SToshiaki Makita *vid = pvid; 5238580e211SToshiaki Makita if (likely(!tagged)) 524b90356ceSToshiaki Makita /* Untagged Frame. */ 5256dada9b1SNikolay Aleksandrov __vlan_hwaccel_put_tag(skb, br->vlan_proto, pvid); 526b90356ceSToshiaki Makita else 527b90356ceSToshiaki Makita /* Priority-tagged Frame. 5285978f8a9SMichał Mirosław * At this point, we know that skb->vlan_tci VID 5295978f8a9SMichał Mirosław * field was 0. 530b90356ceSToshiaki Makita * We update only VID field and preserve PCP field. 531b90356ceSToshiaki Makita */ 532b90356ceSToshiaki Makita skb->vlan_tci |= pvid; 533b90356ceSToshiaki Makita 5346dada9b1SNikolay Aleksandrov /* if stats are disabled we can avoid the lookup */ 535ae75767eSNikolay Aleksandrov if (!br_opt_get(br, BROPT_VLAN_STATS_ENABLED)) 53678851988SVlad Yasevich return true; 53778851988SVlad Yasevich } 53877751ee8SNikolay Aleksandrov v = br_vlan_find(vg, *vid); 5396dada9b1SNikolay Aleksandrov if (!v || !br_vlan_should_use(v)) 5406dada9b1SNikolay Aleksandrov goto drop; 5416dada9b1SNikolay Aleksandrov 542ae75767eSNikolay Aleksandrov if (br_opt_get(br, BROPT_VLAN_STATS_ENABLED)) { 5436dada9b1SNikolay Aleksandrov stats = this_cpu_ptr(v->stats); 5446dada9b1SNikolay Aleksandrov u64_stats_update_begin(&stats->syncp); 5456dada9b1SNikolay Aleksandrov stats->rx_bytes += skb->len; 5466dada9b1SNikolay Aleksandrov stats->rx_packets++; 5476dada9b1SNikolay Aleksandrov u64_stats_update_end(&stats->syncp); 5486dada9b1SNikolay Aleksandrov } 5496dada9b1SNikolay Aleksandrov 550a37b85c9SVlad Yasevich return true; 5516dada9b1SNikolay Aleksandrov 552eb707618SToshiaki Makita drop: 553eb707618SToshiaki Makita kfree_skb(skb); 554a37b85c9SVlad Yasevich return false; 555a37b85c9SVlad Yasevich } 556a37b85c9SVlad Yasevich 55777751ee8SNikolay Aleksandrov bool br_allowed_ingress(const struct net_bridge *br, 55877751ee8SNikolay Aleksandrov struct net_bridge_vlan_group *vg, struct sk_buff *skb, 5592594e906SNikolay Aleksandrov u16 *vid) 5602594e906SNikolay Aleksandrov { 5612594e906SNikolay Aleksandrov /* If VLAN filtering is disabled on the bridge, all packets are 5622594e906SNikolay Aleksandrov * permitted. 5632594e906SNikolay Aleksandrov */ 564ae75767eSNikolay Aleksandrov if (!br_opt_get(br, BROPT_VLAN_ENABLED)) { 5652594e906SNikolay Aleksandrov BR_INPUT_SKB_CB(skb)->vlan_filtered = false; 5662594e906SNikolay Aleksandrov return true; 5672594e906SNikolay Aleksandrov } 5682594e906SNikolay Aleksandrov 5696dada9b1SNikolay Aleksandrov return __allowed_ingress(br, vg, skb, vid); 5702594e906SNikolay Aleksandrov } 5712594e906SNikolay Aleksandrov 57285f46c6bSVlad Yasevich /* Called under RCU. */ 5732594e906SNikolay Aleksandrov bool br_allowed_egress(struct net_bridge_vlan_group *vg, 57485f46c6bSVlad Yasevich const struct sk_buff *skb) 57585f46c6bSVlad Yasevich { 5762594e906SNikolay Aleksandrov const struct net_bridge_vlan *v; 57785f46c6bSVlad Yasevich u16 vid; 57885f46c6bSVlad Yasevich 57920adfa1aSVlad Yasevich /* If this packet was not filtered at input, let it pass */ 58020adfa1aSVlad Yasevich if (!BR_INPUT_SKB_CB(skb)->vlan_filtered) 58185f46c6bSVlad Yasevich return true; 58285f46c6bSVlad Yasevich 58385f46c6bSVlad Yasevich br_vlan_get_tag(skb, &vid); 5842594e906SNikolay Aleksandrov v = br_vlan_find(vg, vid); 5852594e906SNikolay Aleksandrov if (v && br_vlan_should_use(v)) 58685f46c6bSVlad Yasevich return true; 58785f46c6bSVlad Yasevich 58885f46c6bSVlad Yasevich return false; 58985f46c6bSVlad Yasevich } 59085f46c6bSVlad Yasevich 591e0d7968aSToshiaki Makita /* Called under RCU */ 592e0d7968aSToshiaki Makita bool br_should_learn(struct net_bridge_port *p, struct sk_buff *skb, u16 *vid) 593e0d7968aSToshiaki Makita { 594468e7944SNikolay Aleksandrov struct net_bridge_vlan_group *vg; 595e0d7968aSToshiaki Makita struct net_bridge *br = p->br; 596e0d7968aSToshiaki Makita 59720adfa1aSVlad Yasevich /* If filtering was disabled at input, let it pass. */ 598ae75767eSNikolay Aleksandrov if (!br_opt_get(br, BROPT_VLAN_ENABLED)) 599e0d7968aSToshiaki Makita return true; 600e0d7968aSToshiaki Makita 601eca1e006SIdo Schimmel vg = nbp_vlan_group_rcu(p); 602468e7944SNikolay Aleksandrov if (!vg || !vg->num_vlans) 603e0d7968aSToshiaki Makita return false; 604e0d7968aSToshiaki Makita 6058580e211SToshiaki Makita if (!br_vlan_get_tag(skb, vid) && skb->vlan_proto != br->vlan_proto) 6068580e211SToshiaki Makita *vid = 0; 6078580e211SToshiaki Makita 608e0d7968aSToshiaki Makita if (!*vid) { 60977751ee8SNikolay Aleksandrov *vid = br_get_pvid(vg); 6103df6bf45SVlad Yasevich if (!*vid) 611e0d7968aSToshiaki Makita return false; 612e0d7968aSToshiaki Makita 613e0d7968aSToshiaki Makita return true; 614e0d7968aSToshiaki Makita } 615e0d7968aSToshiaki Makita 61677751ee8SNikolay Aleksandrov if (br_vlan_find(vg, *vid)) 617e0d7968aSToshiaki Makita return true; 618e0d7968aSToshiaki Makita 619e0d7968aSToshiaki Makita return false; 620e0d7968aSToshiaki Makita } 621e0d7968aSToshiaki Makita 622dbd6dc75SPetr Machata static int br_vlan_add_existing(struct net_bridge *br, 623dbd6dc75SPetr Machata struct net_bridge_vlan_group *vg, 624dbd6dc75SPetr Machata struct net_bridge_vlan *vlan, 625169327d5SPetr Machata u16 flags, bool *changed, 626169327d5SPetr Machata struct netlink_ext_ack *extack) 627dbd6dc75SPetr Machata { 628dbd6dc75SPetr Machata int err; 629dbd6dc75SPetr Machata 630169327d5SPetr Machata err = br_switchdev_port_vlan_add(br->dev, vlan->vid, flags, extack); 6319c86ce2cSPetr Machata if (err && err != -EOPNOTSUPP) 6329c86ce2cSPetr Machata return err; 6339c86ce2cSPetr Machata 634dbd6dc75SPetr Machata if (!br_vlan_is_brentry(vlan)) { 635dbd6dc75SPetr Machata /* Trying to change flags of non-existent bridge vlan */ 6369c86ce2cSPetr Machata if (!(flags & BRIDGE_VLAN_INFO_BRENTRY)) { 6379c86ce2cSPetr Machata err = -EINVAL; 6389c86ce2cSPetr Machata goto err_flags; 6399c86ce2cSPetr Machata } 640dbd6dc75SPetr Machata /* It was only kept for port vlans, now make it real */ 641dbd6dc75SPetr Machata err = br_fdb_insert(br, NULL, br->dev->dev_addr, 642dbd6dc75SPetr Machata vlan->vid); 643dbd6dc75SPetr Machata if (err) { 644dbd6dc75SPetr Machata br_err(br, "failed to insert local address into bridge forwarding table\n"); 6459c86ce2cSPetr Machata goto err_fdb_insert; 646dbd6dc75SPetr Machata } 647dbd6dc75SPetr Machata 648dbd6dc75SPetr Machata refcount_inc(&vlan->refcnt); 649dbd6dc75SPetr Machata vlan->flags |= BRIDGE_VLAN_INFO_BRENTRY; 650dbd6dc75SPetr Machata vg->num_vlans++; 651dbd6dc75SPetr Machata *changed = true; 652dbd6dc75SPetr Machata } 653dbd6dc75SPetr Machata 654dbd6dc75SPetr Machata if (__vlan_add_flags(vlan, flags)) 655dbd6dc75SPetr Machata *changed = true; 656dbd6dc75SPetr Machata 657dbd6dc75SPetr Machata return 0; 6589c86ce2cSPetr Machata 6599c86ce2cSPetr Machata err_fdb_insert: 6609c86ce2cSPetr Machata err_flags: 6619c86ce2cSPetr Machata br_switchdev_port_vlan_del(br->dev, vlan->vid); 6629c86ce2cSPetr Machata return err; 663dbd6dc75SPetr Machata } 664dbd6dc75SPetr Machata 6658adff41cSToshiaki Makita /* Must be protected by RTNL. 6668adff41cSToshiaki Makita * Must be called with vid in range from 1 to 4094 inclusive. 667f418af63SNikolay Aleksandrov * changed must be true only if the vlan was created or updated 6688adff41cSToshiaki Makita */ 669169327d5SPetr Machata int br_vlan_add(struct net_bridge *br, u16 vid, u16 flags, bool *changed, 670169327d5SPetr Machata struct netlink_ext_ack *extack) 671243a2e63SVlad Yasevich { 672907b1e6eSNikolay Aleksandrov struct net_bridge_vlan_group *vg; 6732594e906SNikolay Aleksandrov struct net_bridge_vlan *vlan; 6742594e906SNikolay Aleksandrov int ret; 675243a2e63SVlad Yasevich 676243a2e63SVlad Yasevich ASSERT_RTNL(); 677243a2e63SVlad Yasevich 678f418af63SNikolay Aleksandrov *changed = false; 679907b1e6eSNikolay Aleksandrov vg = br_vlan_group(br); 680907b1e6eSNikolay Aleksandrov vlan = br_vlan_find(vg, vid); 681dbd6dc75SPetr Machata if (vlan) 682169327d5SPetr Machata return br_vlan_add_existing(br, vg, vlan, flags, changed, 683169327d5SPetr Machata extack); 684243a2e63SVlad Yasevich 6852594e906SNikolay Aleksandrov vlan = kzalloc(sizeof(*vlan), GFP_KERNEL); 6862594e906SNikolay Aleksandrov if (!vlan) 687243a2e63SVlad Yasevich return -ENOMEM; 688243a2e63SVlad Yasevich 6896dada9b1SNikolay Aleksandrov vlan->stats = netdev_alloc_pcpu_stats(struct br_vlan_stats); 6906dada9b1SNikolay Aleksandrov if (!vlan->stats) { 6916dada9b1SNikolay Aleksandrov kfree(vlan); 6926dada9b1SNikolay Aleksandrov return -ENOMEM; 6936dada9b1SNikolay Aleksandrov } 6942594e906SNikolay Aleksandrov vlan->vid = vid; 6952594e906SNikolay Aleksandrov vlan->flags = flags | BRIDGE_VLAN_INFO_MASTER; 6962594e906SNikolay Aleksandrov vlan->flags &= ~BRIDGE_VLAN_INFO_PVID; 6972594e906SNikolay Aleksandrov vlan->br = br; 6982594e906SNikolay Aleksandrov if (flags & BRIDGE_VLAN_INFO_BRENTRY) 69925127759SReshetova, Elena refcount_set(&vlan->refcnt, 1); 700169327d5SPetr Machata ret = __vlan_add(vlan, flags, extack); 7016dada9b1SNikolay Aleksandrov if (ret) { 7026dada9b1SNikolay Aleksandrov free_percpu(vlan->stats); 7032594e906SNikolay Aleksandrov kfree(vlan); 704f418af63SNikolay Aleksandrov } else { 705f418af63SNikolay Aleksandrov *changed = true; 7066dada9b1SNikolay Aleksandrov } 707243a2e63SVlad Yasevich 7082594e906SNikolay Aleksandrov return ret; 709243a2e63SVlad Yasevich } 710243a2e63SVlad Yasevich 7118adff41cSToshiaki Makita /* Must be protected by RTNL. 7128adff41cSToshiaki Makita * Must be called with vid in range from 1 to 4094 inclusive. 7138adff41cSToshiaki Makita */ 714243a2e63SVlad Yasevich int br_vlan_delete(struct net_bridge *br, u16 vid) 715243a2e63SVlad Yasevich { 716907b1e6eSNikolay Aleksandrov struct net_bridge_vlan_group *vg; 7172594e906SNikolay Aleksandrov struct net_bridge_vlan *v; 718243a2e63SVlad Yasevich 719243a2e63SVlad Yasevich ASSERT_RTNL(); 720243a2e63SVlad Yasevich 721907b1e6eSNikolay Aleksandrov vg = br_vlan_group(br); 722907b1e6eSNikolay Aleksandrov v = br_vlan_find(vg, vid); 7232594e906SNikolay Aleksandrov if (!v || !br_vlan_is_brentry(v)) 7242594e906SNikolay Aleksandrov return -ENOENT; 725243a2e63SVlad Yasevich 726424bb9c9SToshiaki Makita br_fdb_find_delete_local(br, NULL, br->dev->dev_addr, vid); 7273741873bSRoopa Prabhu br_fdb_delete_by_port(br, NULL, vid, 0); 728bc9a25d2SVlad Yasevich 729efa5356bSRoopa Prabhu vlan_tunnel_info_del(vg, v); 730efa5356bSRoopa Prabhu 7312594e906SNikolay Aleksandrov return __vlan_del(v); 732243a2e63SVlad Yasevich } 733243a2e63SVlad Yasevich 734243a2e63SVlad Yasevich void br_vlan_flush(struct net_bridge *br) 735243a2e63SVlad Yasevich { 736f409d0edSNikolay Aleksandrov struct net_bridge_vlan_group *vg; 737f409d0edSNikolay Aleksandrov 738243a2e63SVlad Yasevich ASSERT_RTNL(); 739243a2e63SVlad Yasevich 740f409d0edSNikolay Aleksandrov vg = br_vlan_group(br); 741f545923bSNikolay Aleksandrov __vlan_flush(br, NULL, vg); 742f409d0edSNikolay Aleksandrov RCU_INIT_POINTER(br->vlgrp, NULL); 743f409d0edSNikolay Aleksandrov synchronize_rcu(); 744f409d0edSNikolay Aleksandrov __vlan_group_free(vg); 745243a2e63SVlad Yasevich } 746243a2e63SVlad Yasevich 7472594e906SNikolay Aleksandrov struct net_bridge_vlan *br_vlan_find(struct net_bridge_vlan_group *vg, u16 vid) 7482b292fb4SToshiaki Makita { 7492594e906SNikolay Aleksandrov if (!vg) 7502594e906SNikolay Aleksandrov return NULL; 7512b292fb4SToshiaki Makita 7522594e906SNikolay Aleksandrov return br_vlan_lookup(&vg->vlan_hash, vid); 7532b292fb4SToshiaki Makita } 7542b292fb4SToshiaki Makita 755204177f3SToshiaki Makita /* Must be protected by RTNL. */ 756204177f3SToshiaki Makita static void recalculate_group_addr(struct net_bridge *br) 757204177f3SToshiaki Makita { 758be3664a0SNikolay Aleksandrov if (br_opt_get(br, BROPT_GROUP_ADDR_SET)) 759204177f3SToshiaki Makita return; 760204177f3SToshiaki Makita 761204177f3SToshiaki Makita spin_lock_bh(&br->lock); 762ae75767eSNikolay Aleksandrov if (!br_opt_get(br, BROPT_VLAN_ENABLED) || 763ae75767eSNikolay Aleksandrov br->vlan_proto == htons(ETH_P_8021Q)) { 764204177f3SToshiaki Makita /* Bridge Group Address */ 765204177f3SToshiaki Makita br->group_addr[5] = 0x00; 766204177f3SToshiaki Makita } else { /* vlan_enabled && ETH_P_8021AD */ 767204177f3SToshiaki Makita /* Provider Bridge Group Address */ 768204177f3SToshiaki Makita br->group_addr[5] = 0x08; 769204177f3SToshiaki Makita } 770204177f3SToshiaki Makita spin_unlock_bh(&br->lock); 771204177f3SToshiaki Makita } 772204177f3SToshiaki Makita 773204177f3SToshiaki Makita /* Must be protected by RTNL. */ 774204177f3SToshiaki Makita void br_recalculate_fwd_mask(struct net_bridge *br) 775204177f3SToshiaki Makita { 776ae75767eSNikolay Aleksandrov if (!br_opt_get(br, BROPT_VLAN_ENABLED) || 777ae75767eSNikolay Aleksandrov br->vlan_proto == htons(ETH_P_8021Q)) 778204177f3SToshiaki Makita br->group_fwd_mask_required = BR_GROUPFWD_DEFAULT; 779204177f3SToshiaki Makita else /* vlan_enabled && ETH_P_8021AD */ 780204177f3SToshiaki Makita br->group_fwd_mask_required = BR_GROUPFWD_8021AD & 781204177f3SToshiaki Makita ~(1u << br->group_addr[5]); 782204177f3SToshiaki Makita } 783204177f3SToshiaki Makita 784a7854037SNikolay Aleksandrov int __br_vlan_filter_toggle(struct net_bridge *br, unsigned long val) 785243a2e63SVlad Yasevich { 7866b72a770SElad Raz struct switchdev_attr attr = { 7876b72a770SElad Raz .orig_dev = br->dev, 7886b72a770SElad Raz .id = SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING, 7896b72a770SElad Raz .flags = SWITCHDEV_F_SKIP_EOPNOTSUPP, 7906b72a770SElad Raz .u.vlan_filtering = val, 7916b72a770SElad Raz }; 7926b72a770SElad Raz int err; 7936b72a770SElad Raz 794ae75767eSNikolay Aleksandrov if (br_opt_get(br, BROPT_VLAN_ENABLED) == !!val) 795a7854037SNikolay Aleksandrov return 0; 796243a2e63SVlad Yasevich 7976b72a770SElad Raz err = switchdev_port_attr_set(br->dev, &attr); 7986b72a770SElad Raz if (err && err != -EOPNOTSUPP) 7996b72a770SElad Raz return err; 8006b72a770SElad Raz 801ae75767eSNikolay Aleksandrov br_opt_toggle(br, BROPT_VLAN_ENABLED, !!val); 8022796d0c6SVlad Yasevich br_manage_promisc(br); 803204177f3SToshiaki Makita recalculate_group_addr(br); 804204177f3SToshiaki Makita br_recalculate_fwd_mask(br); 805243a2e63SVlad Yasevich 806a7854037SNikolay Aleksandrov return 0; 807a7854037SNikolay Aleksandrov } 808a7854037SNikolay Aleksandrov 809a7854037SNikolay Aleksandrov int br_vlan_filter_toggle(struct net_bridge *br, unsigned long val) 810a7854037SNikolay Aleksandrov { 811047831a9SXin Long return __br_vlan_filter_toggle(br, val); 812243a2e63SVlad Yasevich } 813243a2e63SVlad Yasevich 8141f51445aSIdo Schimmel bool br_vlan_enabled(const struct net_device *dev) 8151f51445aSIdo Schimmel { 8161f51445aSIdo Schimmel struct net_bridge *br = netdev_priv(dev); 8171f51445aSIdo Schimmel 818ae75767eSNikolay Aleksandrov return br_opt_get(br, BROPT_VLAN_ENABLED); 8191f51445aSIdo Schimmel } 8201f51445aSIdo Schimmel EXPORT_SYMBOL_GPL(br_vlan_enabled); 8211f51445aSIdo Schimmel 82231aed46fSwenxu int br_vlan_get_proto(const struct net_device *dev, u16 *p_proto) 82331aed46fSwenxu { 82431aed46fSwenxu struct net_bridge *br = netdev_priv(dev); 82531aed46fSwenxu 82631aed46fSwenxu *p_proto = ntohs(br->vlan_proto); 82731aed46fSwenxu 82831aed46fSwenxu return 0; 82931aed46fSwenxu } 83031aed46fSwenxu EXPORT_SYMBOL_GPL(br_vlan_get_proto); 83131aed46fSwenxu 832d2d427b3SToshiaki Makita int __br_vlan_set_proto(struct net_bridge *br, __be16 proto) 833204177f3SToshiaki Makita { 834204177f3SToshiaki Makita int err = 0; 835204177f3SToshiaki Makita struct net_bridge_port *p; 8362594e906SNikolay Aleksandrov struct net_bridge_vlan *vlan; 837907b1e6eSNikolay Aleksandrov struct net_bridge_vlan_group *vg; 838d2d427b3SToshiaki Makita __be16 oldproto; 839204177f3SToshiaki Makita 840204177f3SToshiaki Makita if (br->vlan_proto == proto) 841d2d427b3SToshiaki Makita return 0; 842204177f3SToshiaki Makita 843204177f3SToshiaki Makita /* Add VLANs for the new proto to the device filter. */ 844204177f3SToshiaki Makita list_for_each_entry(p, &br->port_list, list) { 845907b1e6eSNikolay Aleksandrov vg = nbp_vlan_group(p); 846907b1e6eSNikolay Aleksandrov list_for_each_entry(vlan, &vg->vlan_list, vlist) { 8472594e906SNikolay Aleksandrov err = vlan_vid_add(p->dev, proto, vlan->vid); 848204177f3SToshiaki Makita if (err) 849204177f3SToshiaki Makita goto err_filt; 850204177f3SToshiaki Makita } 851204177f3SToshiaki Makita } 852204177f3SToshiaki Makita 853204177f3SToshiaki Makita oldproto = br->vlan_proto; 854204177f3SToshiaki Makita br->vlan_proto = proto; 855204177f3SToshiaki Makita 856204177f3SToshiaki Makita recalculate_group_addr(br); 857204177f3SToshiaki Makita br_recalculate_fwd_mask(br); 858204177f3SToshiaki Makita 859204177f3SToshiaki Makita /* Delete VLANs for the old proto from the device filter. */ 860907b1e6eSNikolay Aleksandrov list_for_each_entry(p, &br->port_list, list) { 861907b1e6eSNikolay Aleksandrov vg = nbp_vlan_group(p); 862907b1e6eSNikolay Aleksandrov list_for_each_entry(vlan, &vg->vlan_list, vlist) 8632594e906SNikolay Aleksandrov vlan_vid_del(p->dev, oldproto, vlan->vid); 864907b1e6eSNikolay Aleksandrov } 865204177f3SToshiaki Makita 866d2d427b3SToshiaki Makita return 0; 867204177f3SToshiaki Makita 868204177f3SToshiaki Makita err_filt: 869907b1e6eSNikolay Aleksandrov list_for_each_entry_continue_reverse(vlan, &vg->vlan_list, vlist) 8702594e906SNikolay Aleksandrov vlan_vid_del(p->dev, proto, vlan->vid); 871204177f3SToshiaki Makita 872907b1e6eSNikolay Aleksandrov list_for_each_entry_continue_reverse(p, &br->port_list, list) { 873907b1e6eSNikolay Aleksandrov vg = nbp_vlan_group(p); 874907b1e6eSNikolay Aleksandrov list_for_each_entry(vlan, &vg->vlan_list, vlist) 8752594e906SNikolay Aleksandrov vlan_vid_del(p->dev, proto, vlan->vid); 876907b1e6eSNikolay Aleksandrov } 877204177f3SToshiaki Makita 878d2d427b3SToshiaki Makita return err; 879d2d427b3SToshiaki Makita } 880d2d427b3SToshiaki Makita 881d2d427b3SToshiaki Makita int br_vlan_set_proto(struct net_bridge *br, unsigned long val) 882d2d427b3SToshiaki Makita { 883d2d427b3SToshiaki Makita if (val != ETH_P_8021Q && val != ETH_P_8021AD) 884d2d427b3SToshiaki Makita return -EPROTONOSUPPORT; 885d2d427b3SToshiaki Makita 886047831a9SXin Long return __br_vlan_set_proto(br, htons(val)); 887204177f3SToshiaki Makita } 888204177f3SToshiaki Makita 8896dada9b1SNikolay Aleksandrov int br_vlan_set_stats(struct net_bridge *br, unsigned long val) 8906dada9b1SNikolay Aleksandrov { 8916dada9b1SNikolay Aleksandrov switch (val) { 8926dada9b1SNikolay Aleksandrov case 0: 8936dada9b1SNikolay Aleksandrov case 1: 894ae75767eSNikolay Aleksandrov br_opt_toggle(br, BROPT_VLAN_STATS_ENABLED, !!val); 8956dada9b1SNikolay Aleksandrov break; 8966dada9b1SNikolay Aleksandrov default: 8976dada9b1SNikolay Aleksandrov return -EINVAL; 8986dada9b1SNikolay Aleksandrov } 8996dada9b1SNikolay Aleksandrov 9006dada9b1SNikolay Aleksandrov return 0; 9016dada9b1SNikolay Aleksandrov } 9026dada9b1SNikolay Aleksandrov 9039163a0fcSNikolay Aleksandrov int br_vlan_set_stats_per_port(struct net_bridge *br, unsigned long val) 9049163a0fcSNikolay Aleksandrov { 9059163a0fcSNikolay Aleksandrov struct net_bridge_port *p; 9069163a0fcSNikolay Aleksandrov 9079163a0fcSNikolay Aleksandrov /* allow to change the option if there are no port vlans configured */ 9089163a0fcSNikolay Aleksandrov list_for_each_entry(p, &br->port_list, list) { 9099163a0fcSNikolay Aleksandrov struct net_bridge_vlan_group *vg = nbp_vlan_group(p); 9109163a0fcSNikolay Aleksandrov 9119163a0fcSNikolay Aleksandrov if (vg->num_vlans) 9129163a0fcSNikolay Aleksandrov return -EBUSY; 9139163a0fcSNikolay Aleksandrov } 9149163a0fcSNikolay Aleksandrov 9159163a0fcSNikolay Aleksandrov switch (val) { 9169163a0fcSNikolay Aleksandrov case 0: 9179163a0fcSNikolay Aleksandrov case 1: 9189163a0fcSNikolay Aleksandrov br_opt_toggle(br, BROPT_VLAN_STATS_PER_PORT, !!val); 9199163a0fcSNikolay Aleksandrov break; 9209163a0fcSNikolay Aleksandrov default: 9219163a0fcSNikolay Aleksandrov return -EINVAL; 9229163a0fcSNikolay Aleksandrov } 9239163a0fcSNikolay Aleksandrov 9249163a0fcSNikolay Aleksandrov return 0; 9259163a0fcSNikolay Aleksandrov } 9269163a0fcSNikolay Aleksandrov 92777751ee8SNikolay Aleksandrov static bool vlan_default_pvid(struct net_bridge_vlan_group *vg, u16 vid) 9285be5a2dfSVlad Yasevich { 9292594e906SNikolay Aleksandrov struct net_bridge_vlan *v; 9302594e906SNikolay Aleksandrov 93177751ee8SNikolay Aleksandrov if (vid != vg->pvid) 9322594e906SNikolay Aleksandrov return false; 9332594e906SNikolay Aleksandrov 9342594e906SNikolay Aleksandrov v = br_vlan_lookup(&vg->vlan_hash, vid); 9352594e906SNikolay Aleksandrov if (v && br_vlan_should_use(v) && 9362594e906SNikolay Aleksandrov (v->flags & BRIDGE_VLAN_INFO_UNTAGGED)) 9372594e906SNikolay Aleksandrov return true; 9382594e906SNikolay Aleksandrov 9392594e906SNikolay Aleksandrov return false; 9405be5a2dfSVlad Yasevich } 9415be5a2dfSVlad Yasevich 9425be5a2dfSVlad Yasevich static void br_vlan_disable_default_pvid(struct net_bridge *br) 9435be5a2dfSVlad Yasevich { 9445be5a2dfSVlad Yasevich struct net_bridge_port *p; 9455be5a2dfSVlad Yasevich u16 pvid = br->default_pvid; 9465be5a2dfSVlad Yasevich 9475be5a2dfSVlad Yasevich /* Disable default_pvid on all ports where it is still 9485be5a2dfSVlad Yasevich * configured. 9495be5a2dfSVlad Yasevich */ 950f545923bSNikolay Aleksandrov if (vlan_default_pvid(br_vlan_group(br), pvid)) { 951f545923bSNikolay Aleksandrov if (!br_vlan_delete(br, pvid)) 952f545923bSNikolay Aleksandrov br_vlan_notify(br, NULL, pvid, 0, RTM_DELVLAN); 953f545923bSNikolay Aleksandrov } 9545be5a2dfSVlad Yasevich 9555be5a2dfSVlad Yasevich list_for_each_entry(p, &br->port_list, list) { 956f545923bSNikolay Aleksandrov if (vlan_default_pvid(nbp_vlan_group(p), pvid) && 957f545923bSNikolay Aleksandrov !nbp_vlan_delete(p, pvid)) 958f545923bSNikolay Aleksandrov br_vlan_notify(br, p, pvid, 0, RTM_DELVLAN); 9595be5a2dfSVlad Yasevich } 9605be5a2dfSVlad Yasevich 9615be5a2dfSVlad Yasevich br->default_pvid = 0; 9625be5a2dfSVlad Yasevich } 9635be5a2dfSVlad Yasevich 964169327d5SPetr Machata int __br_vlan_set_default_pvid(struct net_bridge *br, u16 pvid, 965169327d5SPetr Machata struct netlink_ext_ack *extack) 9665be5a2dfSVlad Yasevich { 9672594e906SNikolay Aleksandrov const struct net_bridge_vlan *pvent; 968907b1e6eSNikolay Aleksandrov struct net_bridge_vlan_group *vg; 9695be5a2dfSVlad Yasevich struct net_bridge_port *p; 970f418af63SNikolay Aleksandrov unsigned long *changed; 971f418af63SNikolay Aleksandrov bool vlchange; 9725be5a2dfSVlad Yasevich u16 old_pvid; 9735be5a2dfSVlad Yasevich int err = 0; 9745be5a2dfSVlad Yasevich 9750f963b75SNikolay Aleksandrov if (!pvid) { 9760f963b75SNikolay Aleksandrov br_vlan_disable_default_pvid(br); 9770f963b75SNikolay Aleksandrov return 0; 9780f963b75SNikolay Aleksandrov } 9790f963b75SNikolay Aleksandrov 980459479daSAndy Shevchenko changed = bitmap_zalloc(BR_MAX_PORTS, GFP_KERNEL); 9815be5a2dfSVlad Yasevich if (!changed) 9825be5a2dfSVlad Yasevich return -ENOMEM; 9835be5a2dfSVlad Yasevich 9845be5a2dfSVlad Yasevich old_pvid = br->default_pvid; 9855be5a2dfSVlad Yasevich 9865be5a2dfSVlad Yasevich /* Update default_pvid config only if we do not conflict with 9875be5a2dfSVlad Yasevich * user configuration. 9885be5a2dfSVlad Yasevich */ 989907b1e6eSNikolay Aleksandrov vg = br_vlan_group(br); 990907b1e6eSNikolay Aleksandrov pvent = br_vlan_find(vg, pvid); 991907b1e6eSNikolay Aleksandrov if ((!old_pvid || vlan_default_pvid(vg, old_pvid)) && 9922594e906SNikolay Aleksandrov (!pvent || !br_vlan_should_use(pvent))) { 9935be5a2dfSVlad Yasevich err = br_vlan_add(br, pvid, 9945be5a2dfSVlad Yasevich BRIDGE_VLAN_INFO_PVID | 9952594e906SNikolay Aleksandrov BRIDGE_VLAN_INFO_UNTAGGED | 996f418af63SNikolay Aleksandrov BRIDGE_VLAN_INFO_BRENTRY, 997169327d5SPetr Machata &vlchange, extack); 9985be5a2dfSVlad Yasevich if (err) 9995be5a2dfSVlad Yasevich goto out; 1000f545923bSNikolay Aleksandrov 1001f545923bSNikolay Aleksandrov if (br_vlan_delete(br, old_pvid)) 1002f545923bSNikolay Aleksandrov br_vlan_notify(br, NULL, old_pvid, 0, RTM_DELVLAN); 1003f545923bSNikolay Aleksandrov br_vlan_notify(br, NULL, pvid, 0, RTM_NEWVLAN); 10045be5a2dfSVlad Yasevich set_bit(0, changed); 10055be5a2dfSVlad Yasevich } 10065be5a2dfSVlad Yasevich 10075be5a2dfSVlad Yasevich list_for_each_entry(p, &br->port_list, list) { 10085be5a2dfSVlad Yasevich /* Update default_pvid config only if we do not conflict with 10095be5a2dfSVlad Yasevich * user configuration. 10105be5a2dfSVlad Yasevich */ 1011907b1e6eSNikolay Aleksandrov vg = nbp_vlan_group(p); 10125be5a2dfSVlad Yasevich if ((old_pvid && 1013907b1e6eSNikolay Aleksandrov !vlan_default_pvid(vg, old_pvid)) || 1014907b1e6eSNikolay Aleksandrov br_vlan_find(vg, pvid)) 10155be5a2dfSVlad Yasevich continue; 10165be5a2dfSVlad Yasevich 10175be5a2dfSVlad Yasevich err = nbp_vlan_add(p, pvid, 10185be5a2dfSVlad Yasevich BRIDGE_VLAN_INFO_PVID | 1019f418af63SNikolay Aleksandrov BRIDGE_VLAN_INFO_UNTAGGED, 1020169327d5SPetr Machata &vlchange, extack); 10215be5a2dfSVlad Yasevich if (err) 10225be5a2dfSVlad Yasevich goto err_port; 1023f545923bSNikolay Aleksandrov if (nbp_vlan_delete(p, old_pvid)) 1024f545923bSNikolay Aleksandrov br_vlan_notify(br, p, old_pvid, 0, RTM_DELVLAN); 1025f545923bSNikolay Aleksandrov br_vlan_notify(p->br, p, pvid, 0, RTM_NEWVLAN); 10265be5a2dfSVlad Yasevich set_bit(p->port_no, changed); 10275be5a2dfSVlad Yasevich } 10285be5a2dfSVlad Yasevich 10295be5a2dfSVlad Yasevich br->default_pvid = pvid; 10305be5a2dfSVlad Yasevich 10315be5a2dfSVlad Yasevich out: 1032459479daSAndy Shevchenko bitmap_free(changed); 10335be5a2dfSVlad Yasevich return err; 10345be5a2dfSVlad Yasevich 10355be5a2dfSVlad Yasevich err_port: 10365be5a2dfSVlad Yasevich list_for_each_entry_continue_reverse(p, &br->port_list, list) { 10375be5a2dfSVlad Yasevich if (!test_bit(p->port_no, changed)) 10385be5a2dfSVlad Yasevich continue; 10395be5a2dfSVlad Yasevich 1040f545923bSNikolay Aleksandrov if (old_pvid) { 10415be5a2dfSVlad Yasevich nbp_vlan_add(p, old_pvid, 10425be5a2dfSVlad Yasevich BRIDGE_VLAN_INFO_PVID | 1043f418af63SNikolay Aleksandrov BRIDGE_VLAN_INFO_UNTAGGED, 1044169327d5SPetr Machata &vlchange, NULL); 1045f545923bSNikolay Aleksandrov br_vlan_notify(p->br, p, old_pvid, 0, RTM_NEWVLAN); 1046f545923bSNikolay Aleksandrov } 10475be5a2dfSVlad Yasevich nbp_vlan_delete(p, pvid); 1048f545923bSNikolay Aleksandrov br_vlan_notify(br, p, pvid, 0, RTM_DELVLAN); 10495be5a2dfSVlad Yasevich } 10505be5a2dfSVlad Yasevich 10515be5a2dfSVlad Yasevich if (test_bit(0, changed)) { 1052f545923bSNikolay Aleksandrov if (old_pvid) { 10535be5a2dfSVlad Yasevich br_vlan_add(br, old_pvid, 10545be5a2dfSVlad Yasevich BRIDGE_VLAN_INFO_PVID | 10552594e906SNikolay Aleksandrov BRIDGE_VLAN_INFO_UNTAGGED | 1056f418af63SNikolay Aleksandrov BRIDGE_VLAN_INFO_BRENTRY, 1057169327d5SPetr Machata &vlchange, NULL); 1058f545923bSNikolay Aleksandrov br_vlan_notify(br, NULL, old_pvid, 0, RTM_NEWVLAN); 1059f545923bSNikolay Aleksandrov } 10605be5a2dfSVlad Yasevich br_vlan_delete(br, pvid); 1061f545923bSNikolay Aleksandrov br_vlan_notify(br, NULL, pvid, 0, RTM_DELVLAN); 10625be5a2dfSVlad Yasevich } 10635be5a2dfSVlad Yasevich goto out; 10645be5a2dfSVlad Yasevich } 10655be5a2dfSVlad Yasevich 106696a20d9dSVlad Yasevich int br_vlan_set_default_pvid(struct net_bridge *br, unsigned long val) 106796a20d9dSVlad Yasevich { 106896a20d9dSVlad Yasevich u16 pvid = val; 106996a20d9dSVlad Yasevich int err = 0; 107096a20d9dSVlad Yasevich 10715be5a2dfSVlad Yasevich if (val >= VLAN_VID_MASK) 107296a20d9dSVlad Yasevich return -EINVAL; 107396a20d9dSVlad Yasevich 107496a20d9dSVlad Yasevich if (pvid == br->default_pvid) 1075047831a9SXin Long goto out; 107696a20d9dSVlad Yasevich 107796a20d9dSVlad Yasevich /* Only allow default pvid change when filtering is disabled */ 1078ae75767eSNikolay Aleksandrov if (br_opt_get(br, BROPT_VLAN_ENABLED)) { 107996a20d9dSVlad Yasevich pr_info_once("Please disable vlan filtering to change default_pvid\n"); 108096a20d9dSVlad Yasevich err = -EPERM; 1081047831a9SXin Long goto out; 108296a20d9dSVlad Yasevich } 1083169327d5SPetr Machata err = __br_vlan_set_default_pvid(br, pvid, NULL); 1084047831a9SXin Long out: 108596a20d9dSVlad Yasevich return err; 108696a20d9dSVlad Yasevich } 108796a20d9dSVlad Yasevich 10885be5a2dfSVlad Yasevich int br_vlan_init(struct net_bridge *br) 10898580e211SToshiaki Makita { 1090907b1e6eSNikolay Aleksandrov struct net_bridge_vlan_group *vg; 10912594e906SNikolay Aleksandrov int ret = -ENOMEM; 10922594e906SNikolay Aleksandrov 1093907b1e6eSNikolay Aleksandrov vg = kzalloc(sizeof(*vg), GFP_KERNEL); 1094907b1e6eSNikolay Aleksandrov if (!vg) 10952594e906SNikolay Aleksandrov goto out; 1096907b1e6eSNikolay Aleksandrov ret = rhashtable_init(&vg->vlan_hash, &br_vlan_rht_params); 10972594e906SNikolay Aleksandrov if (ret) 10982594e906SNikolay Aleksandrov goto err_rhtbl; 1099efa5356bSRoopa Prabhu ret = vlan_tunnel_init(vg); 1100efa5356bSRoopa Prabhu if (ret) 1101efa5356bSRoopa Prabhu goto err_tunnel_init; 1102907b1e6eSNikolay Aleksandrov INIT_LIST_HEAD(&vg->vlan_list); 11038580e211SToshiaki Makita br->vlan_proto = htons(ETH_P_8021Q); 110496a20d9dSVlad Yasevich br->default_pvid = 1; 1105907b1e6eSNikolay Aleksandrov rcu_assign_pointer(br->vlgrp, vg); 11062594e906SNikolay Aleksandrov 11072594e906SNikolay Aleksandrov out: 11082594e906SNikolay Aleksandrov return ret; 11092594e906SNikolay Aleksandrov 1110efa5356bSRoopa Prabhu err_tunnel_init: 1111907b1e6eSNikolay Aleksandrov rhashtable_destroy(&vg->vlan_hash); 11122594e906SNikolay Aleksandrov err_rhtbl: 1113907b1e6eSNikolay Aleksandrov kfree(vg); 11142594e906SNikolay Aleksandrov 11152594e906SNikolay Aleksandrov goto out; 11162594e906SNikolay Aleksandrov } 11172594e906SNikolay Aleksandrov 1118169327d5SPetr Machata int nbp_vlan_init(struct net_bridge_port *p, struct netlink_ext_ack *extack) 11192594e906SNikolay Aleksandrov { 1120404cdbf0SElad Raz struct switchdev_attr attr = { 1121404cdbf0SElad Raz .orig_dev = p->br->dev, 1122404cdbf0SElad Raz .id = SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING, 1123404cdbf0SElad Raz .flags = SWITCHDEV_F_SKIP_EOPNOTSUPP, 1124ae75767eSNikolay Aleksandrov .u.vlan_filtering = br_opt_get(p->br, BROPT_VLAN_ENABLED), 1125404cdbf0SElad Raz }; 1126263344e6SNikolay Aleksandrov struct net_bridge_vlan_group *vg; 11272594e906SNikolay Aleksandrov int ret = -ENOMEM; 11282594e906SNikolay Aleksandrov 1129263344e6SNikolay Aleksandrov vg = kzalloc(sizeof(struct net_bridge_vlan_group), GFP_KERNEL); 1130263344e6SNikolay Aleksandrov if (!vg) 11312594e906SNikolay Aleksandrov goto out; 11322594e906SNikolay Aleksandrov 1133404cdbf0SElad Raz ret = switchdev_port_attr_set(p->dev, &attr); 1134404cdbf0SElad Raz if (ret && ret != -EOPNOTSUPP) 1135404cdbf0SElad Raz goto err_vlan_enabled; 1136404cdbf0SElad Raz 1137263344e6SNikolay Aleksandrov ret = rhashtable_init(&vg->vlan_hash, &br_vlan_rht_params); 11382594e906SNikolay Aleksandrov if (ret) 11392594e906SNikolay Aleksandrov goto err_rhtbl; 1140efa5356bSRoopa Prabhu ret = vlan_tunnel_init(vg); 1141efa5356bSRoopa Prabhu if (ret) 1142efa5356bSRoopa Prabhu goto err_tunnel_init; 1143263344e6SNikolay Aleksandrov INIT_LIST_HEAD(&vg->vlan_list); 1144907b1e6eSNikolay Aleksandrov rcu_assign_pointer(p->vlgrp, vg); 11452594e906SNikolay Aleksandrov if (p->br->default_pvid) { 1146f418af63SNikolay Aleksandrov bool changed; 1147f418af63SNikolay Aleksandrov 11482594e906SNikolay Aleksandrov ret = nbp_vlan_add(p, p->br->default_pvid, 11492594e906SNikolay Aleksandrov BRIDGE_VLAN_INFO_PVID | 1150f418af63SNikolay Aleksandrov BRIDGE_VLAN_INFO_UNTAGGED, 1151169327d5SPetr Machata &changed, extack); 11522594e906SNikolay Aleksandrov if (ret) 11532594e906SNikolay Aleksandrov goto err_vlan_add; 1154f545923bSNikolay Aleksandrov br_vlan_notify(p->br, p, p->br->default_pvid, 0, RTM_NEWVLAN); 11552594e906SNikolay Aleksandrov } 11562594e906SNikolay Aleksandrov out: 11572594e906SNikolay Aleksandrov return ret; 11582594e906SNikolay Aleksandrov 11592594e906SNikolay Aleksandrov err_vlan_add: 116007bc588fSIdo Schimmel RCU_INIT_POINTER(p->vlgrp, NULL); 116107bc588fSIdo Schimmel synchronize_rcu(); 1162efa5356bSRoopa Prabhu vlan_tunnel_deinit(vg); 1163efa5356bSRoopa Prabhu err_tunnel_init: 1164efa5356bSRoopa Prabhu rhashtable_destroy(&vg->vlan_hash); 11652594e906SNikolay Aleksandrov err_rhtbl: 1166df2c4334SYotam Gigi err_vlan_enabled: 1167263344e6SNikolay Aleksandrov kfree(vg); 11682594e906SNikolay Aleksandrov 11692594e906SNikolay Aleksandrov goto out; 11708580e211SToshiaki Makita } 11718580e211SToshiaki Makita 11728adff41cSToshiaki Makita /* Must be protected by RTNL. 11738adff41cSToshiaki Makita * Must be called with vid in range from 1 to 4094 inclusive. 1174f418af63SNikolay Aleksandrov * changed must be true only if the vlan was created or updated 11758adff41cSToshiaki Makita */ 1176f418af63SNikolay Aleksandrov int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags, 1177169327d5SPetr Machata bool *changed, struct netlink_ext_ack *extack) 1178243a2e63SVlad Yasevich { 11792594e906SNikolay Aleksandrov struct net_bridge_vlan *vlan; 11802594e906SNikolay Aleksandrov int ret; 1181243a2e63SVlad Yasevich 1182243a2e63SVlad Yasevich ASSERT_RTNL(); 1183243a2e63SVlad Yasevich 1184f418af63SNikolay Aleksandrov *changed = false; 1185907b1e6eSNikolay Aleksandrov vlan = br_vlan_find(nbp_vlan_group(port), vid); 11862594e906SNikolay Aleksandrov if (vlan) { 11877fbac984SIdo Schimmel /* Pass the flags to the hardware bridge */ 1188169327d5SPetr Machata ret = br_switchdev_port_vlan_add(port->dev, vid, flags, extack); 11897fbac984SIdo Schimmel if (ret && ret != -EOPNOTSUPP) 11907fbac984SIdo Schimmel return ret; 1191f418af63SNikolay Aleksandrov *changed = __vlan_add_flags(vlan, flags); 1192f418af63SNikolay Aleksandrov 11932594e906SNikolay Aleksandrov return 0; 1194243a2e63SVlad Yasevich } 1195243a2e63SVlad Yasevich 11962594e906SNikolay Aleksandrov vlan = kzalloc(sizeof(*vlan), GFP_KERNEL); 11972594e906SNikolay Aleksandrov if (!vlan) 11982594e906SNikolay Aleksandrov return -ENOMEM; 1199243a2e63SVlad Yasevich 12002594e906SNikolay Aleksandrov vlan->vid = vid; 12012594e906SNikolay Aleksandrov vlan->port = port; 1202169327d5SPetr Machata ret = __vlan_add(vlan, flags, extack); 12032594e906SNikolay Aleksandrov if (ret) 12042594e906SNikolay Aleksandrov kfree(vlan); 1205f418af63SNikolay Aleksandrov else 1206f418af63SNikolay Aleksandrov *changed = true; 1207243a2e63SVlad Yasevich 12082594e906SNikolay Aleksandrov return ret; 1209243a2e63SVlad Yasevich } 1210243a2e63SVlad Yasevich 12118adff41cSToshiaki Makita /* Must be protected by RTNL. 12128adff41cSToshiaki Makita * Must be called with vid in range from 1 to 4094 inclusive. 12138adff41cSToshiaki Makita */ 1214243a2e63SVlad Yasevich int nbp_vlan_delete(struct net_bridge_port *port, u16 vid) 1215243a2e63SVlad Yasevich { 12162594e906SNikolay Aleksandrov struct net_bridge_vlan *v; 1217243a2e63SVlad Yasevich 1218243a2e63SVlad Yasevich ASSERT_RTNL(); 1219243a2e63SVlad Yasevich 1220907b1e6eSNikolay Aleksandrov v = br_vlan_find(nbp_vlan_group(port), vid); 12212594e906SNikolay Aleksandrov if (!v) 12222594e906SNikolay Aleksandrov return -ENOENT; 1223424bb9c9SToshiaki Makita br_fdb_find_delete_local(port->br, port, port->dev->dev_addr, vid); 12241ea2d020SNikolay Aleksandrov br_fdb_delete_by_port(port->br, port, vid, 0); 1225bc9a25d2SVlad Yasevich 12262594e906SNikolay Aleksandrov return __vlan_del(v); 1227243a2e63SVlad Yasevich } 1228243a2e63SVlad Yasevich 1229243a2e63SVlad Yasevich void nbp_vlan_flush(struct net_bridge_port *port) 1230243a2e63SVlad Yasevich { 1231f409d0edSNikolay Aleksandrov struct net_bridge_vlan_group *vg; 1232f409d0edSNikolay Aleksandrov 1233243a2e63SVlad Yasevich ASSERT_RTNL(); 1234243a2e63SVlad Yasevich 1235f409d0edSNikolay Aleksandrov vg = nbp_vlan_group(port); 1236f545923bSNikolay Aleksandrov __vlan_flush(port->br, port, vg); 1237f409d0edSNikolay Aleksandrov RCU_INIT_POINTER(port->vlgrp, NULL); 1238f409d0edSNikolay Aleksandrov synchronize_rcu(); 1239f409d0edSNikolay Aleksandrov __vlan_group_free(vg); 12405be5a2dfSVlad Yasevich } 1241a60c0903SNikolay Aleksandrov 1242a60c0903SNikolay Aleksandrov void br_vlan_get_stats(const struct net_bridge_vlan *v, 1243a60c0903SNikolay Aleksandrov struct br_vlan_stats *stats) 1244a60c0903SNikolay Aleksandrov { 1245a60c0903SNikolay Aleksandrov int i; 1246a60c0903SNikolay Aleksandrov 1247a60c0903SNikolay Aleksandrov memset(stats, 0, sizeof(*stats)); 1248a60c0903SNikolay Aleksandrov for_each_possible_cpu(i) { 1249a60c0903SNikolay Aleksandrov u64 rxpackets, rxbytes, txpackets, txbytes; 1250a60c0903SNikolay Aleksandrov struct br_vlan_stats *cpu_stats; 1251a60c0903SNikolay Aleksandrov unsigned int start; 1252a60c0903SNikolay Aleksandrov 1253a60c0903SNikolay Aleksandrov cpu_stats = per_cpu_ptr(v->stats, i); 1254a60c0903SNikolay Aleksandrov do { 1255a60c0903SNikolay Aleksandrov start = u64_stats_fetch_begin_irq(&cpu_stats->syncp); 1256a60c0903SNikolay Aleksandrov rxpackets = cpu_stats->rx_packets; 1257a60c0903SNikolay Aleksandrov rxbytes = cpu_stats->rx_bytes; 1258a60c0903SNikolay Aleksandrov txbytes = cpu_stats->tx_bytes; 1259a60c0903SNikolay Aleksandrov txpackets = cpu_stats->tx_packets; 1260a60c0903SNikolay Aleksandrov } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start)); 1261a60c0903SNikolay Aleksandrov 1262a60c0903SNikolay Aleksandrov stats->rx_packets += rxpackets; 1263a60c0903SNikolay Aleksandrov stats->rx_bytes += rxbytes; 1264a60c0903SNikolay Aleksandrov stats->tx_bytes += txbytes; 1265a60c0903SNikolay Aleksandrov stats->tx_packets += txpackets; 1266a60c0903SNikolay Aleksandrov } 1267a60c0903SNikolay Aleksandrov } 12684d4fd361SPetr Machata 12697582f5b7SPablo Neira Ayuso static int __br_vlan_get_pvid(const struct net_device *dev, 12707582f5b7SPablo Neira Ayuso struct net_bridge_port *p, u16 *p_pvid) 12714d4fd361SPetr Machata { 12724d4fd361SPetr Machata struct net_bridge_vlan_group *vg; 12734d4fd361SPetr Machata 12745a6db04cSIdo Schimmel if (p) 12755a6db04cSIdo Schimmel vg = nbp_vlan_group(p); 12765a6db04cSIdo Schimmel else if (netif_is_bridge_master(dev)) 12774d4fd361SPetr Machata vg = br_vlan_group(netdev_priv(dev)); 12784d4fd361SPetr Machata else 12794d4fd361SPetr Machata return -EINVAL; 12804d4fd361SPetr Machata 12814d4fd361SPetr Machata *p_pvid = br_get_pvid(vg); 12824d4fd361SPetr Machata return 0; 12834d4fd361SPetr Machata } 12847582f5b7SPablo Neira Ayuso 12857582f5b7SPablo Neira Ayuso int br_vlan_get_pvid(const struct net_device *dev, u16 *p_pvid) 12867582f5b7SPablo Neira Ayuso { 12877582f5b7SPablo Neira Ayuso ASSERT_RTNL(); 12887582f5b7SPablo Neira Ayuso 12897582f5b7SPablo Neira Ayuso return __br_vlan_get_pvid(dev, br_port_get_check_rtnl(dev), p_pvid); 12907582f5b7SPablo Neira Ayuso } 12914d4fd361SPetr Machata EXPORT_SYMBOL_GPL(br_vlan_get_pvid); 12924d4fd361SPetr Machata 12937582f5b7SPablo Neira Ayuso int br_vlan_get_pvid_rcu(const struct net_device *dev, u16 *p_pvid) 12947582f5b7SPablo Neira Ayuso { 12957582f5b7SPablo Neira Ayuso return __br_vlan_get_pvid(dev, br_port_get_check_rcu(dev), p_pvid); 12967582f5b7SPablo Neira Ayuso } 12977582f5b7SPablo Neira Ayuso EXPORT_SYMBOL_GPL(br_vlan_get_pvid_rcu); 12987582f5b7SPablo Neira Ayuso 12994d4fd361SPetr Machata int br_vlan_get_info(const struct net_device *dev, u16 vid, 13004d4fd361SPetr Machata struct bridge_vlan_info *p_vinfo) 13014d4fd361SPetr Machata { 13024d4fd361SPetr Machata struct net_bridge_vlan_group *vg; 13034d4fd361SPetr Machata struct net_bridge_vlan *v; 13044d4fd361SPetr Machata struct net_bridge_port *p; 13054d4fd361SPetr Machata 13064d4fd361SPetr Machata ASSERT_RTNL(); 13074d4fd361SPetr Machata p = br_port_get_check_rtnl(dev); 13084d4fd361SPetr Machata if (p) 13094d4fd361SPetr Machata vg = nbp_vlan_group(p); 13102b18d79eSPetr Machata else if (netif_is_bridge_master(dev)) 13112b18d79eSPetr Machata vg = br_vlan_group(netdev_priv(dev)); 13124d4fd361SPetr Machata else 13134d4fd361SPetr Machata return -EINVAL; 13144d4fd361SPetr Machata 13154d4fd361SPetr Machata v = br_vlan_find(vg, vid); 13164d4fd361SPetr Machata if (!v) 13174d4fd361SPetr Machata return -ENOENT; 13184d4fd361SPetr Machata 13194d4fd361SPetr Machata p_vinfo->vid = vid; 13204d4fd361SPetr Machata p_vinfo->flags = v->flags; 1321f40d9b20SVladimir Oltean if (vid == br_get_pvid(vg)) 1322f40d9b20SVladimir Oltean p_vinfo->flags |= BRIDGE_VLAN_INFO_PVID; 13234d4fd361SPetr Machata return 0; 13244d4fd361SPetr Machata } 13254d4fd361SPetr Machata EXPORT_SYMBOL_GPL(br_vlan_get_info); 13269c0ec2e7SMike Manning 13279c0ec2e7SMike Manning static int br_vlan_is_bind_vlan_dev(const struct net_device *dev) 13289c0ec2e7SMike Manning { 13299c0ec2e7SMike Manning return is_vlan_dev(dev) && 13309c0ec2e7SMike Manning !!(vlan_dev_priv(dev)->flags & VLAN_FLAG_BRIDGE_BINDING); 13319c0ec2e7SMike Manning } 13329c0ec2e7SMike Manning 13339c0ec2e7SMike Manning static int br_vlan_is_bind_vlan_dev_fn(struct net_device *dev, 13349c0ec2e7SMike Manning __always_unused void *data) 13359c0ec2e7SMike Manning { 13369c0ec2e7SMike Manning return br_vlan_is_bind_vlan_dev(dev); 13379c0ec2e7SMike Manning } 13389c0ec2e7SMike Manning 13399c0ec2e7SMike Manning static bool br_vlan_has_upper_bind_vlan_dev(struct net_device *dev) 13409c0ec2e7SMike Manning { 13419c0ec2e7SMike Manning int found; 13429c0ec2e7SMike Manning 13439c0ec2e7SMike Manning rcu_read_lock(); 13449c0ec2e7SMike Manning found = netdev_walk_all_upper_dev_rcu(dev, br_vlan_is_bind_vlan_dev_fn, 13459c0ec2e7SMike Manning NULL); 13469c0ec2e7SMike Manning rcu_read_unlock(); 13479c0ec2e7SMike Manning 13489c0ec2e7SMike Manning return !!found; 13499c0ec2e7SMike Manning } 13509c0ec2e7SMike Manning 13519c0ec2e7SMike Manning struct br_vlan_bind_walk_data { 13529c0ec2e7SMike Manning u16 vid; 13539c0ec2e7SMike Manning struct net_device *result; 13549c0ec2e7SMike Manning }; 13559c0ec2e7SMike Manning 13569c0ec2e7SMike Manning static int br_vlan_match_bind_vlan_dev_fn(struct net_device *dev, 13579c0ec2e7SMike Manning void *data_in) 13589c0ec2e7SMike Manning { 13599c0ec2e7SMike Manning struct br_vlan_bind_walk_data *data = data_in; 13609c0ec2e7SMike Manning int found = 0; 13619c0ec2e7SMike Manning 13629c0ec2e7SMike Manning if (br_vlan_is_bind_vlan_dev(dev) && 13639c0ec2e7SMike Manning vlan_dev_priv(dev)->vlan_id == data->vid) { 13649c0ec2e7SMike Manning data->result = dev; 13659c0ec2e7SMike Manning found = 1; 13669c0ec2e7SMike Manning } 13679c0ec2e7SMike Manning 13689c0ec2e7SMike Manning return found; 13699c0ec2e7SMike Manning } 13709c0ec2e7SMike Manning 13719c0ec2e7SMike Manning static struct net_device * 13729c0ec2e7SMike Manning br_vlan_get_upper_bind_vlan_dev(struct net_device *dev, u16 vid) 13739c0ec2e7SMike Manning { 13749c0ec2e7SMike Manning struct br_vlan_bind_walk_data data = { 13759c0ec2e7SMike Manning .vid = vid, 13769c0ec2e7SMike Manning }; 13779c0ec2e7SMike Manning 13789c0ec2e7SMike Manning rcu_read_lock(); 13799c0ec2e7SMike Manning netdev_walk_all_upper_dev_rcu(dev, br_vlan_match_bind_vlan_dev_fn, 13809c0ec2e7SMike Manning &data); 13819c0ec2e7SMike Manning rcu_read_unlock(); 13829c0ec2e7SMike Manning 13839c0ec2e7SMike Manning return data.result; 13849c0ec2e7SMike Manning } 13859c0ec2e7SMike Manning 13869c0ec2e7SMike Manning static bool br_vlan_is_dev_up(const struct net_device *dev) 13879c0ec2e7SMike Manning { 13889c0ec2e7SMike Manning return !!(dev->flags & IFF_UP) && netif_oper_up(dev); 13899c0ec2e7SMike Manning } 13909c0ec2e7SMike Manning 13919c0ec2e7SMike Manning static void br_vlan_set_vlan_dev_state(const struct net_bridge *br, 13929c0ec2e7SMike Manning struct net_device *vlan_dev) 13939c0ec2e7SMike Manning { 13949c0ec2e7SMike Manning u16 vid = vlan_dev_priv(vlan_dev)->vlan_id; 13959c0ec2e7SMike Manning struct net_bridge_vlan_group *vg; 13969c0ec2e7SMike Manning struct net_bridge_port *p; 13979c0ec2e7SMike Manning bool has_carrier = false; 13989c0ec2e7SMike Manning 13998e1acd4fSMike Manning if (!netif_carrier_ok(br->dev)) { 14008e1acd4fSMike Manning netif_carrier_off(vlan_dev); 14018e1acd4fSMike Manning return; 14028e1acd4fSMike Manning } 14038e1acd4fSMike Manning 14049c0ec2e7SMike Manning list_for_each_entry(p, &br->port_list, list) { 14059c0ec2e7SMike Manning vg = nbp_vlan_group(p); 14069c0ec2e7SMike Manning if (br_vlan_find(vg, vid) && br_vlan_is_dev_up(p->dev)) { 14079c0ec2e7SMike Manning has_carrier = true; 14089c0ec2e7SMike Manning break; 14099c0ec2e7SMike Manning } 14109c0ec2e7SMike Manning } 14119c0ec2e7SMike Manning 14129c0ec2e7SMike Manning if (has_carrier) 14139c0ec2e7SMike Manning netif_carrier_on(vlan_dev); 14149c0ec2e7SMike Manning else 14159c0ec2e7SMike Manning netif_carrier_off(vlan_dev); 14169c0ec2e7SMike Manning } 14179c0ec2e7SMike Manning 14189c0ec2e7SMike Manning static void br_vlan_set_all_vlan_dev_state(struct net_bridge_port *p) 14199c0ec2e7SMike Manning { 14209c0ec2e7SMike Manning struct net_bridge_vlan_group *vg = nbp_vlan_group(p); 14219c0ec2e7SMike Manning struct net_bridge_vlan *vlan; 14229c0ec2e7SMike Manning struct net_device *vlan_dev; 14239c0ec2e7SMike Manning 14249c0ec2e7SMike Manning list_for_each_entry(vlan, &vg->vlan_list, vlist) { 14259c0ec2e7SMike Manning vlan_dev = br_vlan_get_upper_bind_vlan_dev(p->br->dev, 14269c0ec2e7SMike Manning vlan->vid); 14279c0ec2e7SMike Manning if (vlan_dev) { 14288e1acd4fSMike Manning if (br_vlan_is_dev_up(p->dev)) { 14298e1acd4fSMike Manning if (netif_carrier_ok(p->br->dev)) 14309c0ec2e7SMike Manning netif_carrier_on(vlan_dev); 14318e1acd4fSMike Manning } else { 14329c0ec2e7SMike Manning br_vlan_set_vlan_dev_state(p->br, vlan_dev); 14339c0ec2e7SMike Manning } 14349c0ec2e7SMike Manning } 14359c0ec2e7SMike Manning } 14368e1acd4fSMike Manning } 14379c0ec2e7SMike Manning 14389c0ec2e7SMike Manning static void br_vlan_upper_change(struct net_device *dev, 14399c0ec2e7SMike Manning struct net_device *upper_dev, 14409c0ec2e7SMike Manning bool linking) 14419c0ec2e7SMike Manning { 14429c0ec2e7SMike Manning struct net_bridge *br = netdev_priv(dev); 14439c0ec2e7SMike Manning 14449c0ec2e7SMike Manning if (!br_vlan_is_bind_vlan_dev(upper_dev)) 14459c0ec2e7SMike Manning return; 14469c0ec2e7SMike Manning 14479c0ec2e7SMike Manning if (linking) { 14489c0ec2e7SMike Manning br_vlan_set_vlan_dev_state(br, upper_dev); 14499c0ec2e7SMike Manning br_opt_toggle(br, BROPT_VLAN_BRIDGE_BINDING, true); 14509c0ec2e7SMike Manning } else { 14519c0ec2e7SMike Manning br_opt_toggle(br, BROPT_VLAN_BRIDGE_BINDING, 14529c0ec2e7SMike Manning br_vlan_has_upper_bind_vlan_dev(dev)); 14539c0ec2e7SMike Manning } 14549c0ec2e7SMike Manning } 14559c0ec2e7SMike Manning 14568e1acd4fSMike Manning struct br_vlan_link_state_walk_data { 14578e1acd4fSMike Manning struct net_bridge *br; 14588e1acd4fSMike Manning }; 14598e1acd4fSMike Manning 14608e1acd4fSMike Manning static int br_vlan_link_state_change_fn(struct net_device *vlan_dev, 14618e1acd4fSMike Manning void *data_in) 14628e1acd4fSMike Manning { 14638e1acd4fSMike Manning struct br_vlan_link_state_walk_data *data = data_in; 14648e1acd4fSMike Manning 14658e1acd4fSMike Manning if (br_vlan_is_bind_vlan_dev(vlan_dev)) 14668e1acd4fSMike Manning br_vlan_set_vlan_dev_state(data->br, vlan_dev); 14678e1acd4fSMike Manning 14688e1acd4fSMike Manning return 0; 14698e1acd4fSMike Manning } 14708e1acd4fSMike Manning 14718e1acd4fSMike Manning static void br_vlan_link_state_change(struct net_device *dev, 14728e1acd4fSMike Manning struct net_bridge *br) 14738e1acd4fSMike Manning { 14748e1acd4fSMike Manning struct br_vlan_link_state_walk_data data = { 14758e1acd4fSMike Manning .br = br 14768e1acd4fSMike Manning }; 14778e1acd4fSMike Manning 14788e1acd4fSMike Manning rcu_read_lock(); 14798e1acd4fSMike Manning netdev_walk_all_upper_dev_rcu(dev, br_vlan_link_state_change_fn, 14808e1acd4fSMike Manning &data); 14818e1acd4fSMike Manning rcu_read_unlock(); 14828e1acd4fSMike Manning } 14838e1acd4fSMike Manning 14849c0ec2e7SMike Manning /* Must be protected by RTNL. */ 148580900acdSMike Manning static void nbp_vlan_set_vlan_dev_state(struct net_bridge_port *p, u16 vid) 148680900acdSMike Manning { 148780900acdSMike Manning struct net_device *vlan_dev; 148880900acdSMike Manning 148980900acdSMike Manning if (!br_opt_get(p->br, BROPT_VLAN_BRIDGE_BINDING)) 149080900acdSMike Manning return; 149180900acdSMike Manning 149280900acdSMike Manning vlan_dev = br_vlan_get_upper_bind_vlan_dev(p->br->dev, vid); 149380900acdSMike Manning if (vlan_dev) 149480900acdSMike Manning br_vlan_set_vlan_dev_state(p->br, vlan_dev); 149580900acdSMike Manning } 149680900acdSMike Manning 149780900acdSMike Manning /* Must be protected by RTNL. */ 1498091adf9bSNikolay Aleksandrov int br_vlan_bridge_event(struct net_device *dev, unsigned long event, void *ptr) 14999c0ec2e7SMike Manning { 15009c0ec2e7SMike Manning struct netdev_notifier_changeupper_info *info; 1501091adf9bSNikolay Aleksandrov struct net_bridge *br = netdev_priv(dev); 1502f545923bSNikolay Aleksandrov int vlcmd = 0, ret = 0; 1503f545923bSNikolay Aleksandrov bool changed = false; 15049c0ec2e7SMike Manning 15059c0ec2e7SMike Manning switch (event) { 1506091adf9bSNikolay Aleksandrov case NETDEV_REGISTER: 1507091adf9bSNikolay Aleksandrov ret = br_vlan_add(br, br->default_pvid, 1508091adf9bSNikolay Aleksandrov BRIDGE_VLAN_INFO_PVID | 1509091adf9bSNikolay Aleksandrov BRIDGE_VLAN_INFO_UNTAGGED | 1510091adf9bSNikolay Aleksandrov BRIDGE_VLAN_INFO_BRENTRY, &changed, NULL); 1511f545923bSNikolay Aleksandrov vlcmd = RTM_NEWVLAN; 1512091adf9bSNikolay Aleksandrov break; 1513091adf9bSNikolay Aleksandrov case NETDEV_UNREGISTER: 1514f545923bSNikolay Aleksandrov changed = !br_vlan_delete(br, br->default_pvid); 1515f545923bSNikolay Aleksandrov vlcmd = RTM_DELVLAN; 1516091adf9bSNikolay Aleksandrov break; 15179c0ec2e7SMike Manning case NETDEV_CHANGEUPPER: 15189c0ec2e7SMike Manning info = ptr; 15199c0ec2e7SMike Manning br_vlan_upper_change(dev, info->upper_dev, info->linking); 15209c0ec2e7SMike Manning break; 15218e1acd4fSMike Manning 15228e1acd4fSMike Manning case NETDEV_CHANGE: 15238e1acd4fSMike Manning case NETDEV_UP: 15248e1acd4fSMike Manning if (!br_opt_get(br, BROPT_VLAN_BRIDGE_BINDING)) 1525091adf9bSNikolay Aleksandrov break; 15268e1acd4fSMike Manning br_vlan_link_state_change(dev, br); 15278e1acd4fSMike Manning break; 15289c0ec2e7SMike Manning } 1529f545923bSNikolay Aleksandrov if (changed) 1530f545923bSNikolay Aleksandrov br_vlan_notify(br, NULL, br->default_pvid, 0, vlcmd); 1531091adf9bSNikolay Aleksandrov 1532091adf9bSNikolay Aleksandrov return ret; 15339c0ec2e7SMike Manning } 15349c0ec2e7SMike Manning 15359c0ec2e7SMike Manning /* Must be protected by RTNL. */ 15369c0ec2e7SMike Manning void br_vlan_port_event(struct net_bridge_port *p, unsigned long event) 15379c0ec2e7SMike Manning { 15389c0ec2e7SMike Manning if (!br_opt_get(p->br, BROPT_VLAN_BRIDGE_BINDING)) 15399c0ec2e7SMike Manning return; 15409c0ec2e7SMike Manning 15419c0ec2e7SMike Manning switch (event) { 15429c0ec2e7SMike Manning case NETDEV_CHANGE: 15439c0ec2e7SMike Manning case NETDEV_DOWN: 15449c0ec2e7SMike Manning case NETDEV_UP: 15459c0ec2e7SMike Manning br_vlan_set_all_vlan_dev_state(p); 15469c0ec2e7SMike Manning break; 15479c0ec2e7SMike Manning } 15489c0ec2e7SMike Manning } 15498dcea187SNikolay Aleksandrov 15507a53e718SNikolay Aleksandrov /* v_opts is used to dump the options which must be equal in the whole range */ 15510ab55879SNikolay Aleksandrov static bool br_vlan_fill_vids(struct sk_buff *skb, u16 vid, u16 vid_range, 15527a53e718SNikolay Aleksandrov const struct net_bridge_vlan *v_opts, 15530ab55879SNikolay Aleksandrov u16 flags) 15548dcea187SNikolay Aleksandrov { 15558dcea187SNikolay Aleksandrov struct bridge_vlan_info info; 15568dcea187SNikolay Aleksandrov struct nlattr *nest; 15578dcea187SNikolay Aleksandrov 15588dcea187SNikolay Aleksandrov nest = nla_nest_start(skb, BRIDGE_VLANDB_ENTRY); 15598dcea187SNikolay Aleksandrov if (!nest) 15608dcea187SNikolay Aleksandrov return false; 15618dcea187SNikolay Aleksandrov 15628dcea187SNikolay Aleksandrov memset(&info, 0, sizeof(info)); 15638dcea187SNikolay Aleksandrov info.vid = vid; 15648dcea187SNikolay Aleksandrov if (flags & BRIDGE_VLAN_INFO_UNTAGGED) 15658dcea187SNikolay Aleksandrov info.flags |= BRIDGE_VLAN_INFO_UNTAGGED; 15668dcea187SNikolay Aleksandrov if (flags & BRIDGE_VLAN_INFO_PVID) 15678dcea187SNikolay Aleksandrov info.flags |= BRIDGE_VLAN_INFO_PVID; 15688dcea187SNikolay Aleksandrov 15698dcea187SNikolay Aleksandrov if (nla_put(skb, BRIDGE_VLANDB_ENTRY_INFO, sizeof(info), &info)) 15708dcea187SNikolay Aleksandrov goto out_err; 15718dcea187SNikolay Aleksandrov 15720ab55879SNikolay Aleksandrov if (vid_range && vid < vid_range && 15730ab55879SNikolay Aleksandrov !(flags & BRIDGE_VLAN_INFO_PVID) && 15740ab55879SNikolay Aleksandrov nla_put_u16(skb, BRIDGE_VLANDB_ENTRY_RANGE, vid_range)) 15750ab55879SNikolay Aleksandrov goto out_err; 15760ab55879SNikolay Aleksandrov 15777a53e718SNikolay Aleksandrov if (v_opts && !br_vlan_opts_fill(skb, v_opts)) 15787a53e718SNikolay Aleksandrov goto out_err; 15797a53e718SNikolay Aleksandrov 15808dcea187SNikolay Aleksandrov nla_nest_end(skb, nest); 15818dcea187SNikolay Aleksandrov 15828dcea187SNikolay Aleksandrov return true; 15838dcea187SNikolay Aleksandrov 15848dcea187SNikolay Aleksandrov out_err: 15858dcea187SNikolay Aleksandrov nla_nest_cancel(skb, nest); 15868dcea187SNikolay Aleksandrov return false; 15878dcea187SNikolay Aleksandrov } 15888dcea187SNikolay Aleksandrov 1589cf5bddb9SNikolay Aleksandrov static size_t rtnl_vlan_nlmsg_size(void) 1590cf5bddb9SNikolay Aleksandrov { 1591cf5bddb9SNikolay Aleksandrov return NLMSG_ALIGN(sizeof(struct br_vlan_msg)) 1592cf5bddb9SNikolay Aleksandrov + nla_total_size(0) /* BRIDGE_VLANDB_ENTRY */ 1593cf5bddb9SNikolay Aleksandrov + nla_total_size(sizeof(u16)) /* BRIDGE_VLANDB_ENTRY_RANGE */ 15947a53e718SNikolay Aleksandrov + nla_total_size(sizeof(struct bridge_vlan_info)) /* BRIDGE_VLANDB_ENTRY_INFO */ 15957a53e718SNikolay Aleksandrov + br_vlan_opts_nl_size(); /* bridge vlan options */ 1596cf5bddb9SNikolay Aleksandrov } 1597cf5bddb9SNikolay Aleksandrov 1598cf5bddb9SNikolay Aleksandrov void br_vlan_notify(const struct net_bridge *br, 1599cf5bddb9SNikolay Aleksandrov const struct net_bridge_port *p, 1600cf5bddb9SNikolay Aleksandrov u16 vid, u16 vid_range, 1601cf5bddb9SNikolay Aleksandrov int cmd) 1602cf5bddb9SNikolay Aleksandrov { 1603cf5bddb9SNikolay Aleksandrov struct net_bridge_vlan_group *vg; 16047a53e718SNikolay Aleksandrov struct net_bridge_vlan *v = NULL; 1605cf5bddb9SNikolay Aleksandrov struct br_vlan_msg *bvm; 1606cf5bddb9SNikolay Aleksandrov struct nlmsghdr *nlh; 1607cf5bddb9SNikolay Aleksandrov struct sk_buff *skb; 1608cf5bddb9SNikolay Aleksandrov int err = -ENOBUFS; 1609cf5bddb9SNikolay Aleksandrov struct net *net; 1610cf5bddb9SNikolay Aleksandrov u16 flags = 0; 1611cf5bddb9SNikolay Aleksandrov int ifindex; 1612cf5bddb9SNikolay Aleksandrov 1613cf5bddb9SNikolay Aleksandrov /* right now notifications are done only with rtnl held */ 1614cf5bddb9SNikolay Aleksandrov ASSERT_RTNL(); 1615cf5bddb9SNikolay Aleksandrov 1616cf5bddb9SNikolay Aleksandrov if (p) { 1617cf5bddb9SNikolay Aleksandrov ifindex = p->dev->ifindex; 1618cf5bddb9SNikolay Aleksandrov vg = nbp_vlan_group(p); 1619cf5bddb9SNikolay Aleksandrov net = dev_net(p->dev); 1620cf5bddb9SNikolay Aleksandrov } else { 1621cf5bddb9SNikolay Aleksandrov ifindex = br->dev->ifindex; 1622cf5bddb9SNikolay Aleksandrov vg = br_vlan_group(br); 1623cf5bddb9SNikolay Aleksandrov net = dev_net(br->dev); 1624cf5bddb9SNikolay Aleksandrov } 1625cf5bddb9SNikolay Aleksandrov 1626cf5bddb9SNikolay Aleksandrov skb = nlmsg_new(rtnl_vlan_nlmsg_size(), GFP_KERNEL); 1627cf5bddb9SNikolay Aleksandrov if (!skb) 1628cf5bddb9SNikolay Aleksandrov goto out_err; 1629cf5bddb9SNikolay Aleksandrov 1630cf5bddb9SNikolay Aleksandrov err = -EMSGSIZE; 1631cf5bddb9SNikolay Aleksandrov nlh = nlmsg_put(skb, 0, 0, cmd, sizeof(*bvm), 0); 1632cf5bddb9SNikolay Aleksandrov if (!nlh) 1633cf5bddb9SNikolay Aleksandrov goto out_err; 1634cf5bddb9SNikolay Aleksandrov bvm = nlmsg_data(nlh); 1635cf5bddb9SNikolay Aleksandrov memset(bvm, 0, sizeof(*bvm)); 1636cf5bddb9SNikolay Aleksandrov bvm->family = AF_BRIDGE; 1637cf5bddb9SNikolay Aleksandrov bvm->ifindex = ifindex; 1638cf5bddb9SNikolay Aleksandrov 1639cf5bddb9SNikolay Aleksandrov switch (cmd) { 1640cf5bddb9SNikolay Aleksandrov case RTM_NEWVLAN: 1641cf5bddb9SNikolay Aleksandrov /* need to find the vlan due to flags/options */ 1642cf5bddb9SNikolay Aleksandrov v = br_vlan_find(vg, vid); 1643cf5bddb9SNikolay Aleksandrov if (!v || !br_vlan_should_use(v)) 1644cf5bddb9SNikolay Aleksandrov goto out_kfree; 1645cf5bddb9SNikolay Aleksandrov 1646cf5bddb9SNikolay Aleksandrov flags = v->flags; 1647cf5bddb9SNikolay Aleksandrov if (br_get_pvid(vg) == v->vid) 1648cf5bddb9SNikolay Aleksandrov flags |= BRIDGE_VLAN_INFO_PVID; 1649cf5bddb9SNikolay Aleksandrov break; 1650cf5bddb9SNikolay Aleksandrov case RTM_DELVLAN: 1651cf5bddb9SNikolay Aleksandrov break; 1652cf5bddb9SNikolay Aleksandrov default: 1653cf5bddb9SNikolay Aleksandrov goto out_kfree; 1654cf5bddb9SNikolay Aleksandrov } 1655cf5bddb9SNikolay Aleksandrov 16567a53e718SNikolay Aleksandrov if (!br_vlan_fill_vids(skb, vid, vid_range, v, flags)) 1657cf5bddb9SNikolay Aleksandrov goto out_err; 1658cf5bddb9SNikolay Aleksandrov 1659cf5bddb9SNikolay Aleksandrov nlmsg_end(skb, nlh); 1660cf5bddb9SNikolay Aleksandrov rtnl_notify(skb, net, 0, RTNLGRP_BRVLAN, NULL, GFP_KERNEL); 1661cf5bddb9SNikolay Aleksandrov return; 1662cf5bddb9SNikolay Aleksandrov 1663cf5bddb9SNikolay Aleksandrov out_err: 1664cf5bddb9SNikolay Aleksandrov rtnl_set_sk_err(net, RTNLGRP_BRVLAN, err); 1665cf5bddb9SNikolay Aleksandrov out_kfree: 1666cf5bddb9SNikolay Aleksandrov kfree_skb(skb); 1667cf5bddb9SNikolay Aleksandrov } 1668cf5bddb9SNikolay Aleksandrov 16690ab55879SNikolay Aleksandrov /* check if v_curr can enter a range ending in range_end */ 16700ab55879SNikolay Aleksandrov static bool br_vlan_can_enter_range(const struct net_bridge_vlan *v_curr, 16710ab55879SNikolay Aleksandrov const struct net_bridge_vlan *range_end) 16720ab55879SNikolay Aleksandrov { 16730ab55879SNikolay Aleksandrov return v_curr->vid - range_end->vid == 1 && 16747a53e718SNikolay Aleksandrov range_end->flags == v_curr->flags && 16757a53e718SNikolay Aleksandrov br_vlan_opts_eq(v_curr, range_end); 16760ab55879SNikolay Aleksandrov } 16770ab55879SNikolay Aleksandrov 16788dcea187SNikolay Aleksandrov static int br_vlan_dump_dev(const struct net_device *dev, 16798dcea187SNikolay Aleksandrov struct sk_buff *skb, 16808dcea187SNikolay Aleksandrov struct netlink_callback *cb) 16818dcea187SNikolay Aleksandrov { 16820ab55879SNikolay Aleksandrov struct net_bridge_vlan *v, *range_start = NULL, *range_end = NULL; 16838dcea187SNikolay Aleksandrov struct net_bridge_vlan_group *vg; 16848dcea187SNikolay Aleksandrov int idx = 0, s_idx = cb->args[1]; 16858dcea187SNikolay Aleksandrov struct nlmsghdr *nlh = NULL; 16868dcea187SNikolay Aleksandrov struct net_bridge_port *p; 16878dcea187SNikolay Aleksandrov struct br_vlan_msg *bvm; 16888dcea187SNikolay Aleksandrov struct net_bridge *br; 16898dcea187SNikolay Aleksandrov int err = 0; 16908dcea187SNikolay Aleksandrov u16 pvid; 16918dcea187SNikolay Aleksandrov 16928dcea187SNikolay Aleksandrov if (!netif_is_bridge_master(dev) && !netif_is_bridge_port(dev)) 16938dcea187SNikolay Aleksandrov return -EINVAL; 16948dcea187SNikolay Aleksandrov 16958dcea187SNikolay Aleksandrov if (netif_is_bridge_master(dev)) { 16968dcea187SNikolay Aleksandrov br = netdev_priv(dev); 16978dcea187SNikolay Aleksandrov vg = br_vlan_group_rcu(br); 16988dcea187SNikolay Aleksandrov p = NULL; 16998dcea187SNikolay Aleksandrov } else { 17008dcea187SNikolay Aleksandrov p = br_port_get_rcu(dev); 17018dcea187SNikolay Aleksandrov if (WARN_ON(!p)) 17028dcea187SNikolay Aleksandrov return -EINVAL; 17038dcea187SNikolay Aleksandrov vg = nbp_vlan_group_rcu(p); 17048dcea187SNikolay Aleksandrov br = p->br; 17058dcea187SNikolay Aleksandrov } 17068dcea187SNikolay Aleksandrov 17078dcea187SNikolay Aleksandrov if (!vg) 17088dcea187SNikolay Aleksandrov return 0; 17098dcea187SNikolay Aleksandrov 17108dcea187SNikolay Aleksandrov nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, 17118dcea187SNikolay Aleksandrov RTM_NEWVLAN, sizeof(*bvm), NLM_F_MULTI); 17128dcea187SNikolay Aleksandrov if (!nlh) 17138dcea187SNikolay Aleksandrov return -EMSGSIZE; 17148dcea187SNikolay Aleksandrov bvm = nlmsg_data(nlh); 17158dcea187SNikolay Aleksandrov memset(bvm, 0, sizeof(*bvm)); 17168dcea187SNikolay Aleksandrov bvm->family = PF_BRIDGE; 17178dcea187SNikolay Aleksandrov bvm->ifindex = dev->ifindex; 17188dcea187SNikolay Aleksandrov pvid = br_get_pvid(vg); 17198dcea187SNikolay Aleksandrov 17200ab55879SNikolay Aleksandrov /* idx must stay at range's beginning until it is filled in */ 17218dcea187SNikolay Aleksandrov list_for_each_entry_rcu(v, &vg->vlan_list, vlist) { 17228dcea187SNikolay Aleksandrov if (!br_vlan_should_use(v)) 17238dcea187SNikolay Aleksandrov continue; 17240ab55879SNikolay Aleksandrov if (idx < s_idx) { 17250ab55879SNikolay Aleksandrov idx++; 17260ab55879SNikolay Aleksandrov continue; 17270ab55879SNikolay Aleksandrov } 17280ab55879SNikolay Aleksandrov 17290ab55879SNikolay Aleksandrov if (!range_start) { 17300ab55879SNikolay Aleksandrov range_start = v; 17310ab55879SNikolay Aleksandrov range_end = v; 17320ab55879SNikolay Aleksandrov continue; 17330ab55879SNikolay Aleksandrov } 17340ab55879SNikolay Aleksandrov 17350ab55879SNikolay Aleksandrov if (v->vid == pvid || !br_vlan_can_enter_range(v, range_end)) { 17360ab55879SNikolay Aleksandrov u16 flags = br_vlan_flags(range_start, pvid); 17370ab55879SNikolay Aleksandrov 17380ab55879SNikolay Aleksandrov if (!br_vlan_fill_vids(skb, range_start->vid, 17397a53e718SNikolay Aleksandrov range_end->vid, range_start, 17407a53e718SNikolay Aleksandrov flags)) { 17418dcea187SNikolay Aleksandrov err = -EMSGSIZE; 17428dcea187SNikolay Aleksandrov break; 17438dcea187SNikolay Aleksandrov } 17440ab55879SNikolay Aleksandrov /* advance number of filled vlans */ 17450ab55879SNikolay Aleksandrov idx += range_end->vid - range_start->vid + 1; 17460ab55879SNikolay Aleksandrov 17470ab55879SNikolay Aleksandrov range_start = v; 17488dcea187SNikolay Aleksandrov } 17490ab55879SNikolay Aleksandrov range_end = v; 17500ab55879SNikolay Aleksandrov } 17510ab55879SNikolay Aleksandrov 17520ab55879SNikolay Aleksandrov /* err will be 0 and range_start will be set in 3 cases here: 17530ab55879SNikolay Aleksandrov * - first vlan (range_start == range_end) 17540ab55879SNikolay Aleksandrov * - last vlan (range_start == range_end, not in range) 17550ab55879SNikolay Aleksandrov * - last vlan range (range_start != range_end, in range) 17560ab55879SNikolay Aleksandrov */ 17570ab55879SNikolay Aleksandrov if (!err && range_start && 17580ab55879SNikolay Aleksandrov !br_vlan_fill_vids(skb, range_start->vid, range_end->vid, 17597a53e718SNikolay Aleksandrov range_start, br_vlan_flags(range_start, pvid))) 17600ab55879SNikolay Aleksandrov err = -EMSGSIZE; 17610ab55879SNikolay Aleksandrov 17620ab55879SNikolay Aleksandrov cb->args[1] = err ? idx : 0; 17630ab55879SNikolay Aleksandrov 17648dcea187SNikolay Aleksandrov nlmsg_end(skb, nlh); 17658dcea187SNikolay Aleksandrov 17668dcea187SNikolay Aleksandrov return err; 17678dcea187SNikolay Aleksandrov } 17688dcea187SNikolay Aleksandrov 17698dcea187SNikolay Aleksandrov static int br_vlan_rtm_dump(struct sk_buff *skb, struct netlink_callback *cb) 17708dcea187SNikolay Aleksandrov { 17718dcea187SNikolay Aleksandrov int idx = 0, err = 0, s_idx = cb->args[0]; 17728dcea187SNikolay Aleksandrov struct net *net = sock_net(skb->sk); 17738dcea187SNikolay Aleksandrov struct br_vlan_msg *bvm; 17748dcea187SNikolay Aleksandrov struct net_device *dev; 17758dcea187SNikolay Aleksandrov 17768dcea187SNikolay Aleksandrov err = nlmsg_parse(cb->nlh, sizeof(*bvm), NULL, 0, NULL, cb->extack); 17778dcea187SNikolay Aleksandrov if (err < 0) 17788dcea187SNikolay Aleksandrov return err; 17798dcea187SNikolay Aleksandrov 17808dcea187SNikolay Aleksandrov bvm = nlmsg_data(cb->nlh); 17818dcea187SNikolay Aleksandrov 17828dcea187SNikolay Aleksandrov rcu_read_lock(); 17838dcea187SNikolay Aleksandrov if (bvm->ifindex) { 17848dcea187SNikolay Aleksandrov dev = dev_get_by_index_rcu(net, bvm->ifindex); 17858dcea187SNikolay Aleksandrov if (!dev) { 17868dcea187SNikolay Aleksandrov err = -ENODEV; 17878dcea187SNikolay Aleksandrov goto out_err; 17888dcea187SNikolay Aleksandrov } 17898dcea187SNikolay Aleksandrov err = br_vlan_dump_dev(dev, skb, cb); 17908dcea187SNikolay Aleksandrov if (err && err != -EMSGSIZE) 17918dcea187SNikolay Aleksandrov goto out_err; 17928dcea187SNikolay Aleksandrov } else { 17938dcea187SNikolay Aleksandrov for_each_netdev_rcu(net, dev) { 17948dcea187SNikolay Aleksandrov if (idx < s_idx) 17958dcea187SNikolay Aleksandrov goto skip; 17968dcea187SNikolay Aleksandrov 17978dcea187SNikolay Aleksandrov err = br_vlan_dump_dev(dev, skb, cb); 17988dcea187SNikolay Aleksandrov if (err == -EMSGSIZE) 17998dcea187SNikolay Aleksandrov break; 18008dcea187SNikolay Aleksandrov skip: 18018dcea187SNikolay Aleksandrov idx++; 18028dcea187SNikolay Aleksandrov } 18038dcea187SNikolay Aleksandrov } 18048dcea187SNikolay Aleksandrov cb->args[0] = idx; 18058dcea187SNikolay Aleksandrov rcu_read_unlock(); 18068dcea187SNikolay Aleksandrov 18078dcea187SNikolay Aleksandrov return skb->len; 18088dcea187SNikolay Aleksandrov 18098dcea187SNikolay Aleksandrov out_err: 18108dcea187SNikolay Aleksandrov rcu_read_unlock(); 18118dcea187SNikolay Aleksandrov 18128dcea187SNikolay Aleksandrov return err; 18138dcea187SNikolay Aleksandrov } 18148dcea187SNikolay Aleksandrov 1815f26b2965SNikolay Aleksandrov static const struct nla_policy br_vlan_db_policy[BRIDGE_VLANDB_ENTRY_MAX + 1] = { 1816f26b2965SNikolay Aleksandrov [BRIDGE_VLANDB_ENTRY_INFO] = { .type = NLA_EXACT_LEN, 1817f26b2965SNikolay Aleksandrov .len = sizeof(struct bridge_vlan_info) }, 18180ab55879SNikolay Aleksandrov [BRIDGE_VLANDB_ENTRY_RANGE] = { .type = NLA_U16 }, 1819f26b2965SNikolay Aleksandrov }; 1820f26b2965SNikolay Aleksandrov 1821f26b2965SNikolay Aleksandrov static int br_vlan_rtm_process_one(struct net_device *dev, 1822f26b2965SNikolay Aleksandrov const struct nlattr *attr, 1823f26b2965SNikolay Aleksandrov int cmd, struct netlink_ext_ack *extack) 1824f26b2965SNikolay Aleksandrov { 18250ab55879SNikolay Aleksandrov struct bridge_vlan_info *vinfo, vrange_end, *vinfo_last = NULL; 1826f26b2965SNikolay Aleksandrov struct nlattr *tb[BRIDGE_VLANDB_ENTRY_MAX + 1]; 1827f26b2965SNikolay Aleksandrov struct net_bridge_vlan_group *vg; 1828f26b2965SNikolay Aleksandrov struct net_bridge_port *p = NULL; 1829f26b2965SNikolay Aleksandrov int err = 0, cmdmap = 0; 1830f26b2965SNikolay Aleksandrov struct net_bridge *br; 1831f26b2965SNikolay Aleksandrov bool changed = false; 1832f26b2965SNikolay Aleksandrov 1833f26b2965SNikolay Aleksandrov if (netif_is_bridge_master(dev)) { 1834f26b2965SNikolay Aleksandrov br = netdev_priv(dev); 1835f26b2965SNikolay Aleksandrov vg = br_vlan_group(br); 1836f26b2965SNikolay Aleksandrov } else { 1837f26b2965SNikolay Aleksandrov p = br_port_get_rtnl(dev); 1838f26b2965SNikolay Aleksandrov if (WARN_ON(!p)) 1839f26b2965SNikolay Aleksandrov return -ENODEV; 1840f26b2965SNikolay Aleksandrov br = p->br; 1841f26b2965SNikolay Aleksandrov vg = nbp_vlan_group(p); 1842f26b2965SNikolay Aleksandrov } 1843f26b2965SNikolay Aleksandrov 1844f26b2965SNikolay Aleksandrov if (WARN_ON(!vg)) 1845f26b2965SNikolay Aleksandrov return -ENODEV; 1846f26b2965SNikolay Aleksandrov 1847f26b2965SNikolay Aleksandrov err = nla_parse_nested(tb, BRIDGE_VLANDB_ENTRY_MAX, attr, 1848f26b2965SNikolay Aleksandrov br_vlan_db_policy, extack); 1849f26b2965SNikolay Aleksandrov if (err) 1850f26b2965SNikolay Aleksandrov return err; 1851f26b2965SNikolay Aleksandrov 1852f26b2965SNikolay Aleksandrov if (!tb[BRIDGE_VLANDB_ENTRY_INFO]) { 1853f26b2965SNikolay Aleksandrov NL_SET_ERR_MSG_MOD(extack, "Missing vlan entry info"); 1854f26b2965SNikolay Aleksandrov return -EINVAL; 1855f26b2965SNikolay Aleksandrov } 18560ab55879SNikolay Aleksandrov memset(&vrange_end, 0, sizeof(vrange_end)); 1857f26b2965SNikolay Aleksandrov 1858f26b2965SNikolay Aleksandrov vinfo = nla_data(tb[BRIDGE_VLANDB_ENTRY_INFO]); 1859f26b2965SNikolay Aleksandrov if (vinfo->flags & (BRIDGE_VLAN_INFO_RANGE_BEGIN | 1860f26b2965SNikolay Aleksandrov BRIDGE_VLAN_INFO_RANGE_END)) { 1861f26b2965SNikolay Aleksandrov NL_SET_ERR_MSG_MOD(extack, "Old-style vlan ranges are not allowed when using RTM vlan calls"); 1862f26b2965SNikolay Aleksandrov return -EINVAL; 1863f26b2965SNikolay Aleksandrov } 1864f26b2965SNikolay Aleksandrov if (!br_vlan_valid_id(vinfo->vid, extack)) 1865f26b2965SNikolay Aleksandrov return -EINVAL; 1866f26b2965SNikolay Aleksandrov 18670ab55879SNikolay Aleksandrov if (tb[BRIDGE_VLANDB_ENTRY_RANGE]) { 18680ab55879SNikolay Aleksandrov vrange_end.vid = nla_get_u16(tb[BRIDGE_VLANDB_ENTRY_RANGE]); 18690ab55879SNikolay Aleksandrov /* validate user-provided flags without RANGE_BEGIN */ 18700ab55879SNikolay Aleksandrov vrange_end.flags = BRIDGE_VLAN_INFO_RANGE_END | vinfo->flags; 18710ab55879SNikolay Aleksandrov vinfo->flags |= BRIDGE_VLAN_INFO_RANGE_BEGIN; 18720ab55879SNikolay Aleksandrov 18730ab55879SNikolay Aleksandrov /* vinfo_last is the range start, vinfo the range end */ 18740ab55879SNikolay Aleksandrov vinfo_last = vinfo; 18750ab55879SNikolay Aleksandrov vinfo = &vrange_end; 18760ab55879SNikolay Aleksandrov 18770ab55879SNikolay Aleksandrov if (!br_vlan_valid_id(vinfo->vid, extack) || 18780ab55879SNikolay Aleksandrov !br_vlan_valid_range(vinfo, vinfo_last, extack)) 18790ab55879SNikolay Aleksandrov return -EINVAL; 18800ab55879SNikolay Aleksandrov } 18810ab55879SNikolay Aleksandrov 1882f26b2965SNikolay Aleksandrov switch (cmd) { 1883f26b2965SNikolay Aleksandrov case RTM_NEWVLAN: 1884f26b2965SNikolay Aleksandrov cmdmap = RTM_SETLINK; 1885f26b2965SNikolay Aleksandrov break; 1886adb3ce9bSNikolay Aleksandrov case RTM_DELVLAN: 1887adb3ce9bSNikolay Aleksandrov cmdmap = RTM_DELLINK; 1888adb3ce9bSNikolay Aleksandrov break; 1889f26b2965SNikolay Aleksandrov } 1890f26b2965SNikolay Aleksandrov 1891f26b2965SNikolay Aleksandrov err = br_process_vlan_info(br, p, cmdmap, vinfo, &vinfo_last, &changed, 1892f26b2965SNikolay Aleksandrov extack); 1893f26b2965SNikolay Aleksandrov if (changed) 1894f26b2965SNikolay Aleksandrov br_ifinfo_notify(cmdmap, br, p); 1895f26b2965SNikolay Aleksandrov 1896f26b2965SNikolay Aleksandrov return err; 1897f26b2965SNikolay Aleksandrov } 1898f26b2965SNikolay Aleksandrov 1899f26b2965SNikolay Aleksandrov static int br_vlan_rtm_process(struct sk_buff *skb, struct nlmsghdr *nlh, 1900f26b2965SNikolay Aleksandrov struct netlink_ext_ack *extack) 1901f26b2965SNikolay Aleksandrov { 1902f26b2965SNikolay Aleksandrov struct net *net = sock_net(skb->sk); 1903f26b2965SNikolay Aleksandrov struct br_vlan_msg *bvm; 1904f26b2965SNikolay Aleksandrov struct net_device *dev; 1905f26b2965SNikolay Aleksandrov struct nlattr *attr; 1906f26b2965SNikolay Aleksandrov int err, vlans = 0; 1907f26b2965SNikolay Aleksandrov int rem; 1908f26b2965SNikolay Aleksandrov 1909f26b2965SNikolay Aleksandrov /* this should validate the header and check for remaining bytes */ 1910f26b2965SNikolay Aleksandrov err = nlmsg_parse(nlh, sizeof(*bvm), NULL, BRIDGE_VLANDB_MAX, NULL, 1911f26b2965SNikolay Aleksandrov extack); 1912f26b2965SNikolay Aleksandrov if (err < 0) 1913f26b2965SNikolay Aleksandrov return err; 1914f26b2965SNikolay Aleksandrov 1915f26b2965SNikolay Aleksandrov bvm = nlmsg_data(nlh); 1916f26b2965SNikolay Aleksandrov dev = __dev_get_by_index(net, bvm->ifindex); 1917f26b2965SNikolay Aleksandrov if (!dev) 1918f26b2965SNikolay Aleksandrov return -ENODEV; 1919f26b2965SNikolay Aleksandrov 1920f26b2965SNikolay Aleksandrov if (!netif_is_bridge_master(dev) && !netif_is_bridge_port(dev)) { 1921f26b2965SNikolay Aleksandrov NL_SET_ERR_MSG_MOD(extack, "The device is not a valid bridge or bridge port"); 1922f26b2965SNikolay Aleksandrov return -EINVAL; 1923f26b2965SNikolay Aleksandrov } 1924f26b2965SNikolay Aleksandrov 1925f26b2965SNikolay Aleksandrov nlmsg_for_each_attr(attr, nlh, sizeof(*bvm), rem) { 1926f26b2965SNikolay Aleksandrov if (nla_type(attr) != BRIDGE_VLANDB_ENTRY) 1927f26b2965SNikolay Aleksandrov continue; 1928f26b2965SNikolay Aleksandrov 1929f26b2965SNikolay Aleksandrov vlans++; 1930f26b2965SNikolay Aleksandrov err = br_vlan_rtm_process_one(dev, attr, nlh->nlmsg_type, 1931f26b2965SNikolay Aleksandrov extack); 1932f26b2965SNikolay Aleksandrov if (err) 1933f26b2965SNikolay Aleksandrov break; 1934f26b2965SNikolay Aleksandrov } 1935f26b2965SNikolay Aleksandrov if (!vlans) { 1936f26b2965SNikolay Aleksandrov NL_SET_ERR_MSG_MOD(extack, "No vlans found to process"); 1937f26b2965SNikolay Aleksandrov err = -EINVAL; 1938f26b2965SNikolay Aleksandrov } 1939f26b2965SNikolay Aleksandrov 1940f26b2965SNikolay Aleksandrov return err; 1941f26b2965SNikolay Aleksandrov } 1942f26b2965SNikolay Aleksandrov 19438dcea187SNikolay Aleksandrov void br_vlan_rtnl_init(void) 19448dcea187SNikolay Aleksandrov { 19458dcea187SNikolay Aleksandrov rtnl_register_module(THIS_MODULE, PF_BRIDGE, RTM_GETVLAN, NULL, 19468dcea187SNikolay Aleksandrov br_vlan_rtm_dump, 0); 1947f26b2965SNikolay Aleksandrov rtnl_register_module(THIS_MODULE, PF_BRIDGE, RTM_NEWVLAN, 1948f26b2965SNikolay Aleksandrov br_vlan_rtm_process, NULL, 0); 1949adb3ce9bSNikolay Aleksandrov rtnl_register_module(THIS_MODULE, PF_BRIDGE, RTM_DELVLAN, 1950adb3ce9bSNikolay Aleksandrov br_vlan_rtm_process, NULL, 0); 19518dcea187SNikolay Aleksandrov } 19528dcea187SNikolay Aleksandrov 19538dcea187SNikolay Aleksandrov void br_vlan_rtnl_uninit(void) 19548dcea187SNikolay Aleksandrov { 19558dcea187SNikolay Aleksandrov rtnl_unregister(PF_BRIDGE, RTM_GETVLAN); 1956f26b2965SNikolay Aleksandrov rtnl_unregister(PF_BRIDGE, RTM_NEWVLAN); 1957adb3ce9bSNikolay Aleksandrov rtnl_unregister(PF_BRIDGE, RTM_DELVLAN); 19588dcea187SNikolay Aleksandrov } 1959