Skip to content

Commit

Permalink
net: bridge: propagate error code and extack from br_mc_disabled_update
Browse files Browse the repository at this point in the history
[ Upstream commit ae1ea84 ]

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>
  • Loading branch information
ffainelli authored and gregkh committed May 19, 2021
1 parent dc49a63 commit a9863a2
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 16 deletions.
28 changes: 21 additions & 7 deletions net/bridge/br_multicast.c
Original file line number Diff line number Diff line change
Expand Up @@ -1593,7 +1593,8 @@ static void br_multicast_port_group_rexmit(struct timer_list *t)
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,
Expand All @@ -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;

Expand All @@ -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)
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -3590,7 +3604,7 @@ int br_multicast_toggle(struct net_bridge *br, unsigned long val)
br_multicast_leave_snoopers(br);
}

return 0;
return err;
}

bool br_multicast_enabled(const struct net_device *dev)
Expand Down
4 changes: 3 additions & 1 deletion net/bridge/br_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -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]) {
Expand Down
3 changes: 2 additions & 1 deletion net/bridge/br_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
8 changes: 1 addition & 7 deletions net/bridge/br_sysfs_br.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down

0 comments on commit a9863a2

Please sign in to comment.