1243a2e63SVlad Yasevich #include <linux/kernel.h> 2243a2e63SVlad Yasevich #include <linux/netdevice.h> 3243a2e63SVlad Yasevich #include <linux/rtnetlink.h> 4243a2e63SVlad Yasevich #include <linux/slab.h> 57f109539SScott Feldman #include <net/switchdev.h> 6243a2e63SVlad Yasevich 7243a2e63SVlad Yasevich #include "br_private.h" 8efa5356bSRoopa Prabhu #include "br_private_tunnel.h" 9243a2e63SVlad Yasevich 102594e906SNikolay Aleksandrov static inline int br_vlan_cmp(struct rhashtable_compare_arg *arg, 112594e906SNikolay Aleksandrov const void *ptr) 12552406c4SVlad Yasevich { 132594e906SNikolay Aleksandrov const struct net_bridge_vlan *vle = ptr; 142594e906SNikolay Aleksandrov u16 vid = *(u16 *)arg->key; 152594e906SNikolay Aleksandrov 162594e906SNikolay Aleksandrov return vle->vid != vid; 172594e906SNikolay Aleksandrov } 182594e906SNikolay Aleksandrov 192594e906SNikolay Aleksandrov static const struct rhashtable_params br_vlan_rht_params = { 202594e906SNikolay Aleksandrov .head_offset = offsetof(struct net_bridge_vlan, vnode), 212594e906SNikolay Aleksandrov .key_offset = offsetof(struct net_bridge_vlan, vid), 222594e906SNikolay Aleksandrov .key_len = sizeof(u16), 238af78b64SNikolay Aleksandrov .nelem_hint = 3, 248af78b64SNikolay Aleksandrov .locks_mul = 1, 252594e906SNikolay Aleksandrov .max_size = VLAN_N_VID, 262594e906SNikolay Aleksandrov .obj_cmpfn = br_vlan_cmp, 272594e906SNikolay Aleksandrov .automatic_shrinking = true, 282594e906SNikolay Aleksandrov }; 292594e906SNikolay Aleksandrov 302594e906SNikolay Aleksandrov static struct net_bridge_vlan *br_vlan_lookup(struct rhashtable *tbl, u16 vid) 312594e906SNikolay Aleksandrov { 322594e906SNikolay Aleksandrov return rhashtable_lookup_fast(tbl, &vid, br_vlan_rht_params); 332594e906SNikolay Aleksandrov } 342594e906SNikolay Aleksandrov 35f418af63SNikolay Aleksandrov static bool __vlan_add_pvid(struct net_bridge_vlan_group *vg, u16 vid) 362594e906SNikolay Aleksandrov { 3777751ee8SNikolay Aleksandrov if (vg->pvid == vid) 38f418af63SNikolay Aleksandrov return false; 39552406c4SVlad Yasevich 40552406c4SVlad Yasevich smp_wmb(); 4177751ee8SNikolay Aleksandrov vg->pvid = vid; 42f418af63SNikolay Aleksandrov 43f418af63SNikolay Aleksandrov return true; 44552406c4SVlad Yasevich } 45552406c4SVlad Yasevich 46f418af63SNikolay Aleksandrov static bool __vlan_delete_pvid(struct net_bridge_vlan_group *vg, u16 vid) 47552406c4SVlad Yasevich { 4877751ee8SNikolay Aleksandrov if (vg->pvid != vid) 49f418af63SNikolay Aleksandrov return false; 50552406c4SVlad Yasevich 51552406c4SVlad Yasevich smp_wmb(); 5277751ee8SNikolay Aleksandrov vg->pvid = 0; 53f418af63SNikolay Aleksandrov 54f418af63SNikolay Aleksandrov return true; 55552406c4SVlad Yasevich } 56552406c4SVlad Yasevich 57f418af63SNikolay Aleksandrov /* return true if anything changed, false otherwise */ 58f418af63SNikolay Aleksandrov static bool __vlan_add_flags(struct net_bridge_vlan *v, u16 flags) 5935e03f3aSVlad Yasevich { 6077751ee8SNikolay Aleksandrov struct net_bridge_vlan_group *vg; 61f418af63SNikolay Aleksandrov u16 old_flags = v->flags; 62f418af63SNikolay Aleksandrov bool ret; 6377751ee8SNikolay Aleksandrov 642594e906SNikolay Aleksandrov if (br_vlan_is_master(v)) 65907b1e6eSNikolay Aleksandrov vg = br_vlan_group(v->br); 66635126b7SVlad Yasevich else 67907b1e6eSNikolay Aleksandrov vg = nbp_vlan_group(v->port); 6877751ee8SNikolay Aleksandrov 6977751ee8SNikolay Aleksandrov if (flags & BRIDGE_VLAN_INFO_PVID) 70f418af63SNikolay Aleksandrov ret = __vlan_add_pvid(vg, v->vid); 712594e906SNikolay Aleksandrov else 72f418af63SNikolay Aleksandrov ret = __vlan_delete_pvid(vg, v->vid); 7335e03f3aSVlad Yasevich 7435e03f3aSVlad Yasevich if (flags & BRIDGE_VLAN_INFO_UNTAGGED) 752594e906SNikolay Aleksandrov v->flags |= BRIDGE_VLAN_INFO_UNTAGGED; 76635126b7SVlad Yasevich else 772594e906SNikolay Aleksandrov v->flags &= ~BRIDGE_VLAN_INFO_UNTAGGED; 78f418af63SNikolay Aleksandrov 79f418af63SNikolay Aleksandrov return ret || !!(old_flags ^ v->flags); 8035e03f3aSVlad Yasevich } 8135e03f3aSVlad Yasevich 827f109539SScott Feldman static int __vlan_vid_add(struct net_device *dev, struct net_bridge *br, 837f109539SScott Feldman u16 vid, u16 flags) 847f109539SScott Feldman { 858f24f309SJiri Pirko struct switchdev_obj_port_vlan v = { 866ff64f6fSIdo Schimmel .obj.orig_dev = dev, 879e8f4a54SJiri Pirko .obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN, 887f109539SScott Feldman .flags = flags, 893e3a78b4SScott Feldman .vid_begin = vid, 907f109539SScott Feldman .vid_end = vid, 917f109539SScott Feldman }; 920944d6b5SJiri Pirko int err; 937f109539SScott Feldman 940944d6b5SJiri Pirko /* Try switchdev op first. In case it is not supported, fallback to 950944d6b5SJiri Pirko * 8021q add. 960944d6b5SJiri Pirko */ 979e8f4a54SJiri Pirko err = switchdev_port_obj_add(dev, &v.obj); 987f109539SScott Feldman if (err == -EOPNOTSUPP) 990944d6b5SJiri Pirko return vlan_vid_add(dev, br->vlan_proto, vid); 1007f109539SScott Feldman return err; 1017f109539SScott Feldman } 1027f109539SScott Feldman 1032594e906SNikolay Aleksandrov static void __vlan_add_list(struct net_bridge_vlan *v) 104243a2e63SVlad Yasevich { 105907b1e6eSNikolay Aleksandrov struct net_bridge_vlan_group *vg; 1062594e906SNikolay Aleksandrov struct list_head *headp, *hpos; 1072594e906SNikolay Aleksandrov struct net_bridge_vlan *vent; 108243a2e63SVlad Yasevich 109907b1e6eSNikolay Aleksandrov if (br_vlan_is_master(v)) 110907b1e6eSNikolay Aleksandrov vg = br_vlan_group(v->br); 111907b1e6eSNikolay Aleksandrov else 112907b1e6eSNikolay Aleksandrov vg = nbp_vlan_group(v->port); 113907b1e6eSNikolay Aleksandrov 114907b1e6eSNikolay Aleksandrov headp = &vg->vlan_list; 1152594e906SNikolay Aleksandrov list_for_each_prev(hpos, headp) { 1162594e906SNikolay Aleksandrov vent = list_entry(hpos, struct net_bridge_vlan, vlist); 1172594e906SNikolay Aleksandrov if (v->vid < vent->vid) 1182594e906SNikolay Aleksandrov continue; 1192594e906SNikolay Aleksandrov else 1202594e906SNikolay Aleksandrov break; 1212594e906SNikolay Aleksandrov } 122586c2b57SNikolay Aleksandrov list_add_rcu(&v->vlist, hpos); 123552406c4SVlad Yasevich } 124243a2e63SVlad Yasevich 1252594e906SNikolay Aleksandrov static void __vlan_del_list(struct net_bridge_vlan *v) 1262594e906SNikolay Aleksandrov { 127586c2b57SNikolay Aleksandrov list_del_rcu(&v->vlist); 128243a2e63SVlad Yasevich } 129243a2e63SVlad Yasevich 130bf361ad3SVivien Didelot static int __vlan_vid_del(struct net_device *dev, struct net_bridge *br, 1317f109539SScott Feldman u16 vid) 1327f109539SScott Feldman { 1338f24f309SJiri Pirko struct switchdev_obj_port_vlan v = { 1346ff64f6fSIdo Schimmel .obj.orig_dev = dev, 1359e8f4a54SJiri Pirko .obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN, 1363e3a78b4SScott Feldman .vid_begin = vid, 1377f109539SScott Feldman .vid_end = vid, 1387f109539SScott Feldman }; 1390944d6b5SJiri Pirko int err; 1407f109539SScott Feldman 1410944d6b5SJiri Pirko /* Try switchdev op first. In case it is not supported, fallback to 1420944d6b5SJiri Pirko * 8021q del. 1430944d6b5SJiri Pirko */ 1449e8f4a54SJiri Pirko err = switchdev_port_obj_del(dev, &v.obj); 1450944d6b5SJiri Pirko if (err == -EOPNOTSUPP) { 1460944d6b5SJiri Pirko vlan_vid_del(dev, br->vlan_proto, vid); 1470944d6b5SJiri Pirko return 0; 1487f109539SScott Feldman } 149bf361ad3SVivien Didelot return err; 1507f109539SScott Feldman } 1517f109539SScott Feldman 152f8ed289fSNikolay Aleksandrov /* Returns a master vlan, if it didn't exist it gets created. In all cases a 153f8ed289fSNikolay Aleksandrov * a reference is taken to the master vlan before returning. 154f8ed289fSNikolay Aleksandrov */ 155f8ed289fSNikolay Aleksandrov static struct net_bridge_vlan *br_vlan_get_master(struct net_bridge *br, u16 vid) 156f8ed289fSNikolay Aleksandrov { 157907b1e6eSNikolay Aleksandrov struct net_bridge_vlan_group *vg; 158f8ed289fSNikolay Aleksandrov struct net_bridge_vlan *masterv; 159f8ed289fSNikolay Aleksandrov 160907b1e6eSNikolay Aleksandrov vg = br_vlan_group(br); 161907b1e6eSNikolay Aleksandrov masterv = br_vlan_find(vg, vid); 162f8ed289fSNikolay Aleksandrov if (!masterv) { 163f418af63SNikolay Aleksandrov bool changed; 164f418af63SNikolay Aleksandrov 165f8ed289fSNikolay Aleksandrov /* missing global ctx, create it now */ 166f418af63SNikolay Aleksandrov if (br_vlan_add(br, vid, 0, &changed)) 167f8ed289fSNikolay Aleksandrov return NULL; 168907b1e6eSNikolay Aleksandrov masterv = br_vlan_find(vg, vid); 169f8ed289fSNikolay Aleksandrov if (WARN_ON(!masterv)) 170f8ed289fSNikolay Aleksandrov return NULL; 1710e5a82efSIdo Schimmel refcount_set(&masterv->refcnt, 1); 1720e5a82efSIdo Schimmel return masterv; 173f8ed289fSNikolay Aleksandrov } 17425127759SReshetova, Elena refcount_inc(&masterv->refcnt); 175f8ed289fSNikolay Aleksandrov 176f8ed289fSNikolay Aleksandrov return masterv; 177f8ed289fSNikolay Aleksandrov } 178f8ed289fSNikolay Aleksandrov 1796dada9b1SNikolay Aleksandrov static void br_master_vlan_rcu_free(struct rcu_head *rcu) 1806dada9b1SNikolay Aleksandrov { 1816dada9b1SNikolay Aleksandrov struct net_bridge_vlan *v; 1826dada9b1SNikolay Aleksandrov 1836dada9b1SNikolay Aleksandrov v = container_of(rcu, struct net_bridge_vlan, rcu); 1846dada9b1SNikolay Aleksandrov WARN_ON(!br_vlan_is_master(v)); 1856dada9b1SNikolay Aleksandrov free_percpu(v->stats); 1866dada9b1SNikolay Aleksandrov v->stats = NULL; 1876dada9b1SNikolay Aleksandrov kfree(v); 1886dada9b1SNikolay Aleksandrov } 1896dada9b1SNikolay Aleksandrov 190f8ed289fSNikolay Aleksandrov static void br_vlan_put_master(struct net_bridge_vlan *masterv) 191f8ed289fSNikolay Aleksandrov { 192907b1e6eSNikolay Aleksandrov struct net_bridge_vlan_group *vg; 193907b1e6eSNikolay Aleksandrov 194f8ed289fSNikolay Aleksandrov if (!br_vlan_is_master(masterv)) 195f8ed289fSNikolay Aleksandrov return; 196f8ed289fSNikolay Aleksandrov 197907b1e6eSNikolay Aleksandrov vg = br_vlan_group(masterv->br); 19825127759SReshetova, Elena if (refcount_dec_and_test(&masterv->refcnt)) { 199907b1e6eSNikolay Aleksandrov rhashtable_remove_fast(&vg->vlan_hash, 200f8ed289fSNikolay Aleksandrov &masterv->vnode, br_vlan_rht_params); 201f8ed289fSNikolay Aleksandrov __vlan_del_list(masterv); 2026dada9b1SNikolay Aleksandrov call_rcu(&masterv->rcu, br_master_vlan_rcu_free); 203f8ed289fSNikolay Aleksandrov } 204f8ed289fSNikolay Aleksandrov } 205f8ed289fSNikolay Aleksandrov 2062594e906SNikolay Aleksandrov /* This is the shared VLAN add function which works for both ports and bridge 2072594e906SNikolay Aleksandrov * devices. There are four possible calls to this function in terms of the 2082594e906SNikolay Aleksandrov * vlan entry type: 2092594e906SNikolay Aleksandrov * 1. vlan is being added on a port (no master flags, global entry exists) 210ddd611d3SIdo Schimmel * 2. vlan is being added on a bridge (both master and brentry flags) 2112594e906SNikolay Aleksandrov * 3. vlan is being added on a port, but a global entry didn't exist which 212ddd611d3SIdo Schimmel * is being created right now (master flag set, brentry flag unset), the 2132594e906SNikolay Aleksandrov * global entry is used for global per-vlan features, but not for filtering 214ddd611d3SIdo Schimmel * 4. same as 3 but with both master and brentry flags set so the entry 2152594e906SNikolay Aleksandrov * will be used for filtering in both the port and the bridge 2162594e906SNikolay Aleksandrov */ 2172594e906SNikolay Aleksandrov static int __vlan_add(struct net_bridge_vlan *v, u16 flags) 218243a2e63SVlad Yasevich { 2192594e906SNikolay Aleksandrov struct net_bridge_vlan *masterv = NULL; 2202594e906SNikolay Aleksandrov struct net_bridge_port *p = NULL; 2216be144f6SNikolay Aleksandrov struct net_bridge_vlan_group *vg; 2222594e906SNikolay Aleksandrov struct net_device *dev; 2232594e906SNikolay Aleksandrov struct net_bridge *br; 224bf361ad3SVivien Didelot int err; 225bf361ad3SVivien Didelot 2262594e906SNikolay Aleksandrov if (br_vlan_is_master(v)) { 2272594e906SNikolay Aleksandrov br = v->br; 2282594e906SNikolay Aleksandrov dev = br->dev; 229907b1e6eSNikolay Aleksandrov vg = br_vlan_group(br); 2302594e906SNikolay Aleksandrov } else { 2312594e906SNikolay Aleksandrov p = v->port; 2322594e906SNikolay Aleksandrov br = p->br; 2332594e906SNikolay Aleksandrov dev = p->dev; 234907b1e6eSNikolay Aleksandrov vg = nbp_vlan_group(p); 2352594e906SNikolay Aleksandrov } 2362594e906SNikolay Aleksandrov 2372594e906SNikolay Aleksandrov if (p) { 2382594e906SNikolay Aleksandrov /* Add VLAN to the device filter if it is supported. 2392594e906SNikolay Aleksandrov * This ensures tagged traffic enters the bridge when 2402594e906SNikolay Aleksandrov * promiscuous mode is disabled by br_manage_promisc(). 2412594e906SNikolay Aleksandrov */ 2422594e906SNikolay Aleksandrov err = __vlan_vid_add(dev, br, v->vid, flags); 243bf361ad3SVivien Didelot if (err) 2442594e906SNikolay Aleksandrov goto out; 2452594e906SNikolay Aleksandrov 2462594e906SNikolay Aleksandrov /* need to work on the master vlan too */ 2472594e906SNikolay Aleksandrov if (flags & BRIDGE_VLAN_INFO_MASTER) { 248f418af63SNikolay Aleksandrov bool changed; 249f418af63SNikolay Aleksandrov 250f418af63SNikolay Aleksandrov err = br_vlan_add(br, v->vid, 251f418af63SNikolay Aleksandrov flags | BRIDGE_VLAN_INFO_BRENTRY, 252f418af63SNikolay Aleksandrov &changed); 2532594e906SNikolay Aleksandrov if (err) 2542594e906SNikolay Aleksandrov goto out_filt; 2552594e906SNikolay Aleksandrov } 2562594e906SNikolay Aleksandrov 257f8ed289fSNikolay Aleksandrov masterv = br_vlan_get_master(br, v->vid); 258f8ed289fSNikolay Aleksandrov if (!masterv) 2592594e906SNikolay Aleksandrov goto out_filt; 2602594e906SNikolay Aleksandrov v->brvlan = masterv; 2616dada9b1SNikolay Aleksandrov v->stats = masterv->stats; 2622594e906SNikolay Aleksandrov } 2632594e906SNikolay Aleksandrov 2646be144f6SNikolay Aleksandrov /* Add the dev mac and count the vlan only if it's usable */ 2652594e906SNikolay Aleksandrov if (br_vlan_should_use(v)) { 2662594e906SNikolay Aleksandrov err = br_fdb_insert(br, p, dev->dev_addr, v->vid); 2672594e906SNikolay Aleksandrov if (err) { 2682594e906SNikolay Aleksandrov br_err(br, "failed insert local address into bridge forwarding table\n"); 2692594e906SNikolay Aleksandrov goto out_filt; 2702594e906SNikolay Aleksandrov } 2716be144f6SNikolay Aleksandrov vg->num_vlans++; 2722594e906SNikolay Aleksandrov } 2732594e906SNikolay Aleksandrov 2746be144f6SNikolay Aleksandrov err = rhashtable_lookup_insert_fast(&vg->vlan_hash, &v->vnode, 2756be144f6SNikolay Aleksandrov br_vlan_rht_params); 2762594e906SNikolay Aleksandrov if (err) 2772594e906SNikolay Aleksandrov goto out_fdb_insert; 2782594e906SNikolay Aleksandrov 2792594e906SNikolay Aleksandrov __vlan_add_list(v); 2802594e906SNikolay Aleksandrov __vlan_add_flags(v, flags); 2812594e906SNikolay Aleksandrov out: 2822594e906SNikolay Aleksandrov return err; 2832594e906SNikolay Aleksandrov 2842594e906SNikolay Aleksandrov out_fdb_insert: 2856be144f6SNikolay Aleksandrov if (br_vlan_should_use(v)) { 2866be144f6SNikolay Aleksandrov br_fdb_find_delete_local(br, p, dev->dev_addr, v->vid); 2876be144f6SNikolay Aleksandrov vg->num_vlans--; 2886be144f6SNikolay Aleksandrov } 2892594e906SNikolay Aleksandrov 2902594e906SNikolay Aleksandrov out_filt: 2912594e906SNikolay Aleksandrov if (p) { 2922594e906SNikolay Aleksandrov __vlan_vid_del(dev, br, v->vid); 2932594e906SNikolay Aleksandrov if (masterv) { 294f8ed289fSNikolay Aleksandrov br_vlan_put_master(masterv); 2952594e906SNikolay Aleksandrov v->brvlan = NULL; 2962594e906SNikolay Aleksandrov } 2972594e906SNikolay Aleksandrov } 2982594e906SNikolay Aleksandrov 2992594e906SNikolay Aleksandrov goto out; 3002594e906SNikolay Aleksandrov } 3012594e906SNikolay Aleksandrov 3022594e906SNikolay Aleksandrov static int __vlan_del(struct net_bridge_vlan *v) 3032594e906SNikolay Aleksandrov { 3042594e906SNikolay Aleksandrov struct net_bridge_vlan *masterv = v; 30577751ee8SNikolay Aleksandrov struct net_bridge_vlan_group *vg; 3062594e906SNikolay Aleksandrov struct net_bridge_port *p = NULL; 3072594e906SNikolay Aleksandrov int err = 0; 3082594e906SNikolay Aleksandrov 3092594e906SNikolay Aleksandrov if (br_vlan_is_master(v)) { 310907b1e6eSNikolay Aleksandrov vg = br_vlan_group(v->br); 3112594e906SNikolay Aleksandrov } else { 3122594e906SNikolay Aleksandrov p = v->port; 313907b1e6eSNikolay Aleksandrov vg = nbp_vlan_group(v->port); 3142594e906SNikolay Aleksandrov masterv = v->brvlan; 3152594e906SNikolay Aleksandrov } 3162594e906SNikolay Aleksandrov 31777751ee8SNikolay Aleksandrov __vlan_delete_pvid(vg, v->vid); 3182594e906SNikolay Aleksandrov if (p) { 3192594e906SNikolay Aleksandrov err = __vlan_vid_del(p->dev, p->br, v->vid); 3202594e906SNikolay Aleksandrov if (err) 3212594e906SNikolay Aleksandrov goto out; 3222594e906SNikolay Aleksandrov } 3232594e906SNikolay Aleksandrov 3246be144f6SNikolay Aleksandrov if (br_vlan_should_use(v)) { 3252594e906SNikolay Aleksandrov v->flags &= ~BRIDGE_VLAN_INFO_BRENTRY; 3266be144f6SNikolay Aleksandrov vg->num_vlans--; 3272594e906SNikolay Aleksandrov } 3282594e906SNikolay Aleksandrov 3292594e906SNikolay Aleksandrov if (masterv != v) { 330efa5356bSRoopa Prabhu vlan_tunnel_info_del(vg, v); 33177751ee8SNikolay Aleksandrov rhashtable_remove_fast(&vg->vlan_hash, &v->vnode, 33277751ee8SNikolay Aleksandrov br_vlan_rht_params); 3332594e906SNikolay Aleksandrov __vlan_del_list(v); 3342594e906SNikolay Aleksandrov kfree_rcu(v, rcu); 3352594e906SNikolay Aleksandrov } 3362594e906SNikolay Aleksandrov 337f8ed289fSNikolay Aleksandrov br_vlan_put_master(masterv); 3382594e906SNikolay Aleksandrov out: 339bf361ad3SVivien Didelot return err; 3408580e211SToshiaki Makita } 341243a2e63SVlad Yasevich 342f409d0edSNikolay Aleksandrov static void __vlan_group_free(struct net_bridge_vlan_group *vg) 343f409d0edSNikolay Aleksandrov { 344f409d0edSNikolay Aleksandrov WARN_ON(!list_empty(&vg->vlan_list)); 345f409d0edSNikolay Aleksandrov rhashtable_destroy(&vg->vlan_hash); 346efa5356bSRoopa Prabhu vlan_tunnel_deinit(vg); 347f409d0edSNikolay Aleksandrov kfree(vg); 348f409d0edSNikolay Aleksandrov } 349f409d0edSNikolay Aleksandrov 350f409d0edSNikolay Aleksandrov static void __vlan_flush(struct net_bridge_vlan_group *vg) 351243a2e63SVlad Yasevich { 3522594e906SNikolay Aleksandrov struct net_bridge_vlan *vlan, *tmp; 3532594e906SNikolay Aleksandrov 354f409d0edSNikolay Aleksandrov __vlan_delete_pvid(vg, vg->pvid); 355f409d0edSNikolay Aleksandrov list_for_each_entry_safe(vlan, tmp, &vg->vlan_list, vlist) 3562594e906SNikolay Aleksandrov __vlan_del(vlan); 357243a2e63SVlad Yasevich } 358243a2e63SVlad Yasevich 35978851988SVlad Yasevich struct sk_buff *br_handle_vlan(struct net_bridge *br, 36011538d03SRoopa Prabhu const struct net_bridge_port *p, 3612594e906SNikolay Aleksandrov struct net_bridge_vlan_group *vg, 362a37b85c9SVlad Yasevich struct sk_buff *skb) 363a37b85c9SVlad Yasevich { 3646dada9b1SNikolay Aleksandrov struct br_vlan_stats *stats; 3652594e906SNikolay Aleksandrov struct net_bridge_vlan *v; 366a37b85c9SVlad Yasevich u16 vid; 367a37b85c9SVlad Yasevich 36820adfa1aSVlad Yasevich /* If this packet was not filtered at input, let it pass */ 36920adfa1aSVlad Yasevich if (!BR_INPUT_SKB_CB(skb)->vlan_filtered) 37078851988SVlad Yasevich goto out; 37178851988SVlad Yasevich 3722594e906SNikolay Aleksandrov /* At this point, we know that the frame was filtered and contains 3732594e906SNikolay Aleksandrov * a valid vlan id. If the vlan id has untagged flag set, 3742594e906SNikolay Aleksandrov * send untagged; otherwise, send tagged. 3752594e906SNikolay Aleksandrov */ 3762594e906SNikolay Aleksandrov br_vlan_get_tag(skb, &vid); 3772594e906SNikolay Aleksandrov v = br_vlan_find(vg, vid); 3782594e906SNikolay Aleksandrov /* Vlan entry must be configured at this point. The 379fc92f745SVlad Yasevich * only exception is the bridge is set in promisc mode and the 380fc92f745SVlad Yasevich * packet is destined for the bridge device. In this case 381fc92f745SVlad Yasevich * pass the packet as is. 382fc92f745SVlad Yasevich */ 3832594e906SNikolay Aleksandrov if (!v || !br_vlan_should_use(v)) { 384fc92f745SVlad Yasevich if ((br->dev->flags & IFF_PROMISC) && skb->dev == br->dev) { 385fc92f745SVlad Yasevich goto out; 386fc92f745SVlad Yasevich } else { 387fc92f745SVlad Yasevich kfree_skb(skb); 388fc92f745SVlad Yasevich return NULL; 389fc92f745SVlad Yasevich } 390fc92f745SVlad Yasevich } 3916dada9b1SNikolay Aleksandrov if (br->vlan_stats_enabled) { 3926dada9b1SNikolay Aleksandrov stats = this_cpu_ptr(v->stats); 3936dada9b1SNikolay Aleksandrov u64_stats_update_begin(&stats->syncp); 3946dada9b1SNikolay Aleksandrov stats->tx_bytes += skb->len; 3956dada9b1SNikolay Aleksandrov stats->tx_packets++; 3966dada9b1SNikolay Aleksandrov u64_stats_update_end(&stats->syncp); 3976dada9b1SNikolay Aleksandrov } 3986dada9b1SNikolay Aleksandrov 3992594e906SNikolay Aleksandrov if (v->flags & BRIDGE_VLAN_INFO_UNTAGGED) 40099b192daSToshiaki Makita skb->vlan_tci = 0; 40111538d03SRoopa Prabhu 40211538d03SRoopa Prabhu if (p && (p->flags & BR_VLAN_TUNNEL) && 40311538d03SRoopa Prabhu br_handle_egress_vlan_tunnel(skb, v)) { 40411538d03SRoopa Prabhu kfree_skb(skb); 40511538d03SRoopa Prabhu return NULL; 40611538d03SRoopa Prabhu } 40778851988SVlad Yasevich out: 40878851988SVlad Yasevich return skb; 40978851988SVlad Yasevich } 41078851988SVlad Yasevich 41178851988SVlad Yasevich /* Called under RCU */ 4126dada9b1SNikolay Aleksandrov static bool __allowed_ingress(const struct net_bridge *br, 4136dada9b1SNikolay Aleksandrov struct net_bridge_vlan_group *vg, 41478851988SVlad Yasevich struct sk_buff *skb, u16 *vid) 41578851988SVlad Yasevich { 4166dada9b1SNikolay Aleksandrov struct br_vlan_stats *stats; 4176dada9b1SNikolay Aleksandrov struct net_bridge_vlan *v; 4188580e211SToshiaki Makita bool tagged; 419a37b85c9SVlad Yasevich 42020adfa1aSVlad Yasevich BR_INPUT_SKB_CB(skb)->vlan_filtered = true; 42112464bb8SToshiaki Makita /* If vlan tx offload is disabled on bridge device and frame was 42212464bb8SToshiaki Makita * sent from vlan device on the bridge device, it does not have 42312464bb8SToshiaki Makita * HW accelerated vlan tag. 42412464bb8SToshiaki Makita */ 425df8a39deSJiri Pirko if (unlikely(!skb_vlan_tag_present(skb) && 4266dada9b1SNikolay Aleksandrov skb->protocol == br->vlan_proto)) { 4270d5501c1SVlad Yasevich skb = skb_vlan_untag(skb); 42812464bb8SToshiaki Makita if (unlikely(!skb)) 42912464bb8SToshiaki Makita return false; 43012464bb8SToshiaki Makita } 43112464bb8SToshiaki Makita 4328580e211SToshiaki Makita if (!br_vlan_get_tag(skb, vid)) { 4338580e211SToshiaki Makita /* Tagged frame */ 4346dada9b1SNikolay Aleksandrov if (skb->vlan_proto != br->vlan_proto) { 4358580e211SToshiaki Makita /* Protocol-mismatch, empty out vlan_tci for new tag */ 4368580e211SToshiaki Makita skb_push(skb, ETH_HLEN); 43762749e2cSJiri Pirko skb = vlan_insert_tag_set_proto(skb, skb->vlan_proto, 438df8a39deSJiri Pirko skb_vlan_tag_get(skb)); 4398580e211SToshiaki Makita if (unlikely(!skb)) 4408580e211SToshiaki Makita return false; 4418580e211SToshiaki Makita 4428580e211SToshiaki Makita skb_pull(skb, ETH_HLEN); 4438580e211SToshiaki Makita skb_reset_mac_len(skb); 4448580e211SToshiaki Makita *vid = 0; 4458580e211SToshiaki Makita tagged = false; 4468580e211SToshiaki Makita } else { 4478580e211SToshiaki Makita tagged = true; 4488580e211SToshiaki Makita } 4498580e211SToshiaki Makita } else { 4508580e211SToshiaki Makita /* Untagged frame */ 4518580e211SToshiaki Makita tagged = false; 4528580e211SToshiaki Makita } 4538580e211SToshiaki Makita 454b90356ceSToshiaki Makita if (!*vid) { 45577751ee8SNikolay Aleksandrov u16 pvid = br_get_pvid(vg); 45677751ee8SNikolay Aleksandrov 457b90356ceSToshiaki Makita /* Frame had a tag with VID 0 or did not have a tag. 458b90356ceSToshiaki Makita * See if pvid is set on this port. That tells us which 459b90356ceSToshiaki Makita * vlan untagged or priority-tagged traffic belongs to. 46078851988SVlad Yasevich */ 4613df6bf45SVlad Yasevich if (!pvid) 462eb707618SToshiaki Makita goto drop; 46378851988SVlad Yasevich 464b90356ceSToshiaki Makita /* PVID is set on this port. Any untagged or priority-tagged 465b90356ceSToshiaki Makita * ingress frame is considered to belong to this vlan. 46678851988SVlad Yasevich */ 467dfb5fa32SToshiaki Makita *vid = pvid; 4688580e211SToshiaki Makita if (likely(!tagged)) 469b90356ceSToshiaki Makita /* Untagged Frame. */ 4706dada9b1SNikolay Aleksandrov __vlan_hwaccel_put_tag(skb, br->vlan_proto, pvid); 471b90356ceSToshiaki Makita else 472b90356ceSToshiaki Makita /* Priority-tagged Frame. 473b90356ceSToshiaki Makita * At this point, We know that skb->vlan_tci had 474b90356ceSToshiaki Makita * VLAN_TAG_PRESENT bit and its VID field was 0x000. 475b90356ceSToshiaki Makita * We update only VID field and preserve PCP field. 476b90356ceSToshiaki Makita */ 477b90356ceSToshiaki Makita skb->vlan_tci |= pvid; 478b90356ceSToshiaki Makita 4796dada9b1SNikolay Aleksandrov /* if stats are disabled we can avoid the lookup */ 4806dada9b1SNikolay Aleksandrov if (!br->vlan_stats_enabled) 48178851988SVlad Yasevich return true; 48278851988SVlad Yasevich } 48377751ee8SNikolay Aleksandrov v = br_vlan_find(vg, *vid); 4846dada9b1SNikolay Aleksandrov if (!v || !br_vlan_should_use(v)) 4856dada9b1SNikolay Aleksandrov goto drop; 4866dada9b1SNikolay Aleksandrov 4876dada9b1SNikolay Aleksandrov if (br->vlan_stats_enabled) { 4886dada9b1SNikolay Aleksandrov stats = this_cpu_ptr(v->stats); 4896dada9b1SNikolay Aleksandrov u64_stats_update_begin(&stats->syncp); 4906dada9b1SNikolay Aleksandrov stats->rx_bytes += skb->len; 4916dada9b1SNikolay Aleksandrov stats->rx_packets++; 4926dada9b1SNikolay Aleksandrov u64_stats_update_end(&stats->syncp); 4936dada9b1SNikolay Aleksandrov } 4946dada9b1SNikolay Aleksandrov 495a37b85c9SVlad Yasevich return true; 4966dada9b1SNikolay Aleksandrov 497eb707618SToshiaki Makita drop: 498eb707618SToshiaki Makita kfree_skb(skb); 499a37b85c9SVlad Yasevich return false; 500a37b85c9SVlad Yasevich } 501a37b85c9SVlad Yasevich 50277751ee8SNikolay Aleksandrov bool br_allowed_ingress(const struct net_bridge *br, 50377751ee8SNikolay Aleksandrov struct net_bridge_vlan_group *vg, struct sk_buff *skb, 5042594e906SNikolay Aleksandrov u16 *vid) 5052594e906SNikolay Aleksandrov { 5062594e906SNikolay Aleksandrov /* If VLAN filtering is disabled on the bridge, all packets are 5072594e906SNikolay Aleksandrov * permitted. 5082594e906SNikolay Aleksandrov */ 5092594e906SNikolay Aleksandrov if (!br->vlan_enabled) { 5102594e906SNikolay Aleksandrov BR_INPUT_SKB_CB(skb)->vlan_filtered = false; 5112594e906SNikolay Aleksandrov return true; 5122594e906SNikolay Aleksandrov } 5132594e906SNikolay Aleksandrov 5146dada9b1SNikolay Aleksandrov return __allowed_ingress(br, vg, skb, vid); 5152594e906SNikolay Aleksandrov } 5162594e906SNikolay Aleksandrov 51785f46c6bSVlad Yasevich /* Called under RCU. */ 5182594e906SNikolay Aleksandrov bool br_allowed_egress(struct net_bridge_vlan_group *vg, 51985f46c6bSVlad Yasevich const struct sk_buff *skb) 52085f46c6bSVlad Yasevich { 5212594e906SNikolay Aleksandrov const struct net_bridge_vlan *v; 52285f46c6bSVlad Yasevich u16 vid; 52385f46c6bSVlad Yasevich 52420adfa1aSVlad Yasevich /* If this packet was not filtered at input, let it pass */ 52520adfa1aSVlad Yasevich if (!BR_INPUT_SKB_CB(skb)->vlan_filtered) 52685f46c6bSVlad Yasevich return true; 52785f46c6bSVlad Yasevich 52885f46c6bSVlad Yasevich br_vlan_get_tag(skb, &vid); 5292594e906SNikolay Aleksandrov v = br_vlan_find(vg, vid); 5302594e906SNikolay Aleksandrov if (v && br_vlan_should_use(v)) 53185f46c6bSVlad Yasevich return true; 53285f46c6bSVlad Yasevich 53385f46c6bSVlad Yasevich return false; 53485f46c6bSVlad Yasevich } 53585f46c6bSVlad Yasevich 536e0d7968aSToshiaki Makita /* Called under RCU */ 537e0d7968aSToshiaki Makita bool br_should_learn(struct net_bridge_port *p, struct sk_buff *skb, u16 *vid) 538e0d7968aSToshiaki Makita { 539468e7944SNikolay Aleksandrov struct net_bridge_vlan_group *vg; 540e0d7968aSToshiaki Makita struct net_bridge *br = p->br; 541e0d7968aSToshiaki Makita 54220adfa1aSVlad Yasevich /* If filtering was disabled at input, let it pass. */ 543c095f248SVlad Yasevich if (!br->vlan_enabled) 544e0d7968aSToshiaki Makita return true; 545e0d7968aSToshiaki Makita 546eca1e006SIdo Schimmel vg = nbp_vlan_group_rcu(p); 547468e7944SNikolay Aleksandrov if (!vg || !vg->num_vlans) 548e0d7968aSToshiaki Makita return false; 549e0d7968aSToshiaki Makita 5508580e211SToshiaki Makita if (!br_vlan_get_tag(skb, vid) && skb->vlan_proto != br->vlan_proto) 5518580e211SToshiaki Makita *vid = 0; 5528580e211SToshiaki Makita 553e0d7968aSToshiaki Makita if (!*vid) { 55477751ee8SNikolay Aleksandrov *vid = br_get_pvid(vg); 5553df6bf45SVlad Yasevich if (!*vid) 556e0d7968aSToshiaki Makita return false; 557e0d7968aSToshiaki Makita 558e0d7968aSToshiaki Makita return true; 559e0d7968aSToshiaki Makita } 560e0d7968aSToshiaki Makita 56177751ee8SNikolay Aleksandrov if (br_vlan_find(vg, *vid)) 562e0d7968aSToshiaki Makita return true; 563e0d7968aSToshiaki Makita 564e0d7968aSToshiaki Makita return false; 565e0d7968aSToshiaki Makita } 566e0d7968aSToshiaki Makita 5678adff41cSToshiaki Makita /* Must be protected by RTNL. 5688adff41cSToshiaki Makita * Must be called with vid in range from 1 to 4094 inclusive. 569f418af63SNikolay Aleksandrov * changed must be true only if the vlan was created or updated 5708adff41cSToshiaki Makita */ 571f418af63SNikolay Aleksandrov int br_vlan_add(struct net_bridge *br, u16 vid, u16 flags, bool *changed) 572243a2e63SVlad Yasevich { 573907b1e6eSNikolay Aleksandrov struct net_bridge_vlan_group *vg; 5742594e906SNikolay Aleksandrov struct net_bridge_vlan *vlan; 5752594e906SNikolay Aleksandrov int ret; 576243a2e63SVlad Yasevich 577243a2e63SVlad Yasevich ASSERT_RTNL(); 578243a2e63SVlad Yasevich 579f418af63SNikolay Aleksandrov *changed = false; 580907b1e6eSNikolay Aleksandrov vg = br_vlan_group(br); 581907b1e6eSNikolay Aleksandrov vlan = br_vlan_find(vg, vid); 5822594e906SNikolay Aleksandrov if (vlan) { 5832594e906SNikolay Aleksandrov if (!br_vlan_is_brentry(vlan)) { 5842594e906SNikolay Aleksandrov /* Trying to change flags of non-existent bridge vlan */ 5852594e906SNikolay Aleksandrov if (!(flags & BRIDGE_VLAN_INFO_BRENTRY)) 5862594e906SNikolay Aleksandrov return -EINVAL; 5872594e906SNikolay Aleksandrov /* It was only kept for port vlans, now make it real */ 5882594e906SNikolay Aleksandrov ret = br_fdb_insert(br, NULL, br->dev->dev_addr, 5892594e906SNikolay Aleksandrov vlan->vid); 5902594e906SNikolay Aleksandrov if (ret) { 5912594e906SNikolay Aleksandrov br_err(br, "failed insert local address into bridge forwarding table\n"); 5922594e906SNikolay Aleksandrov return ret; 5932594e906SNikolay Aleksandrov } 59425127759SReshetova, Elena refcount_inc(&vlan->refcnt); 5952594e906SNikolay Aleksandrov vlan->flags |= BRIDGE_VLAN_INFO_BRENTRY; 596907b1e6eSNikolay Aleksandrov vg->num_vlans++; 597f418af63SNikolay Aleksandrov *changed = true; 5982594e906SNikolay Aleksandrov } 599f418af63SNikolay Aleksandrov if (__vlan_add_flags(vlan, flags)) 600f418af63SNikolay Aleksandrov *changed = true; 601f418af63SNikolay Aleksandrov 6022594e906SNikolay Aleksandrov return 0; 6032594e906SNikolay Aleksandrov } 604243a2e63SVlad Yasevich 6052594e906SNikolay Aleksandrov vlan = kzalloc(sizeof(*vlan), GFP_KERNEL); 6062594e906SNikolay Aleksandrov if (!vlan) 607243a2e63SVlad Yasevich return -ENOMEM; 608243a2e63SVlad Yasevich 6096dada9b1SNikolay Aleksandrov vlan->stats = netdev_alloc_pcpu_stats(struct br_vlan_stats); 6106dada9b1SNikolay Aleksandrov if (!vlan->stats) { 6116dada9b1SNikolay Aleksandrov kfree(vlan); 6126dada9b1SNikolay Aleksandrov return -ENOMEM; 6136dada9b1SNikolay Aleksandrov } 6142594e906SNikolay Aleksandrov vlan->vid = vid; 6152594e906SNikolay Aleksandrov vlan->flags = flags | BRIDGE_VLAN_INFO_MASTER; 6162594e906SNikolay Aleksandrov vlan->flags &= ~BRIDGE_VLAN_INFO_PVID; 6172594e906SNikolay Aleksandrov vlan->br = br; 6182594e906SNikolay Aleksandrov if (flags & BRIDGE_VLAN_INFO_BRENTRY) 61925127759SReshetova, Elena refcount_set(&vlan->refcnt, 1); 6202594e906SNikolay Aleksandrov ret = __vlan_add(vlan, flags); 6216dada9b1SNikolay Aleksandrov if (ret) { 6226dada9b1SNikolay Aleksandrov free_percpu(vlan->stats); 6232594e906SNikolay Aleksandrov kfree(vlan); 624f418af63SNikolay Aleksandrov } else { 625f418af63SNikolay Aleksandrov *changed = true; 6266dada9b1SNikolay Aleksandrov } 627243a2e63SVlad Yasevich 6282594e906SNikolay Aleksandrov return ret; 629243a2e63SVlad Yasevich } 630243a2e63SVlad Yasevich 6318adff41cSToshiaki Makita /* Must be protected by RTNL. 6328adff41cSToshiaki Makita * Must be called with vid in range from 1 to 4094 inclusive. 6338adff41cSToshiaki Makita */ 634243a2e63SVlad Yasevich int br_vlan_delete(struct net_bridge *br, u16 vid) 635243a2e63SVlad Yasevich { 636907b1e6eSNikolay Aleksandrov struct net_bridge_vlan_group *vg; 6372594e906SNikolay Aleksandrov struct net_bridge_vlan *v; 638243a2e63SVlad Yasevich 639243a2e63SVlad Yasevich ASSERT_RTNL(); 640243a2e63SVlad Yasevich 641907b1e6eSNikolay Aleksandrov vg = br_vlan_group(br); 642907b1e6eSNikolay Aleksandrov v = br_vlan_find(vg, vid); 6432594e906SNikolay Aleksandrov if (!v || !br_vlan_is_brentry(v)) 6442594e906SNikolay Aleksandrov return -ENOENT; 645243a2e63SVlad Yasevich 646424bb9c9SToshiaki Makita br_fdb_find_delete_local(br, NULL, br->dev->dev_addr, vid); 6473741873bSRoopa Prabhu br_fdb_delete_by_port(br, NULL, vid, 0); 648bc9a25d2SVlad Yasevich 649efa5356bSRoopa Prabhu vlan_tunnel_info_del(vg, v); 650efa5356bSRoopa Prabhu 6512594e906SNikolay Aleksandrov return __vlan_del(v); 652243a2e63SVlad Yasevich } 653243a2e63SVlad Yasevich 654243a2e63SVlad Yasevich void br_vlan_flush(struct net_bridge *br) 655243a2e63SVlad Yasevich { 656f409d0edSNikolay Aleksandrov struct net_bridge_vlan_group *vg; 657f409d0edSNikolay Aleksandrov 658243a2e63SVlad Yasevich ASSERT_RTNL(); 659243a2e63SVlad Yasevich 660f409d0edSNikolay Aleksandrov vg = br_vlan_group(br); 661f409d0edSNikolay Aleksandrov __vlan_flush(vg); 662f409d0edSNikolay Aleksandrov RCU_INIT_POINTER(br->vlgrp, NULL); 663f409d0edSNikolay Aleksandrov synchronize_rcu(); 664f409d0edSNikolay Aleksandrov __vlan_group_free(vg); 665243a2e63SVlad Yasevich } 666243a2e63SVlad Yasevich 6672594e906SNikolay Aleksandrov struct net_bridge_vlan *br_vlan_find(struct net_bridge_vlan_group *vg, u16 vid) 6682b292fb4SToshiaki Makita { 6692594e906SNikolay Aleksandrov if (!vg) 6702594e906SNikolay Aleksandrov return NULL; 6712b292fb4SToshiaki Makita 6722594e906SNikolay Aleksandrov return br_vlan_lookup(&vg->vlan_hash, vid); 6732b292fb4SToshiaki Makita } 6742b292fb4SToshiaki Makita 675204177f3SToshiaki Makita /* Must be protected by RTNL. */ 676204177f3SToshiaki Makita static void recalculate_group_addr(struct net_bridge *br) 677204177f3SToshiaki Makita { 678204177f3SToshiaki Makita if (br->group_addr_set) 679204177f3SToshiaki Makita return; 680204177f3SToshiaki Makita 681204177f3SToshiaki Makita spin_lock_bh(&br->lock); 682204177f3SToshiaki Makita if (!br->vlan_enabled || br->vlan_proto == htons(ETH_P_8021Q)) { 683204177f3SToshiaki Makita /* Bridge Group Address */ 684204177f3SToshiaki Makita br->group_addr[5] = 0x00; 685204177f3SToshiaki Makita } else { /* vlan_enabled && ETH_P_8021AD */ 686204177f3SToshiaki Makita /* Provider Bridge Group Address */ 687204177f3SToshiaki Makita br->group_addr[5] = 0x08; 688204177f3SToshiaki Makita } 689204177f3SToshiaki Makita spin_unlock_bh(&br->lock); 690204177f3SToshiaki Makita } 691204177f3SToshiaki Makita 692204177f3SToshiaki Makita /* Must be protected by RTNL. */ 693204177f3SToshiaki Makita void br_recalculate_fwd_mask(struct net_bridge *br) 694204177f3SToshiaki Makita { 695204177f3SToshiaki Makita if (!br->vlan_enabled || br->vlan_proto == htons(ETH_P_8021Q)) 696204177f3SToshiaki Makita br->group_fwd_mask_required = BR_GROUPFWD_DEFAULT; 697204177f3SToshiaki Makita else /* vlan_enabled && ETH_P_8021AD */ 698204177f3SToshiaki Makita br->group_fwd_mask_required = BR_GROUPFWD_8021AD & 699204177f3SToshiaki Makita ~(1u << br->group_addr[5]); 700204177f3SToshiaki Makita } 701204177f3SToshiaki Makita 702a7854037SNikolay Aleksandrov int __br_vlan_filter_toggle(struct net_bridge *br, unsigned long val) 703243a2e63SVlad Yasevich { 7046b72a770SElad Raz struct switchdev_attr attr = { 7056b72a770SElad Raz .orig_dev = br->dev, 7066b72a770SElad Raz .id = SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING, 7076b72a770SElad Raz .flags = SWITCHDEV_F_SKIP_EOPNOTSUPP, 7086b72a770SElad Raz .u.vlan_filtering = val, 7096b72a770SElad Raz }; 7106b72a770SElad Raz int err; 7116b72a770SElad Raz 712243a2e63SVlad Yasevich if (br->vlan_enabled == val) 713a7854037SNikolay Aleksandrov return 0; 714243a2e63SVlad Yasevich 7156b72a770SElad Raz err = switchdev_port_attr_set(br->dev, &attr); 7166b72a770SElad Raz if (err && err != -EOPNOTSUPP) 7176b72a770SElad Raz return err; 7186b72a770SElad Raz 719243a2e63SVlad Yasevich br->vlan_enabled = val; 7202796d0c6SVlad Yasevich br_manage_promisc(br); 721204177f3SToshiaki Makita recalculate_group_addr(br); 722204177f3SToshiaki Makita br_recalculate_fwd_mask(br); 723243a2e63SVlad Yasevich 724a7854037SNikolay Aleksandrov return 0; 725a7854037SNikolay Aleksandrov } 726a7854037SNikolay Aleksandrov 727a7854037SNikolay Aleksandrov int br_vlan_filter_toggle(struct net_bridge *br, unsigned long val) 728a7854037SNikolay Aleksandrov { 729047831a9SXin Long return __br_vlan_filter_toggle(br, val); 730243a2e63SVlad Yasevich } 731243a2e63SVlad Yasevich 7321f51445aSIdo Schimmel bool br_vlan_enabled(const struct net_device *dev) 7331f51445aSIdo Schimmel { 7341f51445aSIdo Schimmel struct net_bridge *br = netdev_priv(dev); 7351f51445aSIdo Schimmel 7361f51445aSIdo Schimmel return !!br->vlan_enabled; 7371f51445aSIdo Schimmel } 7381f51445aSIdo Schimmel EXPORT_SYMBOL_GPL(br_vlan_enabled); 7391f51445aSIdo Schimmel 740d2d427b3SToshiaki Makita int __br_vlan_set_proto(struct net_bridge *br, __be16 proto) 741204177f3SToshiaki Makita { 742204177f3SToshiaki Makita int err = 0; 743204177f3SToshiaki Makita struct net_bridge_port *p; 7442594e906SNikolay Aleksandrov struct net_bridge_vlan *vlan; 745907b1e6eSNikolay Aleksandrov struct net_bridge_vlan_group *vg; 746d2d427b3SToshiaki Makita __be16 oldproto; 747204177f3SToshiaki Makita 748204177f3SToshiaki Makita if (br->vlan_proto == proto) 749d2d427b3SToshiaki Makita return 0; 750204177f3SToshiaki Makita 751204177f3SToshiaki Makita /* Add VLANs for the new proto to the device filter. */ 752204177f3SToshiaki Makita list_for_each_entry(p, &br->port_list, list) { 753907b1e6eSNikolay Aleksandrov vg = nbp_vlan_group(p); 754907b1e6eSNikolay Aleksandrov list_for_each_entry(vlan, &vg->vlan_list, vlist) { 7552594e906SNikolay Aleksandrov err = vlan_vid_add(p->dev, proto, vlan->vid); 756204177f3SToshiaki Makita if (err) 757204177f3SToshiaki Makita goto err_filt; 758204177f3SToshiaki Makita } 759204177f3SToshiaki Makita } 760204177f3SToshiaki Makita 761204177f3SToshiaki Makita oldproto = br->vlan_proto; 762204177f3SToshiaki Makita br->vlan_proto = proto; 763204177f3SToshiaki Makita 764204177f3SToshiaki Makita recalculate_group_addr(br); 765204177f3SToshiaki Makita br_recalculate_fwd_mask(br); 766204177f3SToshiaki Makita 767204177f3SToshiaki Makita /* Delete VLANs for the old proto from the device filter. */ 768907b1e6eSNikolay Aleksandrov list_for_each_entry(p, &br->port_list, list) { 769907b1e6eSNikolay Aleksandrov vg = nbp_vlan_group(p); 770907b1e6eSNikolay Aleksandrov list_for_each_entry(vlan, &vg->vlan_list, vlist) 7712594e906SNikolay Aleksandrov vlan_vid_del(p->dev, oldproto, vlan->vid); 772907b1e6eSNikolay Aleksandrov } 773204177f3SToshiaki Makita 774d2d427b3SToshiaki Makita return 0; 775204177f3SToshiaki Makita 776204177f3SToshiaki Makita err_filt: 777907b1e6eSNikolay Aleksandrov list_for_each_entry_continue_reverse(vlan, &vg->vlan_list, vlist) 7782594e906SNikolay Aleksandrov vlan_vid_del(p->dev, proto, vlan->vid); 779204177f3SToshiaki Makita 780907b1e6eSNikolay Aleksandrov list_for_each_entry_continue_reverse(p, &br->port_list, list) { 781907b1e6eSNikolay Aleksandrov vg = nbp_vlan_group(p); 782907b1e6eSNikolay Aleksandrov list_for_each_entry(vlan, &vg->vlan_list, vlist) 7832594e906SNikolay Aleksandrov vlan_vid_del(p->dev, proto, vlan->vid); 784907b1e6eSNikolay Aleksandrov } 785204177f3SToshiaki Makita 786d2d427b3SToshiaki Makita return err; 787d2d427b3SToshiaki Makita } 788d2d427b3SToshiaki Makita 789d2d427b3SToshiaki Makita int br_vlan_set_proto(struct net_bridge *br, unsigned long val) 790d2d427b3SToshiaki Makita { 791d2d427b3SToshiaki Makita if (val != ETH_P_8021Q && val != ETH_P_8021AD) 792d2d427b3SToshiaki Makita return -EPROTONOSUPPORT; 793d2d427b3SToshiaki Makita 794047831a9SXin Long return __br_vlan_set_proto(br, htons(val)); 795204177f3SToshiaki Makita } 796204177f3SToshiaki Makita 7976dada9b1SNikolay Aleksandrov int br_vlan_set_stats(struct net_bridge *br, unsigned long val) 7986dada9b1SNikolay Aleksandrov { 7996dada9b1SNikolay Aleksandrov switch (val) { 8006dada9b1SNikolay Aleksandrov case 0: 8016dada9b1SNikolay Aleksandrov case 1: 8026dada9b1SNikolay Aleksandrov br->vlan_stats_enabled = val; 8036dada9b1SNikolay Aleksandrov break; 8046dada9b1SNikolay Aleksandrov default: 8056dada9b1SNikolay Aleksandrov return -EINVAL; 8066dada9b1SNikolay Aleksandrov } 8076dada9b1SNikolay Aleksandrov 8086dada9b1SNikolay Aleksandrov return 0; 8096dada9b1SNikolay Aleksandrov } 8106dada9b1SNikolay Aleksandrov 81177751ee8SNikolay Aleksandrov static bool vlan_default_pvid(struct net_bridge_vlan_group *vg, u16 vid) 8125be5a2dfSVlad Yasevich { 8132594e906SNikolay Aleksandrov struct net_bridge_vlan *v; 8142594e906SNikolay Aleksandrov 81577751ee8SNikolay Aleksandrov if (vid != vg->pvid) 8162594e906SNikolay Aleksandrov return false; 8172594e906SNikolay Aleksandrov 8182594e906SNikolay Aleksandrov v = br_vlan_lookup(&vg->vlan_hash, vid); 8192594e906SNikolay Aleksandrov if (v && br_vlan_should_use(v) && 8202594e906SNikolay Aleksandrov (v->flags & BRIDGE_VLAN_INFO_UNTAGGED)) 8212594e906SNikolay Aleksandrov return true; 8222594e906SNikolay Aleksandrov 8232594e906SNikolay Aleksandrov return false; 8245be5a2dfSVlad Yasevich } 8255be5a2dfSVlad Yasevich 8265be5a2dfSVlad Yasevich static void br_vlan_disable_default_pvid(struct net_bridge *br) 8275be5a2dfSVlad Yasevich { 8285be5a2dfSVlad Yasevich struct net_bridge_port *p; 8295be5a2dfSVlad Yasevich u16 pvid = br->default_pvid; 8305be5a2dfSVlad Yasevich 8315be5a2dfSVlad Yasevich /* Disable default_pvid on all ports where it is still 8325be5a2dfSVlad Yasevich * configured. 8335be5a2dfSVlad Yasevich */ 834907b1e6eSNikolay Aleksandrov if (vlan_default_pvid(br_vlan_group(br), pvid)) 8355be5a2dfSVlad Yasevich br_vlan_delete(br, pvid); 8365be5a2dfSVlad Yasevich 8375be5a2dfSVlad Yasevich list_for_each_entry(p, &br->port_list, list) { 838907b1e6eSNikolay Aleksandrov if (vlan_default_pvid(nbp_vlan_group(p), pvid)) 8395be5a2dfSVlad Yasevich nbp_vlan_delete(p, pvid); 8405be5a2dfSVlad Yasevich } 8415be5a2dfSVlad Yasevich 8425be5a2dfSVlad Yasevich br->default_pvid = 0; 8435be5a2dfSVlad Yasevich } 8445be5a2dfSVlad Yasevich 8450f963b75SNikolay Aleksandrov int __br_vlan_set_default_pvid(struct net_bridge *br, u16 pvid) 8465be5a2dfSVlad Yasevich { 8472594e906SNikolay Aleksandrov const struct net_bridge_vlan *pvent; 848907b1e6eSNikolay Aleksandrov struct net_bridge_vlan_group *vg; 8495be5a2dfSVlad Yasevich struct net_bridge_port *p; 850f418af63SNikolay Aleksandrov unsigned long *changed; 851f418af63SNikolay Aleksandrov bool vlchange; 8525be5a2dfSVlad Yasevich u16 old_pvid; 8535be5a2dfSVlad Yasevich int err = 0; 8545be5a2dfSVlad Yasevich 8550f963b75SNikolay Aleksandrov if (!pvid) { 8560f963b75SNikolay Aleksandrov br_vlan_disable_default_pvid(br); 8570f963b75SNikolay Aleksandrov return 0; 8580f963b75SNikolay Aleksandrov } 8590f963b75SNikolay Aleksandrov 8605be5a2dfSVlad Yasevich changed = kcalloc(BITS_TO_LONGS(BR_MAX_PORTS), sizeof(unsigned long), 8615be5a2dfSVlad Yasevich GFP_KERNEL); 8625be5a2dfSVlad Yasevich if (!changed) 8635be5a2dfSVlad Yasevich return -ENOMEM; 8645be5a2dfSVlad Yasevich 8655be5a2dfSVlad Yasevich old_pvid = br->default_pvid; 8665be5a2dfSVlad Yasevich 8675be5a2dfSVlad Yasevich /* Update default_pvid config only if we do not conflict with 8685be5a2dfSVlad Yasevich * user configuration. 8695be5a2dfSVlad Yasevich */ 870907b1e6eSNikolay Aleksandrov vg = br_vlan_group(br); 871907b1e6eSNikolay Aleksandrov pvent = br_vlan_find(vg, pvid); 872907b1e6eSNikolay Aleksandrov if ((!old_pvid || vlan_default_pvid(vg, old_pvid)) && 8732594e906SNikolay Aleksandrov (!pvent || !br_vlan_should_use(pvent))) { 8745be5a2dfSVlad Yasevich err = br_vlan_add(br, pvid, 8755be5a2dfSVlad Yasevich BRIDGE_VLAN_INFO_PVID | 8762594e906SNikolay Aleksandrov BRIDGE_VLAN_INFO_UNTAGGED | 877f418af63SNikolay Aleksandrov BRIDGE_VLAN_INFO_BRENTRY, 878f418af63SNikolay Aleksandrov &vlchange); 8795be5a2dfSVlad Yasevich if (err) 8805be5a2dfSVlad Yasevich goto out; 8815be5a2dfSVlad Yasevich br_vlan_delete(br, old_pvid); 8825be5a2dfSVlad Yasevich set_bit(0, changed); 8835be5a2dfSVlad Yasevich } 8845be5a2dfSVlad Yasevich 8855be5a2dfSVlad Yasevich list_for_each_entry(p, &br->port_list, list) { 8865be5a2dfSVlad Yasevich /* Update default_pvid config only if we do not conflict with 8875be5a2dfSVlad Yasevich * user configuration. 8885be5a2dfSVlad Yasevich */ 889907b1e6eSNikolay Aleksandrov vg = nbp_vlan_group(p); 8905be5a2dfSVlad Yasevich if ((old_pvid && 891907b1e6eSNikolay Aleksandrov !vlan_default_pvid(vg, old_pvid)) || 892907b1e6eSNikolay Aleksandrov br_vlan_find(vg, pvid)) 8935be5a2dfSVlad Yasevich continue; 8945be5a2dfSVlad Yasevich 8955be5a2dfSVlad Yasevich err = nbp_vlan_add(p, pvid, 8965be5a2dfSVlad Yasevich BRIDGE_VLAN_INFO_PVID | 897f418af63SNikolay Aleksandrov BRIDGE_VLAN_INFO_UNTAGGED, 898f418af63SNikolay Aleksandrov &vlchange); 8995be5a2dfSVlad Yasevich if (err) 9005be5a2dfSVlad Yasevich goto err_port; 9015be5a2dfSVlad Yasevich nbp_vlan_delete(p, old_pvid); 9025be5a2dfSVlad Yasevich set_bit(p->port_no, changed); 9035be5a2dfSVlad Yasevich } 9045be5a2dfSVlad Yasevich 9055be5a2dfSVlad Yasevich br->default_pvid = pvid; 9065be5a2dfSVlad Yasevich 9075be5a2dfSVlad Yasevich out: 9085be5a2dfSVlad Yasevich kfree(changed); 9095be5a2dfSVlad Yasevich return err; 9105be5a2dfSVlad Yasevich 9115be5a2dfSVlad Yasevich err_port: 9125be5a2dfSVlad Yasevich list_for_each_entry_continue_reverse(p, &br->port_list, list) { 9135be5a2dfSVlad Yasevich if (!test_bit(p->port_no, changed)) 9145be5a2dfSVlad Yasevich continue; 9155be5a2dfSVlad Yasevich 9165be5a2dfSVlad Yasevich if (old_pvid) 9175be5a2dfSVlad Yasevich nbp_vlan_add(p, old_pvid, 9185be5a2dfSVlad Yasevich BRIDGE_VLAN_INFO_PVID | 919f418af63SNikolay Aleksandrov BRIDGE_VLAN_INFO_UNTAGGED, 920f418af63SNikolay Aleksandrov &vlchange); 9215be5a2dfSVlad Yasevich nbp_vlan_delete(p, pvid); 9225be5a2dfSVlad Yasevich } 9235be5a2dfSVlad Yasevich 9245be5a2dfSVlad Yasevich if (test_bit(0, changed)) { 9255be5a2dfSVlad Yasevich if (old_pvid) 9265be5a2dfSVlad Yasevich br_vlan_add(br, old_pvid, 9275be5a2dfSVlad Yasevich BRIDGE_VLAN_INFO_PVID | 9282594e906SNikolay Aleksandrov BRIDGE_VLAN_INFO_UNTAGGED | 929f418af63SNikolay Aleksandrov BRIDGE_VLAN_INFO_BRENTRY, 930f418af63SNikolay Aleksandrov &vlchange); 9315be5a2dfSVlad Yasevich br_vlan_delete(br, pvid); 9325be5a2dfSVlad Yasevich } 9335be5a2dfSVlad Yasevich goto out; 9345be5a2dfSVlad Yasevich } 9355be5a2dfSVlad Yasevich 93696a20d9dSVlad Yasevich int br_vlan_set_default_pvid(struct net_bridge *br, unsigned long val) 93796a20d9dSVlad Yasevich { 93896a20d9dSVlad Yasevich u16 pvid = val; 93996a20d9dSVlad Yasevich int err = 0; 94096a20d9dSVlad Yasevich 9415be5a2dfSVlad Yasevich if (val >= VLAN_VID_MASK) 94296a20d9dSVlad Yasevich return -EINVAL; 94396a20d9dSVlad Yasevich 94496a20d9dSVlad Yasevich if (pvid == br->default_pvid) 945047831a9SXin Long goto out; 94696a20d9dSVlad Yasevich 94796a20d9dSVlad Yasevich /* Only allow default pvid change when filtering is disabled */ 94896a20d9dSVlad Yasevich if (br->vlan_enabled) { 94996a20d9dSVlad Yasevich pr_info_once("Please disable vlan filtering to change default_pvid\n"); 95096a20d9dSVlad Yasevich err = -EPERM; 951047831a9SXin Long goto out; 95296a20d9dSVlad Yasevich } 9535be5a2dfSVlad Yasevich err = __br_vlan_set_default_pvid(br, pvid); 954047831a9SXin Long out: 95596a20d9dSVlad Yasevich return err; 95696a20d9dSVlad Yasevich } 95796a20d9dSVlad Yasevich 9585be5a2dfSVlad Yasevich int br_vlan_init(struct net_bridge *br) 9598580e211SToshiaki Makita { 960907b1e6eSNikolay Aleksandrov struct net_bridge_vlan_group *vg; 9612594e906SNikolay Aleksandrov int ret = -ENOMEM; 962f418af63SNikolay Aleksandrov bool changed; 9632594e906SNikolay Aleksandrov 964907b1e6eSNikolay Aleksandrov vg = kzalloc(sizeof(*vg), GFP_KERNEL); 965907b1e6eSNikolay Aleksandrov if (!vg) 9662594e906SNikolay Aleksandrov goto out; 967907b1e6eSNikolay Aleksandrov ret = rhashtable_init(&vg->vlan_hash, &br_vlan_rht_params); 9682594e906SNikolay Aleksandrov if (ret) 9692594e906SNikolay Aleksandrov goto err_rhtbl; 970efa5356bSRoopa Prabhu ret = vlan_tunnel_init(vg); 971efa5356bSRoopa Prabhu if (ret) 972efa5356bSRoopa Prabhu goto err_tunnel_init; 973907b1e6eSNikolay Aleksandrov INIT_LIST_HEAD(&vg->vlan_list); 9748580e211SToshiaki Makita br->vlan_proto = htons(ETH_P_8021Q); 97596a20d9dSVlad Yasevich br->default_pvid = 1; 976907b1e6eSNikolay Aleksandrov rcu_assign_pointer(br->vlgrp, vg); 9772594e906SNikolay Aleksandrov ret = br_vlan_add(br, 1, 9782594e906SNikolay Aleksandrov BRIDGE_VLAN_INFO_PVID | BRIDGE_VLAN_INFO_UNTAGGED | 979f418af63SNikolay Aleksandrov BRIDGE_VLAN_INFO_BRENTRY, &changed); 9802594e906SNikolay Aleksandrov if (ret) 9812594e906SNikolay Aleksandrov goto err_vlan_add; 9822594e906SNikolay Aleksandrov 9832594e906SNikolay Aleksandrov out: 9842594e906SNikolay Aleksandrov return ret; 9852594e906SNikolay Aleksandrov 9862594e906SNikolay Aleksandrov err_vlan_add: 987efa5356bSRoopa Prabhu vlan_tunnel_deinit(vg); 988efa5356bSRoopa Prabhu err_tunnel_init: 989907b1e6eSNikolay Aleksandrov rhashtable_destroy(&vg->vlan_hash); 9902594e906SNikolay Aleksandrov err_rhtbl: 991907b1e6eSNikolay Aleksandrov kfree(vg); 9922594e906SNikolay Aleksandrov 9932594e906SNikolay Aleksandrov goto out; 9942594e906SNikolay Aleksandrov } 9952594e906SNikolay Aleksandrov 9962594e906SNikolay Aleksandrov int nbp_vlan_init(struct net_bridge_port *p) 9972594e906SNikolay Aleksandrov { 998404cdbf0SElad Raz struct switchdev_attr attr = { 999404cdbf0SElad Raz .orig_dev = p->br->dev, 1000404cdbf0SElad Raz .id = SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING, 1001404cdbf0SElad Raz .flags = SWITCHDEV_F_SKIP_EOPNOTSUPP, 1002404cdbf0SElad Raz .u.vlan_filtering = p->br->vlan_enabled, 1003404cdbf0SElad Raz }; 1004263344e6SNikolay Aleksandrov struct net_bridge_vlan_group *vg; 10052594e906SNikolay Aleksandrov int ret = -ENOMEM; 10062594e906SNikolay Aleksandrov 1007263344e6SNikolay Aleksandrov vg = kzalloc(sizeof(struct net_bridge_vlan_group), GFP_KERNEL); 1008263344e6SNikolay Aleksandrov if (!vg) 10092594e906SNikolay Aleksandrov goto out; 10102594e906SNikolay Aleksandrov 1011404cdbf0SElad Raz ret = switchdev_port_attr_set(p->dev, &attr); 1012404cdbf0SElad Raz if (ret && ret != -EOPNOTSUPP) 1013404cdbf0SElad Raz goto err_vlan_enabled; 1014404cdbf0SElad Raz 1015263344e6SNikolay Aleksandrov ret = rhashtable_init(&vg->vlan_hash, &br_vlan_rht_params); 10162594e906SNikolay Aleksandrov if (ret) 10172594e906SNikolay Aleksandrov goto err_rhtbl; 1018efa5356bSRoopa Prabhu ret = vlan_tunnel_init(vg); 1019efa5356bSRoopa Prabhu if (ret) 1020efa5356bSRoopa Prabhu goto err_tunnel_init; 1021263344e6SNikolay Aleksandrov INIT_LIST_HEAD(&vg->vlan_list); 1022907b1e6eSNikolay Aleksandrov rcu_assign_pointer(p->vlgrp, vg); 10232594e906SNikolay Aleksandrov if (p->br->default_pvid) { 1024f418af63SNikolay Aleksandrov bool changed; 1025f418af63SNikolay Aleksandrov 10262594e906SNikolay Aleksandrov ret = nbp_vlan_add(p, p->br->default_pvid, 10272594e906SNikolay Aleksandrov BRIDGE_VLAN_INFO_PVID | 1028f418af63SNikolay Aleksandrov BRIDGE_VLAN_INFO_UNTAGGED, 1029f418af63SNikolay Aleksandrov &changed); 10302594e906SNikolay Aleksandrov if (ret) 10312594e906SNikolay Aleksandrov goto err_vlan_add; 10322594e906SNikolay Aleksandrov } 10332594e906SNikolay Aleksandrov out: 10342594e906SNikolay Aleksandrov return ret; 10352594e906SNikolay Aleksandrov 10362594e906SNikolay Aleksandrov err_vlan_add: 103707bc588fSIdo Schimmel RCU_INIT_POINTER(p->vlgrp, NULL); 103807bc588fSIdo Schimmel synchronize_rcu(); 1039efa5356bSRoopa Prabhu vlan_tunnel_deinit(vg); 1040efa5356bSRoopa Prabhu err_tunnel_init: 1041efa5356bSRoopa Prabhu rhashtable_destroy(&vg->vlan_hash); 10422594e906SNikolay Aleksandrov err_rhtbl: 1043df2c4334SYotam Gigi err_vlan_enabled: 1044263344e6SNikolay Aleksandrov kfree(vg); 10452594e906SNikolay Aleksandrov 10462594e906SNikolay Aleksandrov goto out; 10478580e211SToshiaki Makita } 10488580e211SToshiaki Makita 10498adff41cSToshiaki Makita /* Must be protected by RTNL. 10508adff41cSToshiaki Makita * Must be called with vid in range from 1 to 4094 inclusive. 1051f418af63SNikolay Aleksandrov * changed must be true only if the vlan was created or updated 10528adff41cSToshiaki Makita */ 1053f418af63SNikolay Aleksandrov int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags, 1054f418af63SNikolay Aleksandrov bool *changed) 1055243a2e63SVlad Yasevich { 10567fbac984SIdo Schimmel struct switchdev_obj_port_vlan v = { 10577fbac984SIdo Schimmel .obj.orig_dev = port->dev, 10587fbac984SIdo Schimmel .obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN, 10597fbac984SIdo Schimmel .flags = flags, 10607fbac984SIdo Schimmel .vid_begin = vid, 10617fbac984SIdo Schimmel .vid_end = vid, 10627fbac984SIdo Schimmel }; 10632594e906SNikolay Aleksandrov struct net_bridge_vlan *vlan; 10642594e906SNikolay Aleksandrov int ret; 1065243a2e63SVlad Yasevich 1066243a2e63SVlad Yasevich ASSERT_RTNL(); 1067243a2e63SVlad Yasevich 1068f418af63SNikolay Aleksandrov *changed = false; 1069907b1e6eSNikolay Aleksandrov vlan = br_vlan_find(nbp_vlan_group(port), vid); 10702594e906SNikolay Aleksandrov if (vlan) { 10717fbac984SIdo Schimmel /* Pass the flags to the hardware bridge */ 10727fbac984SIdo Schimmel ret = switchdev_port_obj_add(port->dev, &v.obj); 10737fbac984SIdo Schimmel if (ret && ret != -EOPNOTSUPP) 10747fbac984SIdo Schimmel return ret; 1075f418af63SNikolay Aleksandrov *changed = __vlan_add_flags(vlan, flags); 1076f418af63SNikolay Aleksandrov 10772594e906SNikolay Aleksandrov return 0; 1078243a2e63SVlad Yasevich } 1079243a2e63SVlad Yasevich 10802594e906SNikolay Aleksandrov vlan = kzalloc(sizeof(*vlan), GFP_KERNEL); 10812594e906SNikolay Aleksandrov if (!vlan) 10822594e906SNikolay Aleksandrov return -ENOMEM; 1083243a2e63SVlad Yasevich 10842594e906SNikolay Aleksandrov vlan->vid = vid; 10852594e906SNikolay Aleksandrov vlan->port = port; 10862594e906SNikolay Aleksandrov ret = __vlan_add(vlan, flags); 10872594e906SNikolay Aleksandrov if (ret) 10882594e906SNikolay Aleksandrov kfree(vlan); 1089f418af63SNikolay Aleksandrov else 1090f418af63SNikolay Aleksandrov *changed = true; 1091243a2e63SVlad Yasevich 10922594e906SNikolay Aleksandrov return ret; 1093243a2e63SVlad Yasevich } 1094243a2e63SVlad Yasevich 10958adff41cSToshiaki Makita /* Must be protected by RTNL. 10968adff41cSToshiaki Makita * Must be called with vid in range from 1 to 4094 inclusive. 10978adff41cSToshiaki Makita */ 1098243a2e63SVlad Yasevich int nbp_vlan_delete(struct net_bridge_port *port, u16 vid) 1099243a2e63SVlad Yasevich { 11002594e906SNikolay Aleksandrov struct net_bridge_vlan *v; 1101243a2e63SVlad Yasevich 1102243a2e63SVlad Yasevich ASSERT_RTNL(); 1103243a2e63SVlad Yasevich 1104907b1e6eSNikolay Aleksandrov v = br_vlan_find(nbp_vlan_group(port), vid); 11052594e906SNikolay Aleksandrov if (!v) 11062594e906SNikolay Aleksandrov return -ENOENT; 1107424bb9c9SToshiaki Makita br_fdb_find_delete_local(port->br, port, port->dev->dev_addr, vid); 11081ea2d020SNikolay Aleksandrov br_fdb_delete_by_port(port->br, port, vid, 0); 1109bc9a25d2SVlad Yasevich 11102594e906SNikolay Aleksandrov return __vlan_del(v); 1111243a2e63SVlad Yasevich } 1112243a2e63SVlad Yasevich 1113243a2e63SVlad Yasevich void nbp_vlan_flush(struct net_bridge_port *port) 1114243a2e63SVlad Yasevich { 1115f409d0edSNikolay Aleksandrov struct net_bridge_vlan_group *vg; 1116f409d0edSNikolay Aleksandrov 1117243a2e63SVlad Yasevich ASSERT_RTNL(); 1118243a2e63SVlad Yasevich 1119f409d0edSNikolay Aleksandrov vg = nbp_vlan_group(port); 1120f409d0edSNikolay Aleksandrov __vlan_flush(vg); 1121f409d0edSNikolay Aleksandrov RCU_INIT_POINTER(port->vlgrp, NULL); 1122f409d0edSNikolay Aleksandrov synchronize_rcu(); 1123f409d0edSNikolay Aleksandrov __vlan_group_free(vg); 11245be5a2dfSVlad Yasevich } 1125a60c0903SNikolay Aleksandrov 1126a60c0903SNikolay Aleksandrov void br_vlan_get_stats(const struct net_bridge_vlan *v, 1127a60c0903SNikolay Aleksandrov struct br_vlan_stats *stats) 1128a60c0903SNikolay Aleksandrov { 1129a60c0903SNikolay Aleksandrov int i; 1130a60c0903SNikolay Aleksandrov 1131a60c0903SNikolay Aleksandrov memset(stats, 0, sizeof(*stats)); 1132a60c0903SNikolay Aleksandrov for_each_possible_cpu(i) { 1133a60c0903SNikolay Aleksandrov u64 rxpackets, rxbytes, txpackets, txbytes; 1134a60c0903SNikolay Aleksandrov struct br_vlan_stats *cpu_stats; 1135a60c0903SNikolay Aleksandrov unsigned int start; 1136a60c0903SNikolay Aleksandrov 1137a60c0903SNikolay Aleksandrov cpu_stats = per_cpu_ptr(v->stats, i); 1138a60c0903SNikolay Aleksandrov do { 1139a60c0903SNikolay Aleksandrov start = u64_stats_fetch_begin_irq(&cpu_stats->syncp); 1140a60c0903SNikolay Aleksandrov rxpackets = cpu_stats->rx_packets; 1141a60c0903SNikolay Aleksandrov rxbytes = cpu_stats->rx_bytes; 1142a60c0903SNikolay Aleksandrov txbytes = cpu_stats->tx_bytes; 1143a60c0903SNikolay Aleksandrov txpackets = cpu_stats->tx_packets; 1144a60c0903SNikolay Aleksandrov } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start)); 1145a60c0903SNikolay Aleksandrov 1146a60c0903SNikolay Aleksandrov stats->rx_packets += rxpackets; 1147a60c0903SNikolay Aleksandrov stats->rx_bytes += rxbytes; 1148a60c0903SNikolay Aleksandrov stats->tx_bytes += txbytes; 1149a60c0903SNikolay Aleksandrov stats->tx_packets += txpackets; 1150a60c0903SNikolay Aleksandrov } 1151a60c0903SNikolay Aleksandrov } 11524d4fd361SPetr Machata 11534d4fd361SPetr Machata int br_vlan_get_pvid(const struct net_device *dev, u16 *p_pvid) 11544d4fd361SPetr Machata { 11554d4fd361SPetr Machata struct net_bridge_vlan_group *vg; 11564d4fd361SPetr Machata 11574d4fd361SPetr Machata ASSERT_RTNL(); 11584d4fd361SPetr Machata if (netif_is_bridge_master(dev)) 11594d4fd361SPetr Machata vg = br_vlan_group(netdev_priv(dev)); 11604d4fd361SPetr Machata else 11614d4fd361SPetr Machata return -EINVAL; 11624d4fd361SPetr Machata 11634d4fd361SPetr Machata *p_pvid = br_get_pvid(vg); 11644d4fd361SPetr Machata return 0; 11654d4fd361SPetr Machata } 11664d4fd361SPetr Machata EXPORT_SYMBOL_GPL(br_vlan_get_pvid); 11674d4fd361SPetr Machata 11684d4fd361SPetr Machata int br_vlan_get_info(const struct net_device *dev, u16 vid, 11694d4fd361SPetr Machata struct bridge_vlan_info *p_vinfo) 11704d4fd361SPetr Machata { 11714d4fd361SPetr Machata struct net_bridge_vlan_group *vg; 11724d4fd361SPetr Machata struct net_bridge_vlan *v; 11734d4fd361SPetr Machata struct net_bridge_port *p; 11744d4fd361SPetr Machata 11754d4fd361SPetr Machata ASSERT_RTNL(); 11764d4fd361SPetr Machata p = br_port_get_check_rtnl(dev); 11774d4fd361SPetr Machata if (p) 11784d4fd361SPetr Machata vg = nbp_vlan_group(p); 11792b18d79eSPetr Machata else if (netif_is_bridge_master(dev)) 11802b18d79eSPetr Machata vg = br_vlan_group(netdev_priv(dev)); 11814d4fd361SPetr Machata else 11824d4fd361SPetr Machata return -EINVAL; 11834d4fd361SPetr Machata 11844d4fd361SPetr Machata v = br_vlan_find(vg, vid); 11854d4fd361SPetr Machata if (!v) 11864d4fd361SPetr Machata return -ENOENT; 11874d4fd361SPetr Machata 11884d4fd361SPetr Machata p_vinfo->vid = vid; 11894d4fd361SPetr Machata p_vinfo->flags = v->flags; 11904d4fd361SPetr Machata return 0; 11914d4fd361SPetr Machata } 11924d4fd361SPetr Machata EXPORT_SYMBOL_GPL(br_vlan_get_info); 1193