Commit 2ae50dea authored by David S. Miller's avatar David S. Miller

Merge branch 'mlxsw-spectrum_router-Optimize-LPM-trees'

Jiri Pirko says:

====================
mlxsw: spectrum_router: Optimize LPM trees

Ido says:

This set tries to optimize the structure of the LPM trees used for route
lookup by avoiding lookups that are guaranteed not to return a result.
This is done by making sure only used prefix lengths are present in the
tree.

First two patches are small preparatory steps towards the actual change
in the last patch.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 9d6474e4 2b52ce02
...@@ -71,6 +71,7 @@ ...@@ -71,6 +71,7 @@
#include "spectrum_mr_tcam.h" #include "spectrum_mr_tcam.h"
#include "spectrum_router.h" #include "spectrum_router.h"
struct mlxsw_sp_fib;
struct mlxsw_sp_vr; struct mlxsw_sp_vr;
struct mlxsw_sp_lpm_tree; struct mlxsw_sp_lpm_tree;
struct mlxsw_sp_rif_ops; struct mlxsw_sp_rif_ops;
...@@ -84,6 +85,8 @@ struct mlxsw_sp_router { ...@@ -84,6 +85,8 @@ struct mlxsw_sp_router {
struct rhashtable nexthop_ht; struct rhashtable nexthop_ht;
struct list_head nexthop_list; struct list_head nexthop_list;
struct { struct {
/* One tree for each protocol: IPv4 and IPv6 */
struct mlxsw_sp_lpm_tree *proto_trees[2];
struct mlxsw_sp_lpm_tree *trees; struct mlxsw_sp_lpm_tree *trees;
unsigned int tree_count; unsigned int tree_count;
} lpm; } lpm;
...@@ -162,6 +165,15 @@ struct mlxsw_sp_rif_ops { ...@@ -162,6 +165,15 @@ struct mlxsw_sp_rif_ops {
struct mlxsw_sp_fid * (*fid_get)(struct mlxsw_sp_rif *rif); struct mlxsw_sp_fid * (*fid_get)(struct mlxsw_sp_rif *rif);
}; };
static void mlxsw_sp_lpm_tree_hold(struct mlxsw_sp_lpm_tree *lpm_tree);
static void mlxsw_sp_lpm_tree_put(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_lpm_tree *lpm_tree);
static int mlxsw_sp_vr_lpm_tree_bind(struct mlxsw_sp *mlxsw_sp,
const struct mlxsw_sp_fib *fib,
u8 tree_id);
static int mlxsw_sp_vr_lpm_tree_unbind(struct mlxsw_sp *mlxsw_sp,
const struct mlxsw_sp_fib *fib);
static unsigned int * static unsigned int *
mlxsw_sp_rif_p_counter_get(struct mlxsw_sp_rif *rif, mlxsw_sp_rif_p_counter_get(struct mlxsw_sp_rif *rif,
enum mlxsw_sp_rif_counter_dir dir) enum mlxsw_sp_rif_counter_dir dir)
...@@ -349,14 +361,6 @@ mlxsw_sp_prefix_usage_eq(struct mlxsw_sp_prefix_usage *prefix_usage1, ...@@ -349,14 +361,6 @@ mlxsw_sp_prefix_usage_eq(struct mlxsw_sp_prefix_usage *prefix_usage1,
return !memcmp(prefix_usage1, prefix_usage2, sizeof(*prefix_usage1)); return !memcmp(prefix_usage1, prefix_usage2, sizeof(*prefix_usage1));
} }
static bool
mlxsw_sp_prefix_usage_none(struct mlxsw_sp_prefix_usage *prefix_usage)
{
struct mlxsw_sp_prefix_usage prefix_usage_none = {{ 0 } };
return mlxsw_sp_prefix_usage_eq(prefix_usage, &prefix_usage_none);
}
static void static void
mlxsw_sp_prefix_usage_cpy(struct mlxsw_sp_prefix_usage *prefix_usage1, mlxsw_sp_prefix_usage_cpy(struct mlxsw_sp_prefix_usage *prefix_usage1,
struct mlxsw_sp_prefix_usage *prefix_usage2) struct mlxsw_sp_prefix_usage *prefix_usage2)
...@@ -398,7 +402,6 @@ enum mlxsw_sp_fib_entry_type { ...@@ -398,7 +402,6 @@ enum mlxsw_sp_fib_entry_type {
}; };
struct mlxsw_sp_nexthop_group; struct mlxsw_sp_nexthop_group;
struct mlxsw_sp_fib;
struct mlxsw_sp_fib_node { struct mlxsw_sp_fib_node {
struct list_head entry_list; struct list_head entry_list;
...@@ -445,6 +448,7 @@ struct mlxsw_sp_lpm_tree { ...@@ -445,6 +448,7 @@ struct mlxsw_sp_lpm_tree {
u8 id; /* tree ID */ u8 id; /* tree ID */
unsigned int ref_count; unsigned int ref_count;
enum mlxsw_sp_l3proto proto; enum mlxsw_sp_l3proto proto;
unsigned long prefix_ref_count[MLXSW_SP_PREFIX_COUNT];
struct mlxsw_sp_prefix_usage prefix_usage; struct mlxsw_sp_prefix_usage prefix_usage;
}; };
...@@ -453,8 +457,6 @@ struct mlxsw_sp_fib { ...@@ -453,8 +457,6 @@ struct mlxsw_sp_fib {
struct list_head node_list; struct list_head node_list;
struct mlxsw_sp_vr *vr; struct mlxsw_sp_vr *vr;
struct mlxsw_sp_lpm_tree *lpm_tree; struct mlxsw_sp_lpm_tree *lpm_tree;
unsigned long prefix_ref_count[MLXSW_SP_PREFIX_COUNT];
struct mlxsw_sp_prefix_usage prefix_usage;
enum mlxsw_sp_l3proto proto; enum mlxsw_sp_l3proto proto;
}; };
...@@ -469,12 +471,15 @@ struct mlxsw_sp_vr { ...@@ -469,12 +471,15 @@ struct mlxsw_sp_vr {
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(struct mlxsw_sp_vr *vr, static struct mlxsw_sp_fib *mlxsw_sp_fib_create(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_vr *vr,
enum mlxsw_sp_l3proto proto) enum mlxsw_sp_l3proto proto)
{ {
struct mlxsw_sp_lpm_tree *lpm_tree;
struct mlxsw_sp_fib *fib; struct mlxsw_sp_fib *fib;
int err; int err;
lpm_tree = mlxsw_sp->router->lpm.proto_trees[proto];
fib = kzalloc(sizeof(*fib), GFP_KERNEL); fib = kzalloc(sizeof(*fib), GFP_KERNEL);
if (!fib) if (!fib)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
...@@ -484,17 +489,26 @@ static struct mlxsw_sp_fib *mlxsw_sp_fib_create(struct mlxsw_sp_vr *vr, ...@@ -484,17 +489,26 @@ static struct mlxsw_sp_fib *mlxsw_sp_fib_create(struct mlxsw_sp_vr *vr,
INIT_LIST_HEAD(&fib->node_list); INIT_LIST_HEAD(&fib->node_list);
fib->proto = proto; fib->proto = proto;
fib->vr = vr; fib->vr = vr;
fib->lpm_tree = lpm_tree;
mlxsw_sp_lpm_tree_hold(lpm_tree);
err = mlxsw_sp_vr_lpm_tree_bind(mlxsw_sp, fib, lpm_tree->id);
if (err)
goto err_lpm_tree_bind;
return fib; return fib;
err_lpm_tree_bind:
mlxsw_sp_lpm_tree_put(mlxsw_sp, lpm_tree);
err_rhashtable_init: err_rhashtable_init:
kfree(fib); kfree(fib);
return ERR_PTR(err); return ERR_PTR(err);
} }
static void mlxsw_sp_fib_destroy(struct mlxsw_sp_fib *fib) static void mlxsw_sp_fib_destroy(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib *fib)
{ {
mlxsw_sp_vr_lpm_tree_unbind(mlxsw_sp, fib);
mlxsw_sp_lpm_tree_put(mlxsw_sp, fib->lpm_tree);
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);
} }
...@@ -581,6 +595,9 @@ mlxsw_sp_lpm_tree_create(struct mlxsw_sp *mlxsw_sp, ...@@ -581,6 +595,9 @@ mlxsw_sp_lpm_tree_create(struct mlxsw_sp *mlxsw_sp,
goto err_left_struct_set; goto err_left_struct_set;
memcpy(&lpm_tree->prefix_usage, prefix_usage, memcpy(&lpm_tree->prefix_usage, prefix_usage,
sizeof(lpm_tree->prefix_usage)); sizeof(lpm_tree->prefix_usage));
memset(&lpm_tree->prefix_ref_count, 0,
sizeof(lpm_tree->prefix_ref_count));
lpm_tree->ref_count = 1;
return lpm_tree; return lpm_tree;
err_left_struct_set: err_left_struct_set:
...@@ -607,8 +624,10 @@ mlxsw_sp_lpm_tree_get(struct mlxsw_sp *mlxsw_sp, ...@@ -607,8 +624,10 @@ mlxsw_sp_lpm_tree_get(struct mlxsw_sp *mlxsw_sp,
if (lpm_tree->ref_count != 0 && if (lpm_tree->ref_count != 0 &&
lpm_tree->proto == proto && lpm_tree->proto == proto &&
mlxsw_sp_prefix_usage_eq(&lpm_tree->prefix_usage, mlxsw_sp_prefix_usage_eq(&lpm_tree->prefix_usage,
prefix_usage)) prefix_usage)) {
mlxsw_sp_lpm_tree_hold(lpm_tree);
return lpm_tree; return lpm_tree;
}
} }
return mlxsw_sp_lpm_tree_create(mlxsw_sp, prefix_usage, proto); return mlxsw_sp_lpm_tree_create(mlxsw_sp, prefix_usage, proto);
} }
...@@ -629,9 +648,10 @@ static void mlxsw_sp_lpm_tree_put(struct mlxsw_sp *mlxsw_sp, ...@@ -629,9 +648,10 @@ static void mlxsw_sp_lpm_tree_put(struct mlxsw_sp *mlxsw_sp,
static int mlxsw_sp_lpm_init(struct mlxsw_sp *mlxsw_sp) static int mlxsw_sp_lpm_init(struct mlxsw_sp *mlxsw_sp)
{ {
struct mlxsw_sp_prefix_usage req_prefix_usage = {{ 0 } };
struct mlxsw_sp_lpm_tree *lpm_tree; struct mlxsw_sp_lpm_tree *lpm_tree;
u64 max_trees; u64 max_trees;
int i; int err, i;
if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_LPM_TREES)) if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_LPM_TREES))
return -EIO; return -EIO;
...@@ -649,11 +669,42 @@ static int mlxsw_sp_lpm_init(struct mlxsw_sp *mlxsw_sp) ...@@ -649,11 +669,42 @@ static int mlxsw_sp_lpm_init(struct mlxsw_sp *mlxsw_sp)
lpm_tree->id = i + MLXSW_SP_LPM_TREE_MIN; lpm_tree->id = i + MLXSW_SP_LPM_TREE_MIN;
} }
lpm_tree = mlxsw_sp_lpm_tree_get(mlxsw_sp, &req_prefix_usage,
MLXSW_SP_L3_PROTO_IPV4);
if (IS_ERR(lpm_tree)) {
err = PTR_ERR(lpm_tree);
goto err_ipv4_tree_get;
}
mlxsw_sp->router->lpm.proto_trees[MLXSW_SP_L3_PROTO_IPV4] = lpm_tree;
lpm_tree = mlxsw_sp_lpm_tree_get(mlxsw_sp, &req_prefix_usage,
MLXSW_SP_L3_PROTO_IPV6);
if (IS_ERR(lpm_tree)) {
err = PTR_ERR(lpm_tree);
goto err_ipv6_tree_get;
}
mlxsw_sp->router->lpm.proto_trees[MLXSW_SP_L3_PROTO_IPV6] = lpm_tree;
return 0; return 0;
err_ipv6_tree_get:
lpm_tree = mlxsw_sp->router->lpm.proto_trees[MLXSW_SP_L3_PROTO_IPV4];
mlxsw_sp_lpm_tree_put(mlxsw_sp, lpm_tree);
err_ipv4_tree_get:
kfree(mlxsw_sp->router->lpm.trees);
return err;
} }
static void mlxsw_sp_lpm_fini(struct mlxsw_sp *mlxsw_sp) static void mlxsw_sp_lpm_fini(struct mlxsw_sp *mlxsw_sp)
{ {
struct mlxsw_sp_lpm_tree *lpm_tree;
lpm_tree = mlxsw_sp->router->lpm.proto_trees[MLXSW_SP_L3_PROTO_IPV6];
mlxsw_sp_lpm_tree_put(mlxsw_sp, lpm_tree);
lpm_tree = mlxsw_sp->router->lpm.proto_trees[MLXSW_SP_L3_PROTO_IPV4];
mlxsw_sp_lpm_tree_put(mlxsw_sp, lpm_tree);
kfree(mlxsw_sp->router->lpm.trees); kfree(mlxsw_sp->router->lpm.trees);
} }
...@@ -745,10 +796,10 @@ static struct mlxsw_sp_vr *mlxsw_sp_vr_create(struct mlxsw_sp *mlxsw_sp, ...@@ -745,10 +796,10 @@ static struct mlxsw_sp_vr *mlxsw_sp_vr_create(struct mlxsw_sp *mlxsw_sp,
NL_SET_ERR_MSG(extack, "spectrum: Exceeded number of supported virtual routers"); NL_SET_ERR_MSG(extack, "spectrum: Exceeded number of supported virtual routers");
return ERR_PTR(-EBUSY); return ERR_PTR(-EBUSY);
} }
vr->fib4 = mlxsw_sp_fib_create(vr, MLXSW_SP_L3_PROTO_IPV4); vr->fib4 = mlxsw_sp_fib_create(mlxsw_sp, vr, MLXSW_SP_L3_PROTO_IPV4);
if (IS_ERR(vr->fib4)) if (IS_ERR(vr->fib4))
return ERR_CAST(vr->fib4); return ERR_CAST(vr->fib4);
vr->fib6 = mlxsw_sp_fib_create(vr, MLXSW_SP_L3_PROTO_IPV6); vr->fib6 = mlxsw_sp_fib_create(mlxsw_sp, vr, MLXSW_SP_L3_PROTO_IPV6);
if (IS_ERR(vr->fib6)) { if (IS_ERR(vr->fib6)) {
err = PTR_ERR(vr->fib6); err = PTR_ERR(vr->fib6);
goto err_fib6_create; goto err_fib6_create;
...@@ -763,21 +814,22 @@ static struct mlxsw_sp_vr *mlxsw_sp_vr_create(struct mlxsw_sp *mlxsw_sp, ...@@ -763,21 +814,22 @@ static struct mlxsw_sp_vr *mlxsw_sp_vr_create(struct mlxsw_sp *mlxsw_sp,
return vr; return vr;
err_mr_table_create: err_mr_table_create:
mlxsw_sp_fib_destroy(vr->fib6); mlxsw_sp_fib_destroy(mlxsw_sp, vr->fib6);
vr->fib6 = NULL; vr->fib6 = NULL;
err_fib6_create: err_fib6_create:
mlxsw_sp_fib_destroy(vr->fib4); mlxsw_sp_fib_destroy(mlxsw_sp, vr->fib4);
vr->fib4 = NULL; vr->fib4 = NULL;
return ERR_PTR(err); return ERR_PTR(err);
} }
static void mlxsw_sp_vr_destroy(struct mlxsw_sp_vr *vr) static void mlxsw_sp_vr_destroy(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_vr *vr)
{ {
mlxsw_sp_mr_table_destroy(vr->mr4_table); mlxsw_sp_mr_table_destroy(vr->mr4_table);
vr->mr4_table = NULL; vr->mr4_table = NULL;
mlxsw_sp_fib_destroy(vr->fib6); mlxsw_sp_fib_destroy(mlxsw_sp, vr->fib6);
vr->fib6 = NULL; vr->fib6 = NULL;
mlxsw_sp_fib_destroy(vr->fib4); mlxsw_sp_fib_destroy(mlxsw_sp, vr->fib4);
vr->fib4 = NULL; vr->fib4 = NULL;
} }
...@@ -793,12 +845,12 @@ static struct mlxsw_sp_vr *mlxsw_sp_vr_get(struct mlxsw_sp *mlxsw_sp, u32 tb_id, ...@@ -793,12 +845,12 @@ static struct mlxsw_sp_vr *mlxsw_sp_vr_get(struct mlxsw_sp *mlxsw_sp, u32 tb_id,
return vr; return vr;
} }
static void mlxsw_sp_vr_put(struct mlxsw_sp_vr *vr) static void mlxsw_sp_vr_put(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_vr *vr)
{ {
if (!vr->rif_count && list_empty(&vr->fib4->node_list) && if (!vr->rif_count && list_empty(&vr->fib4->node_list) &&
list_empty(&vr->fib6->node_list) && list_empty(&vr->fib6->node_list) &&
mlxsw_sp_mr_table_empty(vr->mr4_table)) mlxsw_sp_mr_table_empty(vr->mr4_table))
mlxsw_sp_vr_destroy(vr); mlxsw_sp_vr_destroy(mlxsw_sp, vr);
} }
static bool static bool
...@@ -809,7 +861,7 @@ mlxsw_sp_vr_lpm_tree_should_replace(struct mlxsw_sp_vr *vr, ...@@ -809,7 +861,7 @@ mlxsw_sp_vr_lpm_tree_should_replace(struct mlxsw_sp_vr *vr,
if (!mlxsw_sp_vr_is_used(vr)) if (!mlxsw_sp_vr_is_used(vr))
return false; return false;
if (fib->lpm_tree && fib->lpm_tree->id == tree_id) if (fib->lpm_tree->id == tree_id)
return true; return true;
return false; return false;
} }
...@@ -839,14 +891,13 @@ static int mlxsw_sp_vrs_lpm_tree_replace(struct mlxsw_sp *mlxsw_sp, ...@@ -839,14 +891,13 @@ static int mlxsw_sp_vrs_lpm_tree_replace(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib *fib, struct mlxsw_sp_fib *fib,
struct mlxsw_sp_lpm_tree *new_tree) struct mlxsw_sp_lpm_tree *new_tree)
{ {
struct mlxsw_sp_lpm_tree *old_tree = fib->lpm_tree;
enum mlxsw_sp_l3proto proto = fib->proto; enum mlxsw_sp_l3proto proto = fib->proto;
struct mlxsw_sp_lpm_tree *old_tree;
u8 old_id, new_id = new_tree->id; u8 old_id, new_id = new_tree->id;
struct mlxsw_sp_vr *vr; struct mlxsw_sp_vr *vr;
int i, err; int i, err;
if (!old_tree) old_tree = mlxsw_sp->router->lpm.proto_trees[proto];
goto no_replace;
old_id = old_tree->id; old_id = old_tree->id;
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++) {
...@@ -860,6 +911,11 @@ static int mlxsw_sp_vrs_lpm_tree_replace(struct mlxsw_sp *mlxsw_sp, ...@@ -860,6 +911,11 @@ static int mlxsw_sp_vrs_lpm_tree_replace(struct mlxsw_sp *mlxsw_sp,
goto err_tree_replace; goto err_tree_replace;
} }
memcpy(new_tree->prefix_ref_count, old_tree->prefix_ref_count,
sizeof(new_tree->prefix_ref_count));
mlxsw_sp->router->lpm.proto_trees[proto] = new_tree;
mlxsw_sp_lpm_tree_put(mlxsw_sp, old_tree);
return 0; return 0;
err_tree_replace: err_tree_replace:
...@@ -871,36 +927,6 @@ static int mlxsw_sp_vrs_lpm_tree_replace(struct mlxsw_sp *mlxsw_sp, ...@@ -871,36 +927,6 @@ static int mlxsw_sp_vrs_lpm_tree_replace(struct mlxsw_sp *mlxsw_sp,
old_tree); old_tree);
} }
return err; return err;
no_replace:
fib->lpm_tree = new_tree;
mlxsw_sp_lpm_tree_hold(new_tree);
err = mlxsw_sp_vr_lpm_tree_bind(mlxsw_sp, fib, new_tree->id);
if (err) {
mlxsw_sp_lpm_tree_put(mlxsw_sp, new_tree);
fib->lpm_tree = NULL;
return err;
}
return 0;
}
static void
mlxsw_sp_vrs_prefixes(struct mlxsw_sp *mlxsw_sp,
enum mlxsw_sp_l3proto proto,
struct mlxsw_sp_prefix_usage *req_prefix_usage)
{
int i;
for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) {
struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[i];
struct mlxsw_sp_fib *fib = mlxsw_sp_vr_fib(vr, proto);
unsigned char prefix;
if (!mlxsw_sp_vr_is_used(vr))
continue;
mlxsw_sp_prefix_usage_for_each(prefix, &fib->prefix_usage)
mlxsw_sp_prefix_usage_set(req_prefix_usage, prefix);
}
} }
static int mlxsw_sp_vrs_init(struct mlxsw_sp *mlxsw_sp) static int mlxsw_sp_vrs_init(struct mlxsw_sp *mlxsw_sp)
...@@ -4201,68 +4227,66 @@ mlxsw_sp_fib_node_entry_is_first(const struct mlxsw_sp_fib_node *fib_node, ...@@ -4201,68 +4227,66 @@ mlxsw_sp_fib_node_entry_is_first(const struct mlxsw_sp_fib_node *fib_node,
} }
static int mlxsw_sp_fib_lpm_tree_link(struct mlxsw_sp *mlxsw_sp, static int mlxsw_sp_fib_lpm_tree_link(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib *fib,
struct mlxsw_sp_fib_node *fib_node) struct mlxsw_sp_fib_node *fib_node)
{ {
struct mlxsw_sp_prefix_usage req_prefix_usage = {{ 0 } }; struct mlxsw_sp_prefix_usage req_prefix_usage;
struct mlxsw_sp_fib *fib = fib_node->fib;
struct mlxsw_sp_lpm_tree *lpm_tree; struct mlxsw_sp_lpm_tree *lpm_tree;
int err; int err;
/* Since the tree is shared between all virtual routers we must lpm_tree = mlxsw_sp->router->lpm.proto_trees[fib->proto];
* make sure it contains all the required prefix lengths. This if (lpm_tree->prefix_ref_count[fib_node->key.prefix_len] != 0)
* can be computed by either adding the new prefix length to the goto out;
* existing prefix usage of a bound tree, or by aggregating the
* prefix lengths across all virtual routers and adding the new
* one as well.
*/
if (fib->lpm_tree)
mlxsw_sp_prefix_usage_cpy(&req_prefix_usage,
&fib->lpm_tree->prefix_usage);
else
mlxsw_sp_vrs_prefixes(mlxsw_sp, fib->proto, &req_prefix_usage);
mlxsw_sp_prefix_usage_set(&req_prefix_usage, fib_node->key.prefix_len);
mlxsw_sp_prefix_usage_cpy(&req_prefix_usage, &lpm_tree->prefix_usage);
mlxsw_sp_prefix_usage_set(&req_prefix_usage, fib_node->key.prefix_len);
lpm_tree = mlxsw_sp_lpm_tree_get(mlxsw_sp, &req_prefix_usage, lpm_tree = mlxsw_sp_lpm_tree_get(mlxsw_sp, &req_prefix_usage,
fib->proto); fib->proto);
if (IS_ERR(lpm_tree)) if (IS_ERR(lpm_tree))
return PTR_ERR(lpm_tree); return PTR_ERR(lpm_tree);
if (fib->lpm_tree && fib->lpm_tree->id == lpm_tree->id)
return 0;
err = mlxsw_sp_vrs_lpm_tree_replace(mlxsw_sp, fib, lpm_tree); err = mlxsw_sp_vrs_lpm_tree_replace(mlxsw_sp, fib, lpm_tree);
if (err) if (err)
return err; goto err_lpm_tree_replace;
out:
lpm_tree->prefix_ref_count[fib_node->key.prefix_len]++;
return 0; return 0;
}
static void mlxsw_sp_fib_lpm_tree_unlink(struct mlxsw_sp *mlxsw_sp, err_lpm_tree_replace:
struct mlxsw_sp_fib *fib) mlxsw_sp_lpm_tree_put(mlxsw_sp, lpm_tree);
{ return err;
if (!mlxsw_sp_prefix_usage_none(&fib->prefix_usage))
return;
mlxsw_sp_vr_lpm_tree_unbind(mlxsw_sp, fib);
mlxsw_sp_lpm_tree_put(mlxsw_sp, fib->lpm_tree);
fib->lpm_tree = NULL;
} }
static void mlxsw_sp_fib_node_prefix_inc(struct mlxsw_sp_fib_node *fib_node) static void mlxsw_sp_fib_lpm_tree_unlink(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_node *fib_node)
{ {
unsigned char prefix_len = fib_node->key.prefix_len; struct mlxsw_sp_lpm_tree *lpm_tree = fib_node->fib->lpm_tree;
struct mlxsw_sp_prefix_usage req_prefix_usage;
struct mlxsw_sp_fib *fib = fib_node->fib; struct mlxsw_sp_fib *fib = fib_node->fib;
int err;
if (fib->prefix_ref_count[prefix_len]++ == 0) if (--lpm_tree->prefix_ref_count[fib_node->key.prefix_len] != 0)
mlxsw_sp_prefix_usage_set(&fib->prefix_usage, prefix_len); return;
} /* Try to construct a new LPM tree from the current prefix usage
* minus the unused one. If we fail, continue using the old one.
*/
mlxsw_sp_prefix_usage_cpy(&req_prefix_usage, &lpm_tree->prefix_usage);
mlxsw_sp_prefix_usage_clear(&req_prefix_usage,
fib_node->key.prefix_len);
lpm_tree = mlxsw_sp_lpm_tree_get(mlxsw_sp, &req_prefix_usage,
fib->proto);
if (IS_ERR(lpm_tree))
return;
static void mlxsw_sp_fib_node_prefix_dec(struct mlxsw_sp_fib_node *fib_node) err = mlxsw_sp_vrs_lpm_tree_replace(mlxsw_sp, fib, lpm_tree);
{ if (err)
unsigned char prefix_len = fib_node->key.prefix_len; goto err_lpm_tree_replace;
struct mlxsw_sp_fib *fib = fib_node->fib;
if (--fib->prefix_ref_count[prefix_len] == 0) return;
mlxsw_sp_prefix_usage_clear(&fib->prefix_usage, prefix_len);
err_lpm_tree_replace:
mlxsw_sp_lpm_tree_put(mlxsw_sp, lpm_tree);
} }
static int mlxsw_sp_fib_node_init(struct mlxsw_sp *mlxsw_sp, static int mlxsw_sp_fib_node_init(struct mlxsw_sp *mlxsw_sp,
...@@ -4276,12 +4300,10 @@ static int mlxsw_sp_fib_node_init(struct mlxsw_sp *mlxsw_sp, ...@@ -4276,12 +4300,10 @@ static int mlxsw_sp_fib_node_init(struct mlxsw_sp *mlxsw_sp,
return err; return err;
fib_node->fib = fib; fib_node->fib = fib;
err = mlxsw_sp_fib_lpm_tree_link(mlxsw_sp, fib, fib_node); err = mlxsw_sp_fib_lpm_tree_link(mlxsw_sp, fib_node);
if (err) if (err)
goto err_fib_lpm_tree_link; goto err_fib_lpm_tree_link;
mlxsw_sp_fib_node_prefix_inc(fib_node);
return 0; return 0;
err_fib_lpm_tree_link: err_fib_lpm_tree_link:
...@@ -4295,8 +4317,7 @@ static void mlxsw_sp_fib_node_fini(struct mlxsw_sp *mlxsw_sp, ...@@ -4295,8 +4317,7 @@ static void mlxsw_sp_fib_node_fini(struct mlxsw_sp *mlxsw_sp,
{ {
struct mlxsw_sp_fib *fib = fib_node->fib; struct mlxsw_sp_fib *fib = fib_node->fib;
mlxsw_sp_fib_node_prefix_dec(fib_node); mlxsw_sp_fib_lpm_tree_unlink(mlxsw_sp, fib_node);
mlxsw_sp_fib_lpm_tree_unlink(mlxsw_sp, fib);
fib_node->fib = NULL; fib_node->fib = NULL;
mlxsw_sp_fib_node_remove(fib, fib_node); mlxsw_sp_fib_node_remove(fib, fib_node);
} }
...@@ -4335,7 +4356,7 @@ mlxsw_sp_fib_node_get(struct mlxsw_sp *mlxsw_sp, u32 tb_id, const void *addr, ...@@ -4335,7 +4356,7 @@ mlxsw_sp_fib_node_get(struct mlxsw_sp *mlxsw_sp, u32 tb_id, const void *addr,
err_fib_node_init: err_fib_node_init:
mlxsw_sp_fib_node_destroy(fib_node); mlxsw_sp_fib_node_destroy(fib_node);
err_fib_node_create: err_fib_node_create:
mlxsw_sp_vr_put(vr); mlxsw_sp_vr_put(mlxsw_sp, vr);
return ERR_PTR(err); return ERR_PTR(err);
} }
...@@ -4348,7 +4369,7 @@ static void mlxsw_sp_fib_node_put(struct mlxsw_sp *mlxsw_sp, ...@@ -4348,7 +4369,7 @@ static void mlxsw_sp_fib_node_put(struct mlxsw_sp *mlxsw_sp,
return; return;
mlxsw_sp_fib_node_fini(mlxsw_sp, fib_node); 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(vr); mlxsw_sp_vr_put(mlxsw_sp, vr);
} }
static struct mlxsw_sp_fib4_entry * static struct mlxsw_sp_fib4_entry *
...@@ -5371,7 +5392,7 @@ static void mlxsw_sp_router_fibmr_del(struct mlxsw_sp *mlxsw_sp, ...@@ -5371,7 +5392,7 @@ static void mlxsw_sp_router_fibmr_del(struct mlxsw_sp *mlxsw_sp,
return; return;
mlxsw_sp_mr_route4_del(vr->mr4_table, men_info->mfc); mlxsw_sp_mr_route4_del(vr->mr4_table, men_info->mfc);
mlxsw_sp_vr_put(vr); mlxsw_sp_vr_put(mlxsw_sp, vr);
} }
static int static int
...@@ -5408,7 +5429,7 @@ mlxsw_sp_router_fibmr_vif_del(struct mlxsw_sp *mlxsw_sp, ...@@ -5408,7 +5429,7 @@ mlxsw_sp_router_fibmr_vif_del(struct mlxsw_sp *mlxsw_sp,
return; return;
mlxsw_sp_mr_vif_del(vr->mr4_table, ven_info->vif_index); mlxsw_sp_mr_vif_del(vr->mr4_table, ven_info->vif_index);
mlxsw_sp_vr_put(vr); mlxsw_sp_vr_put(mlxsw_sp, vr);
} }
static int mlxsw_sp_router_set_abort_trap(struct mlxsw_sp *mlxsw_sp) static int mlxsw_sp_router_set_abort_trap(struct mlxsw_sp *mlxsw_sp)
...@@ -6057,7 +6078,7 @@ mlxsw_sp_rif_create(struct mlxsw_sp *mlxsw_sp, ...@@ -6057,7 +6078,7 @@ mlxsw_sp_rif_create(struct mlxsw_sp *mlxsw_sp,
err_rif_alloc: err_rif_alloc:
err_rif_index_alloc: err_rif_index_alloc:
vr->rif_count--; vr->rif_count--;
mlxsw_sp_vr_put(vr); mlxsw_sp_vr_put(mlxsw_sp, vr);
return ERR_PTR(err); return ERR_PTR(err);
} }
...@@ -6080,7 +6101,7 @@ void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif) ...@@ -6080,7 +6101,7 @@ void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif)
mlxsw_sp_fid_put(fid); mlxsw_sp_fid_put(fid);
kfree(rif); kfree(rif);
vr->rif_count--; vr->rif_count--;
mlxsw_sp_vr_put(vr); mlxsw_sp_vr_put(mlxsw_sp, vr);
} }
static void static void
...@@ -6870,7 +6891,7 @@ mlxsw_sp_rif_ipip_lb_configure(struct mlxsw_sp_rif *rif) ...@@ -6870,7 +6891,7 @@ mlxsw_sp_rif_ipip_lb_configure(struct mlxsw_sp_rif *rif)
return 0; return 0;
err_loopback_op: err_loopback_op:
mlxsw_sp_vr_put(ul_vr); mlxsw_sp_vr_put(mlxsw_sp, ul_vr);
return err; return err;
} }
...@@ -6884,7 +6905,7 @@ static void mlxsw_sp_rif_ipip_lb_deconfigure(struct mlxsw_sp_rif *rif) ...@@ -6884,7 +6905,7 @@ static void mlxsw_sp_rif_ipip_lb_deconfigure(struct mlxsw_sp_rif *rif)
mlxsw_sp_rif_ipip_lb_op(lb_rif, ul_vr, false); mlxsw_sp_rif_ipip_lb_op(lb_rif, ul_vr, false);
--ul_vr->rif_count; --ul_vr->rif_count;
mlxsw_sp_vr_put(ul_vr); mlxsw_sp_vr_put(mlxsw_sp, ul_vr);
} }
static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_ipip_lb_ops = { static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_ipip_lb_ops = {
......
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