Skip to content

Commit fc922bb

Browse files
idoschdavem330
authored andcommitted
mlxsw: spectrum_router: Use one LPM tree for all virtual routers
The number of LPM trees available for lookup is much smaller than the number of virtual routers, which are used to implement VRFs. In addition, an LPM tree can only be used by one protocol - either IPv4 or IPv6. Therefore, in order to increase the number of supported virtual routers to the maximum we need to be able to share LPM trees across virtual routers instead of trying to find an optimized tree for each. Do that by allocating one LPM tree for each protocol, but make sure it will only include prefixes that are actually used, so as to not perform unnecessary lookups. Since changing the structure of a bound tree isn't recommended, whenever a new tree it required, it's first created and then bound to each virtual router, replacing the old one. Signed-off-by: Ido Schimmel <idosch@mellanox.com> Signed-off-by: Jiri Pirko <jiri@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 0adb214 commit fc922bb

File tree

1 file changed

+165
-94
lines changed

1 file changed

+165
-94
lines changed

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

Lines changed: 165 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -320,19 +320,6 @@ struct mlxsw_sp_prefix_usage {
320320
#define mlxsw_sp_prefix_usage_for_each(prefix, prefix_usage) \
321321
for_each_set_bit(prefix, (prefix_usage)->b, MLXSW_SP_PREFIX_COUNT)
322322

323-
static bool
324-
mlxsw_sp_prefix_usage_subset(struct mlxsw_sp_prefix_usage *prefix_usage1,
325-
struct mlxsw_sp_prefix_usage *prefix_usage2)
326-
{
327-
unsigned char prefix;
328-
329-
mlxsw_sp_prefix_usage_for_each(prefix, prefix_usage1) {
330-
if (!test_bit(prefix, prefix_usage2->b))
331-
return false;
332-
}
333-
return true;
334-
}
335-
336323
static bool
337324
mlxsw_sp_prefix_usage_eq(struct mlxsw_sp_prefix_usage *prefix_usage1,
338325
struct mlxsw_sp_prefix_usage *prefix_usage2)
@@ -589,16 +576,14 @@ mlxsw_sp_lpm_tree_get(struct mlxsw_sp *mlxsw_sp,
589576
lpm_tree->proto == proto &&
590577
mlxsw_sp_prefix_usage_eq(&lpm_tree->prefix_usage,
591578
prefix_usage))
592-
goto inc_ref_count;
579+
return lpm_tree;
593580
}
594-
lpm_tree = mlxsw_sp_lpm_tree_create(mlxsw_sp, prefix_usage,
595-
proto);
596-
if (IS_ERR(lpm_tree))
597-
return lpm_tree;
581+
return mlxsw_sp_lpm_tree_create(mlxsw_sp, prefix_usage, proto);
582+
}
598583

599-
inc_ref_count:
584+
static void mlxsw_sp_lpm_tree_hold(struct mlxsw_sp_lpm_tree *lpm_tree)
585+
{
600586
lpm_tree->ref_count++;
601-
return lpm_tree;
602587
}
603588

604589
static void mlxsw_sp_lpm_tree_put(struct mlxsw_sp *mlxsw_sp,
@@ -750,46 +735,6 @@ static void mlxsw_sp_vr_destroy(struct mlxsw_sp_vr *vr)
750735
vr->fib4 = NULL;
751736
}
752737

