mlxsw: Multicast flood update
Subsystems (3)
cover mlxsw: Multicast flood update
From: Jiri Pirko <[email protected]>
Nogah says:
Currently, there are four erroneous flows in MC flood:
1. When MC is disabled it affects only the flood table for unregistered MC packets, but packets that match an entry in the MDB are unaffected.
2. When MC is disabled, MC packets are being sent to all the ports in the bridge (like BC and link-local MC packets) regardless of the designated flag (BR_MCAST_FLAG).
3. When a port is being deleted from a bridge it might remain in the MDB.
4. When MC is enabled packets are flooded to the mrouter ports only if they don't match any entry in the MDB, when they should always be flooded to them.
What these problems have in common is the discrepancy between how the hardware handles MDB and mcast flood, and how the driver does it. Each of these problems needs fixing either in the MDB code, or in mcast flood code, and some in both.
Patches 1-6 change the way the MDB is handled in the driver to make the following changes easier.
Patches 7-8 fix problem number 1 by removing the MDB from the HW when MC is being disabled and restoring it when it is being enabled. Patches 9-10 fix problem number 2 by offloading the flood table by the appropriate flag.
Patch 11 fixes problem number 3 by adding MDB flush to the port removal. Patches 12-14 fix problem number 4 by adding the mrouter ports to every MDB entry in the HW to mimic the wanted behaviour.
Nogah Frankel (16):
mlxsw: spectrum_switchdev: Change mc_router to mrouter
mlxsw: spectrum_switchdev: Add a ports bitmap to the mid db
mlxsw: spectrum_switchdev: Remove reference count from mid
mlxsw: spectrum_switchdev: Save mids list per bridge device
mlxsw: spectrum_switchdev: Break smid write function
mlxsw: spectrum_switchdev: Attach mid id allocation to HW write
mlxsw: spectrum_switchdev: Break mid deletion into two function
mlxsw: spectrum_switchdev: Don't write mids to the HW when mc is
disabled
mlxsw: spectrum_switchdev: Disable mdb when mc is disabled
mlxsw: spectrum_switchdev: Use generic mc flood function
mlxsw: spectrum_switchdev: Flood mc when mc is disabled by user flag
mlxsw: spectrum_switchdev: Flush the mdb when a port is being removed
mlxsw: spectrum_switchdev: Flood all mc packets to mrouter ports
mlxsw: spectrum_switchdev: Update the mdb of mrouter port change
mlxsw: spectrum_switchdev: Remove mrouter flood in mdb flush
mlxsw: spectrum_switchdev: Consider mrouter status for mdb changes
drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 3 +- .../ethernet/mellanox/mlxsw/spectrum_switchdev.c | 417 ++++++++++++++++----- 2 files changed, 323 insertions(+), 97 deletions(-)
Signature · 1 line
2.9.5
PATCH 1/16 mlxsw: spectrum_switchdev: Change mc_router to mrouter
From: Nogah Frankel <[email protected]>
Change the naming of mc_router to mrouter to keep consistency.
--- .../net/ethernet/mellanox/mlxsw/spectrum_switchdev.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-)
drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +9 -9
@@ -699,10 +699,10 @@ static int mlxsw_sp_port_attr_br_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port,return -EINVAL ; } -static int mlxsw_sp_port_attr_mc_router_set (struct mlxsw_sp_port *mlxsw_sp_port, -struct switchdev_trans *trans, -struct net_device *orig_dev, -bool is_port_mc_router) +static int mlxsw_sp_port_attr_mrouter_set (struct mlxsw_sp_port *mlxsw_sp_port, +struct switchdev_trans *trans, +struct net_device *orig_dev, +bool is_port_mrouter) {struct mlxsw_sp_bridge_port *bridge_port;int err;
@@ -720,12 +720,12 @@ static int mlxsw_sp_port_attr_mc_router_set(struct mlxsw_sp_port *mlxsw_sp_port, err =mlxsw_sp_bridge_port_flood_table_set (mlxsw_sp_port, bridge_port,MLXSW_SP_FLOOD_TYPE_MC , - is_port_mc_router); + is_port_mrouter);if (err)return err; out: - bridge_port->mrouter = is_port_mc_router; + bridge_port->mrouter = is_port_mrouter;return 0 ; }
@@ -793,9 +793,9 @@ static int mlxsw_sp_port_attr_set(struct net_device *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->orig_dev, - attr->u.mrouter); + err =mlxsw_sp_port_attr_mrouter_set (mlxsw_sp_port, trans, + attr->orig_dev, + attr->u.mrouter);break ;case SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED : err = mlxsw_sp_port_mc_disabled_set(mlxsw_sp_port, trans,
Signature · 1 line
2.9.5
PATCH 2/16 mlxsw: spectrum_switchdev: Add a ports bitmap to the mid db
In reply to Jiri PirkoFrom: Nogah Frankel <[email protected]>
Add a bitmap of ports to the mid struct to hold the ports that are registered to this mid.
--- drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 1 + .../net/ethernet/mellanox/mlxsw/spectrum_switchdev.c | 20 +++++++++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-)
drivers/net/ethernet/mellanox/mlxsw/spectrum.h +1 -0
@@ -95,6 +95,7 @@ struct mlxsw_sp_mid {u16 fid;u16 mid;unsigned int ref_count; +unsigned long *ports_in_mid;/* bits array */ };enum mlxsw_sp_span_type {
drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +17 -3
@@ -1239,6 +1239,7 @@ static struct mlxsw_sp_mid *__mlxsw_sp_mc_alloc(struct mlxsw_sp *mlxsw_sp, u16 fid) {struct mlxsw_sp_mid *mid; +size_t alloc_size;u16 mid_idx; mid_idx = find_first_zero_bit(mlxsw_sp->bridge->mids_bitmap,
@@ -1250,6 +1251,14 @@ static struct mlxsw_sp_mid *__mlxsw_sp_mc_alloc(struct mlxsw_sp *mlxsw_sp,if (!mid)return NULL ; + alloc_size =sizeof (unsigned long ) * +BITS_TO_LONGS (mlxsw_core_max_ports (mlxsw_sp->core)); + mid->ports_in_mid =kzalloc (alloc_size,GFP_KERNEL ); +if (!mid->ports_in_mid) { +kfree (mid); +return NULL ; + } +set_bit (mid_idx, mlxsw_sp->bridge->mids_bitmap);ether_addr_copy (mid->addr, addr); mid->fid = fid;
@@ -1260,12 +1269,16 @@ static struct mlxsw_sp_mid *__mlxsw_sp_mc_alloc(struct mlxsw_sp *mlxsw_sp,return mid; } -static int __mlxsw_sp_mc_dec_ref (struct mlxsw_sp *mlxsw_sp, +static int __mlxsw_sp_mc_dec_ref (struct mlxsw_sp_port *mlxsw_sp_port,struct mlxsw_sp_mid *mid) { +struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + +clear_bit (mlxsw_sp_port->local_port, mid->ports_in_mid);if (--mid->ref_count ==0 ) {list_del (&mid->list);clear_bit (mid->mid, mlxsw_sp->bridge->mids_bitmap); +kfree (mid->ports_in_mid);kfree (mid);return 1 ; }
@@ -1311,6 +1324,7 @@ static int mlxsw_sp_port_mdb_add(struct mlxsw_sp_port *mlxsw_sp_port, } } mid->ref_count++; +set_bit (mlxsw_sp_port->local_port, mid->ports_in_mid); err =mlxsw_sp_port_smid_set (mlxsw_sp_port, mid->mid, true, mid->ref_count ==1 );
@@ -1331,7 +1345,7 @@ static int mlxsw_sp_port_mdb_add(struct mlxsw_sp_port *mlxsw_sp_port,return 0 ; err_out: -__mlxsw_sp_mc_dec_ref (mlxsw_sp, mid); +__mlxsw_sp_mc_dec_ref (mlxsw_sp_port, mid);return err; }
@@ -1437,7 +1451,7 @@ static int mlxsw_sp_port_mdb_del(struct mlxsw_sp_port *mlxsw_sp_port,netdev_err (dev,"Unable to remove port from SMID\n" ); mid_idx = mid->mid; -if (__mlxsw_sp_mc_dec_ref (mlxsw_sp, mid)) { +if (__mlxsw_sp_mc_dec_ref (mlxsw_sp_port, mid)) { err =mlxsw_sp_port_mdb_op (mlxsw_sp, mdb->addr, fid_index, mid_idx, false);if (err)
Signature · 1 line
2.9.5
PATCH 3/16 mlxsw: spectrum_switchdev: Remove reference count from mid
In reply to Jiri PirkoFrom: Nogah Frankel <[email protected]>
Since there is a bitmap for the ports registered to each mid, there is no need for a ref count, since it will always be the number of set bits in this bitmap. Any check of the ref count was replaced with checking if the bitmap is empty.
--- drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 1 - .../net/ethernet/mellanox/mlxsw/spectrum_switchdev.c | 20 ++++++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-)
drivers/net/ethernet/mellanox/mlxsw/spectrum.h +0 -1
@@ -94,7 +94,6 @@ struct mlxsw_sp_mid {unsigned char addr[ETH_ALEN ];u16 fid;u16 mid; -unsigned int ref_count;unsigned long *ports_in_mid;/* bits array */ };
drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +10 -10
@@ -1263,19 +1263,19 @@ static struct mlxsw_sp_mid *__mlxsw_sp_mc_alloc(struct mlxsw_sp *mlxsw_sp,ether_addr_copy (mid->addr, addr); mid->fid = fid; mid->mid = mid_idx; - mid->ref_count =0 ;list_add_tail (&mid->list, &mlxsw_sp->bridge->mids_list);return mid; } -static int __mlxsw_sp_mc_dec_ref (struct mlxsw_sp_port *mlxsw_sp_port, -struct mlxsw_sp_mid *mid) +static int mlxsw_sp_port_remove_from_mid (struct mlxsw_sp_port *mlxsw_sp_port, +struct mlxsw_sp_mid *mid) {struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;clear_bit (mlxsw_sp_port->local_port, mid->ports_in_mid); -if (--mid->ref_count ==0 ) { +if (bitmap_empty (mid->ports_in_mid, +mlxsw_core_max_ports (mlxsw_sp->core))) {list_del (&mid->list);clear_bit (mid->mid, mlxsw_sp->bridge->mids_bitmap);kfree (mid->ports_in_mid);
@@ -1296,6 +1296,7 @@ static int mlxsw_sp_port_mdb_add(struct mlxsw_sp_port *mlxsw_sp_port,struct mlxsw_sp_bridge_device *bridge_device;struct mlxsw_sp_bridge_port *bridge_port;struct mlxsw_sp_mid *mid; +bool is_new_mid = false;u16 fid_index;int err =0 ;
@@ -1322,18 +1323,17 @@ static int mlxsw_sp_port_mdb_add(struct mlxsw_sp_port *mlxsw_sp_port,netdev_err (dev,"Unable to allocate MC group\n" );return -ENOMEM ; } + is_new_mid = true; } - mid->ref_count++;set_bit (mlxsw_sp_port->local_port, mid->ports_in_mid); - err =mlxsw_sp_port_smid_set (mlxsw_sp_port, mid->mid, true, - mid->ref_count ==1 ); + err =mlxsw_sp_port_smid_set (mlxsw_sp_port, mid->mid, true, is_new_mid);if (err) {netdev_err (dev,"Unable to set SMID\n" ); goto err_out; } -if (mid->ref_count ==1 ) { +if (is_new_mid) { err =mlxsw_sp_port_mdb_op (mlxsw_sp, mdb->addr, fid_index, mid->mid, true);if (err) {
@@ -1345,7 +1345,7 @@ static int mlxsw_sp_port_mdb_add(struct mlxsw_sp_port *mlxsw_sp_port,return 0 ; err_out: -__mlxsw_sp_mc_dec_ref (mlxsw_sp_port, mid); +mlxsw_sp_port_remove_from_mid (mlxsw_sp_port, mid);return err; }
@@ -1451,7 +1451,7 @@ static int mlxsw_sp_port_mdb_del(struct mlxsw_sp_port *mlxsw_sp_port,netdev_err (dev,"Unable to remove port from SMID\n" ); mid_idx = mid->mid; -if (__mlxsw_sp_mc_dec_ref (mlxsw_sp_port, mid)) { +if (mlxsw_sp_port_remove_from_mid (mlxsw_sp_port, mid)) { err =mlxsw_sp_port_mdb_op (mlxsw_sp, mdb->addr, fid_index, mid_idx, false);if (err)
Signature · 1 line
2.9.5
PATCH 4/16 mlxsw: spectrum_switchdev: Save mids list per bridge device
In reply to Jiri PirkoFrom: Nogah Frankel <[email protected]>
Instead of saving all the mids in the same list, save them per vlan device. This change allows a more efficient mid find.
Also, in the next patches, there will be added a lot of loops over all the mids in bridge device for multicast disable, mrouter change and ndb flush.
--- .../ethernet/mellanox/mlxsw/spectrum_switchdev.c | 49 +++++++++++----------- 1 file changed, 24 insertions(+), 25 deletions(-)
drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +24 -25
@@ -67,7 +67,6 @@ struct mlxsw_sp_bridge {u32 ageing_time;bool vlan_enabled_exists;struct list_head bridges_list; -struct list_head mids_list;DECLARE_BITMAP (mids_bitmap,MLXSW_SP_MID_MAX );const struct mlxsw_sp_bridge_ops *bridge_8021q_ops;const struct mlxsw_sp_bridge_ops *bridge_8021d_ops;
@@ -77,6 +76,7 @@ struct mlxsw_sp_bridge_device {struct net_device *dev;struct list_head list;struct list_head ports_list; +struct list_head mids_list; u8 vlan_enabled:1, multicast_enabled:1;const struct mlxsw_sp_bridge_ops *ops;
@@ -161,6 +161,7 @@ mlxsw_sp_bridge_device_create(struct mlxsw_sp_bridge *bridge, }else { bridge_device->ops = bridge->bridge_8021d_ops; } +INIT_LIST_HEAD (&bridge_device->mids_list);list_add (&bridge_device->list, &bridge->bridges_list);return bridge_device;
@@ -170,10 +171,17 @@ static void mlxsw_sp_bridge_device_destroy(struct mlxsw_sp_bridge *bridge, struct mlxsw_sp_bridge_device *bridge_device) { + struct mlxsw_sp_mid *mid, *tmp; +list_del (&bridge_device->list);if (bridge_device->vlan_enabled) bridge->vlan_enabled_exists = false;WARN_ON (!list_empty (&bridge_device->ports_list)); +list_for_each_entry_safe (mid, tmp, &bridge_device->mids_list, list) { +list_del (&mid->list); +clear_bit (mid->mid, bridge->mids_bitmap); +kfree (mid); + }kfree (bridge_device); }
@@ -1221,22 +1229,25 @@ static int mlxsw_sp_port_smid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 mid,return err; } -static struct mlxsw_sp_mid *__mlxsw_sp_mc_get (struct mlxsw_sp *mlxsw_sp, -const unsigned char *addr, -u16 fid) +static struct +mlxsw_sp_mid *__mlxsw_sp_mc_get (struct mlxsw_sp_bridge_device *bridge_device, +const unsigned char *addr, +u16 fid) {struct mlxsw_sp_mid *mid; -list_for_each_entry (mid, &mlxsw_sp->bridge->mids_list, list) { +list_for_each_entry (mid, &bridge_device->mids_list, list) {if (ether_addr_equal (mid->addr, addr) && mid->fid == fid)return mid; }return NULL ; } -static struct mlxsw_sp_mid *__mlxsw_sp_mc_alloc (struct mlxsw_sp *mlxsw_sp, -const unsigned char *addr, -u16 fid) +static struct +mlxsw_sp_mid *__mlxsw_sp_mc_alloc (struct mlxsw_sp *mlxsw_sp, +struct mlxsw_sp_bridge_device *bridge_device, +const unsigned char *addr, +u16 fid) {struct mlxsw_sp_mid *mid;size_t alloc_size;
@@ -1263,7 +1274,7 @@ static struct mlxsw_sp_mid *__mlxsw_sp_mc_alloc(struct mlxsw_sp *mlxsw_sp,ether_addr_copy (mid->addr, addr); mid->fid = fid; mid->mid = mid_idx; -list_add_tail (&mid->list, &mlxsw_sp->bridge->mids_list); +list_add_tail (&mid->list, &bridge_device->mids_list);return mid; }
@@ -1316,9 +1327,10 @@ static int mlxsw_sp_port_mdb_add(struct mlxsw_sp_port *mlxsw_sp_port, fid_index =mlxsw_sp_fid_index (mlxsw_sp_port_vlan->fid); - mid =__mlxsw_sp_mc_get (mlxsw_sp, mdb->addr, fid_index); + mid =__mlxsw_sp_mc_get (bridge_device, mdb->addr, fid_index);if (!mid) { - mid =__mlxsw_sp_mc_alloc (mlxsw_sp, mdb->addr, fid_index); + mid =__mlxsw_sp_mc_alloc (mlxsw_sp, bridge_device, mdb->addr, + fid_index);if (!mid) {netdev_err (dev,"Unable to allocate MC group\n" );return -ENOMEM ;
@@ -1440,7 +1452,7 @@ static int mlxsw_sp_port_mdb_del(struct mlxsw_sp_port *mlxsw_sp_port, fid_index =mlxsw_sp_fid_index (mlxsw_sp_port_vlan->fid); - mid =__mlxsw_sp_mc_get (mlxsw_sp, mdb->addr, fid_index); + mid =__mlxsw_sp_mc_get (bridge_device, mdb->addr, fid_index);if (!mid) {netdev_err (dev,"Unable to remove port from MC DB\n" );return -EINVAL ;
@@ -1995,17 +2007,6 @@ static void mlxsw_sp_fdb_fini(struct mlxsw_sp *mlxsw_sp) } -static void mlxsw_sp_mids_fini (struct mlxsw_sp *mlxsw_sp) -{ -struct mlxsw_sp_mid *mid, *tmp; - -list_for_each_entry_safe (mid, tmp, &mlxsw_sp->bridge->mids_list, list) { -list_del (&mid->list); -clear_bit (mid->mid, mlxsw_sp->bridge->mids_bitmap); -kfree (mid); - } -} -int mlxsw_sp_switchdev_init (struct mlxsw_sp *mlxsw_sp) {struct mlxsw_sp_bridge *bridge;
@@ -2017,7 +2018,6 @@ int mlxsw_sp_switchdev_init(struct mlxsw_sp *mlxsw_sp) bridge->mlxsw_sp = mlxsw_sp;INIT_LIST_HEAD (&mlxsw_sp->bridge->bridges_list); -INIT_LIST_HEAD (&mlxsw_sp->bridge->mids_list); bridge->bridge_8021q_ops = &mlxsw_sp_bridge_8021q_ops; bridge->bridge_8021d_ops = &mlxsw_sp_bridge_8021d_ops;
@@ -2028,7 +2028,6 @@ int mlxsw_sp_switchdev_init(struct mlxsw_sp *mlxsw_sp)void mlxsw_sp_switchdev_fini (struct mlxsw_sp *mlxsw_sp) {mlxsw_sp_fdb_fini (mlxsw_sp); -mlxsw_sp_mids_fini (mlxsw_sp);WARN_ON (!list_empty (&mlxsw_sp->bridge->bridges_list));kfree (mlxsw_sp->bridge); }
Signature · 1 line
2.9.5
PATCH 5/16 mlxsw: spectrum_switchdev: Break smid write function
In reply to Jiri PirkoFrom: Nogah Frankel <[email protected]>
Break the smid write function into two, one that cleans the ports that might be still written there and one that changes an exiting mid entry.
--- .../ethernet/mellanox/mlxsw/spectrum_switchdev.c | 42 +++++++++++++++------- 1 file changed, 30 insertions(+), 12 deletions(-)
drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +30 -12
@@ -1190,7 +1190,7 @@ mlxsw_sp_port_fdb_set(struct mlxsw_sp_port *mlxsw_sp_port, }static int mlxsw_sp_port_mdb_op (struct mlxsw_sp *mlxsw_sp,const char *addr, -u16 fid,u16 mid,bool adding) +u16 fid,u16 mid_idx,bool adding) {char *sfd_pl;int err;
@@ -1201,16 +1201,16 @@ static int mlxsw_sp_port_mdb_op(struct mlxsw_sp *mlxsw_sp, const char *addr,mlxsw_reg_sfd_pack (sfd_pl,mlxsw_sp_sfd_op (adding),0 );mlxsw_reg_sfd_mc_pack (sfd_pl,0 , addr, fid, -MLXSW_REG_SFD_REC_ACTION_NOP , mid); +MLXSW_REG_SFD_REC_ACTION_NOP , mid_idx); err =mlxsw_reg_write (mlxsw_sp->core,MLXSW_REG (sfd), sfd_pl);kfree (sfd_pl);return err; } -static int mlxsw_sp_port_smid_set (struct mlxsw_sp_port *mlxsw_sp_port,u16 mid, -bool add,bool clear_all_ports) +/* clean the an entry from the HW and write there a full new entry */ +static int mlxsw_sp_port_smid_full_entry (struct mlxsw_sp *mlxsw_sp, +u16 mid_idx) { -struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;char *smid_pl;int err, i;
@@ -1218,12 +1218,29 @@ static int mlxsw_sp_port_smid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 mid,if (!smid_pl)return -ENOMEM ; -mlxsw_reg_smid_pack (smid_pl, mid, mlxsw_sp_port->local_port, add); -if (clear_all_ports) { -for (i =1 ; i <mlxsw_core_max_ports (mlxsw_sp->core); i++) -if (mlxsw_sp->ports[i]) -mlxsw_reg_smid_port_mask_set (smid_pl, i,1 ); +mlxsw_reg_smid_pack (smid_pl, mid_idx,0 , false); +for (i =1 ; i <mlxsw_core_max_ports (mlxsw_sp->core); i++) { +if (mlxsw_sp->ports[i]) +mlxsw_reg_smid_port_mask_set (smid_pl, i,1 ); } + + err =mlxsw_reg_write (mlxsw_sp->core,MLXSW_REG (smid), smid_pl); +kfree (smid_pl); +return err; +} + +static int mlxsw_sp_port_smid_set (struct mlxsw_sp_port *mlxsw_sp_port, +u16 mid_idx,bool add) +{ +struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; +char *smid_pl; +int err; + + smid_pl =kmalloc (MLXSW_REG_SMID_LEN ,GFP_KERNEL ); +if (!smid_pl) +return -ENOMEM ; + +mlxsw_reg_smid_pack (smid_pl, mid_idx, mlxsw_sp_port->local_port, add); err =mlxsw_reg_write (mlxsw_sp->core,MLXSW_REG (smid), smid_pl);kfree (smid_pl);return err;
@@ -1336,10 +1353,11 @@ static int mlxsw_sp_port_mdb_add(struct mlxsw_sp_port *mlxsw_sp_port,return -ENOMEM ; } is_new_mid = true; +mlxsw_sp_port_smid_full_entry (mlxsw_sp, mid->mid); }set_bit (mlxsw_sp_port->local_port, mid->ports_in_mid); - err =mlxsw_sp_port_smid_set (mlxsw_sp_port, mid->mid, true, is_new_mid); + err =mlxsw_sp_port_smid_set (mlxsw_sp_port, mid->mid, true);if (err) {netdev_err (dev,"Unable to set SMID\n" ); goto err_out;
@@ -1458,7 +1476,7 @@ static int mlxsw_sp_port_mdb_del(struct mlxsw_sp_port *mlxsw_sp_port,return -EINVAL ; } - err =mlxsw_sp_port_smid_set (mlxsw_sp_port, mid->mid, false, false); + err =mlxsw_sp_port_smid_set (mlxsw_sp_port, mid->mid, false);if (err)netdev_err (dev,"Unable to remove port from SMID\n" );
Signature · 1 line
2.9.5
PATCH 6/16 mlxsw: spectrum_switchdev: Attach mid id allocation to HW write
In reply to Jiri PirkoFrom: Nogah Frankel <[email protected]>
Attach mid getting and releasing mid id to the HW write / remove, and add a flag to indicate whether the mid is in the HW. It is done because mid id is also HW index to this mid.
This change allows adding in the following patches the ability to have a mid in the mdb cache but not in the HW. It will be useful for being able to disable the multicast.
It means that the mdb is being written / delete to the HW in the mid allocation / removing function, not after them.
--- drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 1 + .../ethernet/mellanox/mlxsw/spectrum_switchdev.c | 88 ++++++++++++++-------- 2 files changed, 56 insertions(+), 33 deletions(-)
drivers/net/ethernet/mellanox/mlxsw/spectrum.h +1 -0
@@ -94,6 +94,7 @@ struct mlxsw_sp_mid {unsigned char addr[ETH_ALEN ];u16 fid;u16 mid; +bool in_hw;unsigned long *ports_in_mid;/* bits array */ };
drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +55 -33
151 lines not on this page · raw message
Signature · 1 line
2.9.5
PATCH 7/16 mlxsw: spectrum_switchdev: Break mid deletion into two function
In reply to Jiri PirkoFrom: Nogah Frankel <[email protected]>
Break mid deletion into two function, so it will be possible in the future to delete a mid entry for other reasons then switchdev command (like port deletion).
--- .../ethernet/mellanox/mlxsw/spectrum_switchdev.c | 32 ++++++++++++++-------- 1 file changed, 20 insertions(+), 12 deletions(-)
drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +20 -12
@@ -1468,6 +1468,25 @@ static int mlxsw_sp_port_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port,return 0 ; } +static int +__mlxsw_sp_port_mdb_del (struct mlxsw_sp_port *mlxsw_sp_port, +struct mlxsw_sp_bridge_port *bridge_port, +struct mlxsw_sp_mid *mid) +{ +struct net_device *dev = mlxsw_sp_port->dev; +int err; + + err =mlxsw_sp_port_smid_set (mlxsw_sp_port, mid->mid, false); +if (err) +netdev_err (dev,"Unable to remove port from SMID\n" ); + + err =mlxsw_sp_port_remove_from_mid (mlxsw_sp_port, mid); +if (err) +netdev_err (dev,"Unable to remove MC SFD\n" ); + +return err; +} +static int mlxsw_sp_port_mdb_del (struct mlxsw_sp_port *mlxsw_sp_port,const struct switchdev_obj_port_mdb *mdb) {
@@ -1479,8 +1498,6 @@ static int mlxsw_sp_port_mdb_del(struct mlxsw_sp_port *mlxsw_sp_port,struct mlxsw_sp_bridge_port *bridge_port;struct mlxsw_sp_mid *mid;u16 fid_index; -u16 mid_idx; -int err =0 ; bridge_port =mlxsw_sp_bridge_port_find (mlxsw_sp->bridge, orig_dev);if (!bridge_port)
@@ -1501,16 +1518,7 @@ static int mlxsw_sp_port_mdb_del(struct mlxsw_sp_port *mlxsw_sp_port,return -EINVAL ; } - err =mlxsw_sp_port_smid_set (mlxsw_sp_port, mid->mid, false); -if (err) -netdev_err (dev,"Unable to remove port from SMID\n" ); - - mid_idx = mid->mid; - err =mlxsw_sp_port_remove_from_mid (mlxsw_sp_port, mid); -if (err) -netdev_err (dev,"Unable to remove MC SFD\n" ); - -return err; +return __mlxsw_sp_port_mdb_del (mlxsw_sp_port, bridge_port, mid); } static int mlxsw_sp_port_obj_del(struct net_device *dev,
Signature · 1 line
2.9.5
PATCH 8/16 mlxsw: spectrum_switchdev: Don't write mids to the HW when mc is disabled
In reply to Jiri PirkoFrom: Nogah Frankel <[email protected]>
Don't write multicast related data to the HW when mc is disabled. Also, don't allocate mid id to new mids (so the remove function could know that they weren't wrote to the HW)
--- .../ethernet/mellanox/mlxsw/spectrum_switchdev.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-)
drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +17 -4
@@ -1290,6 +1290,9 @@ mlxsw_sp_mc_write_mdb_entry(struct mlxsw_sp *mlxsw_sp,static int mlxsw_sp_mc_remove_mdb_entry (struct mlxsw_sp *mlxsw_sp,struct mlxsw_sp_mid *mid) { +if (!mid->in_hw) +return 0 ; +clear_bit (mid->mid, mlxsw_sp->bridge->mids_bitmap); mid->in_hw = false; return mlxsw_sp_port_mdb_op(mlxsw_sp, mid->addr, mid->fid, mid->mid,
@@ -1319,11 +1322,15 @@ mlxsw_sp_mid *__mlxsw_sp_mc_alloc(struct mlxsw_sp *mlxsw_sp,ether_addr_copy (mid->addr, addr); mid->fid = fid; mid->in_hw = false; + +if (!bridge_device->multicast_enabled) + goto out; +if (!mlxsw_sp_mc_write_mdb_entry (mlxsw_sp, mid)) goto err_write_mdb_entry; +out:list_add_tail (&mid->list, &bridge_device->mids_list); -return mid; err_write_mdb_entry:
@@ -1391,6 +1398,9 @@ static int mlxsw_sp_port_mdb_add(struct mlxsw_sp_port *mlxsw_sp_port, }set_bit (mlxsw_sp_port->local_port, mid->ports_in_mid); +if (!bridge_device->multicast_enabled) +return 0 ; + err =mlxsw_sp_port_smid_set (mlxsw_sp_port, mid->mid, true);if (err) {netdev_err (dev,"Unable to set SMID\n" );
@@ -1476,9 +1486,12 @@ __mlxsw_sp_port_mdb_del(struct mlxsw_sp_port *mlxsw_sp_port,struct net_device *dev = mlxsw_sp_port->dev;int err; - err =mlxsw_sp_port_smid_set (mlxsw_sp_port, mid->mid, false); -if (err) -netdev_err (dev,"Unable to remove port from SMID\n" ); +if (bridge_port->bridge_device->multicast_enabled) { + err =mlxsw_sp_port_smid_set (mlxsw_sp_port, mid->mid, false); + +if (err) +netdev_err (dev,"Unable to remove port from SMID\n" ); + } err =mlxsw_sp_port_remove_from_mid (mlxsw_sp_port, mid);if (err)
Signature · 1 line
2.9.5
PATCH 9/16 mlxsw: spectrum_switchdev: Disable mdb when mc is disabled
In reply to Jiri PirkoFrom: Nogah Frankel <[email protected]>
Remove all the mdb entries from the HW when mc is being disabled and re-write them when it is being enabled.
--- .../ethernet/mellanox/mlxsw/spectrum_switchdev.c | 41 +++++++++++++++++++--- 1 file changed, 37 insertions(+), 4 deletions(-)
drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +37 -4
@@ -121,6 +121,11 @@ mlxsw_sp_bridge_port_fdb_flush(struct mlxsw_sp *mlxsw_sp,struct mlxsw_sp_bridge_port *bridge_port, u16 fid_index); +static void +mlxsw_sp_bridge_mdb_mc_enable_sync (struct mlxsw_sp_port *mlxsw_sp_port, +struct mlxsw_sp_bridge_device + *bridge_device); +static struct mlxsw_sp_bridge_device *mlxsw_sp_bridge_device_find (const struct mlxsw_sp_bridge *bridge,const struct net_device *br_dev)
@@ -757,6 +762,12 @@ static int mlxsw_sp_port_mc_disabled_set(struct mlxsw_sp_port *mlxsw_sp_port,if (!bridge_device)return 0 ; +if (bridge_device->multicast_enabled != !mc_disabled) { + bridge_device->multicast_enabled = !mc_disabled; +mlxsw_sp_bridge_mdb_mc_enable_sync (mlxsw_sp_port, + bridge_device); + } +list_for_each_entry (bridge_port, &bridge_device->ports_list, list) {enum mlxsw_sp_flood_type packet_type =MLXSW_SP_FLOOD_TYPE_MC ;bool member = mc_disabled ? true : bridge_port->mrouter;
@@ -1207,9 +1218,8 @@ static int mlxsw_sp_port_mdb_op(struct mlxsw_sp *mlxsw_sp, const char *addr,return err; } -/* clean the an entry from the HW and write there a full new entry */ -static int mlxsw_sp_port_smid_full_entry (struct mlxsw_sp *mlxsw_sp, -u16 mid_idx) +static int mlxsw_sp_port_smid_full_entry (struct mlxsw_sp *mlxsw_sp,u16 mid_idx, +long *ports_bitmap) {char *smid_pl;int err, i;
@@ -1224,6 +1234,9 @@ static int mlxsw_sp_port_smid_full_entry(struct mlxsw_sp *mlxsw_sp,mlxsw_reg_smid_port_mask_set (smid_pl, i,1 ); } +for_each_set_bit (i, ports_bitmap,mlxsw_core_max_ports (mlxsw_sp->core)) +mlxsw_reg_smid_port_set (smid_pl, i,1 ); + err =mlxsw_reg_write (mlxsw_sp->core,MLXSW_REG (smid), smid_pl);kfree (smid_pl);return err;
@@ -1273,7 +1286,8 @@ mlxsw_sp_mc_write_mdb_entry(struct mlxsw_sp *mlxsw_sp,return false; mid->mid = mid_idx; - err =mlxsw_sp_port_smid_full_entry (mlxsw_sp, mid_idx); + err =mlxsw_sp_port_smid_full_entry (mlxsw_sp, mid_idx, + mid->ports_in_mid);if (err)return false;
@@ -1414,6 +1428,25 @@ static int mlxsw_sp_port_mdb_add(struct mlxsw_sp_port *mlxsw_sp_port,return err; } +static void +mlxsw_sp_bridge_mdb_mc_enable_sync (struct mlxsw_sp_port *mlxsw_sp_port, +struct mlxsw_sp_bridge_device + *bridge_device) +{ +struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; +struct mlxsw_sp_mid *mid; +bool mc_enabled; + + mc_enabled = bridge_device->multicast_enabled; + +list_for_each_entry (mid, &bridge_device->mids_list, list) { +if (mc_enabled) +mlxsw_sp_mc_write_mdb_entry (mlxsw_sp, mid); +else +mlxsw_sp_mc_remove_mdb_entry (mlxsw_sp, mid); + } +} +static int mlxsw_sp_port_obj_add (struct net_device *dev,const struct switchdev_obj *obj,struct switchdev_trans *trans)
Signature · 1 line
2.9.5
PATCH 10/16 mlxsw: spectrum_switchdev: Use generic mc flood function
In reply to Jiri PirkoFrom: Nogah Frankel <[email protected]>
Use the generic mc flood function to decide whether to flood mc to a port when mc is being enabled / disabled.
Move this function in the file to avoid forward declaration.
--- .../net/ethernet/mellanox/mlxsw/spectrum_switchdev.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-)
drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +9 -9
@@ -742,6 +742,14 @@ static int mlxsw_sp_port_attr_mrouter_set(struct mlxsw_sp_port *mlxsw_sp_port,return 0 ; } +static bool mlxsw_sp_mc_flood (const struct mlxsw_sp_bridge_port *bridge_port) +{ +const struct mlxsw_sp_bridge_device *bridge_device; + + bridge_device = bridge_port->bridge_device; +return !bridge_device->multicast_enabled ? true : bridge_port->mrouter; +} + static int mlxsw_sp_port_mc_disabled_set(struct mlxsw_sp_port *mlxsw_sp_port, struct switchdev_trans *trans, struct net_device *orig_dev,
@@ -770,7 +778,7 @@ static int mlxsw_sp_port_mc_disabled_set(struct mlxsw_sp_port *mlxsw_sp_port,list_for_each_entry (bridge_port, &bridge_device->ports_list, list) {enum mlxsw_sp_flood_type packet_type =MLXSW_SP_FLOOD_TYPE_MC ; -bool member = mc_disabled ? true : bridge_port->mrouter; +bool member =mlxsw_sp_mc_flood (bridge_port); err = mlxsw_sp_bridge_port_flood_table_set(mlxsw_sp_port, bridge_port,
@@ -829,14 +837,6 @@ static int mlxsw_sp_port_attr_set(struct net_device *dev,return err; } -static bool mlxsw_sp_mc_flood (const struct mlxsw_sp_bridge_port *bridge_port) -{ -const struct mlxsw_sp_bridge_device *bridge_device; - - bridge_device = bridge_port->bridge_device; -return !bridge_device->multicast_enabled ? true : bridge_port->mrouter; -} -static int mlxsw_sp_port_vlan_fid_join (struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,struct mlxsw_sp_bridge_port *bridge_port)
Signature · 1 line
2.9.5
PATCH 11/16 mlxsw: spectrum_switchdev: Flood mc when mc is disabled by user flag
In reply to Jiri PirkoFrom: Nogah Frankel <[email protected]>
When multicast is disabled, flood mc packets only to port that are marked BR_MCAST_FLOOD (instead to all).
--- .../ethernet/mellanox/mlxsw/spectrum_switchdev.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-)
drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +17 -4
@@ -262,7 +262,8 @@ mlxsw_sp_bridge_port_create(struct mlxsw_sp_bridge_device *bridge_device, bridge_port->dev = brport_dev; bridge_port->bridge_device = bridge_device; bridge_port->stp_state =BR_STATE_DISABLED ; - bridge_port->flags =BR_LEARNING |BR_FLOOD |BR_LEARNING_SYNC ; + bridge_port->flags =BR_LEARNING |BR_FLOOD |BR_LEARNING_SYNC | +BR_MCAST_FLOOD ;INIT_LIST_HEAD (&bridge_port->vlans_list);list_add (&bridge_port->list, &bridge_device->ports_list); bridge_port->ref_count =1 ;
@@ -468,7 +469,8 @@ static int mlxsw_sp_port_attr_get(struct net_device *dev, &attr->u.brport_flags);break ;case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS_SUPPORT : - attr->u.brport_flags_support =BR_LEARNING |BR_FLOOD ; + attr->u.brport_flags_support =BR_LEARNING |BR_FLOOD | +BR_MCAST_FLOOD ;break ;default :return -EOPNOTSUPP ;
@@ -653,8 +655,18 @@ static int mlxsw_sp_port_attr_br_flags_set(struct mlxsw_sp_port *mlxsw_sp_port,if (err)return err; -memcpy (&bridge_port->flags, &brport_flags,sizeof (brport_flags)); +if (bridge_port->bridge_device->multicast_enabled) + goto out; + err =mlxsw_sp_bridge_port_flood_table_set (mlxsw_sp_port, bridge_port, +MLXSW_SP_FLOOD_TYPE_MC , + brport_flags & +BR_MCAST_FLOOD ); +if (err) +return err; + +out: +memcpy (&bridge_port->flags, &brport_flags,sizeof (brport_flags));return 0 ; }
@@ -747,7 +759,8 @@ static bool mlxsw_sp_mc_flood(const struct mlxsw_sp_bridge_port *bridge_port)const struct mlxsw_sp_bridge_device *bridge_device; bridge_device = bridge_port->bridge_device; -return !bridge_device->multicast_enabled ? true : bridge_port->mrouter; +return bridge_device->multicast_enabled ? bridge_port->mrouter : + bridge_port->flags &BR_MCAST_FLOOD ; } static int mlxsw_sp_port_mc_disabled_set(struct mlxsw_sp_port *mlxsw_sp_port,
Signature · 1 line
2.9.5
PATCH 12/16 mlxsw: spectrum_switchdev: Flush the mdb when a port is being removed
In reply to Jiri PirkoFrom: Nogah Frankel <[email protected]>
When a port is being removed from a bridge, flush the bridge mdb to remove the mids of that port.
--- .../ethernet/mellanox/mlxsw/spectrum_switchdev.c | 39 ++++++++++++++++------ 1 file changed, 29 insertions(+), 10 deletions(-)
drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +29 -10
@@ -122,6 +122,10 @@ mlxsw_sp_bridge_port_fdb_flush(struct mlxsw_sp *mlxsw_sp, u16 fid_index);static void +mlxsw_sp_bridge_port_mdb_flush (struct mlxsw_sp_port *mlxsw_sp_port, +struct mlxsw_sp_bridge_port *bridge_port); + +static void mlxsw_sp_bridge_mdb_mc_enable_sync (struct mlxsw_sp_port *mlxsw_sp_port,struct mlxsw_sp_bridge_device *bridge_device);
@@ -176,17 +180,11 @@ static void mlxsw_sp_bridge_device_destroy(struct mlxsw_sp_bridge *bridge, struct mlxsw_sp_bridge_device *bridge_device) { - struct mlxsw_sp_mid *mid, *tmp; - list_del(&bridge_device->list);if (bridge_device->vlan_enabled) bridge->vlan_enabled_exists = false;WARN_ON (!list_empty (&bridge_device->ports_list)); -list_for_each_entry_safe (mid, tmp, &bridge_device->mids_list, list) { -list_del (&mid->list); -clear_bit (mid->mid, bridge->mids_bitmap); -kfree (mid); - } +WARN_ON (!list_empty (&bridge_device->mids_list));kfree (bridge_device); }
@@ -987,24 +985,28 @@ mlxsw_sp_port_vlan_bridge_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)struct mlxsw_sp_bridge_vlan *bridge_vlan;struct mlxsw_sp_bridge_port *bridge_port;u16 vid = mlxsw_sp_port_vlan->vid; -bool last; +bool last_port, last_vlan;if (WARN_ON (mlxsw_sp_fid_type (fid) !=MLXSW_SP_FID_TYPE_8021Q &&mlxsw_sp_fid_type (fid) !=MLXSW_SP_FID_TYPE_8021D ))return ; bridge_port = mlxsw_sp_port_vlan->bridge_port; + last_vlan =list_is_singular (&bridge_port->vlans_list); bridge_vlan =mlxsw_sp_bridge_vlan_find (bridge_port, vid); - last =list_is_singular (&bridge_vlan->port_vlan_list); + last_port =list_is_singular (&bridge_vlan->port_vlan_list);list_del (&mlxsw_sp_port_vlan->bridge_vlan_node);mlxsw_sp_bridge_vlan_put (bridge_vlan);mlxsw_sp_port_vid_stp_set (mlxsw_sp_port, vid,BR_STATE_DISABLED );mlxsw_sp_port_vid_learning_set (mlxsw_sp_port, vid, false); -if (last) +if (last_port)mlxsw_sp_bridge_port_fdb_flush (mlxsw_sp_port->mlxsw_sp, bridge_port,mlxsw_sp_fid_index (fid)); +if (last_vlan) +mlxsw_sp_bridge_port_mdb_flush (mlxsw_sp_port, bridge_port); +mlxsw_sp_port_vlan_fid_leave (mlxsw_sp_port_vlan);mlxsw_sp_bridge_port_put (mlxsw_sp_port->mlxsw_sp->bridge, bridge_port);
@@ -1580,6 +1582,23 @@ static int mlxsw_sp_port_mdb_del(struct mlxsw_sp_port *mlxsw_sp_port,return __mlxsw_sp_port_mdb_del (mlxsw_sp_port, bridge_port, mid); } +static void +mlxsw_sp_bridge_port_mdb_flush (struct mlxsw_sp_port *mlxsw_sp_port, +struct mlxsw_sp_bridge_port *bridge_port) +{ +struct mlxsw_sp_bridge_device *bridge_device; +struct mlxsw_sp_mid *mid, *tmp; + + bridge_device = bridge_port->bridge_device; + +list_for_each_entry_safe (mid, tmp, &bridge_device->mids_list, list) { +if (test_bit (mlxsw_sp_port->local_port, mid->ports_in_mid)) { +__mlxsw_sp_port_mdb_del (mlxsw_sp_port, bridge_port, + mid); + } + } +} +static int mlxsw_sp_port_obj_del (struct net_device *dev,const struct switchdev_obj *obj) {
Signature · 1 line
2.9.5
PATCH 13/16 mlxsw: spectrum_switchdev: Flood all mc packets to mrouter ports
In reply to Jiri PirkoFrom: Nogah Frankel <[email protected]>
When mc is enabled, whenever a mc packet doesn't hit any mdb entry it is being flood to the ports marked as mrouters. However, all mc packets should be flooded to them even if they match an entry in the mdb.
This patch adds the mrouter ports to every mdb entry that is being written to the HW.
--- .../ethernet/mellanox/mlxsw/spectrum_switchdev.c | 65 ++++++++++++++++++++-- 1 file changed, 60 insertions(+), 5 deletions(-)
drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +60 -5
@@ -1288,10 +1288,55 @@ mlxsw_sp_mid *__mlxsw_sp_mc_get(struct mlxsw_sp_bridge_device *bridge_device,return NULL ; } +static void +mlxsw_sp_bridge_port_get_ports_bitmap (struct mlxsw_sp *mlxsw_sp, +struct mlxsw_sp_bridge_port *bridge_port, +unsigned long *ports_bitmap) +{ +struct mlxsw_sp_port *mlxsw_sp_port; +u64 max_lag_members, i; +int lag_id; + +if (!bridge_port->lagged) { +set_bit (bridge_port->system_port, ports_bitmap); + }else { + max_lag_members =MLXSW_CORE_RES_GET (mlxsw_sp->core, +MAX_LAG_MEMBERS ); + lag_id = bridge_port->lag_id; +for (i =0 ; i < max_lag_members; i++) { + mlxsw_sp_port =mlxsw_sp_port_lagged_get (mlxsw_sp, + lag_id, i); +if (mlxsw_sp_port) +set_bit (mlxsw_sp_port->local_port, + ports_bitmap); + } + } +} + +static void +mlxsw_sp_mc_get_mrouters_bitmap (unsigned long *flood_bitmap, +struct mlxsw_sp_bridge_device *bridge_device, +struct mlxsw_sp *mlxsw_sp) +{ +struct mlxsw_sp_bridge_port *bridge_port; + +list_for_each_entry (bridge_port, &bridge_device->ports_list, list) { +if (bridge_port->mrouter) { +mlxsw_sp_bridge_port_get_ports_bitmap (mlxsw_sp, + bridge_port, + flood_bitmap); + } + } +} +static bool mlxsw_sp_mc_write_mdb_entry (struct mlxsw_sp *mlxsw_sp, -struct mlxsw_sp_mid *mid) +struct mlxsw_sp_mid *mid, +struct mlxsw_sp_bridge_device *bridge_device) { +long *flood_bitmap; +int num_of_ports; +int alloc_size;u16 mid_idx;int err;
@@ -1300,9 +1345,18 @@ mlxsw_sp_mc_write_mdb_entry(struct mlxsw_sp *mlxsw_sp,if (mid_idx ==MLXSW_SP_MID_MAX )return false; + num_of_ports =mlxsw_core_max_ports (mlxsw_sp->core); + alloc_size =sizeof (long ) *BITS_TO_LONGS (num_of_ports); + flood_bitmap =kzalloc (alloc_size,GFP_KERNEL ); +if (!flood_bitmap) +return false; + +bitmap_copy (flood_bitmap, mid->ports_in_mid, num_of_ports); +mlxsw_sp_mc_get_mrouters_bitmap (flood_bitmap, bridge_device, mlxsw_sp); + mid->mid = mid_idx; - err =mlxsw_sp_port_smid_full_entry (mlxsw_sp, mid_idx, - mid->ports_in_mid); + err =mlxsw_sp_port_smid_full_entry (mlxsw_sp, mid_idx, flood_bitmap); +kfree (flood_bitmap);if (err)return false;
@@ -1355,7 +1409,7 @@ mlxsw_sp_mid *__mlxsw_sp_mc_alloc(struct mlxsw_sp *mlxsw_sp,if (!bridge_device->multicast_enabled) goto out; -if (!mlxsw_sp_mc_write_mdb_entry (mlxsw_sp, mid)) +if (!mlxsw_sp_mc_write_mdb_entry (mlxsw_sp, mid, bridge_device)) goto err_write_mdb_entry; out:
@@ -1456,7 +1510,8 @@ mlxsw_sp_bridge_mdb_mc_enable_sync(struct mlxsw_sp_port *mlxsw_sp_port,list_for_each_entry (mid, &bridge_device->mids_list, list) {if (mc_enabled) -mlxsw_sp_mc_write_mdb_entry (mlxsw_sp, mid); +mlxsw_sp_mc_write_mdb_entry (mlxsw_sp, mid, + bridge_device);else mlxsw_sp_mc_remove_mdb_entry (mlxsw_sp, mid); }
Signature · 1 line
2.9.5
PATCH 14/16 mlxsw: spectrum_switchdev: Update the mdb of mrouter port change
In reply to Jiri PirkoFrom: Nogah Frankel <[email protected]>
Whenever a port starts / stops being mrouter, update all the mdb entries in the HW to flood / stop flooding mc packets there.
The change should happen only if the port is not in the mid. (If it is, the mid should flood mc packets to this port anyway)
--- .../ethernet/mellanox/mlxsw/spectrum_switchdev.c | 23 ++++++++++++++++++++++ 1 file changed, 23 insertions(+)
drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +23 -0
@@ -130,6 +130,11 @@ mlxsw_sp_bridge_mdb_mc_enable_sync(struct mlxsw_sp_port *mlxsw_sp_port,struct mlxsw_sp_bridge_device *bridge_device); +static void +mlxsw_sp_port_mrouter_update_mdb (struct mlxsw_sp_port *mlxsw_sp_port, +struct mlxsw_sp_bridge_port *bridge_port, +bool add); +static struct mlxsw_sp_bridge_device *mlxsw_sp_bridge_device_find (const struct mlxsw_sp_bridge *bridge,const struct net_device *br_dev)
@@ -747,6 +752,8 @@ static int mlxsw_sp_port_attr_mrouter_set(struct mlxsw_sp_port *mlxsw_sp_port,if (err)return err; +mlxsw_sp_port_mrouter_update_mdb (mlxsw_sp_port, bridge_port, + is_port_mrouter); out: bridge_port->mrouter = is_port_mrouter;return 0 ;
@@ -1517,6 +1524,22 @@ mlxsw_sp_bridge_mdb_mc_enable_sync(struct mlxsw_sp_port *mlxsw_sp_port, } } +static void +mlxsw_sp_port_mrouter_update_mdb (struct mlxsw_sp_port *mlxsw_sp_port, +struct mlxsw_sp_bridge_port *bridge_port, +bool add) +{ +struct mlxsw_sp_bridge_device *bridge_device; +struct mlxsw_sp_mid *mid; + + bridge_device = bridge_port->bridge_device; + +list_for_each_entry (mid, &bridge_device->mids_list, list) { +if (!test_bit (mlxsw_sp_port->local_port, mid->ports_in_mid)) +mlxsw_sp_port_smid_set (mlxsw_sp_port, mid->mid, add); + } +} +static int mlxsw_sp_port_obj_add (struct net_device *dev,const struct switchdev_obj *obj,struct switchdev_trans *trans)
Signature · 1 line
2.9.5
PATCH 15/16 mlxsw: spectrum_switchdev: Remove mrouter flood in mdb flush
In reply to Jiri PirkoFrom: Nogah Frankel <[email protected]>
In mdb flush the port is being removed from all the mids it is registered to. But if the port is mrouter, all the mids floods to it. This patch remove mrouter ports from mids it is not registered to in the mdb flush.
--- drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +3 -0
@@ -1673,6 +1673,9 @@ mlxsw_sp_bridge_port_mdb_flush(struct mlxsw_sp_port *mlxsw_sp_port,if (test_bit (mlxsw_sp_port->local_port, mid->ports_in_mid)) {__mlxsw_sp_port_mdb_del (mlxsw_sp_port, bridge_port, mid); + }else if (bridge_device->multicast_enabled && + bridge_port->mrouter) { +mlxsw_sp_port_smid_set (mlxsw_sp_port, mid->mid, false); } } }
Signature · 1 line
2.9.5
PATCH 16/16 mlxsw: spectrum_switchdev: Consider mrouter status for mdb changes
In reply to Jiri PirkoFrom: Nogah Frankel <[email protected]>
When a mrouter is registered or leaves a mid, don't update the HW.
--- drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +9 -4
@@ -1491,6 +1491,9 @@ static int mlxsw_sp_port_mdb_add(struct mlxsw_sp_port *mlxsw_sp_port,if (!bridge_device->multicast_enabled)return 0 ; +if (bridge_port->mrouter) +return 0 ; + err =mlxsw_sp_port_smid_set (mlxsw_sp_port, mid->mid, true);if (err) {netdev_err (dev,"Unable to set SMID\n" );
@@ -1613,10 +1616,12 @@ __mlxsw_sp_port_mdb_del(struct mlxsw_sp_port *mlxsw_sp_port,int err;if (bridge_port->bridge_device->multicast_enabled) { - err =mlxsw_sp_port_smid_set (mlxsw_sp_port, mid->mid, false); - -if (err) -netdev_err (dev,"Unable to remove port from SMID\n" ); +if (bridge_port->bridge_device->multicast_enabled) { + err =mlxsw_sp_port_smid_set (mlxsw_sp_port, mid->mid, + false); +if (err) +netdev_err (dev,"Unable to remove port from SMID\n" ); + } } err =mlxsw_sp_port_remove_from_mid (mlxsw_sp_port, mid);
Signature · 1 line
2.9.5
David Miller
maintainerFrom: Jiri Pirko <[email protected]>
Date: Wed, 20 Sep 2017 16:15:00 +0200
Quoted 20 lines
From: Jiri Pirko <[email protected]>
Nogah says:
Currently, there are four erroneous flows in MC flood:
1. When MC is disabled it affects only the flood table for unregistered MC packets, but packets that match an entry in the MDB are unaffected.
2. When MC is disabled, MC packets are being sent to all the ports in the bridge (like BC and link-local MC packets) regardless of the designated flag (BR_MCAST_FLAG).
3. When a port is being deleted from a bridge it might remain in the MDB.
4. When MC is enabled packets are flooded to the mrouter ports only if they don't match any entry in the MDB, when they should always be flooded to them.What these problems have in common is the discrepancy between how the hardware handles MDB and mcast flood, and how the driver does it. Each of these problems needs fixing either in the MDB code, or in mcast flood code, and some in both.
Quoted 9 lines
Patches 1-6 change the way the MDB is handled in the driver to make the following changes easier.
Patches 7-8 fix problem number 1 by removing the MDB from the HW when MC is being disabled and restoring it when it is being enabled. Patches 9-10 fix problem number 2 by offloading the flood table by the appropriate flag.
Patch 11 fixes problem number 3 by adding MDB flush to the port removal. Patches 12-14 fix problem number 4 by adding the mrouter ports to every MDB entry in the HW to mimic the wanted behaviour.
Looks good, series applied, thanks!