Skip to content

Commit 701b186

Browse files
idoschdavem330
authored andcommitted
mlxsw: spectrum: Configure FIDs based on bridge events
Before introducing support for L3 interfaces on top of the VLAN-aware bridge we need to add some missing infrastructure. Such an interface can either be the bridge device itself or a VLAN device on top of it. In the first case the router interface (RIF) is associated with FID 1, which is created whenever the first port netdev joins the bridge. We currently assume the default PVID is 1 and that it's already created, as it seems reasonable. This can be extended in the future. However, in the second case it's entirely possible we've yet to create a matching FID. This can happen if the VLAN device was configured before making any bridge port member in the VLAN. Prevent such ordering problems by using the VLAN device's CHANGEUPPER event to configure the FID. Make the VLAN device hold a reference to the FID and prevent it from being destroyed even if none of the port netdevs is using it. Signed-off-by: Ido Schimmel <[email protected]> Signed-off-by: Jiri Pirko <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 3ba2ebf commit 701b186

File tree

3 files changed

+107
-24
lines changed

3 files changed

+107
-24
lines changed

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

Lines changed: 78 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2887,6 +2887,17 @@ int mlxsw_sp_port_fdb_flush(struct mlxsw_sp_port *mlxsw_sp_port, u16 fid)
28872887
return mlxsw_sp_port_fdb_flush_by_port_fid(mlxsw_sp_port, fid);
28882888
}
28892889

2890+
static void mlxsw_sp_master_bridge_gone_sync(struct mlxsw_sp *mlxsw_sp)
2891+
{
2892+
struct mlxsw_sp_fid *f, *tmp;
2893+
2894+
list_for_each_entry_safe(f, tmp, &mlxsw_sp->fids, list)
2895+
if (--f->ref_count == 0)
2896+
mlxsw_sp_fid_destroy(mlxsw_sp, f);
2897+
else
2898+
WARN_ON_ONCE(1);
2899+
}
2900+
28902901
static bool mlxsw_sp_master_bridge_check(struct mlxsw_sp *mlxsw_sp,
28912902
struct net_device *br_dev)
28922903
{
@@ -2903,8 +2914,15 @@ static void mlxsw_sp_master_bridge_inc(struct mlxsw_sp *mlxsw_sp,
29032914

29042915
static void mlxsw_sp_master_bridge_dec(struct mlxsw_sp *mlxsw_sp)
29052916
{
2906-
if (--mlxsw_sp->master_bridge.ref_count == 0)
2917+
if (--mlxsw_sp->master_bridge.ref_count == 0) {
29072918
mlxsw_sp->master_bridge.dev = NULL;
2919+
/* It's possible upper VLAN devices are still holding
2920+
* references to underlying FIDs. Drop the reference
2921+
* and release the resources if it was the last one.
2922+
* If it wasn't, then something bad happened.
2923+
*/
2924+
mlxsw_sp_master_bridge_gone_sync(mlxsw_sp);
2925+
}
29082926
}
29092927

29102928
static int mlxsw_sp_port_bridge_join(struct mlxsw_sp_port *mlxsw_sp_port,
@@ -3373,18 +3391,68 @@ static int mlxsw_sp_netdevice_lag_event(struct net_device *lag_dev,
33733391
return 0;
33743392
}
33753393

3376-
static struct mlxsw_sp_fid *
3377-
mlxsw_sp_vfid_find(const struct mlxsw_sp *mlxsw_sp,
3378-
const struct net_device *br_dev)
3394+
static int mlxsw_sp_master_bridge_vlan_link(struct mlxsw_sp *mlxsw_sp,
3395+
struct net_device *vlan_dev)
33793396
{
3397+
u16 fid = vlan_dev_vlan_id(vlan_dev);
33803398
struct mlxsw_sp_fid *f;
33813399

3382-
list_for_each_entry(f, &mlxsw_sp->vfids.list, list) {
3383-
if (f->dev == br_dev)
3384-
return f;
3400+
f = mlxsw_sp_fid_find(mlxsw_sp, fid);
3401+
if (!f) {
3402+
f = mlxsw_sp_fid_create(mlxsw_sp, fid);
3403+
if (IS_ERR(f))
3404+
return PTR_ERR(f);
33853405
}
33863406

3387-
return NULL;
3407+
f->ref_count++;
3408+
3409+
return 0;
3410+
}
3411+
3412+
static void mlxsw_sp_master_bridge_vlan_unlink(struct mlxsw_sp *mlxsw_sp,
3413+
struct net_device *vlan_dev)
3414+
{
3415+
u16 fid = vlan_dev_vlan_id(vlan_dev);
3416+
struct mlxsw_sp_fid *f;
3417+
3418+
f = mlxsw_sp_fid_find(mlxsw_sp, fid);
3419+
if (f && --f->ref_count == 0)
3420+
mlxsw_sp_fid_destroy(mlxsw_sp, f);
3421+
}
3422+
3423+
static int mlxsw_sp_netdevice_bridge_event(struct net_device *br_dev,
3424+
unsigned long event, void *ptr)
3425+
{
3426+
struct netdev_notifier_changeupper_info *info;
3427+
struct net_device *upper_dev;
3428+
struct mlxsw_sp *mlxsw_sp;
3429+
int err;
3430+
3431+
mlxsw_sp = mlxsw_sp_lower_get(br_dev);
3432+
if (!mlxsw_sp)
3433+
return 0;
3434+
if (br_dev != mlxsw_sp->master_bridge.dev)
3435+
return 0;
3436+
3437+
info = ptr;
3438+
3439+
switch (event) {
3440+
case NETDEV_CHANGEUPPER:
3441+
upper_dev = info->upper_dev;
3442+
if (!is_vlan_dev(upper_dev))
3443+
break;
3444+
if (info->linking) {
3445+
err = mlxsw_sp_master_bridge_vlan_link(mlxsw_sp,
3446+
upper_dev);
3447+
if (err)
3448+
return err;
3449+
} else {
3450+
mlxsw_sp_master_bridge_vlan_unlink(mlxsw_sp, upper_dev);
3451+
}
3452+
break;
3453+
}
3454+
3455+
return 0;
33883456
}
33893457

33903458
static u16 mlxsw_sp_avail_vfid_get(const struct mlxsw_sp *mlxsw_sp)
@@ -3675,6 +3743,8 @@ static int mlxsw_sp_netdevice_event(struct notifier_block *unused,
36753743
err = mlxsw_sp_netdevice_port_event(dev, event, ptr);
36763744
else if (netif_is_lag_master(dev))
36773745
err = mlxsw_sp_netdevice_lag_event(dev, event, ptr);
3746+
else if (netif_is_bridge_master(dev))
3747+
err = mlxsw_sp_netdevice_bridge_event(dev, event, ptr);
36783748
else if (is_vlan_dev(dev))
36793749
err = mlxsw_sp_netdevice_vlan_event(dev, event, ptr);
36803750

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

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,31 @@ mlxsw_sp_port_vport_find_by_fid(const struct mlxsw_sp_port *mlxsw_sp_port,
387387
return NULL;
388388
}
389389

390+
static inline struct mlxsw_sp_fid *mlxsw_sp_fid_find(struct mlxsw_sp *mlxsw_sp,
391+
u16 fid)
392+
{
393+
struct mlxsw_sp_fid *f;
394+
395+
list_for_each_entry(f, &mlxsw_sp->fids, list)
396+
if (f->fid == fid)
397+
return f;
398+
399+
return NULL;
400+
}
401+
402+
static inline struct mlxsw_sp_fid *
403+
mlxsw_sp_vfid_find(const struct mlxsw_sp *mlxsw_sp,
404+
const struct net_device *br_dev)
405+
{
406+
struct mlxsw_sp_fid *f;
407+
408+
list_for_each_entry(f, &mlxsw_sp->vfids.list, list)
409+
if (f->dev == br_dev)
410+
return f;
411+
412+
return NULL;
413+
}
414+
390415
static inline struct mlxsw_sp_rif *
391416
mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp *mlxsw_sp,
392417
const struct net_device *dev)
@@ -459,6 +484,8 @@ int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid);
459484
int mlxsw_sp_port_fdb_flush(struct mlxsw_sp_port *mlxsw_sp_port, u16 fid);
460485
int mlxsw_sp_rif_fdb_op(struct mlxsw_sp *mlxsw_sp, const char *mac, u16 fid,
461486
bool adding);
487+
struct mlxsw_sp_fid *mlxsw_sp_fid_create(struct mlxsw_sp *mlxsw_sp, u16 fid);
488+
void mlxsw_sp_fid_destroy(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fid *f);
462489
int mlxsw_sp_port_ets_set(struct mlxsw_sp_port *mlxsw_sp_port,
463490
enum mlxsw_reg_qeec_hr hr, u8 index, u8 next_index,
464491
bool dwrr, u8 dwrr_weight);

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

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -374,18 +374,6 @@ static int mlxsw_sp_port_attr_set(struct net_device *dev,
374374
return err;
375375
}
376376

377-
static struct mlxsw_sp_fid *mlxsw_sp_fid_find(struct mlxsw_sp *mlxsw_sp,
378-
u16 fid)
379-
{
380-
struct mlxsw_sp_fid *f;
381-
382-
list_for_each_entry(f, &mlxsw_sp->fids, list)
383-
if (f->fid == fid)
384-
return f;
385-
386-
return NULL;
387-
}
388-
389377
static int mlxsw_sp_fid_op(struct mlxsw_sp *mlxsw_sp, u16 fid, bool create)
390378
{
391379
char sfmr_pl[MLXSW_REG_SFMR_LEN];
@@ -416,8 +404,7 @@ static struct mlxsw_sp_fid *mlxsw_sp_fid_alloc(u16 fid)
416404
return f;
417405
}
418406

419-
static struct mlxsw_sp_fid *mlxsw_sp_fid_create(struct mlxsw_sp *mlxsw_sp,
420-
u16 fid)
407+
struct mlxsw_sp_fid *mlxsw_sp_fid_create(struct mlxsw_sp *mlxsw_sp, u16 fid)
421408
{
422409
struct mlxsw_sp_fid *f;
423410
int err;
@@ -452,8 +439,7 @@ static struct mlxsw_sp_fid *mlxsw_sp_fid_create(struct mlxsw_sp *mlxsw_sp,
452439
return ERR_PTR(err);
453440
}
454441

455-
static void mlxsw_sp_fid_destroy(struct mlxsw_sp *mlxsw_sp,
456-
struct mlxsw_sp_fid *f)
442+
void mlxsw_sp_fid_destroy(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fid *f)
457443
{
458444
u16 fid = f->fid;
459445

0 commit comments

Comments
 (0)