753-
static int
754-
mlxsw_sp_vr_lpm_tree_check(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fib *fib,
755-
struct mlxsw_sp_prefix_usage *req_prefix_usage)
756-
{
757-
struct mlxsw_sp_lpm_tree *lpm_tree = fib->lpm_tree;
758-
struct mlxsw_sp_lpm_tree *new_tree;
759-
int err;
760-
761-
if (mlxsw_sp_prefix_usage_eq(req_prefix_usage, &lpm_tree->prefix_usage))
762-
return 0;
763-
764-
new_tree = mlxsw_sp_lpm_tree_get(mlxsw_sp, req_prefix_usage,
765-
fib->proto);
766-
if (IS_ERR(new_tree)) {
767-
/* We failed to get a tree according to the required
768-
* prefix usage. However, the current tree might be still good
769-
* for us if our requirement is subset of the prefixes used
770-
* in the tree.
771-
*/
772-
if (mlxsw_sp_prefix_usage_subset(req_prefix_usage,
773-
&lpm_tree->prefix_usage))
774-
return 0;
775-
return PTR_ERR(new_tree);
776-
}
777-
778-
/* Prevent packet loss by overwriting existing binding */
779-
fib->lpm_tree = new_tree;
780-
err = mlxsw_sp_vr_lpm_tree_bind(mlxsw_sp, fib, new_tree->id);
781-
if (err)
782-
goto err_tree_bind;
783-
mlxsw_sp_lpm_tree_put(mlxsw_sp, lpm_tree);
784-
785-
return 0;
786-
787-
err_tree_bind:
788-
fib->lpm_tree = lpm_tree;
789-
mlxsw_sp_lpm_tree_put(mlxsw_sp, new_tree);
790-
return err;
791-
}
792-
793738
static struct mlxsw_sp_vr *mlxsw_sp_vr_get(struct mlxsw_sp *mlxsw_sp, u32 tb_id)
794739
{
795740
struct mlxsw_sp_vr *vr;
@@ -808,6 +753,100 @@ static void mlxsw_sp_vr_put(struct mlxsw_sp_vr *vr)
808753
mlxsw_sp_vr_destroy(vr);
809754
}
810755

756+
static bool
757+
mlxsw_sp_vr_lpm_tree_should_replace(struct mlxsw_sp_vr *vr,
758+
enum mlxsw_sp_l3proto proto, u8 tree_id)
759+
{
760+
struct mlxsw_sp_fib *fib = mlxsw_sp_vr_fib(vr, proto);
761+
762+
if (!mlxsw_sp_vr_is_used(vr))
763+
return false;
764+
if (fib->lpm_tree && fib->lpm_tree->id == tree_id)
765+
return true;
766+
return false;
767+
}
768+
769+
static int mlxsw_sp_vr_lpm_tree_replace(struct mlxsw_sp *mlxsw_sp,
770+
struct mlxsw_sp_fib *fib,
771+
struct mlxsw_sp_lpm_tree *new_tree)
772+
{
773+
struct mlxsw_sp_lpm_tree *old_tree = fib->lpm_tree;
774+
int err;
775+
776+
err = mlxsw_sp_vr_lpm_tree_bind(mlxsw_sp, fib, new_tree->id);
777+
if (err)
778+
return err;
779+
fib->lpm_tree = new_tree;
780+
mlxsw_sp_lpm_tree_hold(new_tree);
781+
mlxsw_sp_lpm_tree_put(mlxsw_sp, old_tree);
782+
return 0;
783+
}
784+
785+
static int mlxsw_sp_vrs_lpm_tree_replace(struct mlxsw_sp *mlxsw_sp,
786+
struct mlxsw_sp_fib *fib,
787+
struct mlxsw_sp_lpm_tree *new_tree)
788+
{
789+
struct mlxsw_sp_lpm_tree *old_tree = fib->lpm_tree;
790+
enum mlxsw_sp_l3proto proto = fib->proto;
791+
u8 old_id, new_id = new_tree->id;
792+
struct mlxsw_sp_vr *vr;
793+
int i, err;
794+
795+
if (!old_tree)
796+
goto no_replace;
797+
old_id = old_tree->id;
798+
799+
for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) {
800+
vr = &mlxsw_sp->router->vrs[i];
801+
if (!mlxsw_sp_vr_lpm_tree_should_replace(vr, proto, old_id))
802+
continue;
803+
err = mlxsw_sp_vr_lpm_tree_replace(mlxsw_sp,
804+
mlxsw_sp_vr_fib(vr, proto),
805+
new_tree);
806+
if (err)
807+
goto err_tree_replace;
808+
}
809+
810+
return 0;
811+
812+
err_tree_replace:
813+
for (i--; i >= 0; i--) {
814+
if (!mlxsw_sp_vr_lpm_tree_should_replace(vr, proto, new_id))
815+
continue;
816+
mlxsw_sp_vr_lpm_tree_replace(mlxsw_sp,
817+
mlxsw_sp_vr_fib(vr, proto),
818+
old_tree);
819+
}
820+
return err;
821+
822+
no_replace:
823+
err = mlxsw_sp_vr_lpm_tree_bind(mlxsw_sp, fib, new_tree->id);
824+
if (err)
825+
return err;
826+
fib->lpm_tree = new_tree;
827+
mlxsw_sp_lpm_tree_hold(new_tree);
828+
return 0;
829+
}
830+
831+
static void
832+
mlxsw_sp_vrs_prefixes(struct mlxsw_sp *mlxsw_sp,
833+
enum mlxsw_sp_l3proto proto,
834+
struct mlxsw_sp_prefix_usage *req_prefix_usage)
835+
{
836+
int i;
837+
838+
for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) {
839+
struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[i];
840+
struct mlxsw_sp_fib *fib = mlxsw_sp_vr_fib(vr, proto);
841+
unsigned char prefix;
842+
843+
if (!mlxsw_sp_vr_is_used(vr))
844+
continue;
845+
mlxsw_sp_prefix_usage_for_each(prefix, &fib->prefix_usage)
846+
mlxsw_sp_prefix_usage_set(req_prefix_usage, prefix);
847+
}
848+
}
849+
811850
static int mlxsw_sp_vrs_init(struct mlxsw_sp *mlxsw_sp)
812851
{
813852
struct mlxsw_sp_vr *vr;
@@ -2586,6 +2625,67 @@ mlxsw_sp_fib_node_entry_is_first(const struct mlxsw_sp_fib_node *fib_node,
25862625
struct mlxsw_sp_fib_entry, list) == fib_entry;
25872626
}
25882627

