OSDN Git Service

Merge tag 'mips_fixes_4.21_1' of git://git.kernel.org/pub/scm/linux/kernel/git/mips...
[uclinux-h8/linux.git] / net / bridge / br_vlan.c
index 8c9297a..4a2f311 100644 (file)
@@ -80,14 +80,14 @@ static bool __vlan_add_flags(struct net_bridge_vlan *v, u16 flags)
 }
 
 static int __vlan_vid_add(struct net_device *dev, struct net_bridge *br,
-                         u16 vid, u16 flags)
+                         u16 vid, u16 flags, struct netlink_ext_ack *extack)
 {
        int err;
 
        /* Try switchdev op first. In case it is not supported, fallback to
         * 8021q add.
         */
-       err = br_switchdev_port_vlan_add(dev, vid, flags);
+       err = br_switchdev_port_vlan_add(dev, vid, flags, extack);
        if (err == -EOPNOTSUPP)
                return vlan_vid_add(dev, br->vlan_proto, vid);
        return err;
@@ -139,7 +139,9 @@ static int __vlan_vid_del(struct net_device *dev, struct net_bridge *br,
 /* Returns a master vlan, if it didn't exist it gets created. In all cases a
  * a reference is taken to the master vlan before returning.
  */
-static struct net_bridge_vlan *br_vlan_get_master(struct net_bridge *br, u16 vid)
+static struct net_bridge_vlan *
+br_vlan_get_master(struct net_bridge *br, u16 vid,
+                  struct netlink_ext_ack *extack)
 {
        struct net_bridge_vlan_group *vg;
        struct net_bridge_vlan *masterv;
@@ -150,7 +152,7 @@ static struct net_bridge_vlan *br_vlan_get_master(struct net_bridge *br, u16 vid
                bool changed;
 
                /* missing global ctx, create it now */
-               if (br_vlan_add(br, vid, 0, &changed))
+               if (br_vlan_add(br, vid, 0, &changed, extack))
                        return NULL;
                masterv = br_vlan_find(vg, vid);
                if (WARN_ON(!masterv))
@@ -197,7 +199,7 @@ static void nbp_vlan_rcu_free(struct rcu_head *rcu)
        v = container_of(rcu, struct net_bridge_vlan, rcu);
        WARN_ON(br_vlan_is_master(v));
        /* if we had per-port stats configured then free them here */
-       if (v->brvlan->stats != v->stats)
+       if (v->priv_flags & BR_VLFLAG_PER_PORT_STATS)
                free_percpu(v->stats);
        v->stats = NULL;
        kfree(v);
@@ -214,7 +216,8 @@ static void nbp_vlan_rcu_free(struct rcu_head *rcu)
  * 4. same as 3 but with both master and brentry flags set so the entry
  *    will be used for filtering in both the port and the bridge
  */
-static int __vlan_add(struct net_bridge_vlan *v, u16 flags)
+static int __vlan_add(struct net_bridge_vlan *v, u16 flags,
+                     struct netlink_ext_ack *extack)
 {
        struct net_bridge_vlan *masterv = NULL;
        struct net_bridge_port *p = NULL;
@@ -239,7 +242,7 @@ static int __vlan_add(struct net_bridge_vlan *v, u16 flags)
                 * This ensures tagged traffic enters the bridge when
                 * promiscuous mode is disabled by br_manage_promisc().
                 */
-               err = __vlan_vid_add(dev, br, v->vid, flags);
+               err = __vlan_vid_add(dev, br, v->vid, flags, extack);
                if (err)
                        goto out;
 
@@ -249,12 +252,12 @@ static int __vlan_add(struct net_bridge_vlan *v, u16 flags)
 
                        err = br_vlan_add(br, v->vid,
                                          flags | BRIDGE_VLAN_INFO_BRENTRY,
-                                         &changed);
+                                         &changed, extack);
                        if (err)
                                goto out_filt;
                }
 
-               masterv = br_vlan_get_master(br, v->vid);
+               masterv = br_vlan_get_master(br, v->vid, extack);
                if (!masterv)
                        goto out_filt;
                v->brvlan = masterv;
@@ -264,11 +267,12 @@ static int __vlan_add(struct net_bridge_vlan *v, u16 flags)
                                err = -ENOMEM;
                                goto out_filt;
                        }
+                       v->priv_flags |= BR_VLFLAG_PER_PORT_STATS;
                } else {
                        v->stats = masterv->stats;
                }
        } else {
-               err = br_switchdev_port_vlan_add(dev, v->vid, flags);
+               err = br_switchdev_port_vlan_add(dev, v->vid, flags, extack);
                if (err && err != -EOPNOTSUPP)
                        goto out;
        }
