Commit 76610ebb authored by Ido Schimmel's avatar Ido Schimmel Committed by David S. Miller

mlxsw: spectrum_router: Refactor virtual router handling

A virtual router (VR) is an entity within the device to which routing
tables and interfaces can be bound to. It can be used to implement VRFs.

In the initial implementation we associated the VR with a specific
protocol (e.g., IPv4) and an LPM tree. However, this isn't really
accurate, as the same VR can be used for both IPv4 and IPv6 traffic, by
binding a different LPM tree to a {VR, Proto} pair.

This patch aims to restructure the VR code according to the above logic,
so that VRs are more accurately represented by the driver's data
structures. The main motivation behind this change is to prepare the
driver for VRF offload.
Signed-off-by: default avatarIdo Schimmel <idosch@mellanox.com>
Signed-off-by: default avatarJiri Pirko <jiri@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 382dbb40
...@@ -186,11 +186,8 @@ struct mlxsw_sp_fib; ...@@ -186,11 +186,8 @@ struct mlxsw_sp_fib;
struct mlxsw_sp_vr { struct mlxsw_sp_vr {
u16 id; /* virtual router ID */ u16 id; /* virtual router ID */
bool used;
enum mlxsw_sp_l3proto proto;
u32 tb_id; /* kernel fib table id */ u32 tb_id; /* kernel fib table id */
struct mlxsw_sp_lpm_tree *lpm_tree; struct mlxsw_sp_fib *fib4;
struct mlxsw_sp_fib *fib;
}; };
enum mlxsw_sp_span_type { enum mlxsw_sp_span_type {
......
...@@ -102,12 +102,6 @@ mlxsw_sp_prefix_usage_cpy(struct mlxsw_sp_prefix_usage *prefix_usage1, ...@@ -102,12 +102,6 @@ mlxsw_sp_prefix_usage_cpy(struct mlxsw_sp_prefix_usage *prefix_usage1,
memcpy(prefix_usage1, prefix_usage2, sizeof(*prefix_usage1)); memcpy(prefix_usage1, prefix_usage2, sizeof(*prefix_usage1));
} }
static void
mlxsw_sp_prefix_usage_zero(struct mlxsw_sp_prefix_usage *prefix_usage)
{
memset(prefix_usage, 0, sizeof(*prefix_usage));
}
static void static void
mlxsw_sp_prefix_usage_set(struct mlxsw_sp_prefix_usage *prefix_usage, mlxsw_sp_prefix_usage_set(struct mlxsw_sp_prefix_usage *prefix_usage,
unsigned char prefix_len) unsigned char prefix_len)
...@@ -139,7 +133,7 @@ struct mlxsw_sp_fib_node { ...@@ -139,7 +133,7 @@ struct mlxsw_sp_fib_node {
struct list_head entry_list; struct list_head entry_list;
struct list_head list; struct list_head list;
struct rhash_head ht_node; struct rhash_head ht_node;
struct mlxsw_sp_vr *vr; struct mlxsw_sp_fib *fib;
struct mlxsw_sp_fib_key key; struct mlxsw_sp_fib_key key;
}; };
...@@ -163,13 +157,17 @@ struct mlxsw_sp_fib_entry { ...@@ -163,13 +157,17 @@ struct mlxsw_sp_fib_entry {
struct mlxsw_sp_fib { struct mlxsw_sp_fib {
struct rhashtable ht; struct rhashtable ht;
struct list_head node_list; struct list_head node_list;
struct mlxsw_sp_vr *vr;
struct mlxsw_sp_lpm_tree *lpm_tree;
unsigned long prefix_ref_count[MLXSW_SP_PREFIX_COUNT]; unsigned long prefix_ref_count[MLXSW_SP_PREFIX_COUNT];
struct mlxsw_sp_prefix_usage prefix_usage; struct mlxsw_sp_prefix_usage prefix_usage;
enum mlxsw_sp_l3proto proto;
}; };
static const struct rhashtable_params mlxsw_sp_fib_ht_params; static const struct rhashtable_params mlxsw_sp_fib_ht_params;
static struct mlxsw_sp_fib *mlxsw_sp_fib_create(void) static struct mlxsw_sp_fib *mlxsw_sp_fib_create(struct mlxsw_sp_vr *vr,
enum mlxsw_sp_l3proto proto)
{ {
struct mlxsw_sp_fib *fib; struct mlxsw_sp_fib *fib;
int err; int err;
...@@ -181,6 +179,8 @@ static struct mlxsw_sp_fib *mlxsw_sp_fib_create(void) ...@@ -181,6 +179,8 @@ static struct mlxsw_sp_fib *mlxsw_sp_fib_create(void)
if (err) if (err)
goto err_rhashtable_init; goto err_rhashtable_init;
INIT_LIST_HEAD(&fib->node_list); INIT_LIST_HEAD(&fib->node_list);
fib->proto = proto;
fib->vr = vr;
return fib; return fib;
err_rhashtable_init: err_rhashtable_init:
...@@ -191,6 +191,7 @@ static struct mlxsw_sp_fib *mlxsw_sp_fib_create(void) ...@@ -191,6 +191,7 @@ static struct mlxsw_sp_fib *mlxsw_sp_fib_create(void)
static void mlxsw_sp_fib_destroy(struct mlxsw_sp_fib *fib) static void mlxsw_sp_fib_destroy(struct mlxsw_sp_fib *fib)
{ {
WARN_ON(!list_empty(&fib->node_list)); WARN_ON(!list_empty(&fib->node_list));
WARN_ON(fib->lpm_tree);
rhashtable_destroy(&fib->ht); rhashtable_destroy(&fib->ht);
kfree(fib); kfree(fib);
} }
...@@ -335,6 +336,11 @@ static void mlxsw_sp_lpm_init(struct mlxsw_sp *mlxsw_sp) ...@@ -335,6 +336,11 @@ static void mlxsw_sp_lpm_init(struct mlxsw_sp *mlxsw_sp)
} }
} }
static bool mlxsw_sp_vr_is_used(const struct mlxsw_sp_vr *vr)
{
return !!vr->fib4;
}
static struct mlxsw_sp_vr *mlxsw_sp_vr_find_unused(struct mlxsw_sp *mlxsw_sp) static struct mlxsw_sp_vr *mlxsw_sp_vr_find_unused(struct mlxsw_sp *mlxsw_sp)
{ {
struct mlxsw_sp_vr *vr; struct mlxsw_sp_vr *vr;
...@@ -342,31 +348,31 @@ static struct mlxsw_sp_vr *mlxsw_sp_vr_find_unused(struct mlxsw_sp *mlxsw_sp) ...@@ -342,31 +348,31 @@ static struct mlxsw_sp_vr *mlxsw_sp_vr_find_unused(struct mlxsw_sp *mlxsw_sp)
for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) { for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) {
vr = &mlxsw_sp->router.vrs[i]; vr = &mlxsw_sp->router.vrs[i];
if (!vr->used) if (!mlxsw_sp_vr_is_used(vr))
return vr; return vr;
} }
return NULL; return NULL;
} }
static int mlxsw_sp_vr_lpm_tree_bind(struct mlxsw_sp *mlxsw_sp, static int mlxsw_sp_vr_lpm_tree_bind(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_vr *vr) const struct mlxsw_sp_fib *fib)
{ {
char raltb_pl[MLXSW_REG_RALTB_LEN]; char raltb_pl[MLXSW_REG_RALTB_LEN];
mlxsw_reg_raltb_pack(raltb_pl, vr->id, mlxsw_reg_raltb_pack(raltb_pl, fib->vr->id,
(enum mlxsw_reg_ralxx_protocol) vr->proto, (enum mlxsw_reg_ralxx_protocol) fib->proto,
vr->lpm_tree->id); fib->lpm_tree->id);
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(raltb), raltb_pl); return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(raltb), raltb_pl);
} }
static int mlxsw_sp_vr_lpm_tree_unbind(struct mlxsw_sp *mlxsw_sp, static int mlxsw_sp_vr_lpm_tree_unbind(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_vr *vr) const struct mlxsw_sp_fib *fib)
{ {
char raltb_pl[MLXSW_REG_RALTB_LEN]; char raltb_pl[MLXSW_REG_RALTB_LEN];
/* Bind to tree 0 which is default */ /* Bind to tree 0 which is default */
mlxsw_reg_raltb_pack(raltb_pl, vr->id, mlxsw_reg_raltb_pack(raltb_pl, fib->vr->id,
(enum mlxsw_reg_ralxx_protocol) vr->proto, 0); (enum mlxsw_reg_ralxx_protocol) fib->proto, 0);
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(raltb), raltb_pl); return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(raltb), raltb_pl);
} }
...@@ -379,8 +385,7 @@ static u32 mlxsw_sp_fix_tb_id(u32 tb_id) ...@@ -379,8 +385,7 @@ static u32 mlxsw_sp_fix_tb_id(u32 tb_id)
} }
static struct mlxsw_sp_vr *mlxsw_sp_vr_find(struct mlxsw_sp *mlxsw_sp, static struct mlxsw_sp_vr *mlxsw_sp_vr_find(struct mlxsw_sp *mlxsw_sp,
u32 tb_id, u32 tb_id)
enum mlxsw_sp_l3proto proto)
{ {
struct mlxsw_sp_vr *vr; struct mlxsw_sp_vr *vr;
int i; int i;
...@@ -389,69 +394,50 @@ static struct mlxsw_sp_vr *mlxsw_sp_vr_find(struct mlxsw_sp *mlxsw_sp, ...@@ -389,69 +394,50 @@ static struct mlxsw_sp_vr *mlxsw_sp_vr_find(struct mlxsw_sp *mlxsw_sp,
for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) { for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) {
vr = &mlxsw_sp->router.vrs[i]; vr = &mlxsw_sp->router.vrs[i];
if (vr->used && vr->proto == proto && vr->tb_id == tb_id) if (mlxsw_sp_vr_is_used(vr) && vr->tb_id == tb_id)
return vr; return vr;
} }
return NULL; return NULL;
} }
static struct mlxsw_sp_fib *mlxsw_sp_vr_fib(const struct mlxsw_sp_vr *vr,
enum mlxsw_sp_l3proto proto)
{
switch (proto) {
case MLXSW_SP_L3_PROTO_IPV4:
return vr->fib4;
case MLXSW_SP_L3_PROTO_IPV6:
BUG_ON(1);
}
return NULL;
}
static struct mlxsw_sp_vr *mlxsw_sp_vr_create(struct mlxsw_sp *mlxsw_sp, static struct mlxsw_sp_vr *mlxsw_sp_vr_create(struct mlxsw_sp *mlxsw_sp,
unsigned char prefix_len, u32 tb_id)
u32 tb_id,
enum mlxsw_sp_l3proto proto)
{ {
struct mlxsw_sp_prefix_usage req_prefix_usage;
struct mlxsw_sp_lpm_tree *lpm_tree;
struct mlxsw_sp_vr *vr; struct mlxsw_sp_vr *vr;
int err;
vr = mlxsw_sp_vr_find_unused(mlxsw_sp); vr = mlxsw_sp_vr_find_unused(mlxsw_sp);
if (!vr) if (!vr)
return ERR_PTR(-EBUSY); return ERR_PTR(-EBUSY);
vr->fib = mlxsw_sp_fib_create(); vr->fib4 = mlxsw_sp_fib_create(vr, MLXSW_SP_L3_PROTO_IPV4);
if (IS_ERR(vr->fib)) if (IS_ERR(vr->fib4))
return ERR_CAST(vr->fib); return ERR_CAST(vr->fib4);
vr->proto = proto;
vr->tb_id = tb_id; vr->tb_id = tb_id;
mlxsw_sp_prefix_usage_zero(&req_prefix_usage);
mlxsw_sp_prefix_usage_set(&req_prefix_usage, prefix_len);
lpm_tree = mlxsw_sp_lpm_tree_get(mlxsw_sp, &req_prefix_usage,
proto);
if (IS_ERR(lpm_tree)) {
err = PTR_ERR(lpm_tree);
goto err_tree_get;
}
vr->lpm_tree = lpm_tree;
err = mlxsw_sp_vr_lpm_tree_bind(mlxsw_sp, vr);
if (err)
goto err_tree_bind;
vr->used = true;
return vr; return vr;
err_tree_bind:
mlxsw_sp_lpm_tree_put(mlxsw_sp, vr->lpm_tree);
err_tree_get:
mlxsw_sp_fib_destroy(vr->fib);
return ERR_PTR(err);
} }
static void mlxsw_sp_vr_destroy(struct mlxsw_sp *mlxsw_sp, static void mlxsw_sp_vr_destroy(struct mlxsw_sp_vr *vr)
struct mlxsw_sp_vr *vr)
{ {
mlxsw_sp_vr_lpm_tree_unbind(mlxsw_sp, vr); mlxsw_sp_fib_destroy(vr->fib4);
mlxsw_sp_lpm_tree_put(mlxsw_sp, vr->lpm_tree); vr->fib4 = NULL;
mlxsw_sp_fib_destroy(vr->fib);
vr->used = false;
} }
static int static int
mlxsw_sp_vr_lpm_tree_check(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_vr *vr, mlxsw_sp_vr_lpm_tree_check(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fib *fib,
struct mlxsw_sp_prefix_usage *req_prefix_usage) struct mlxsw_sp_prefix_usage *req_prefix_usage)
{ {
struct mlxsw_sp_lpm_tree *lpm_tree = vr->lpm_tree; struct mlxsw_sp_lpm_tree *lpm_tree = fib->lpm_tree;
struct mlxsw_sp_lpm_tree *new_tree; struct mlxsw_sp_lpm_tree *new_tree;
int err; int err;
...@@ -459,7 +445,7 @@ mlxsw_sp_vr_lpm_tree_check(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_vr *vr, ...@@ -459,7 +445,7 @@ mlxsw_sp_vr_lpm_tree_check(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_vr *vr,
return 0; return 0;
new_tree = mlxsw_sp_lpm_tree_get(mlxsw_sp, req_prefix_usage, new_tree = mlxsw_sp_lpm_tree_get(mlxsw_sp, req_prefix_usage,
vr->proto); fib->proto);
if (IS_ERR(new_tree)) { if (IS_ERR(new_tree)) {
/* We failed to get a tree according to the required /* We failed to get a tree according to the required
* prefix usage. However, the current tree might be still good * prefix usage. However, the current tree might be still good
...@@ -473,8 +459,8 @@ mlxsw_sp_vr_lpm_tree_check(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_vr *vr, ...@@ -473,8 +459,8 @@ mlxsw_sp_vr_lpm_tree_check(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_vr *vr,
} }
/* Prevent packet loss by overwriting existing binding */ /* Prevent packet loss by overwriting existing binding */
vr->lpm_tree = new_tree; fib->lpm_tree = new_tree;
err = mlxsw_sp_vr_lpm_tree_bind(mlxsw_sp, vr); err = mlxsw_sp_vr_lpm_tree_bind(mlxsw_sp, fib);
if (err) if (err)
goto err_tree_bind; goto err_tree_bind;
mlxsw_sp_lpm_tree_put(mlxsw_sp, lpm_tree); mlxsw_sp_lpm_tree_put(mlxsw_sp, lpm_tree);
...@@ -482,53 +468,26 @@ mlxsw_sp_vr_lpm_tree_check(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_vr *vr, ...@@ -482,53 +468,26 @@ mlxsw_sp_vr_lpm_tree_check(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_vr *vr,
return 0; return 0;
err_tree_bind: err_tree_bind:
vr->lpm_tree = lpm_tree; fib->lpm_tree = lpm_tree;
mlxsw_sp_lpm_tree_put(mlxsw_sp, new_tree); mlxsw_sp_lpm_tree_put(mlxsw_sp, new_tree);
return err; return err;
} }
static struct mlxsw_sp_vr *mlxsw_sp_vr_get(struct mlxsw_sp *mlxsw_sp, static struct mlxsw_sp_vr *mlxsw_sp_vr_get(struct mlxsw_sp *mlxsw_sp, u32 tb_id)
unsigned char prefix_len,
u32 tb_id,
enum mlxsw_sp_l3proto proto)
{ {
struct mlxsw_sp_vr *vr; struct mlxsw_sp_vr *vr;
int err;
tb_id = mlxsw_sp_fix_tb_id(tb_id); tb_id = mlxsw_sp_fix_tb_id(tb_id);
vr = mlxsw_sp_vr_find(mlxsw_sp, tb_id, proto); vr = mlxsw_sp_vr_find(mlxsw_sp, tb_id);
if (!vr) { if (!vr)
vr = mlxsw_sp_vr_create(mlxsw_sp, prefix_len, tb_id, proto); vr = mlxsw_sp_vr_create(mlxsw_sp, tb_id);
if (IS_ERR(vr))
return vr;
} else {
struct mlxsw_sp_prefix_usage req_prefix_usage;
mlxsw_sp_prefix_usage_cpy(&req_prefix_usage,
&vr->fib->prefix_usage);
mlxsw_sp_prefix_usage_set(&req_prefix_usage, prefix_len);
/* Need to replace LPM tree in case new prefix is required. */
err = mlxsw_sp_vr_lpm_tree_check(mlxsw_sp, vr,
&req_prefix_usage);
if (err)
return ERR_PTR(err);
}
return vr; return vr;
} }
static void mlxsw_sp_vr_put(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_vr *vr) static void mlxsw_sp_vr_put(struct mlxsw_sp_vr *vr)
{ {
/* Destroy virtual router entity in case the associated FIB is empty if (list_empty(&vr->fib4->node_list))
* and allow it to be used for other tables in future. Otherwise, mlxsw_sp_vr_destroy(vr);
* check if some prefix usage did not disappear and change tree if
* that is the case. Note that in case new, smaller tree cannot be
* allocated, the original one will be kept being used.
*/
if (mlxsw_sp_prefix_usage_none(&vr->fib->prefix_usage))
mlxsw_sp_vr_destroy(mlxsw_sp, vr);
else
mlxsw_sp_vr_lpm_tree_check(mlxsw_sp, vr,
&vr->fib->prefix_usage);
} }
static int mlxsw_sp_vrs_init(struct mlxsw_sp *mlxsw_sp) static int mlxsw_sp_vrs_init(struct mlxsw_sp *mlxsw_sp)
...@@ -1181,7 +1140,7 @@ mlxsw_sp_nexthop_lookup(struct mlxsw_sp *mlxsw_sp, ...@@ -1181,7 +1140,7 @@ mlxsw_sp_nexthop_lookup(struct mlxsw_sp *mlxsw_sp,
} }
static int mlxsw_sp_adj_index_mass_update_vr(struct mlxsw_sp *mlxsw_sp, static int mlxsw_sp_adj_index_mass_update_vr(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_vr *vr, const struct mlxsw_sp_fib *fib,
u32 adj_index, u16 ecmp_size, u32 adj_index, u16 ecmp_size,
u32 new_adj_index, u32 new_adj_index,
u16 new_ecmp_size) u16 new_ecmp_size)
...@@ -1189,8 +1148,8 @@ static int mlxsw_sp_adj_index_mass_update_vr(struct mlxsw_sp *mlxsw_sp, ...@@ -1189,8 +1148,8 @@ static int mlxsw_sp_adj_index_mass_update_vr(struct mlxsw_sp *mlxsw_sp,
char raleu_pl[MLXSW_REG_RALEU_LEN]; char raleu_pl[MLXSW_REG_RALEU_LEN];
mlxsw_reg_raleu_pack(raleu_pl, mlxsw_reg_raleu_pack(raleu_pl,
(enum mlxsw_reg_ralxx_protocol) vr->proto, vr->id, (enum mlxsw_reg_ralxx_protocol) fib->proto,
adj_index, ecmp_size, new_adj_index, fib->vr->id, adj_index, ecmp_size, new_adj_index,
new_ecmp_size); new_ecmp_size);
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(raleu), raleu_pl); return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(raleu), raleu_pl);
} }
...@@ -1200,14 +1159,14 @@ static int mlxsw_sp_adj_index_mass_update(struct mlxsw_sp *mlxsw_sp, ...@@ -1200,14 +1159,14 @@ static int mlxsw_sp_adj_index_mass_update(struct mlxsw_sp *mlxsw_sp,
u32 old_adj_index, u16 old_ecmp_size) u32 old_adj_index, u16 old_ecmp_size)
{ {
struct mlxsw_sp_fib_entry *fib_entry; struct mlxsw_sp_fib_entry *fib_entry;
struct mlxsw_sp_vr *vr = NULL; struct mlxsw_sp_fib *fib = NULL;
int err; int err;
list_for_each_entry(fib_entry, &nh_grp->fib_list, nexthop_group_node) { list_for_each_entry(fib_entry, &nh_grp->fib_list, nexthop_group_node) {
if (vr == fib_entry->fib_node->vr) if (fib == fib_entry->fib_node->fib)
continue; continue;
vr = fib_entry->fib_node->vr; fib = fib_entry->fib_node->fib;
err = mlxsw_sp_adj_index_mass_update_vr(mlxsw_sp, vr, err = mlxsw_sp_adj_index_mass_update_vr(mlxsw_sp, fib,
old_adj_index, old_adj_index,
old_ecmp_size, old_ecmp_size,
nh_grp->adj_index, nh_grp->adj_index,
...@@ -1712,7 +1671,7 @@ static void mlxsw_sp_fib_entry_offload_set(struct mlxsw_sp_fib_entry *fib_entry) ...@@ -1712,7 +1671,7 @@ static void mlxsw_sp_fib_entry_offload_set(struct mlxsw_sp_fib_entry *fib_entry)
{ {
fib_entry->offloaded = true; fib_entry->offloaded = true;
switch (fib_entry->fib_node->vr->proto) { switch (fib_entry->fib_node->fib->proto) {
case MLXSW_SP_L3_PROTO_IPV4: case MLXSW_SP_L3_PROTO_IPV4:
fib_info_offload_inc(fib_entry->nh_group->key.fi); fib_info_offload_inc(fib_entry->nh_group->key.fi);
break; break;
...@@ -1724,7 +1683,7 @@ static void mlxsw_sp_fib_entry_offload_set(struct mlxsw_sp_fib_entry *fib_entry) ...@@ -1724,7 +1683,7 @@ static void mlxsw_sp_fib_entry_offload_set(struct mlxsw_sp_fib_entry *fib_entry)
static void static void
mlxsw_sp_fib_entry_offload_unset(struct mlxsw_sp_fib_entry *fib_entry) mlxsw_sp_fib_entry_offload_unset(struct mlxsw_sp_fib_entry *fib_entry)
{ {
switch (fib_entry->fib_node->vr->proto) { switch (fib_entry->fib_node->fib->proto) {
case MLXSW_SP_L3_PROTO_IPV4: case MLXSW_SP_L3_PROTO_IPV4:
fib_info_offload_dec(fib_entry->nh_group->key.fi); fib_info_offload_dec(fib_entry->nh_group->key.fi);
break; break;
...@@ -1764,8 +1723,8 @@ static int mlxsw_sp_fib_entry_op4_remote(struct mlxsw_sp *mlxsw_sp, ...@@ -1764,8 +1723,8 @@ static int mlxsw_sp_fib_entry_op4_remote(struct mlxsw_sp *mlxsw_sp,
enum mlxsw_reg_ralue_op op) enum mlxsw_reg_ralue_op op)
{ {
char ralue_pl[MLXSW_REG_RALUE_LEN]; char ralue_pl[MLXSW_REG_RALUE_LEN];
struct mlxsw_sp_fib *fib = fib_entry->fib_node->fib;
u32 *p_dip = (u32 *) fib_entry->fib_node->key.addr; u32 *p_dip = (u32 *) fib_entry->fib_node->key.addr;
struct mlxsw_sp_vr *vr = fib_entry->fib_node->vr;
enum mlxsw_reg_ralue_trap_action trap_action; enum mlxsw_reg_ralue_trap_action trap_action;
u16 trap_id = 0; u16 trap_id = 0;
u32 adjacency_index = 0; u32 adjacency_index = 0;
...@@ -1785,8 +1744,8 @@ static int mlxsw_sp_fib_entry_op4_remote(struct mlxsw_sp *mlxsw_sp, ...@@ -1785,8 +1744,8 @@ static int mlxsw_sp_fib_entry_op4_remote(struct mlxsw_sp *mlxsw_sp,
} }
mlxsw_reg_ralue_pack4(ralue_pl, mlxsw_reg_ralue_pack4(ralue_pl,
(enum mlxsw_reg_ralxx_protocol) vr->proto, op, (enum mlxsw_reg_ralxx_protocol) fib->proto, op,
vr->id, fib_entry->fib_node->key.prefix_len, fib->vr->id, fib_entry->fib_node->key.prefix_len,
*p_dip); *p_dip);
mlxsw_reg_ralue_act_remote_pack(ralue_pl, trap_action, trap_id, mlxsw_reg_ralue_act_remote_pack(ralue_pl, trap_action, trap_id,
adjacency_index, ecmp_size); adjacency_index, ecmp_size);
...@@ -1798,10 +1757,10 @@ static int mlxsw_sp_fib_entry_op4_local(struct mlxsw_sp *mlxsw_sp, ...@@ -1798,10 +1757,10 @@ static int mlxsw_sp_fib_entry_op4_local(struct mlxsw_sp *mlxsw_sp,
enum mlxsw_reg_ralue_op op) enum mlxsw_reg_ralue_op op)
{ {
struct mlxsw_sp_rif *r = fib_entry->nh_group->nh_rif; struct mlxsw_sp_rif *r = fib_entry->nh_group->nh_rif;
struct mlxsw_sp_fib *fib = fib_entry->fib_node->fib;
enum mlxsw_reg_ralue_trap_action trap_action; enum mlxsw_reg_ralue_trap_action trap_action;
char ralue_pl[MLXSW_REG_RALUE_LEN]; char ralue_pl[MLXSW_REG_RALUE_LEN];
u32 *p_dip = (u32 *) fib_entry->fib_node->key.addr; u32 *p_dip = (u32 *) fib_entry->fib_node->key.addr;
struct mlxsw_sp_vr *vr = fib_entry->fib_node->vr;
u16 trap_id = 0; u16 trap_id = 0;
u16 rif = 0; u16 rif = 0;
...@@ -1814,8 +1773,8 @@ static int mlxsw_sp_fib_entry_op4_local(struct mlxsw_sp *mlxsw_sp, ...@@ -1814,8 +1773,8 @@ static int mlxsw_sp_fib_entry_op4_local(struct mlxsw_sp *mlxsw_sp,
} }
mlxsw_reg_ralue_pack4(ralue_pl, mlxsw_reg_ralue_pack4(ralue_pl,
(enum mlxsw_reg_ralxx_protocol) vr->proto, op, (enum mlxsw_reg_ralxx_protocol) fib->proto, op,
vr->id, fib_entry->fib_node->key.prefix_len, fib->vr->id, fib_entry->fib_node->key.prefix_len,
*p_dip); *p_dip);
mlxsw_reg_ralue_act_local_pack(ralue_pl, trap_action, trap_id, rif); mlxsw_reg_ralue_act_local_pack(ralue_pl, trap_action, trap_id, rif);
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl); return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl);
...@@ -1825,13 +1784,13 @@ static int mlxsw_sp_fib_entry_op4_trap(struct mlxsw_sp *mlxsw_sp, ...@@ -1825,13 +1784,13 @@ static int mlxsw_sp_fib_entry_op4_trap(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry *fib_entry, struct mlxsw_sp_fib_entry *fib_entry,
enum mlxsw_reg_ralue_op op) enum mlxsw_reg_ralue_op op)
{ {
struct mlxsw_sp_fib *fib = fib_entry->fib_node->fib;
char ralue_pl[MLXSW_REG_RALUE_LEN]; char ralue_pl[MLXSW_REG_RALUE_LEN];
u32 *p_dip = (u32 *) fib_entry->fib_node->key.addr; u32 *p_dip = (u32 *) fib_entry->fib_node->key.addr;
struct mlxsw_sp_vr *vr = fib_entry->fib_node->vr;
mlxsw_reg_ralue_pack4(ralue_pl, mlxsw_reg_ralue_pack4(ralue_pl,
(enum mlxsw_reg_ralxx_protocol) vr->proto, op, (enum mlxsw_reg_ralxx_protocol) fib->proto, op,
vr->id, fib_entry->fib_node->key.prefix_len, fib->vr->id, fib_entry->fib_node->key.prefix_len,
*p_dip); *p_dip);
mlxsw_reg_ralue_act_ip2me_pack(ralue_pl); mlxsw_reg_ralue_act_ip2me_pack(ralue_pl);
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl); return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl);
...@@ -1858,7 +1817,7 @@ static int mlxsw_sp_fib_entry_op(struct mlxsw_sp *mlxsw_sp, ...@@ -1858,7 +1817,7 @@ static int mlxsw_sp_fib_entry_op(struct mlxsw_sp *mlxsw_sp,
{ {
int err = -EINVAL; int err = -EINVAL;
switch (fib_entry->fib_node->vr->proto) { switch (fib_entry->fib_node->fib->proto) {
case MLXSW_SP_L3_PROTO_IPV4: case MLXSW_SP_L3_PROTO_IPV4:
err = mlxsw_sp_fib_entry_op4(mlxsw_sp, fib_entry, op); err = mlxsw_sp_fib_entry_op4(mlxsw_sp, fib_entry, op);
break; break;
...@@ -2021,7 +1980,7 @@ mlxsw_sp_fib_node_lookup(struct mlxsw_sp_fib *fib, const void *addr, ...@@ -2021,7 +1980,7 @@ mlxsw_sp_fib_node_lookup(struct mlxsw_sp_fib *fib, const void *addr,
} }
static struct mlxsw_sp_fib_node * static struct mlxsw_sp_fib_node *
mlxsw_sp_fib_node_create(struct mlxsw_sp_vr *vr, const void *addr, mlxsw_sp_fib_node_create(struct mlxsw_sp_fib *fib, const void *addr,
size_t addr_len, unsigned char prefix_len) size_t addr_len, unsigned char prefix_len)
{ {
struct mlxsw_sp_fib_node *fib_node; struct mlxsw_sp_fib_node *fib_node;
...@@ -2031,18 +1990,15 @@ mlxsw_sp_fib_node_create(struct mlxsw_sp_vr *vr, const void *addr, ...@@ -2031,18 +1990,15 @@ mlxsw_sp_fib_node_create(struct mlxsw_sp_vr *vr, const void *addr,
return NULL; return NULL;
INIT_LIST_HEAD(&fib_node->entry_list); INIT_LIST_HEAD(&fib_node->entry_list);
list_add(&fib_node->list, &vr->fib->node_list); list_add(&fib_node->list, &fib->node_list);
memcpy(fib_node->key.addr, addr, addr_len); memcpy(fib_node->key.addr, addr, addr_len);
fib_node->key.prefix_len = prefix_len; fib_node->key.prefix_len = prefix_len;
mlxsw_sp_fib_node_insert(vr->fib, fib_node);
fib_node->vr = vr;
return fib_node; return fib_node;
} }
static void mlxsw_sp_fib_node_destroy(struct mlxsw_sp_fib_node *fib_node) static void mlxsw_sp_fib_node_destroy(struct mlxsw_sp_fib_node *fib_node)
{ {
mlxsw_sp_fib_node_remove(fib_node->vr->fib, fib_node);
list_del(&fib_node->list); list_del(&fib_node->list);
WARN_ON(!list_empty(&fib_node->entry_list)); WARN_ON(!list_empty(&fib_node->entry_list));
kfree(fib_node); kfree(fib_node);
...@@ -2059,7 +2015,7 @@ mlxsw_sp_fib_node_entry_is_first(const struct mlxsw_sp_fib_node *fib_node, ...@@ -2059,7 +2015,7 @@ mlxsw_sp_fib_node_entry_is_first(const struct mlxsw_sp_fib_node *fib_node,
static void mlxsw_sp_fib_node_prefix_inc(struct mlxsw_sp_fib_node *fib_node) static void mlxsw_sp_fib_node_prefix_inc(struct mlxsw_sp_fib_node *fib_node)
{ {
unsigned char prefix_len = fib_node->key.prefix_len; unsigned char prefix_len = fib_node->key.prefix_len;
struct mlxsw_sp_fib *fib = fib_node->vr->fib; struct mlxsw_sp_fib *fib = fib_node->fib;
if (fib->prefix_ref_count[prefix_len]++ == 0) if (fib->prefix_ref_count[prefix_len]++ == 0)
mlxsw_sp_prefix_usage_set(&fib->prefix_usage, prefix_len); mlxsw_sp_prefix_usage_set(&fib->prefix_usage, prefix_len);
...@@ -2068,32 +2024,98 @@ static void mlxsw_sp_fib_node_prefix_inc(struct mlxsw_sp_fib_node *fib_node) ...@@ -2068,32 +2024,98 @@ static void mlxsw_sp_fib_node_prefix_inc(struct mlxsw_sp_fib_node *fib_node)
static void mlxsw_sp_fib_node_prefix_dec(struct mlxsw_sp_fib_node *fib_node) static void mlxsw_sp_fib_node_prefix_dec(struct mlxsw_sp_fib_node *fib_node)
{ {
unsigned char prefix_len = fib_node->key.prefix_len; unsigned char prefix_len = fib_node->key.prefix_len;
struct mlxsw_sp_fib *fib = fib_node->vr->fib; struct mlxsw_sp_fib *fib = fib_node->fib;
if (--fib->prefix_ref_count[prefix_len] == 0) if (--fib->prefix_ref_count[prefix_len] == 0)
mlxsw_sp_prefix_usage_clear(&fib->prefix_usage, prefix_len); mlxsw_sp_prefix_usage_clear(&fib->prefix_usage, prefix_len);
} }
static int mlxsw_sp_fib_node_init(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_node *fib_node,
struct mlxsw_sp_fib *fib)
{
struct mlxsw_sp_prefix_usage req_prefix_usage;
struct mlxsw_sp_lpm_tree *lpm_tree;
int err;
err = mlxsw_sp_fib_node_insert(fib, fib_node);
if (err)
return err;
fib_node->fib = fib;
mlxsw_sp_prefix_usage_cpy(&req_prefix_usage, &fib->prefix_usage);
mlxsw_sp_prefix_usage_set(&req_prefix_usage, fib_node->key.prefix_len);
if (!mlxsw_sp_prefix_usage_none(&fib->prefix_usage)) {
err = mlxsw_sp_vr_lpm_tree_check(mlxsw_sp, fib,
&req_prefix_usage);
if (err)
goto err_tree_check;
} else {
lpm_tree = mlxsw_sp_lpm_tree_get(mlxsw_sp, &req_prefix_usage,
fib->proto);
if (IS_ERR(lpm_tree))
return PTR_ERR(lpm_tree);
fib->lpm_tree = lpm_tree;
err = mlxsw_sp_vr_lpm_tree_bind(mlxsw_sp, fib);
if (err)
goto err_tree_bind;
}
mlxsw_sp_fib_node_prefix_inc(fib_node);
return 0;
err_tree_bind:
fib->lpm_tree = NULL;
mlxsw_sp_lpm_tree_put(mlxsw_sp, lpm_tree);
err_tree_check:
fib_node->fib = NULL;
mlxsw_sp_fib_node_remove(fib, fib_node);
return err;
}
static void mlxsw_sp_fib_node_fini(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_node *fib_node)
{
struct mlxsw_sp_lpm_tree *lpm_tree = fib_node->fib->lpm_tree;
struct mlxsw_sp_fib *fib = fib_node->fib;
mlxsw_sp_fib_node_prefix_dec(fib_node);
if (mlxsw_sp_prefix_usage_none(&fib->prefix_usage)) {
mlxsw_sp_vr_lpm_tree_unbind(mlxsw_sp, fib);
fib->lpm_tree = NULL;
mlxsw_sp_lpm_tree_put(mlxsw_sp, lpm_tree);
} else {
mlxsw_sp_vr_lpm_tree_check(mlxsw_sp, fib, &fib->prefix_usage);
}
fib_node->fib = NULL;
mlxsw_sp_fib_node_remove(fib, fib_node);
}
static struct mlxsw_sp_fib_node * static struct mlxsw_sp_fib_node *
mlxsw_sp_fib4_node_get(struct mlxsw_sp *mlxsw_sp, mlxsw_sp_fib4_node_get(struct mlxsw_sp *mlxsw_sp,
const struct fib_entry_notifier_info *fen_info) const struct fib_entry_notifier_info *fen_info)
{ {
struct mlxsw_sp_fib_node *fib_node; struct mlxsw_sp_fib_node *fib_node;
struct mlxsw_sp_fib *fib;
struct mlxsw_sp_vr *vr; struct mlxsw_sp_vr *vr;
int err; int err;
vr = mlxsw_sp_vr_get(mlxsw_sp, fen_info->dst_len, fen_info->tb_id, vr = mlxsw_sp_vr_get(mlxsw_sp, fen_info->tb_id);
MLXSW_SP_L3_PROTO_IPV4);
if (IS_ERR(vr)) if (IS_ERR(vr))
return ERR_CAST(vr); return ERR_CAST(vr);
fib = mlxsw_sp_vr_fib(vr, MLXSW_SP_L3_PROTO_IPV4);
fib_node = mlxsw_sp_fib_node_lookup(vr->fib, &fen_info->dst, fib_node = mlxsw_sp_fib_node_lookup(fib, &fen_info->dst,
sizeof(fen_info->dst), sizeof(fen_info->dst),
fen_info->dst_len); fen_info->dst_len);
if (fib_node) if (fib_node)
return fib_node; return fib_node;
fib_node = mlxsw_sp_fib_node_create(vr, &fen_info->dst, fib_node = mlxsw_sp_fib_node_create(fib, &fen_info->dst,
sizeof(fen_info->dst), sizeof(fen_info->dst),
fen_info->dst_len); fen_info->dst_len);
if (!fib_node) { if (!fib_node) {
...@@ -2101,22 +2123,29 @@ mlxsw_sp_fib4_node_get(struct mlxsw_sp *mlxsw_sp, ...@@ -2101,22 +2123,29 @@ mlxsw_sp_fib4_node_get(struct mlxsw_sp *mlxsw_sp,
goto err_fib_node_create; goto err_fib_node_create;
} }
err = mlxsw_sp_fib_node_init(mlxsw_sp, fib_node, fib);
if (err)
goto err_fib_node_init;
return fib_node; return fib_node;
err_fib_node_init:
mlxsw_sp_fib_node_destroy(fib_node);
err_fib_node_create: err_fib_node_create:
mlxsw_sp_vr_put(mlxsw_sp, vr); mlxsw_sp_vr_put(vr);
return ERR_PTR(err); return ERR_PTR(err);
} }
static void mlxsw_sp_fib4_node_put(struct mlxsw_sp *mlxsw_sp, static void mlxsw_sp_fib4_node_put(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_node *fib_node) struct mlxsw_sp_fib_node *fib_node)
{ {
struct mlxsw_sp_vr *vr = fib_node->vr; struct mlxsw_sp_vr *vr = fib_node->fib->vr;
if (!list_empty(&fib_node->entry_list)) if (!list_empty(&fib_node->entry_list))
return; return;
mlxsw_sp_fib_node_fini(mlxsw_sp, fib_node);
mlxsw_sp_fib_node_destroy(fib_node); mlxsw_sp_fib_node_destroy(fib_node);
mlxsw_sp_vr_put(mlxsw_sp, vr); mlxsw_sp_vr_put(vr);
} }
static struct mlxsw_sp_fib_entry * static struct mlxsw_sp_fib_entry *
...@@ -2261,8 +2290,6 @@ static int mlxsw_sp_fib4_node_entry_link(struct mlxsw_sp *mlxsw_sp, ...@@ -2261,8 +2290,6 @@ static int mlxsw_sp_fib4_node_entry_link(struct mlxsw_sp *mlxsw_sp,
if (err) if (err)
goto err_fib4_node_entry_add; goto err_fib4_node_entry_add;
mlxsw_sp_fib_node_prefix_inc(fib_node);
return 0; return 0;
err_fib4_node_entry_add: err_fib4_node_entry_add:
...@@ -2276,7 +2303,6 @@ mlxsw_sp_fib4_node_entry_unlink(struct mlxsw_sp *mlxsw_sp, ...@@ -2276,7 +2303,6 @@ mlxsw_sp_fib4_node_entry_unlink(struct mlxsw_sp *mlxsw_sp,
{ {
struct mlxsw_sp_fib_node *fib_node = fib_entry->fib_node; struct mlxsw_sp_fib_node *fib_node = fib_entry->fib_node;
mlxsw_sp_fib_node_prefix_dec(fib_node);
mlxsw_sp_fib4_node_entry_del(mlxsw_sp, fib_node, fib_entry); mlxsw_sp_fib4_node_entry_del(mlxsw_sp, fib_node, fib_entry);
mlxsw_sp_fib4_node_list_remove(fib_entry); mlxsw_sp_fib4_node_list_remove(fib_entry);
} }
...@@ -2415,7 +2441,7 @@ static void mlxsw_sp_fib4_node_flush(struct mlxsw_sp *mlxsw_sp, ...@@ -2415,7 +2441,7 @@ static void mlxsw_sp_fib4_node_flush(struct mlxsw_sp *mlxsw_sp,
static void mlxsw_sp_fib_node_flush(struct mlxsw_sp *mlxsw_sp, static void mlxsw_sp_fib_node_flush(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_node *fib_node) struct mlxsw_sp_fib_node *fib_node)
{ {
switch (fib_node->vr->proto) { switch (fib_node->fib->proto) {
case MLXSW_SP_L3_PROTO_IPV4: case MLXSW_SP_L3_PROTO_IPV4:
mlxsw_sp_fib4_node_flush(mlxsw_sp, fib_node); mlxsw_sp_fib4_node_flush(mlxsw_sp, fib_node);
break; break;
...@@ -2425,26 +2451,32 @@ static void mlxsw_sp_fib_node_flush(struct mlxsw_sp *mlxsw_sp, ...@@ -2425,26 +2451,32 @@ static void mlxsw_sp_fib_node_flush(struct mlxsw_sp *mlxsw_sp,
} }
} }
static void mlxsw_sp_router_fib_flush(struct mlxsw_sp *mlxsw_sp) static void mlxsw_sp_vr_fib_flush(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_vr *vr,
enum mlxsw_sp_l3proto proto)
{ {
struct mlxsw_sp_fib *fib = mlxsw_sp_vr_fib(vr, proto);
struct mlxsw_sp_fib_node *fib_node, *tmp; struct mlxsw_sp_fib_node *fib_node, *tmp;
struct mlxsw_sp_vr *vr;
list_for_each_entry_safe(fib_node, tmp, &fib->node_list, list) {
bool do_break = &tmp->list == &fib->node_list;
mlxsw_sp_fib_node_flush(mlxsw_sp, fib_node);
if (do_break)
break;
}
}
static void mlxsw_sp_router_fib_flush(struct mlxsw_sp *mlxsw_sp)
{
int i; int i;
for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) { for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) {
vr = &mlxsw_sp->router.vrs[i]; struct mlxsw_sp_vr *vr = &mlxsw_sp->router.vrs[i];
if (!vr->used) if (!mlxsw_sp_vr_is_used(vr))
continue; continue;
mlxsw_sp_vr_fib_flush(mlxsw_sp, vr, MLXSW_SP_L3_PROTO_IPV4);
list_for_each_entry_safe(fib_node, tmp, &vr->fib->node_list,
list) {
bool do_break = &tmp->list == &vr->fib->node_list;
mlxsw_sp_fib_node_flush(mlxsw_sp, fib_node);
if (do_break)
break;
}
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment