]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
net: bridge: propagate error code and extack from br_mc_disabled_update
authorFlorian Fainelli <f.fainelli@gmail.com>
Wed, 14 Apr 2021 19:22:57 +0000 (22:22 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 19 May 2021 08:56:16 +0000 (10:56 +0200)
[ Upstream commit ae1ea84b33dab45c7b6c1754231ebda5959b504c ]

Some Ethernet switches might only be able to support disabling multicast
snooping globally, which is an issue for example when several bridges
span the same physical device and request contradictory settings.

Propagate the return value of br_mc_disabled_update() such that this
limitation is transmitted correctly to user-space.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Sasha Levin <sashal@kernel.org>
net/bridge/br_multicast.c
net/bridge/br_netlink.c
net/bridge/br_private.h
net/bridge/br_sysfs_br.c

index 229309d7b4ff99d3b097740ee569de4f03b7223a..72b3193b08ecbb889c99961fa144196cfbdd9eef 100644 (file)
@@ -1593,7 +1593,8 @@ out:
        spin_unlock(&br->multicast_lock);
 }
 
-static void br_mc_disabled_update(struct net_device *dev, bool value)
+static int br_mc_disabled_update(struct net_device *dev, bool value,
+                                struct netlink_ext_ack *extack)
 {
        struct switchdev_attr attr = {
                .orig_dev = dev,
@@ -1602,11 +1603,13 @@ static void br_mc_disabled_update(struct net_device *dev, bool value)
                .u.mc_disabled = !value,
        };
 
-       switchdev_port_attr_set(dev, &attr, NULL);
+       return switchdev_port_attr_set(dev, &attr, extack);
 }
 
 int br_multicast_add_port(struct net_bridge_port *port)
 {
+       int err;
+
        port->multicast_router = MDB_RTR_TYPE_TEMP_QUERY;
        port->multicast_eht_hosts_limit = BR_MCAST_DEFAULT_EHT_HOSTS_LIMIT;
 
@@ -1618,8 +1621,12 @@ int br_multicast_add_port(struct net_bridge_port *port)
        timer_setup(&port->ip6_own_query.timer,
                    br_ip6_multicast_port_query_expired, 0);
 #endif
-       br_mc_disabled_update(port->dev,
-                             br_opt_get(port->br, BROPT_MULTICAST_ENABLED));
+       err = br_mc_disabled_update(port->dev,
+                                   br_opt_get(port->br,
+                                              BROPT_MULTICAST_ENABLED),
+                                   NULL);
+       if (err)
+               return err;
 
        port->mcast_stats = netdev_alloc_pcpu_stats(struct bridge_mcast_stats);
        if (!port->mcast_stats)
@@ -3543,16 +3550,23 @@ static void br_multicast_start_querier(struct net_bridge *br,
        rcu_read_unlock();
 }
 
-int br_multicast_toggle(struct net_bridge *br, unsigned long val)
+int br_multicast_toggle(struct net_bridge *br, unsigned long val,
+                       struct netlink_ext_ack *extack)
 {
        struct net_bridge_port *port;
        bool change_snoopers = false;
+       int err = 0;
 
        spin_lock_bh(&br->multicast_lock);
        if (!!br_opt_get(br, BROPT_MULTICAST_ENABLED) == !!val)
                goto unlock;
 
-       br_mc_disabled_update(br->dev, val);
+       err = br_mc_disabled_update(br->dev, val, extack);
+       if (err == -EOPNOTSUPP)
+               err = 0;
+       if (err)
+               goto unlock;
+
        br_opt_toggle(br, BROPT_MULTICAST_ENABLED, !!val);
        if (!br_opt_get(br, BROPT_MULTICAST_ENABLED)) {
                change_snoopers = true;
@@ -3590,7 +3604,7 @@ unlock:
                        br_multicast_leave_snoopers(br);
        }
 
-       return 0;
+       return err;
 }
 
 bool br_multicast_enabled(const struct net_device *dev)
index f2b1343f8332a1c42c097612ebf734a848ec8a99..0456593aceec1143c7682f95b025f670ffee1eb7 100644 (file)
@@ -1293,7 +1293,9 @@ static int br_changelink(struct net_device *brdev, struct nlattr *tb[],
        if (data[IFLA_BR_MCAST_SNOOPING]) {
                u8 mcast_snooping = nla_get_u8(data[IFLA_BR_MCAST_SNOOPING]);
 
-               br_multicast_toggle(br, mcast_snooping);
+               err = br_multicast_toggle(br, mcast_snooping, extack);
+               if (err)
+                       return err;
        }
 
        if (data[IFLA_BR_MCAST_QUERY_USE_IFADDR]) {
index d7d167e10b7053e9656f990d447193283a1dcdc6..af3430c2d6ea8773114d514133a9c9929ce0483a 100644 (file)
@@ -810,7 +810,8 @@ void br_multicast_flood(struct net_bridge_mdb_entry *mdst,
                        struct sk_buff *skb, bool local_rcv, bool local_orig);
 int br_multicast_set_router(struct net_bridge *br, unsigned long val);
 int br_multicast_set_port_router(struct net_bridge_port *p, unsigned long val);
-int br_multicast_toggle(struct net_bridge *br, unsigned long val);
+int br_multicast_toggle(struct net_bridge *br, unsigned long val,
+                       struct netlink_ext_ack *extack);
 int br_multicast_set_querier(struct net_bridge *br, unsigned long val);
 int br_multicast_set_hash_max(struct net_bridge *br, unsigned long val);
 int br_multicast_set_igmp_version(struct net_bridge *br, unsigned long val);
index 072e29840082a02f7190d6501cbcfa5ce107182a..381467b691d5fbb1ed38d80ca76aff4ebb5047f6 100644 (file)
@@ -409,17 +409,11 @@ static ssize_t multicast_snooping_show(struct device *d,
        return sprintf(buf, "%d\n", br_opt_get(br, BROPT_MULTICAST_ENABLED));
 }
 
-static int toggle_multicast(struct net_bridge *br, unsigned long val,
-                           struct netlink_ext_ack *extack)
-{
-       return br_multicast_toggle(br, val);
-}
-
 static ssize_t multicast_snooping_store(struct device *d,
                                        struct device_attribute *attr,
                                        const char *buf, size_t len)
 {
-       return store_bridge_parm(d, buf, len, toggle_multicast);
+       return store_bridge_parm(d, buf, len, br_multicast_toggle);
 }
 static DEVICE_ATTR_RW(multicast_snooping);