@@ -420,7 +424,7 @@ struct sk_buff *br_handle_vlan(struct net_bridge *br,
        }
 
        if (v->flags & BRIDGE_VLAN_INFO_UNTAGGED)
-               skb->vlan_tci = 0;
+               __vlan_hwaccel_clear_tag(skb);
 
        if (p && (p->flags & BR_VLAN_TUNNEL) &&
            br_handle_egress_vlan_tunnel(skb, v)) {
@@ -493,8 +497,8 @@ static bool __allowed_ingress(const struct net_bridge *br,
                        __vlan_hwaccel_put_tag(skb, br->vlan_proto, pvid);
                else
                        /* Priority-tagged Frame.
-                        * At this point, We know that skb->vlan_tci had
-                        * VLAN_TAG_PRESENT bit and its VID field was 0x000.
+                        * At this point, we know that skb->vlan_tci VID
+                        * field was 0.
                         * We update only VID field and preserve PCP field.
                         */
                        skb->vlan_tci |= pvid;
@@ -590,11 +594,12 @@ bool br_should_learn(struct net_bridge_port *p, struct sk_buff *skb, u16 *vid)
 static int br_vlan_add_existing(struct net_bridge *br,
                                struct net_bridge_vlan_group *vg,
                                struct net_bridge_vlan *vlan,
-                               u16 flags, bool *changed)
+                               u16 flags, bool *changed,
+                               struct netlink_ext_ack *extack)
 {
        int err;
 
-       err = br_switchdev_port_vlan_add(br->dev, vlan->vid, flags);
+       err = br_switchdev_port_vlan_add(br->dev, vlan->vid, flags, extack);
        if (err && err != -EOPNOTSUPP)
                return err;
 
@@ -633,7 +638,8 @@ err_flags:
  * Must be called with vid in range from 1 to 4094 inclusive.
  * changed must be true only if the vlan was created or updated
  */
-int br_vlan_add(struct net_bridge *br, u16 vid, u16 flags, bool *changed)
+int br_vlan_add(struct net_bridge *br, u16 vid, u16 flags, bool *changed,
+               struct netlink_ext_ack *extack)
 {
        struct net_bridge_vlan_group *vg;
        struct net_bridge_vlan *vlan;
@@ -645,7 +651,8 @@ int br_vlan_add(struct net_bridge *br, u16 vid, u16 flags, bool *changed)
        vg = br_vlan_group(br);
        vlan = br_vlan_find(vg, vid);
        if (vlan)
-               return br_vlan_add_existing(br, vg, vlan, flags, changed);
+               return br_vlan_add_existing(br, vg, vlan, flags, changed,
+                                           extack);
 
        vlan = kzalloc(sizeof(*vlan), GFP_KERNEL);
        if (!vlan)
@@ -662,7 +669,7 @@ int br_vlan_add(struct net_bridge *br, u16 vid, u16 flags, bool *changed)
        vlan->br = br;
        if (flags & BRIDGE_VLAN_INFO_BRENTRY)
                refcount_set(&vlan->refcnt, 1);
-       ret = __vlan_add(vlan, flags);
+       ret = __vlan_add(vlan, flags, extack);
        if (ret) {
                free_percpu(vlan->stats);
                kfree(vlan);
@@ -913,7 +920,8 @@ static void br_vlan_disable_default_pvid(struct net_bridge *br)
        br->default_pvid = 0;
 }
 
-int __br_vlan_set_default_pvid(struct net_bridge *br, u16 pvid)
+int __br_vlan_set_default_pvid(struct net_bridge *br, u16 pvid,
+                              struct netlink_ext_ack *extack)
 {
        const struct net_bridge_vlan *pvent;
        struct net_bridge_vlan_group *vg;
@@ -945,7 +953,7 @@ int __br_vlan_set_default_pvid(struct net_bridge *br, u16 pvid)
                                  BRIDGE_VLAN_INFO_PVID |
                                  BRIDGE_VLAN_INFO_UNTAGGED |
                                  BRIDGE_VLAN_INFO_BRENTRY,
-                                 &vlchange);
+                                 &vlchange, extack);
                if (err)
                        goto out;
                br_vlan_delete(br, old_pvid);
@@ -965,7 +973,7 @@ int __br_vlan_set_default_pvid(struct net_bridge *br, u16 pvid)
                err = nbp_vlan_add(p, pvid,
                                   BRIDGE_VLAN_INFO_PVID |
                                   BRIDGE_VLAN_INFO_UNTAGGED,
-                                  &vlchange);
+                                  &vlchange, extack);
                if (err)
                        goto err_port;
                nbp_vlan_delete(p, old_pvid);
@@ -987,7 +995,7 @@ err_port:
                        nbp_vlan_add(p, old_pvid,
                                     BRIDGE_VLAN_INFO_PVID |
                                     BRIDGE_VLAN_INFO_UNTAGGED,
-                                    &vlchange);
+                                    &vlchange, NULL);
                nbp_vlan_delete(p, pvid);
        }
 
