Skip to content

Commit 99f44bb

Browse files
idoschdavem330
authored andcommitted
mlxsw: spectrum: Enable L3 interfaces on top of bridge devices
As with the previously introduced L3 interfaces, listen to 'inetaddr' notifications sent for bridges devices configured on top of the port netdevs and create / destroy router interfaces (RIFs) accordingly. This also includes VLAN devices configured on top of the VLAN-aware bridge. The RIFs will be destroyed either when the last IP address is removed or when the underlying FID is is destroyed. Signed-off-by: Ido Schimmel <[email protected]> Signed-off-by: Jiri Pirko <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 701b186 commit 99f44bb

File tree

3 files changed

+143
-1
lines changed

3 files changed

+143
-1
lines changed

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

Lines changed: 138 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2706,10 +2706,135 @@ static int mlxsw_sp_inetaddr_lag_event(struct net_device *lag_dev,
27062706
return __mlxsw_sp_inetaddr_lag_event(lag_dev, lag_dev, event, 1);
27072707
}
27082708

2709+
static struct mlxsw_sp_fid *mlxsw_sp_bridge_fid_get(struct mlxsw_sp *mlxsw_sp,
2710+
struct net_device *l3_dev)
2711+
{
2712+
u16 fid;
2713+
2714+
if (is_vlan_dev(l3_dev))
2715+
fid = vlan_dev_vlan_id(l3_dev);
2716+
else if (mlxsw_sp->master_bridge.dev == l3_dev)
2717+
fid = 1;
2718+
else
2719+
return mlxsw_sp_vfid_find(mlxsw_sp, l3_dev);
2720+
2721+
return mlxsw_sp_fid_find(mlxsw_sp, fid);
2722+
}
2723+
2724+
static enum mlxsw_reg_ritr_if_type mlxsw_sp_rif_type_get(u16 fid)
2725+
{
2726+
if (mlxsw_sp_fid_is_vfid(fid))
2727+
return MLXSW_REG_RITR_FID_IF;
2728+
else
2729+
return MLXSW_REG_RITR_VLAN_IF;
2730+
}
2731+
2732+
static int mlxsw_sp_rif_bridge_op(struct mlxsw_sp *mlxsw_sp,
2733+
struct net_device *l3_dev,
2734+
u16 fid, u16 rif,
2735+
bool create)
2736+
{
2737+
enum mlxsw_reg_ritr_if_type rif_type;
2738+
char ritr_pl[MLXSW_REG_RITR_LEN];
2739+
2740+
rif_type = mlxsw_sp_rif_type_get(fid);
2741+
mlxsw_reg_ritr_pack(ritr_pl, create, rif_type, rif, l3_dev->mtu,
2742+
l3_dev->dev_addr);
2743+
mlxsw_reg_ritr_fid_set(ritr_pl, rif_type, fid);
2744+
2745+
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
2746+
}
2747+
2748+
static int mlxsw_sp_rif_bridge_create(struct mlxsw_sp *mlxsw_sp,
2749+
struct net_device *l3_dev,
2750+
struct mlxsw_sp_fid *f)
2751+
{
2752+
struct mlxsw_sp_rif *r;
2753+
u16 rif;
2754+
int err;
2755+
2756+
rif = mlxsw_sp_avail_rif_get(mlxsw_sp);
2757+
if (rif == MLXSW_SP_RIF_MAX)
2758+
return -ERANGE;
2759+
2760+
err = mlxsw_sp_rif_bridge_op(mlxsw_sp, l3_dev, f->fid, rif, true);
2761+
if (err)
2762+
return err;
2763+
2764+
err = mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, f->fid, true);
2765+
if (err)
2766+
goto err_rif_fdb_op;
2767+
2768+
r = mlxsw_sp_rif_alloc(rif, l3_dev, f);
2769+
if (!r) {
2770+
err = -ENOMEM;
2771+
goto err_rif_alloc;
2772+
}
2773+
2774+
f->r = r;
2775+
mlxsw_sp->rifs[rif] = r;
2776+
2777+
netdev_dbg(l3_dev, "RIF=%d created\n", rif);
2778+
2779+
return 0;
2780+
2781+
err_rif_alloc:
2782+
mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, f->fid, false);
2783+
err_rif_fdb_op:
2784+
mlxsw_sp_rif_bridge_op(mlxsw_sp, l3_dev, f->fid, rif, false);
2785+
return err;
2786+
}
2787+
2788+
void mlxsw_sp_rif_bridge_destroy(struct mlxsw_sp *mlxsw_sp,
2789+
struct mlxsw_sp_rif *r)
2790+
{
2791+
struct net_device *l3_dev = r->dev;
2792+
struct mlxsw_sp_fid *f = r->f;
2793+
u16 rif = r->rif;
2794+
2795+
mlxsw_sp->rifs[rif] = NULL;
2796+
f->r = NULL;
2797+
2798+
kfree(r);
2799+
2800+
mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, f->fid, false);
2801+
2802+
mlxsw_sp_rif_bridge_op(mlxsw_sp, l3_dev, f->fid, rif, false);
2803+
2804+
netdev_dbg(l3_dev, "RIF=%d destroyed\n", rif);
2805+
}
2806+
2807+
static int mlxsw_sp_inetaddr_bridge_event(struct net_device *l3_dev,
2808+
struct net_device *br_dev,
2809+
unsigned long event)
2810+
{
2811+
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(l3_dev);
2812+
struct mlxsw_sp_fid *f;
2813+
2814+
/* FID can either be an actual FID if the L3 device is the
2815+
* VLAN-aware bridge or a VLAN device on top. Otherwise, the
2816+
* L3 device is a VLAN-unaware bridge and we get a vFID.
2817+
*/
2818+
f = mlxsw_sp_bridge_fid_get(mlxsw_sp, l3_dev);
2819+
if (WARN_ON(!f))
2820+
return -EINVAL;
2821+
2822+
switch (event) {
2823+
case NETDEV_UP:
2824+
return mlxsw_sp_rif_bridge_create(mlxsw_sp, l3_dev, f);
2825+
case NETDEV_DOWN:
2826+
mlxsw_sp_rif_bridge_destroy(mlxsw_sp, f->r);
2827+
break;
2828+
}
2829+
2830+
return 0;
2831+
}
2832+
27092833
static int mlxsw_sp_inetaddr_vlan_event(struct net_device *vlan_dev,
27102834
unsigned long event)
27112835
{
27122836
struct net_device *real_dev = vlan_dev_real_dev(vlan_dev);
2837+
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(vlan_dev);
27132838
u16 vid = vlan_dev_vlan_id(vlan_dev);
27142839

27152840
if (mlxsw_sp_port_dev_check(real_dev))
@@ -2718,6 +2843,10 @@ static int mlxsw_sp_inetaddr_vlan_event(struct net_device *vlan_dev,
27182843
else if (netif_is_lag_master(real_dev))
27192844
return __mlxsw_sp_inetaddr_lag_event(vlan_dev, real_dev, event,
27202845
vid);
2846+
else if (netif_is_bridge_master(real_dev) &&
2847+
mlxsw_sp->master_bridge.dev == real_dev)
2848+
return mlxsw_sp_inetaddr_bridge_event(vlan_dev, real_dev,
2849+
event);
27212850

27222851
return 0;
27232852
}
@@ -2743,6 +2872,8 @@ static int mlxsw_sp_inetaddr_event(struct notifier_block *unused,
27432872
err = mlxsw_sp_inetaddr_port_event(dev, event);
27442873
else if (netif_is_lag_master(dev))
27452874
err = mlxsw_sp_inetaddr_lag_event(dev, event);
2875+
else if (netif_is_bridge_master(dev))
2876+
err = mlxsw_sp_inetaddr_bridge_event(dev, dev, event);
27462877
else if (is_vlan_dev(dev))
27472878
err = mlxsw_sp_inetaddr_vlan_event(dev, event);
27482879

@@ -3416,6 +3547,8 @@ static void mlxsw_sp_master_bridge_vlan_unlink(struct mlxsw_sp *mlxsw_sp,
34163547
struct mlxsw_sp_fid *f;
34173548

34183549
f = mlxsw_sp_fid_find(mlxsw_sp, fid);
3550+
if (f && f->r)
3551+
mlxsw_sp_rif_bridge_destroy(mlxsw_sp, f->r);
34193552
if (f && --f->ref_count == 0)
34203553
mlxsw_sp_fid_destroy(mlxsw_sp, f);
34213554
}
@@ -3514,13 +3647,17 @@ static void mlxsw_sp_vfid_destroy(struct mlxsw_sp *mlxsw_sp,
35143647
struct mlxsw_sp_fid *f)
35153648
{
35163649
u16 vfid = mlxsw_sp_fid_to_vfid(f->fid);
3650+
u16 fid = f->fid;
35173651

35183652
clear_bit(vfid, mlxsw_sp->vfids.mapped);
35193653
list_del(&f->list);
35203654

3521-
mlxsw_sp_vfid_op(mlxsw_sp, f->fid, false);
3655+
if (f->r)
3656+
mlxsw_sp_rif_bridge_destroy(mlxsw_sp, f->r);
35223657

35233658
kfree(f);
3659+
3660+
mlxsw_sp_vfid_op(mlxsw_sp, fid, false);
35243661
}
35253662

35263663
static int mlxsw_sp_vport_fid_map(struct mlxsw_sp_port *mlxsw_sp_vport, u16 fid,

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,8 @@ int mlxsw_sp_rif_fdb_op(struct mlxsw_sp *mlxsw_sp, const char *mac, u16 fid,
486486
bool adding);
487487
struct mlxsw_sp_fid *mlxsw_sp_fid_create(struct mlxsw_sp *mlxsw_sp, u16 fid);
488488
void mlxsw_sp_fid_destroy(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fid *f);
489+
void mlxsw_sp_rif_bridge_destroy(struct mlxsw_sp *mlxsw_sp,
490+
struct mlxsw_sp_rif *r);
489491
int mlxsw_sp_port_ets_set(struct mlxsw_sp_port *mlxsw_sp_port,
490492
enum mlxsw_reg_qeec_hr hr, u8 index, u8 next_index,
491493
bool dwrr, u8 dwrr_weight);

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,9 @@ void mlxsw_sp_fid_destroy(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fid *f)
445445

446446
list_del(&f->list);
447447

448+
if (f->r)
449+
mlxsw_sp_rif_bridge_destroy(mlxsw_sp, f->r);
450+
448451
kfree(f);
449452

450453
mlxsw_sp_fid_op(mlxsw_sp, fid, false);

0 commit comments

Comments
 (0)