unsigned char addr[ETH_ALEN];
int mtu;
u16 rif;
+ u16 vr_id;
};
static struct mlxsw_sp_rif *
static void mlxsw_sp_vr_put(struct mlxsw_sp_vr *vr)
{
- if (list_empty(&vr->fib4->node_list))
+ if (!vr->rif_count && list_empty(&vr->fib4->node_list))
mlxsw_sp_vr_destroy(vr);
}
}
static int mlxsw_sp_vport_rif_sp_op(struct mlxsw_sp_port *mlxsw_sp_vport,
- struct net_device *l3_dev, u16 rif,
- bool create)
+ u16 vr_id, struct net_device *l3_dev,
+ u16 rif, bool create)
{
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_vport->mlxsw_sp;
bool lagged = mlxsw_sp_vport->lagged;
char ritr_pl[MLXSW_REG_RITR_LEN];
u16 system_port;
- mlxsw_reg_ritr_pack(ritr_pl, create, MLXSW_REG_RITR_SP_IF, rif,
+ mlxsw_reg_ritr_pack(ritr_pl, create, MLXSW_REG_RITR_SP_IF, rif, vr_id,
l3_dev->mtu, l3_dev->dev_addr);
mlxsw_sp_vport_rif_sp_attr_get(mlxsw_sp_vport, &lagged, &system_port);
}
static struct mlxsw_sp_rif *
-mlxsw_sp_rif_alloc(u16 rif, struct net_device *l3_dev, struct mlxsw_sp_fid *f)
+mlxsw_sp_rif_alloc(u16 rif, u16 vr_id, struct net_device *l3_dev,
+ struct mlxsw_sp_fid *f)
{
struct mlxsw_sp_rif *r;
INIT_LIST_HEAD(&r->neigh_list);
ether_addr_copy(r->addr, l3_dev->dev_addr);
r->mtu = l3_dev->mtu;
+ r->vr_id = vr_id;
r->dev = l3_dev;
r->rif = rif;
r->f = f;
struct net_device *l3_dev)
{
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_vport->mlxsw_sp;
+ struct mlxsw_sp_vr *vr;
struct mlxsw_sp_fid *f;
struct mlxsw_sp_rif *r;
u16 fid, rif;
if (rif == MLXSW_SP_INVALID_RIF)
return ERR_PTR(-ERANGE);
- err = mlxsw_sp_vport_rif_sp_op(mlxsw_sp_vport, l3_dev, rif, true);
+ vr = mlxsw_sp_vr_get(mlxsw_sp, RT_TABLE_MAIN);
+ if (IS_ERR(vr))
+ return ERR_CAST(vr);
+
+ err = mlxsw_sp_vport_rif_sp_op(mlxsw_sp_vport, vr->id, l3_dev, rif,
+ true);
if (err)
- return ERR_PTR(err);
+ goto err_vport_rif_sp_op;
fid = mlxsw_sp_rif_sp_to_fid(rif);
err = mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, fid, true);
goto err_rfid_alloc;
}
- r = mlxsw_sp_rif_alloc(rif, l3_dev, f);
+ r = mlxsw_sp_rif_alloc(rif, vr->id, l3_dev, f);
if (!r) {
err = -ENOMEM;
goto err_rif_alloc;
f->r = r;
mlxsw_sp->rifs[rif] = r;
+ vr->rif_count++;
return r;
err_rfid_alloc:
mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, fid, false);
err_rif_fdb_op:
- mlxsw_sp_vport_rif_sp_op(mlxsw_sp_vport, l3_dev, rif, false);
+ mlxsw_sp_vport_rif_sp_op(mlxsw_sp_vport, vr->id, l3_dev, rif, false);
+err_vport_rif_sp_op:
+ mlxsw_sp_vr_put(vr);
return ERR_PTR(err);
}
struct mlxsw_sp_rif *r)
{
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_vport->mlxsw_sp;
+ struct mlxsw_sp_vr *vr = &mlxsw_sp->router.vrs[r->vr_id];
struct net_device *l3_dev = r->dev;
struct mlxsw_sp_fid *f = r->f;
u16 fid = f->fid;
mlxsw_sp_router_rif_gone_sync(mlxsw_sp, r);
+ vr->rif_count--;
mlxsw_sp->rifs[rif] = NULL;
f->r = NULL;
mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, fid, false);
- mlxsw_sp_vport_rif_sp_op(mlxsw_sp_vport, l3_dev, rif, false);
+ mlxsw_sp_vport_rif_sp_op(mlxsw_sp_vport, vr->id, l3_dev, rif, false);
+
+ mlxsw_sp_vr_put(vr);
}
static int mlxsw_sp_vport_rif_sp_join(struct mlxsw_sp_port *mlxsw_sp_vport,
return MLXSW_REG_RITR_VLAN_IF;
}
-static int mlxsw_sp_rif_bridge_op(struct mlxsw_sp *mlxsw_sp,
+static int mlxsw_sp_rif_bridge_op(struct mlxsw_sp *mlxsw_sp, u16 vr_id,
struct net_device *l3_dev,
u16 fid, u16 rif,
bool create)
char ritr_pl[MLXSW_REG_RITR_LEN];
rif_type = mlxsw_sp_rif_type_get(fid);
- mlxsw_reg_ritr_pack(ritr_pl, create, rif_type, rif, l3_dev->mtu,
+ mlxsw_reg_ritr_pack(ritr_pl, create, rif_type, rif, vr_id, l3_dev->mtu,
l3_dev->dev_addr);
mlxsw_reg_ritr_fid_set(ritr_pl, rif_type, fid);
struct net_device *l3_dev,
struct mlxsw_sp_fid *f)
{
+ struct mlxsw_sp_vr *vr;
struct mlxsw_sp_rif *r;
u16 rif;
int err;
if (rif == MLXSW_SP_INVALID_RIF)
return -ERANGE;
+ vr = mlxsw_sp_vr_get(mlxsw_sp, RT_TABLE_MAIN);
+ if (IS_ERR(vr))
+ return PTR_ERR(vr);
+
err = mlxsw_sp_router_port_flood_set(mlxsw_sp, f->fid, true);
if (err)
- return err;
+ goto err_port_flood_set;
- err = mlxsw_sp_rif_bridge_op(mlxsw_sp, l3_dev, f->fid, rif, true);
+ err = mlxsw_sp_rif_bridge_op(mlxsw_sp, vr->id, l3_dev, f->fid, rif,
+ true);
if (err)
goto err_rif_bridge_op;
if (err)
goto err_rif_fdb_op;
- r = mlxsw_sp_rif_alloc(rif, l3_dev, f);
+ r = mlxsw_sp_rif_alloc(rif, vr->id, l3_dev, f);
if (!r) {
err = -ENOMEM;
goto err_rif_alloc;
f->r = r;
mlxsw_sp->rifs[rif] = r;
+ vr->rif_count++;
netdev_dbg(l3_dev, "RIF=%d created\n", rif);
err_rif_alloc:
mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, f->fid, false);
err_rif_fdb_op:
- mlxsw_sp_rif_bridge_op(mlxsw_sp, l3_dev, f->fid, rif, false);
+ mlxsw_sp_rif_bridge_op(mlxsw_sp, vr->id, l3_dev, f->fid, rif, false);
err_rif_bridge_op:
mlxsw_sp_router_port_flood_set(mlxsw_sp, f->fid, false);
+err_port_flood_set:
+ mlxsw_sp_vr_put(vr);
return err;
}
void mlxsw_sp_rif_bridge_destroy(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_rif *r)
{
+ struct mlxsw_sp_vr *vr = &mlxsw_sp->router.vrs[r->vr_id];
struct net_device *l3_dev = r->dev;
struct mlxsw_sp_fid *f = r->f;
u16 rif = r->rif;
mlxsw_sp_router_rif_gone_sync(mlxsw_sp, r);
+ vr->rif_count--;
mlxsw_sp->rifs[rif] = NULL;
f->r = NULL;
mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, f->fid, false);
- mlxsw_sp_rif_bridge_op(mlxsw_sp, l3_dev, f->fid, rif, false);
+ mlxsw_sp_rif_bridge_op(mlxsw_sp, vr->id, l3_dev, f->fid, rif, false);
mlxsw_sp_router_port_flood_set(mlxsw_sp, f->fid, false);
+ mlxsw_sp_vr_put(vr);
+
netdev_dbg(l3_dev, "RIF=%d destroyed\n", rif);
}