Skip to content

Commit 58be242

Browse files
committed
Merge branch 'mlxsw-offload-mc-flood'
Jiri Pirko says: ==================== mlxsw: Offload MC flood for unregister MC Nogah says: When multicast is enabled, the Linux bridge floods unregistered multicast packets only to ports connected to a multicast router. Devices capable of offloading the Linux bridge need to be made aware of such ports, for proper flooding behavior. On the other hand, when multicast is disabled, such packets should be flooded to all ports. This patchset aims to fix that, by offloading the multicast state and the list of multicast router ports. The first 3 patches adds switchdev attributes to offload this data. The rest of the patchset add implementation for handling this data in the mlxsw driver. The effects this data has on the MDB (namely, when the multicast is disabled the MDB should be considered as invalid, and when it is enabled, a packet that is flooded by it should also be flooded to the multicast routers ports) is subject of future work. Testing of this patchset included: Sending 3 mc packets streams, LL, register and unregistered, and checking that they reached only to the ports that should have received them. The configs were: mc disabled, mc without mc router ports and mc with fixed router port. It was checked for vlan aware bridge, vlan unaware bridge and vlan unaware bridge with another vlan unaware bridge on the same machine ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 94134bf + 90e0f0c commit 58be242

File tree

5 files changed

+198
-54
lines changed

5 files changed

+198
-54
lines changed