@@ -997,7 +1005,7 @@ err_port:
                                    BRIDGE_VLAN_INFO_PVID |
                                    BRIDGE_VLAN_INFO_UNTAGGED |
                                    BRIDGE_VLAN_INFO_BRENTRY,
-                                   &vlchange);
+                                   &vlchange, NULL);
                br_vlan_delete(br, pvid);
        }
        goto out;
@@ -1020,7 +1028,7 @@ int br_vlan_set_default_pvid(struct net_bridge *br, unsigned long val)
                err = -EPERM;
                goto out;
        }
-       err = __br_vlan_set_default_pvid(br, pvid);
+       err = __br_vlan_set_default_pvid(br, pvid, NULL);
 out:
        return err;
 }
@@ -1046,7 +1054,7 @@ int br_vlan_init(struct net_bridge *br)
        rcu_assign_pointer(br->vlgrp, vg);
        ret = br_vlan_add(br, 1,
                          BRIDGE_VLAN_INFO_PVID | BRIDGE_VLAN_INFO_UNTAGGED |
-                         BRIDGE_VLAN_INFO_BRENTRY, &changed);
+                         BRIDGE_VLAN_INFO_BRENTRY, &changed, NULL);
        if (ret)
                goto err_vlan_add;
 
@@ -1063,7 +1071,7 @@ err_rhtbl:
        goto out;
 }
 
-int nbp_vlan_init(struct net_bridge_port *p)
+int nbp_vlan_init(struct net_bridge_port *p, struct netlink_ext_ack *extack)
 {
        struct switchdev_attr attr = {
                .orig_dev = p->br->dev,
@@ -1096,7 +1104,7 @@ int nbp_vlan_init(struct net_bridge_port *p)
                ret = nbp_vlan_add(p, p->br->default_pvid,
                                   BRIDGE_VLAN_INFO_PVID |
                                   BRIDGE_VLAN_INFO_UNTAGGED,
-                                  &changed);
+                                  &changed, extack);
                if (ret)
                        goto err_vlan_add;
        }
@@ -1121,7 +1129,7 @@ err_vlan_enabled:
  * changed must be true only if the vlan was created or updated
  */
 int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags,
-                bool *changed)
+                bool *changed, struct netlink_ext_ack *extack)
 {
        struct net_bridge_vlan *vlan;
        int ret;
@@ -1132,7 +1140,7 @@ int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags,
        vlan = br_vlan_find(nbp_vlan_group(port), vid);
        if (vlan) {
                /* Pass the flags to the hardware bridge */
-               ret = br_switchdev_port_vlan_add(port->dev, vid, flags);
+               ret = br_switchdev_port_vlan_add(port->dev, vid, flags, extack);
                if (ret && ret != -EOPNOTSUPP)
                        return ret;
                *changed = __vlan_add_flags(vlan, flags);
@@ -1146,7 +1154,7 @@ int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags,
 
        vlan->vid = vid;
        vlan->port = port;
-       ret = __vlan_add(vlan, flags);
+       ret = __vlan_add(vlan, flags, extack);
        if (ret)
                kfree(vlan);
        else
@@ -1216,9 +1224,13 @@ void br_vlan_get_stats(const struct net_bridge_vlan *v,
 int br_vlan_get_pvid(const struct net_device *dev, u16 *p_pvid)
 {
        struct net_bridge_vlan_group *vg;
+       struct net_bridge_port *p;
 
        ASSERT_RTNL();
-       if (netif_is_bridge_master(dev))
+       p = br_port_get_check_rtnl(dev);
+       if (p)
+               vg = nbp_vlan_group(p);
+       else if (netif_is_bridge_master(dev))
                vg = br_vlan_group(netdev_priv(dev));
        else
                return -EINVAL;