summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum.c29
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum.h10
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c154
-rw-r--r--include/net/switchdev.h4
-rw-r--r--net/bridge/br_multicast.c55
5 files changed, 198 insertions, 54 deletions
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
index 8de5ed526904..37c018bea5e2 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -3073,10 +3073,17 @@ static int __mlxsw_sp_flood_init(struct mlxsw_core *mlxsw_core,
else
table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFEST;
- if (type == MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST)
+ switch (type) {
+ case MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST:
flood_table = MLXSW_SP_FLOOD_TABLE_UC;
- else
- flood_table = MLXSW_SP_FLOOD_TABLE_BM;
+ break;
+ case MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4:
+ case MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6:
+ flood_table = MLXSW_SP_FLOOD_TABLE_MC;
+ break;
+ default:
+ flood_table = MLXSW_SP_FLOOD_TABLE_BC;
+ }
mlxsw_reg_sfgc_pack(sfgc_pl, type, bridge_type, table_type,
flood_table);
@@ -3270,9 +3277,9 @@ static struct mlxsw_config_profile mlxsw_sp_config_profile = {
.used_flood_tables = 1,
.used_flood_mode = 1,
.flood_mode = 3,
- .max_fid_offset_flood_tables = 2,
+ .max_fid_offset_flood_tables = 3,
.fid_offset_flood_table_size = VLAN_N_VID - 1,
- .max_fid_flood_tables = 2,
+ .max_fid_flood_tables = 3,
.fid_flood_table_size = MLXSW_SP_VFID_MAX,
.used_max_ib_mc = 1,
.max_ib_mc = 0,
@@ -3689,7 +3696,7 @@ static int mlxsw_sp_router_port_flood_set(struct mlxsw_sp *mlxsw_sp, u16 fid,
table_type = mlxsw_sp_flood_table_type_get(fid);
index = mlxsw_sp_flood_table_index_get(fid);
- mlxsw_reg_sftr_pack(sftr_pl, MLXSW_SP_FLOOD_TABLE_BM, index, table_type,
+ mlxsw_reg_sftr_pack(sftr_pl, MLXSW_SP_FLOOD_TABLE_BC, index, table_type,
1, MLXSW_PORT_ROUTER_PORT, set);
err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sftr), sftr_pl);
@@ -4065,6 +4072,9 @@ static int mlxsw_sp_port_bridge_join(struct mlxsw_sp_port *mlxsw_sp_port,
mlxsw_sp_port->learning = 1;
mlxsw_sp_port->learning_sync = 1;
mlxsw_sp_port->uc_flood = 1;
+ mlxsw_sp_port->mc_flood = 1;
+ mlxsw_sp_port->mc_router = 0;
+ mlxsw_sp_port->mc_disabled = 1;
mlxsw_sp_port->bridged = 1;
return 0;
@@ -4081,6 +4091,8 @@ static void mlxsw_sp_port_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_port)
mlxsw_sp_port->learning = 0;
mlxsw_sp_port->learning_sync = 0;
mlxsw_sp_port->uc_flood = 0;
+ mlxsw_sp_port->mc_flood = 0;
+ mlxsw_sp_port->mc_router = 0;
mlxsw_sp_port->bridged = 0;
/* Add implicit VLAN interface in the device, so that untagged
@@ -4743,6 +4755,9 @@ static int mlxsw_sp_vport_bridge_join(struct mlxsw_sp_port *mlxsw_sp_vport,
mlxsw_sp_vport->learning = 1;
mlxsw_sp_vport->learning_sync = 1;
mlxsw_sp_vport->uc_flood = 1;
+ mlxsw_sp_vport->mc_flood = 1;
+ mlxsw_sp_vport->mc_router = 0;
+ mlxsw_sp_vport->mc_disabled = 1;
mlxsw_sp_vport->bridged = 1;
return 0;
@@ -4763,6 +4778,8 @@ static void mlxsw_sp_vport_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_vport)
mlxsw_sp_vport->learning = 0;
mlxsw_sp_vport->learning_sync = 0;
mlxsw_sp_vport->uc_flood = 0;
+ mlxsw_sp_vport->mc_flood = 0;
+ mlxsw_sp_vport->mc_router = 0;
mlxsw_sp_vport->bridged = 0;
}
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
index 145897c5a779..13ec85e7c392 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
@@ -55,7 +55,7 @@
#include "core_acl_flex_actions.h"
#define MLXSW_SP_VFID_BASE VLAN_N_VID
-#define MLXSW_SP_VFID_MAX 6656 /* Bridged VLAN interfaces */
+#define MLXSW_SP_VFID_MAX 1024 /* Bridged VLAN interfaces */
#define MLXSW_SP_RFID_BASE 15360
#define MLXSW_SP_INVALID_RIF 0xffff
@@ -339,9 +339,12 @@ struct mlxsw_sp_port {
struct mlxsw_sp *mlxsw_sp;
u8 local_port;
u8 stp_state;
- u8 learning:1,
+ u16 learning:1,
learning_sync:1,
uc_flood:1,
+ mc_flood:1,
+ mc_router:1,
+ mc_disabled:1,
bridged:1,
lagged:1,
split:1;
@@ -509,7 +512,8 @@ mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp *mlxsw_sp,
enum mlxsw_sp_flood_table {
MLXSW_SP_FLOOD_TABLE_UC,
- MLXSW_SP_FLOOD_TABLE_BM,
+ MLXSW_SP_FLOOD_TABLE_BC,
+ MLXSW_SP_FLOOD_TABLE_MC,
};
int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
index b87ba7d36bc4..598727d578c1 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
@@ -71,8 +71,21 @@ mlxsw_sp_port_orig_get(struct net_device *dev,
struct mlxsw_sp_port *mlxsw_sp_port)
{
struct mlxsw_sp_port *mlxsw_sp_vport;
+ struct mlxsw_sp_fid *fid;
u16 vid;
+ if (netif_is_bridge_master(dev)) {
+ fid = mlxsw_sp_vfid_find(mlxsw_sp_port->mlxsw_sp,
+ dev);
+ if (fid) {
+ mlxsw_sp_vport =
+ mlxsw_sp_port_vport_find_by_fid(mlxsw_sp_port,
+ fid->fid);
+ WARN_ON(!mlxsw_sp_vport);
+ return mlxsw_sp_vport;
+ }
+ }
+
if (!is_vlan_dev(dev))
return mlxsw_sp_port;
@@ -166,9 +179,10 @@ static int mlxsw_sp_port_attr_stp_state_set(struct mlxsw_sp_port *mlxsw_sp_port,
return mlxsw_sp_port_stp_state_set(mlxsw_sp_port, state);
}
-static int __mlxsw_sp_port_flood_set(struct mlxsw_sp_port *mlxsw_sp_port,
- u16 idx_begin, u16 idx_end, bool uc_set,
- bool bm_set)
+static int __mlxsw_sp_port_flood_table_set(struct mlxsw_sp_port *mlxsw_sp_port,
+ u16 idx_begin, u16 idx_end,
+ enum mlxsw_sp_flood_table table,
+ bool set)
{
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
u16 local_port = mlxsw_sp_port->local_port;
@@ -186,31 +200,48 @@ static int __mlxsw_sp_port_flood_set(struct mlxsw_sp_port *mlxsw_sp_port,
if (!sftr_pl)
return -ENOMEM;
- mlxsw_reg_sftr_pack(sftr_pl, MLXSW_SP_FLOOD_TABLE_UC, idx_begin,
- table_type, range, local_port, uc_set);
+ mlxsw_reg_sftr_pack(sftr_pl, table, idx_begin,
+ table_type, range, local_port, set);
err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sftr), sftr_pl);
+
+ kfree(sftr_pl);
+ return err;
+}
+
+static int __mlxsw_sp_port_flood_set(struct mlxsw_sp_port *mlxsw_sp_port,
+ u16 idx_begin, u16 idx_end, bool uc_set,
+ bool bc_set, bool mc_set)
+{
+ int err;
+
+ err = __mlxsw_sp_port_flood_table_set(mlxsw_sp_port, idx_begin, idx_end,
+ MLXSW_SP_FLOOD_TABLE_UC, uc_set);
if (err)
- goto buffer_out;
+ return err;
- mlxsw_reg_sftr_pack(sftr_pl, MLXSW_SP_FLOOD_TABLE_BM, idx_begin,
- table_type, range, local_port, bm_set);
- err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sftr), sftr_pl);
+ err = __mlxsw_sp_port_flood_table_set(mlxsw_sp_port, idx_begin, idx_end,
+ MLXSW_SP_FLOOD_TABLE_BC, bc_set);
if (err)
goto err_flood_bm_set;
- goto buffer_out;
+ err = __mlxsw_sp_port_flood_table_set(mlxsw_sp_port, idx_begin, idx_end,
+ MLXSW_SP_FLOOD_TABLE_MC, mc_set);
+ if (err)
+ goto err_flood_mc_set;
+ return 0;
+err_flood_mc_set:
+ __mlxsw_sp_port_flood_table_set(mlxsw_sp_port, idx_begin, idx_end,
+ MLXSW_SP_FLOOD_TABLE_BC, !bc_set);
err_flood_bm_set:
- mlxsw_reg_sftr_pack(sftr_pl, MLXSW_SP_FLOOD_TABLE_UC, idx_begin,
- table_type, range, local_port, !uc_set);
- mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sftr), sftr_pl);
-buffer_out:
- kfree(sftr_pl);
+ __mlxsw_sp_port_flood_table_set(mlxsw_sp_port, idx_begin, idx_end,
+ MLXSW_SP_FLOOD_TABLE_UC, !uc_set);
return err;
}
-static int mlxsw_sp_port_uc_flood_set(struct mlxsw_sp_port *mlxsw_sp_port,
- bool set)
+static int mlxsw_sp_port_flood_table_set(struct mlxsw_sp_port *mlxsw_sp_port,
+ enum mlxsw_sp_flood_table table,
+ bool set)
{
struct net_device *dev = mlxsw_sp_port->dev;
u16 vid, last_visited_vid;
@@ -220,13 +251,13 @@ static int mlxsw_sp_port_uc_flood_set(struct mlxsw_sp_port *mlxsw_sp_port,
u16 fid = mlxsw_sp_vport_fid_get(mlxsw_sp_port)->fid;
u16 vfid = mlxsw_sp_fid_to_vfid(fid);
- return __mlxsw_sp_port_flood_set(mlxsw_sp_port, vfid, vfid,
- set, true);
+ return __mlxsw_sp_port_flood_table_set(mlxsw_sp_port, vfid,
+ vfid, table, set);
}
for_each_set_bit(vid, mlxsw_sp_port->active_vlans, VLAN_N_VID) {
- err = __mlxsw_sp_port_flood_set(mlxsw_sp_port, vid, vid, set,
- true);
+ err = __mlxsw_sp_port_flood_table_set(mlxsw_sp_port, vid, vid,
+ table, set);
if (err) {
last_visited_vid = vid;
goto err_port_flood_set;
@@ -237,21 +268,53 @@ static int mlxsw_sp_port_uc_flood_set(struct mlxsw_sp_port *mlxsw_sp_port,
err_port_flood_set:
for_each_set_bit(vid, mlxsw_sp_port->active_vlans, last_visited_vid)
- __mlxsw_sp_port_flood_set(mlxsw_sp_port, vid, vid, !set, true);
+ __mlxsw_sp_port_flood_table_set(mlxsw_sp_port, vid, vid, table,
+ !set);
netdev_err(dev, "Failed to configure unicast flooding\n");
return err;
}
+static int mlxsw_sp_port_mc_disabled_set(struct mlxsw_sp_port *mlxsw_sp_port,
+ struct switchdev_trans *trans,
+ bool mc_disabled)
+{
+ int set;
+ int err = 0;
+
+ if (switchdev_trans_ph_prepare(trans))
+ return 0;
+
+ if (mlxsw_sp_port->mc_router != mlxsw_sp_port->mc_flood) {
+ set = mc_disabled ?
+ mlxsw_sp_port->mc_flood : mlxsw_sp_port->mc_router;
+ err = mlxsw_sp_port_flood_table_set(mlxsw_sp_port,
+ MLXSW_SP_FLOOD_TABLE_MC,
+ set);
+ }
+
+ if (!err)
+ mlxsw_sp_port->mc_disabled = mc_disabled;
+
+ return err;
+}
+
int mlxsw_sp_vport_flood_set(struct mlxsw_sp_port *mlxsw_sp_vport, u16 fid,
bool set)
{
+ bool mc_set = set;
u16 vfid;
/* In case of vFIDs, index into the flooding table is relative to
* the start of the vFIDs range.
*/
vfid = mlxsw_sp_fid_to_vfid(fid);
- return __mlxsw_sp_port_flood_set(mlxsw_sp_vport, vfid, vfid, set, set);
+
+ if (set)
+ mc_set = mlxsw_sp_vport->mc_disabled ?
+ mlxsw_sp_vport->mc_flood : mlxsw_sp_vport->mc_router;
+
+ return __mlxsw_sp_port_flood_set(mlxsw_sp_vport, vfid, vfid, set, set,
+ mc_set);
}
static int mlxsw_sp_port_learning_set(struct mlxsw_sp_port *mlxsw_sp_port,
@@ -297,8 +360,9 @@ static int mlxsw_sp_port_attr_br_flags_set(struct mlxsw_sp_port *mlxsw_sp_port,
return 0;
if ((uc_flood ^ brport_flags) & BR_FLOOD) {
- err = mlxsw_sp_port_uc_flood_set(mlxsw_sp_port,
- !mlxsw_sp_port->uc_flood);
+ err = mlxsw_sp_port_flood_table_set(mlxsw_sp_port,
+ MLXSW_SP_FLOOD_TABLE_UC,
+ !mlxsw_sp_port->uc_flood);
if (err)
return err;
}
@@ -318,8 +382,9 @@ static int mlxsw_sp_port_attr_br_flags_set(struct mlxsw_sp_port *mlxsw_sp_port,
err_port_learning_set:
if ((uc_flood ^ brport_flags) & BR_FLOOD)
- mlxsw_sp_port_uc_flood_set(mlxsw_sp_port,
- mlxsw_sp_port->uc_flood);
+ mlxsw_sp_port_flood_table_set(mlxsw_sp_port,
+ MLXSW_SP_FLOOD_TABLE_UC,
+ mlxsw_sp_port->uc_flood);
return err;
}
@@ -371,6 +436,22 @@ static int mlxsw_sp_port_attr_br_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port,
return 0;
}
+static int mlxsw_sp_port_attr_mc_router_set(struct mlxsw_sp_port *mlxsw_sp_port,
+ struct switchdev_trans *trans,
+ bool is_port_mc_router)
+{
+ if (switchdev_trans_ph_prepare(trans))
+ return 0;
+
+ mlxsw_sp_port->mc_router = is_port_mc_router;
+ if (!mlxsw_sp_port->mc_disabled)
+ return mlxsw_sp_port_flood_table_set(mlxsw_sp_port,
+ MLXSW_SP_FLOOD_TABLE_MC,
+ is_port_mc_router);
+
+ return 0;
+}
+
static int mlxsw_sp_port_attr_set(struct net_device *dev,
const struct switchdev_attr *attr,
struct switchdev_trans *trans)
@@ -400,6 +481,14 @@ static int mlxsw_sp_port_attr_set(struct net_device *dev,
attr->orig_dev,
attr->u.vlan_filtering);
break;
+ case SWITCHDEV_ATTR_ID_PORT_MROUTER:
+ err = mlxsw_sp_port_attr_mc_router_set(mlxsw_sp_port, trans,
+ attr->u.mrouter);
+ break;
+ case SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED:
+ err = mlxsw_sp_port_mc_disabled_set(mlxsw_sp_port, trans,
+ attr->u.mc_disabled);
+ break;
default:
err = -EOPNOTSUPP;
break;
@@ -545,6 +634,7 @@ static int mlxsw_sp_port_fid_map(struct mlxsw_sp_port *mlxsw_sp_port, u16 fid,
static int mlxsw_sp_port_fid_join(struct mlxsw_sp_port *mlxsw_sp_port,
u16 fid_begin, u16 fid_end)
{
+ bool mc_flood;
int fid, err;
for (fid = fid_begin; fid <= fid_end; fid++) {
@@ -553,8 +643,12 @@ static int mlxsw_sp_port_fid_join(struct mlxsw_sp_port *mlxsw_sp_port,
goto err_port_fid_join;
}
+ mc_flood = mlxsw_sp_port->mc_disabled ?
+ mlxsw_sp_port->mc_flood : mlxsw_sp_port->mc_router;
+
err = __mlxsw_sp_port_flood_set(mlxsw_sp_port, fid_begin, fid_end,
- mlxsw_sp_port->uc_flood, true);
+ mlxsw_sp_port->uc_flood, true,
+ mc_flood);
if (err)
goto err_port_flood_set;
@@ -570,7 +664,7 @@ err_port_fid_map:
for (fid--; fid >= fid_begin; fid--)
mlxsw_sp_port_fid_map(mlxsw_sp_port, fid, false);
__mlxsw_sp_port_flood_set(mlxsw_sp_port, fid_begin, fid_end, false,
- false);
+ false, false);
err_port_flood_set:
fid = fid_end;
err_port_fid_join:
@@ -588,7 +682,7 @@ static void mlxsw_sp_port_fid_leave(struct mlxsw_sp_port *mlxsw_sp_port,
mlxsw_sp_port_fid_map(mlxsw_sp_port, fid, false);
__mlxsw_sp_port_flood_set(mlxsw_sp_port, fid_begin, fid_end, false,
- false);
+ false, false);
for (fid = fid_begin; fid <= fid_end; fid++)
__mlxsw_sp_port_fid_leave(mlxsw_sp_port, fid);
diff --git a/include/net/switchdev.h b/include/net/switchdev.h
index eba80c4fc56f..929d6af321cd 100644
--- a/include/net/switchdev.h
+++ b/include/net/switchdev.h
@@ -46,8 +46,10 @@ enum switchdev_attr_id {
SWITCHDEV_ATTR_ID_PORT_PARENT_ID,
SWITCHDEV_ATTR_ID_PORT_STP_STATE,
SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS,
+ SWITCHDEV_ATTR_ID_PORT_MROUTER,
SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME,
SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING,
+ SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED,
};
struct switchdev_attr {
@@ -60,8 +62,10 @@ struct switchdev_attr {
struct netdev_phys_item_id ppid; /* PORT_PARENT_ID */
u8 stp_state; /* PORT_STP_STATE */
unsigned long brport_flags; /* PORT_BRIDGE_FLAGS */
+ bool mrouter; /* PORT_MROUTER */
clock_t ageing_time; /* BRIDGE_AGEING_TIME */
bool vlan_filtering; /* BRIDGE_VLAN_FILTERING */
+ bool mc_disabled; /* MC_DISABLED */
} u;
};
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 1de3438e36bf..b760f2620abf 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -27,6 +27,7 @@
#include <linux/inetdevice.h>
#include <linux/mroute.h>
#include <net/ip.h>
+#include <net/switchdev.h>
#if IS_ENABLED(CONFIG_IPV6)
#include <net/ipv6.h>
#include <net/mld.h>
@@ -46,6 +47,7 @@ static void br_ip4_multicast_leave_group(struct net_bridge *br,
__u16 vid,
const unsigned char *src);
+static void __del_port_router(struct net_bridge_port *p);
#if IS_ENABLED(CONFIG_IPV6)
static void br_ip6_multicast_leave_group(struct net_bridge *br,
struct net_bridge_port *port,
@@ -849,16 +851,10 @@ static void br_multicast_router_expired(unsigned long data)
spin_lock(&br->multicast_lock);
if (port->multicast_router == MDB_RTR_TYPE_DISABLED ||
port->multicast_router == MDB_RTR_TYPE_PERM ||
- timer_pending(&port->multicast_router_timer) ||
- hlist_unhashed(&port->rlist))
+ timer_pending(&port->multicast_router_timer))
goto out;
- hlist_del_init_rcu(&port->rlist);
- br_rtr_notify(br->dev, port, RTM_DELMDB);
- /* Don't allow timer refresh if the router expired */
- if (port->multicast_router == MDB_RTR_TYPE_TEMP)
- port->multicast_router = MDB_RTR_TYPE_TEMP_QUERY;
-
+ __del_port_router(port);
out:
spin_unlock(&br->multicast_lock);
}
@@ -1007,6 +1003,18 @@ static void br_ip6_multicast_port_query_expired(unsigned long data)
}
#endif
+static void br_mc_disabled_update(struct net_device *dev, bool value)
+{
+ struct switchdev_attr attr = {
+ .orig_dev = dev,
+ .id = SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED,
+ .flags = SWITCHDEV_F_DEFER,
+ .u.mc_disabled = value,
+ };
+
+ switchdev_port_attr_set(dev, &attr);
+}
+
int br_multicast_add_port(struct net_bridge_port *port)
{
port->multicast_router = MDB_RTR_TYPE_TEMP_QUERY;
@@ -1019,6 +1027,8 @@ int br_multicast_add_port(struct net_bridge_port *port)
setup_timer(&port->ip6_own_query.timer,
br_ip6_multicast_port_query_expired, (unsigned long)port);
#endif
+ br_mc_disabled_update(port->dev, port->br->multicast_disabled);
+
port->mcast_stats = netdev_alloc_pcpu_stats(struct bridge_mcast_stats);
if (!port->mcast_stats)
return -ENOMEM;
@@ -1086,13 +1096,8 @@ void br_multicast_disable_port(struct net_bridge_port *port)
if (!(pg->flags & MDB_PG_FLAGS_PERMANENT))
br_multicast_del_pg(br, pg);
- if (!hlist_unhashed(&port->rlist)) {
- hlist_del_init_rcu(&port->rlist);
- br_rtr_notify(br->dev, port, RTM_DELMDB);
- /* Don't allow timer refresh if disabling */
- if (port->multicast_router == MDB_RTR_TYPE_TEMP)
- port->multicast_router = MDB_RTR_TYPE_TEMP_QUERY;
- }
+ __del_port_router(port);
+
del_timer(&port->multicast_router_timer);
del_timer(&port->ip4_own_query.timer);
#if IS_ENABLED(CONFIG_IPV6)
@@ -1312,6 +1317,19 @@ br_multicast_update_query_timer(struct net_bridge *br,
mod_timer(&query->timer, jiffies + br->multicast_querier_interval);
}
+static void br_port_mc_router_state_change(struct net_bridge_port *p,
+ bool is_mc_router)
+{
+ struct switchdev_attr attr = {
+ .orig_dev = p->dev,
+ .id = SWITCHDEV_ATTR_ID_PORT_MROUTER,
+ .flags = SWITCHDEV_F_DEFER,
+ .u.mrouter = is_mc_router,
+ };
+
+ switchdev_port_attr_set(p->dev, &attr);
+}
+
/*
* Add port to router_list
* list is maintained ordered by pointer value
@@ -1337,6 +1355,7 @@ static void br_multicast_add_router(struct net_bridge *br,
else
hlist_add_head_rcu(&port->rlist, &br->router_list);
br_rtr_notify(br->dev, port, RTM_NEWMDB);
+ br_port_mc_router_state_change(port, true);
}
static void br_multicast_mark_router(struct net_bridge *br,
@@ -2044,6 +2063,11 @@ static void __del_port_router(struct net_bridge_port *p)
return;
hlist_del_init_rcu(&p->rlist);
br_rtr_notify(p->br->dev, p, RTM_DELMDB);
+ br_port_mc_router_state_change(p, false);
+
+ /* don't allow timer refresh */
+ if (p->multicast_router == MDB_RTR_TYPE_TEMP)
+ p->multicast_router = MDB_RTR_TYPE_TEMP_QUERY;
}
int br_multicast_set_port_router(struct net_bridge_port *p, unsigned long val)
@@ -2121,6 +2145,7 @@ int br_multicast_toggle(struct net_bridge *br, unsigned long val)
if (br->multicast_disabled == !val)
goto unlock;
+ br_mc_disabled_update(br->dev, !val);
br->multicast_disabled = !val;
if (br->multicast_disabled)
goto unlock;