drivers/net/ethernet/mellanox/mlxsw/spectrum.c

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3073,10 +3073,17 @@ static int __mlxsw_sp_flood_init(struct mlxsw_core *mlxsw_core,
30733073
else
30743074
table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFEST;
30753075

3076-
if (type == MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST)
3076+
switch (type) {
3077+
case MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST:
30773078
flood_table = MLXSW_SP_FLOOD_TABLE_UC;
3078-
else
3079-
flood_table = MLXSW_SP_FLOOD_TABLE_BM;
3079+
break;
3080+
case MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4:
3081+
case MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6:
3082+
flood_table = MLXSW_SP_FLOOD_TABLE_MC;
3083+
break;
3084+
default:
3085+
flood_table = MLXSW_SP_FLOOD_TABLE_BC;
3086+
}
30803087

30813088
mlxsw_reg_sfgc_pack(sfgc_pl, type, bridge_type, table_type,
30823089
flood_table);
@@ -3270,9 +3277,9 @@ static struct mlxsw_config_profile mlxsw_sp_config_profile = {
32703277
.used_flood_tables = 1,
32713278
.used_flood_mode = 1,
32723279
.flood_mode = 3,
3273-
.max_fid_offset_flood_tables = 2,
3280+
.max_fid_offset_flood_tables = 3,
32743281
.fid_offset_flood_table_size = VLAN_N_VID - 1,
3275-
.max_fid_flood_tables = 2,
3282+
.max_fid_flood_tables = 3,
32763283
.fid_flood_table_size = MLXSW_SP_VFID_MAX,
32773284
.used_max_ib_mc = 1,
32783285
.max_ib_mc = 0,
@@ -3689,7 +3696,7 @@ static int mlxsw_sp_router_port_flood_set(struct mlxsw_sp *mlxsw_sp, u16 fid,
36893696

36903697
table_type = mlxsw_sp_flood_table_type_get(fid);
36913698
index = mlxsw_sp_flood_table_index_get(fid);
3692-
mlxsw_reg_sftr_pack(sftr_pl, MLXSW_SP_FLOOD_TABLE_BM, index, table_type,
3699+
mlxsw_reg_sftr_pack(sftr_pl, MLXSW_SP_FLOOD_TABLE_BC, index, table_type,
36933700
1, MLXSW_PORT_ROUTER_PORT, set);
36943701
err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sftr), sftr_pl);
36953702

@@ -4065,6 +4072,9 @@ static int mlxsw_sp_port_bridge_join(struct mlxsw_sp_port *mlxsw_sp_port,
40654072
mlxsw_sp_port->learning = 1;
40664073
mlxsw_sp_port->learning_sync = 1;
40674074
mlxsw_sp_port->uc_flood = 1;
4075+
mlxsw_sp_port->mc_flood = 1;
4076+
mlxsw_sp_port->mc_router = 0;
4077+
mlxsw_sp_port->mc_disabled = 1;
40684078
mlxsw_sp_port->bridged = 1;
40694079

40704080
return 0;
@@ -4081,6 +4091,8 @@ static void mlxsw_sp_port_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_port)
40814091
mlxsw_sp_port->learning = 0;
40824092
mlxsw_sp_port->learning_sync = 0;
40834093
mlxsw_sp_port->uc_flood = 0;
4094+
mlxsw_sp_port->mc_flood = 0;
4095+
mlxsw_sp_port->mc_router = 0;
40844096
mlxsw_sp_port->bridged = 0;
40854097

40864098
/* 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,
47434755
mlxsw_sp_vport->learning = 1;
47444756
mlxsw_sp_vport->learning_sync = 1;
47454757
mlxsw_sp_vport->uc_flood = 1;
4758+
mlxsw_sp_vport->mc_flood = 1;
4759+
mlxsw_sp_vport->mc_router = 0;
4760+
mlxsw_sp_vport->mc_disabled = 1;
47464761
mlxsw_sp_vport->bridged = 1;
47474762

47484763
return 0;
@@ -4763,6 +4778,8 @@ static void mlxsw_sp_vport_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_vport)
47634778
mlxsw_sp_vport->learning = 0;
47644779
mlxsw_sp_vport->learning_sync = 0;
47654780
mlxsw_sp_vport->uc_flood = 0;
4781+
mlxsw_sp_vport->mc_flood = 0;
4782+
mlxsw_sp_vport->mc_router = 0;
47664783
mlxsw_sp_vport->bridged = 0;
47674784
}
47684785

drivers/net/ethernet/mellanox/mlxsw/spectrum.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
#include "core_acl_flex_actions.h"
5656

5757
#define MLXSW_SP_VFID_BASE VLAN_N_VID
58-
#define MLXSW_SP_VFID_MAX 6656 /* Bridged VLAN interfaces */
58+
#define MLXSW_SP_VFID_MAX 1024 /* Bridged VLAN interfaces */
5959

6060
#define MLXSW_SP_RFID_BASE 15360
6161
#define MLXSW_SP_INVALID_RIF 0xffff
@@ -339,9 +339,12 @@ struct mlxsw_sp_port {
339339
struct mlxsw_sp *mlxsw_sp;
340340
u8 local_port;
341341
u8 stp_state;
342-
u8 learning:1,
342+
u16 learning:1,
343343
learning_sync:1,
344344
uc_flood:1,
345+
mc_flood:1,
346+
mc_router:1,
347+
mc_disabled:1,
345348
bridged:1,
346349
lagged:1,
347350
split:1;
@@ -509,7 +512,8 @@ mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp *mlxsw_sp,
509512

510513
enum mlxsw_sp_flood_table {
511514
MLXSW_SP_FLOOD_TABLE_UC,
512-
MLXSW_SP_FLOOD_TABLE_BM,
515+
MLXSW_SP_FLOOD_TABLE_BC,
516+
MLXSW_SP_FLOOD_TABLE_MC,
513517
};
514518

515519
int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp);

drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c

Lines changed: 124 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,21 @@ mlxsw_sp_port_orig_get(struct net_device *dev,
7171
struct mlxsw_sp_port *mlxsw_sp_port)
7272
{
7373
struct mlxsw_sp_port *mlxsw_sp_vport;
74+
struct mlxsw_sp_fid *fid;
7475
u16 vid;
7576

77+
if (netif_is_bridge_master(dev)) {
78+
fid = mlxsw_sp_vfid_find(mlxsw_sp_port->mlxsw_sp,
79+
dev);
80+
if (fid) {
81+
mlxsw_sp_vport =
82+
mlxsw_sp_port_vport_find_by_fid(mlxsw_sp_port,
83+
fid->fid);
84+
WARN_ON(!mlxsw_sp_vport);
85+
return mlxsw_sp_vport;
86+
}
87+
}
88+
7689
if (!is_vlan_dev(dev))
7790
return mlxsw_sp_port;
7891

@@ -166,9 +179,10 @@ static int mlxsw_sp_port_attr_stp_state_set(struct mlxsw_sp_port *mlxsw_sp_port,
166179
return mlxsw_sp_port_stp_state_set(mlxsw_sp_port, state);
167180
}
168181

169-
static int __mlxsw_sp_port_flood_set(struct mlxsw_sp_port *mlxsw_sp_port,
170-
u16 idx_begin, u16 idx_end, bool uc_set,
171-
bool bm_set)
182+
static int __mlxsw_sp_port_flood_table_set(struct mlxsw_sp_port *mlxsw_sp_port,
183+
u16 idx_begin, u16 idx_end,
184+
enum mlxsw_sp_flood_table table,
185+
bool set)
172186
{
173187
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
174188
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,
186200
if (!sftr_pl)
187201
return -ENOMEM;
188202

189-
mlxsw_reg_sftr_pack(sftr_pl, MLXSW_SP_FLOOD_TABLE_UC, idx_begin,
190-
table_type, range, local_port, uc_set);
203+
mlxsw_reg_sftr_pack(sftr_pl, table, idx_begin,
204+
table_type, range, local_port, set);
191205
err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sftr), sftr_pl);
206+
207+
kfree(sftr_pl);
208+
return err;
209+
}
210+
211+
static int __mlxsw_sp_port_flood_set(struct mlxsw_sp_port *mlxsw_sp_port,
212+
u16 idx_begin, u16 idx_end, bool uc_set,
213+
bool bc_set, bool mc_set)
214+
{
215+
int err;
216+
217+
err = __mlxsw_sp_port_flood_table_set(mlxsw_sp_port, idx_begin, idx_end,
218+
MLXSW_SP_FLOOD_TABLE_UC, uc_set);
192219
if (err)
193-
goto buffer_out;
220+
return err;
194221

195-
mlxsw_reg_sftr_pack(sftr_pl, MLXSW_SP_FLOOD_TABLE_BM, idx_begin,
196-
table_type, range, local_port, bm_set);
197-
err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sftr), sftr_pl);
222+
err = __mlxsw_sp_port_flood_table_set(mlxsw_sp_port, idx_begin, idx_end,
223+
MLXSW_SP_FLOOD_TABLE_BC, bc_set);
198224
if (err)
199225
goto err_flood_bm_set;
200226