2628+
static int mlxsw_sp_fib_lpm_tree_link(struct mlxsw_sp *mlxsw_sp,
2629+
struct mlxsw_sp_fib *fib,
2630+
struct mlxsw_sp_fib_node *fib_node)
2631+
{
2632+
struct mlxsw_sp_prefix_usage req_prefix_usage = {{ 0 } };
2633+
struct mlxsw_sp_lpm_tree *lpm_tree;
2634+
int err;
2635+
2636+
/* Since the tree is shared between all virtual routers we must
2637+
* make sure it contains all the required prefix lengths. This
2638+
* can be computed by either adding the new prefix length to the
2639+
* existing prefix usage of a bound tree, or by aggregating the
2640+
* prefix lengths across all virtual routers and adding the new
2641+
* one as well.
2642+
*/
2643+
if (fib->lpm_tree)
2644+
mlxsw_sp_prefix_usage_cpy(&req_prefix_usage,
2645+
&fib->lpm_tree->prefix_usage);
2646+
else
2647+
mlxsw_sp_vrs_prefixes(mlxsw_sp, fib->proto, &req_prefix_usage);
2648+
mlxsw_sp_prefix_usage_set(&req_prefix_usage, fib_node->key.prefix_len);
2649+
2650+
lpm_tree = mlxsw_sp_lpm_tree_get(mlxsw_sp, &req_prefix_usage,
2651+
fib->proto);
2652+
if (IS_ERR(lpm_tree))
2653+
return PTR_ERR(lpm_tree);
2654+
2655+
if (fib->lpm_tree && fib->lpm_tree->id == lpm_tree->id)
2656+
return 0;
2657+
2658+
err = mlxsw_sp_vrs_lpm_tree_replace(mlxsw_sp, fib, lpm_tree);
2659+
if (err)
2660+
return err;
2661+
2662+
return 0;
2663+
}
2664+
2665+
static void mlxsw_sp_fib_lpm_tree_unlink(struct mlxsw_sp *mlxsw_sp,
2666+
struct mlxsw_sp_fib *fib)
2667+
{
2668+
struct mlxsw_sp_prefix_usage req_prefix_usage = {{ 0 } };
2669+
struct mlxsw_sp_lpm_tree *lpm_tree;
2670+
2671+
/* Aggregate prefix lengths across all virtual routers to make
2672+
* sure we only have used prefix lengths in the LPM tree.
2673+
*/
2674+
mlxsw_sp_vrs_prefixes(mlxsw_sp, fib->proto, &req_prefix_usage);
2675+
lpm_tree = mlxsw_sp_lpm_tree_get(mlxsw_sp, &req_prefix_usage,
2676+
fib->proto);
2677+
if (IS_ERR(lpm_tree))
2678+
goto err_tree_get;
2679+
mlxsw_sp_vrs_lpm_tree_replace(mlxsw_sp, fib, lpm_tree);
2680+
2681+
err_tree_get:
2682+
if (!mlxsw_sp_prefix_usage_none(&fib->prefix_usage))
2683+
return;
2684+
mlxsw_sp_vr_lpm_tree_unbind(mlxsw_sp, fib);
2685+
mlxsw_sp_lpm_tree_put(mlxsw_sp, fib->lpm_tree);
2686+
fib->lpm_tree = NULL;
2687+
}
2688+
25892689
static void mlxsw_sp_fib_node_prefix_inc(struct mlxsw_sp_fib_node *fib_node)
25902690
{
25912691
unsigned char prefix_len = fib_node->key.prefix_len;
@@ -2608,42 +2708,22 @@ static int mlxsw_sp_fib_node_init(struct mlxsw_sp *mlxsw_sp,
26082708
struct mlxsw_sp_fib_node *fib_node,
26092709
struct mlxsw_sp_fib *fib)
26102710
{
2611-
struct mlxsw_sp_prefix_usage req_prefix_usage;
2612-
struct mlxsw_sp_lpm_tree *lpm_tree;
26132711
int err;
26142712

26152713
err = mlxsw_sp_fib_node_insert(fib, fib_node);
26162714
if (err)
26172715
return err;
26182716
fib_node->fib = fib;
26192717

2620-
mlxsw_sp_prefix_usage_cpy(&req_prefix_usage, &fib->prefix_usage);
2621-
mlxsw_sp_prefix_usage_set(&req_prefix_usage, fib_node->key.prefix_len);
2622-
2623-
if (!mlxsw_sp_prefix_usage_none(&fib->prefix_usage)) {
2624-
err = mlxsw_sp_vr_lpm_tree_check(mlxsw_sp, fib,
2625-
&req_prefix_usage);
2626-
if (err)
2627-
goto err_tree_check;
2628-
} else {
2629-
lpm_tree = mlxsw_sp_lpm_tree_get(mlxsw_sp, &req_prefix_usage,
2630-
fib->proto);
2631-
if (IS_ERR(lpm_tree))
2632-
return PTR_ERR(lpm_tree);
2633-
fib->lpm_tree = lpm_tree;
2634-
err = mlxsw_sp_vr_lpm_tree_bind(mlxsw_sp, fib, lpm_tree->id);
2635-
if (err)
2636-
goto err_tree_bind;
2637-
}
2718+
err = mlxsw_sp_fib_lpm_tree_link(mlxsw_sp, fib, fib_node);
2719+
if (err)
2720+
goto err_fib_lpm_tree_link;
26382721

26392722
mlxsw_sp_fib_node_prefix_inc(fib_node);
26402723

26412724
return 0;
26422725

2643-
err_tree_bind:
2644-
fib->lpm_tree = NULL;
2645-
mlxsw_sp_lpm_tree_put(mlxsw_sp, lpm_tree);
2646-
err_tree_check:
2726+
err_fib_lpm_tree_link:
26472727
fib_node->fib = NULL;
26482728
mlxsw_sp_fib_node_remove(fib, fib_node);
26492729
return err;
@@ -2652,19 +2732,10 @@ static int mlxsw_sp_fib_node_init(struct mlxsw_sp *mlxsw_sp,
26522732
static void mlxsw_sp_fib_node_fini(struct mlxsw_sp *mlxsw_sp,
26532733
struct mlxsw_sp_fib_node *fib_node)
26542734
{
2655-
struct mlxsw_sp_lpm_tree *lpm_tree = fib_node->fib->lpm_tree;
26562735
struct mlxsw_sp_fib *fib = fib_node->fib;
26572736

26582737
mlxsw_sp_fib_node_prefix_dec(fib_node);
2659-
2660-
if (mlxsw_sp_prefix_usage_none(&fib->prefix_usage)) {
2661-
mlxsw_sp_vr_lpm_tree_unbind(mlxsw_sp, fib);
2662-
fib->lpm_tree = NULL;
2663-
mlxsw_sp_lpm_tree_put(mlxsw_sp, lpm_tree);
2664-
} else {
2665-
mlxsw_sp_vr_lpm_tree_check(mlxsw_sp, fib, &fib->prefix_usage);
2666-
}
2667-
2738+
mlxsw_sp_fib_lpm_tree_unlink(mlxsw_sp, fib);
26682739
fib_node->fib = NULL;
26692740
mlxsw_sp_fib_node_remove(fib, fib_node);
26702741
}

0 commit comments

Comments
 (0)