201-
goto buffer_out;
227+
err = __mlxsw_sp_port_flood_table_set(mlxsw_sp_port, idx_begin, idx_end,
228+
MLXSW_SP_FLOOD_TABLE_MC, mc_set);
229+
if (err)
230+
goto err_flood_mc_set;
231+
return 0;
202232

233+
err_flood_mc_set:
234+
__mlxsw_sp_port_flood_table_set(mlxsw_sp_port, idx_begin, idx_end,
235+
MLXSW_SP_FLOOD_TABLE_BC, !bc_set);
203236
err_flood_bm_set:
204-
mlxsw_reg_sftr_pack(sftr_pl, MLXSW_SP_FLOOD_TABLE_UC, idx_begin,
205-
table_type, range, local_port, !uc_set);
206-
mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sftr), sftr_pl);
207-
buffer_out:
208-
kfree(sftr_pl);
237+
__mlxsw_sp_port_flood_table_set(mlxsw_sp_port, idx_begin, idx_end,
238+
MLXSW_SP_FLOOD_TABLE_UC, !uc_set);
209239
return err;
210240
}
211241

212-
static int mlxsw_sp_port_uc_flood_set(struct mlxsw_sp_port *mlxsw_sp_port,
213-
bool set)
242+
static int mlxsw_sp_port_flood_table_set(struct mlxsw_sp_port *mlxsw_sp_port,
243+
enum mlxsw_sp_flood_table table,
244+
bool set)
214245
{
215246
struct net_device *dev = mlxsw_sp_port->dev;
216247
u16 vid, last_visited_vid;
@@ -220,13 +251,13 @@ static int mlxsw_sp_port_uc_flood_set(struct mlxsw_sp_port *mlxsw_sp_port,
220251
u16 fid = mlxsw_sp_vport_fid_get(mlxsw_sp_port)->fid;
221252
u16 vfid = mlxsw_sp_fid_to_vfid(fid);
222253

223-
return __mlxsw_sp_port_flood_set(mlxsw_sp_port, vfid, vfid,
224-
set, true);
254+
return __mlxsw_sp_port_flood_table_set(mlxsw_sp_port, vfid,
255+
vfid, table, set);
225256
}
226257

227258
for_each_set_bit(vid, mlxsw_sp_port->active_vlans, VLAN_N_VID) {
228-
err = __mlxsw_sp_port_flood_set(mlxsw_sp_port, vid, vid, set,
229-
true);
259+
err = __mlxsw_sp_port_flood_table_set(mlxsw_sp_port, vid, vid,
260+
table, set);
230261
if (err) {
231262
last_visited_vid = vid;
232263
goto err_port_flood_set;
@@ -237,21 +268,53 @@ static int mlxsw_sp_port_uc_flood_set(struct mlxsw_sp_port *mlxsw_sp_port,
237268

238269
err_port_flood_set:
239270
for_each_set_bit(vid, mlxsw_sp_port->active_vlans, last_visited_vid)
240-
__mlxsw_sp_port_flood_set(mlxsw_sp_port, vid, vid, !set, true);
271+
__mlxsw_sp_port_flood_table_set(mlxsw_sp_port, vid, vid, table,
272+
!set);
241273
netdev_err(dev, "Failed to configure unicast flooding\n");
242274
return err;
243275
}
244276

277+
static int mlxsw_sp_port_mc_disabled_set(struct mlxsw_sp_port *mlxsw_sp_port,
278+
struct switchdev_trans *trans,
279+
bool mc_disabled)
280+
{
281+
int set;
282+
int err = 0;
283+
284+
if (switchdev_trans_ph_prepare(trans))
285+
return 0;
286+
287+
if (mlxsw_sp_port->mc_router != mlxsw_sp_port->mc_flood) {
288+
set = mc_disabled ?
289+
mlxsw_sp_port->mc_flood : mlxsw_sp_port->mc_router;
290+
err = mlxsw_sp_port_flood_table_set(mlxsw_sp_port,
291+
MLXSW_SP_FLOOD_TABLE_MC,
292+
set);
293+
}
294+
295+
if (!err)
296+
mlxsw_sp_port->mc_disabled = mc_disabled;
297+
298+
return err;
299+
}
300+
245301
int mlxsw_sp_vport_flood_set(struct mlxsw_sp_port *mlxsw_sp_vport, u16 fid,
246302
bool set)
247303
{
304+
bool mc_set = set;
248305
u16 vfid;
249306

250307
/* In case of vFIDs, index into the flooding table is relative to
251308
* the start of the vFIDs range.
252309
*/
253310
vfid = mlxsw_sp_fid_to_vfid(fid);
254-
return __mlxsw_sp_port_flood_set(mlxsw_sp_vport, vfid, vfid, set, set);
311+
312+
if (set)
313+
mc_set = mlxsw_sp_vport->mc_disabled ?
314+
mlxsw_sp_vport->mc_flood : mlxsw_sp_vport->mc_router;
315+
316+
return __mlxsw_sp_port_flood_set(mlxsw_sp_vport, vfid, vfid, set, set,
317+
mc_set);
255318
}
256319

257320
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,
297360
return 0;
298361

299362
if ((uc_flood ^ brport_flags) & BR_FLOOD) {
300-
err = mlxsw_sp_port_uc_flood_set(mlxsw_sp_port,
301-
!mlxsw_sp_port->uc_flood);
363+
err = mlxsw_sp_port_flood_table_set(mlxsw_sp_port,
364+
MLXSW_SP_FLOOD_TABLE_UC,
365+
!mlxsw_sp_port->uc_flood);
302366
if (err)
303367
return err;
304368
}
@@ -318,8 +382,9 @@ static int mlxsw_sp_port_attr_br_flags_set(struct mlxsw_sp_port *mlxsw_sp_port,
318382

319383
err_port_learning_set:
320384
if ((uc_flood ^ brport_flags) & BR_FLOOD)
321-
mlxsw_sp_port_uc_flood_set(mlxsw_sp_port,
322-
mlxsw_sp_port->uc_flood);
385+
mlxsw_sp_port_flood_table_set(mlxsw_sp_port,
386+
MLXSW_SP_FLOOD_TABLE_UC,
387+
mlxsw_sp_port->uc_flood);
323388
return err;
324389
}
325390

@@ -371,6 +436,22 @@ static int mlxsw_sp_port_attr_br_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port,
371436
return 0;
372437
}
373438

439+
static int mlxsw_sp_port_attr_mc_router_set(struct mlxsw_sp_port *mlxsw_sp_port,
440+
struct switchdev_trans *trans,
441+
bool is_port_mc_router)
442+
{
443+
if (switchdev_trans_ph_prepare(trans))
444+
return 0;
445+
446+
mlxsw_sp_port->mc_router = is_port_mc_router;
447+
if (!mlxsw_sp_port->mc_disabled)
448+
return mlxsw_sp_port_flood_table_set(mlxsw_sp_port,
449+
MLXSW_SP_FLOOD_TABLE_MC,
450+
is_port_mc_router);
451+
452+
return 0;
453+
}
454+
374455
static int mlxsw_sp_port_attr_set(struct net_device *dev,
375456
const struct switchdev_attr *attr,
376457
struct switchdev_trans *trans)
@@ -400,6 +481,14 @@ static int mlxsw_sp_port_attr_set(struct net_device *dev,
400481
attr->orig_dev,
401482
attr->u.vlan_filtering);
402483
break;
484+
case SWITCHDEV_ATTR_ID_PORT_MROUTER:
485+
err = mlxsw_sp_port_attr_mc_router_set(mlxsw_sp_port, trans,
486+
attr->u.mrouter);
487+
break;
488+
case SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED:
489+
err = mlxsw_sp_port_mc_disabled_set(mlxsw_sp_port, trans,
490+
attr->u.mc_disabled);
491+
break;
403492
default:
404493
err = -EOPNOTSUPP;
405494
break;
@@ -545,6 +634,7 @@ static int mlxsw_sp_port_fid_map(struct mlxsw_sp_port *mlxsw_sp_port, u16 fid,
545634
static int mlxsw_sp_port_fid_join(struct mlxsw_sp_port *mlxsw_sp_port,
546635
u16 fid_begin, u16 fid_end)
547636
{
637+
bool mc_flood;
548638
int fid, err;
549639

550640
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,
553643
goto err_port_fid_join;
554644
}
555645

646+
mc_flood = mlxsw_sp_port->mc_disabled ?
647+
mlxsw_sp_port->mc_flood : mlxsw_sp_port->mc_router;
648+
556649
err = __mlxsw_sp_port_flood_set(mlxsw_sp_port, fid_begin, fid_end,
557-
mlxsw_sp_port->uc_flood, true);
650+
mlxsw_sp_port->uc_flood, true,
651+
mc_flood);
558652
if (err)
559653
goto err_port_flood_set;
560654

@@ -570,7 +664,7 @@ static int mlxsw_sp_port_fid_join(struct mlxsw_sp_port *mlxsw_sp_port,
570664
for (fid--; fid >= fid_begin; fid--)
571665
mlxsw_sp_port_fid_map(mlxsw_sp_port, fid, false);
572666
__mlxsw_sp_port_flood_set(mlxsw_sp_port, fid_begin, fid_end, false,
573-
false);
667+
false, false);
574668
err_port_flood_set:
575669
fid = fid_end;
576670
err_port_fid_join:
@@ -588,7 +682,7 @@ static void mlxsw_sp_port_fid_leave(struct mlxsw_sp_port *mlxsw_sp_port,
588682
mlxsw_sp_port_fid_map(mlxsw_sp_port, fid, false);
589683

590684
__mlxsw_sp_port_flood_set(mlxsw_sp_port, fid_begin, fid_end, false,
591-
false);
685+
false, false);
592686

593687
for (fid = fid_begin; fid <= fid_end; fid++)
594688
__mlxsw_sp_port_fid_leave(mlxsw_sp_port, fid);

0 commit comments

Comments
 (0)