aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2018-01-22 09:22:11 -0500
committerDavid S. Miller <davem@davemloft.net>2018-01-22 09:22:11 -0500
commit2ae50dea1d5566ea054d96e413a86017066d3528 (patch)
tree5f8907de0f205a4f96fd8c4dd5772592006816af
parent9d6474e458b13a94a0d5b141f2b8f38adf1991ae (diff)
parent2b52ce02e1d17986ad7da8bc6e96c632dfa73219 (diff)
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: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c243
1 files changed, 132 insertions, 111 deletions
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
index 31891ae11c9b..91170d940268 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
@@ -71,6 +71,7 @@
71#include "spectrum_mr_tcam.h" 71#include "spectrum_mr_tcam.h"
72#include "spectrum_router.h" 72#include "spectrum_router.h"
73 73
74struct mlxsw_sp_fib;
74struct mlxsw_sp_vr; 75struct mlxsw_sp_vr;
75struct mlxsw_sp_lpm_tree; 76struct mlxsw_sp_lpm_tree;
76struct mlxsw_sp_rif_ops; 77struct mlxsw_sp_rif_ops;
@@ -84,6 +85,8 @@ struct mlxsw_sp_router {
84 struct rhashtable nexthop_ht; 85 struct rhashtable nexthop_ht;
85 struct list_head nexthop_list; 86 struct list_head nexthop_list;
86 struct { 87 struct {
88 /* One tree for each protocol: IPv4 and IPv6 */
89 struct mlxsw_sp_lpm_tree *proto_trees[2];
87 struct mlxsw_sp_lpm_tree *trees; 90 struct mlxsw_sp_lpm_tree *trees;
88 unsigned int tree_count; 91 unsigned int tree_count;
89 } lpm; 92 } lpm;
@@ -162,6 +165,15 @@ struct mlxsw_sp_rif_ops {
162 struct mlxsw_sp_fid * (*fid_get)(struct mlxsw_sp_rif *rif); 165 struct mlxsw_sp_fid * (*fid_get)(struct mlxsw_sp_rif *rif);
163}; 166};
164 167
168static void mlxsw_sp_lpm_tree_hold(struct mlxsw_sp_lpm_tree *lpm_tree);
169static void mlxsw_sp_lpm_tree_put(struct mlxsw_sp *mlxsw_sp,
170 struct mlxsw_sp_lpm_tree *lpm_tree);
171static int mlxsw_sp_vr_lpm_tree_bind(struct mlxsw_sp *mlxsw_sp,
172 const struct mlxsw_sp_fib *fib,
173 u8 tree_id);
174static int mlxsw_sp_vr_lpm_tree_unbind(struct mlxsw_sp *mlxsw_sp,
175 const struct mlxsw_sp_fib *fib);
176
165static unsigned int * 177static unsigned int *
166mlxsw_sp_rif_p_counter_get(struct mlxsw_sp_rif *rif, 178mlxsw_sp_rif_p_counter_get(struct mlxsw_sp_rif *rif,
167 enum mlxsw_sp_rif_counter_dir dir) 179 enum mlxsw_sp_rif_counter_dir dir)
@@ -349,14 +361,6 @@ mlxsw_sp_prefix_usage_eq(struct mlxsw_sp_prefix_usage *prefix_usage1,
349 return !memcmp(prefix_usage1, prefix_usage2, sizeof(*prefix_usage1)); 361 return !memcmp(prefix_usage1, prefix_usage2, sizeof(*prefix_usage1));
350} 362}
351 363
352static bool
353mlxsw_sp_prefix_usage_none(struct mlxsw_sp_prefix_usage *prefix_usage)
354{
355 struct mlxsw_sp_prefix_usage prefix_usage_none = {{ 0 } };
356
357 return mlxsw_sp_prefix_usage_eq(prefix_usage, &prefix_usage_none);
358}
359
360static void 364static void
361mlxsw_sp_prefix_usage_cpy(struct mlxsw_sp_prefix_usage *prefix_usage1, 365mlxsw_sp_prefix_usage_cpy(struct mlxsw_sp_prefix_usage *prefix_usage1,
362 struct mlxsw_sp_prefix_usage *prefix_usage2) 366 struct mlxsw_sp_prefix_usage *prefix_usage2)
@@ -398,7 +402,6 @@ enum mlxsw_sp_fib_entry_type {
398}; 402};
399 403
400struct mlxsw_sp_nexthop_group; 404struct mlxsw_sp_nexthop_group;
401struct mlxsw_sp_fib;
402 405
403struct mlxsw_sp_fib_node { 406struct mlxsw_sp_fib_node {
404 struct list_head entry_list; 407 struct list_head entry_list;
@@ -445,6 +448,7 @@ struct mlxsw_sp_lpm_tree {
445 u8 id; /* tree ID */ 448 u8 id; /* tree ID */
446 unsigned int ref_count; 449 unsigned int ref_count;
447 enum mlxsw_sp_l3proto proto; 450 enum mlxsw_sp_l3proto proto;
451 unsigned long prefix_ref_count[MLXSW_SP_PREFIX_COUNT];
448 struct mlxsw_sp_prefix_usage prefix_usage; 452 struct mlxsw_sp_prefix_usage prefix_usage;
449}; 453};
450 454
@@ -453,8 +457,6 @@ struct mlxsw_sp_fib {
453 struct list_head node_list; 457 struct list_head node_list;
454 struct mlxsw_sp_vr *vr; 458 struct mlxsw_sp_vr *vr;
455 struct mlxsw_sp_lpm_tree *lpm_tree; 459 struct mlxsw_sp_lpm_tree *lpm_tree;
456 unsigned long prefix_ref_count[MLXSW_SP_PREFIX_COUNT];
457 struct mlxsw_sp_prefix_usage prefix_usage;
458 enum mlxsw_sp_l3proto proto; 460 enum mlxsw_sp_l3proto proto;
459}; 461};
460 462
@@ -469,12 +471,15 @@ struct mlxsw_sp_vr {
469 471
470static const struct rhashtable_params mlxsw_sp_fib_ht_params; 472static const struct rhashtable_params mlxsw_sp_fib_ht_params;
471 473
472static struct mlxsw_sp_fib *mlxsw_sp_fib_create(struct mlxsw_sp_vr *vr, 474static struct mlxsw_sp_fib *mlxsw_sp_fib_create(struct mlxsw_sp *mlxsw_sp,
475 struct mlxsw_sp_vr *vr,
473 enum mlxsw_sp_l3proto proto) 476 enum mlxsw_sp_l3proto proto)
474{ 477{
478 struct mlxsw_sp_lpm_tree *lpm_tree;
475 struct mlxsw_sp_fib *fib; 479 struct mlxsw_sp_fib *fib;
476 int err; 480 int err;
477 481
482 lpm_tree = mlxsw_sp->router->lpm.proto_trees[proto];
478 fib = kzalloc(sizeof(*fib), GFP_KERNEL); 483 fib = kzalloc(sizeof(*fib), GFP_KERNEL);
479 if (!fib) 484 if (!fib)
480 return ERR_PTR(-ENOMEM); 485 return ERR_PTR(-ENOMEM);
@@ -484,17 +489,26 @@ static struct mlxsw_sp_fib *mlxsw_sp_fib_create(struct mlxsw_sp_vr *vr,
484 INIT_LIST_HEAD(&fib->node_list); 489 INIT_LIST_HEAD(&fib->node_list);
485 fib->proto = proto; 490 fib->proto = proto;
486 fib->vr = vr; 491 fib->vr = vr;
492 fib->lpm_tree = lpm_tree;
493 mlxsw_sp_lpm_tree_hold(lpm_tree);
494 err = mlxsw_sp_vr_lpm_tree_bind(mlxsw_sp, fib, lpm_tree->id);
495 if (err)
496 goto err_lpm_tree_bind;
487 return fib; 497 return fib;
488 498
499err_lpm_tree_bind:
500 mlxsw_sp_lpm_tree_put(mlxsw_sp, lpm_tree);
489err_rhashtable_init: 501err_rhashtable_init:
490 kfree(fib); 502 kfree(fib);
491 return ERR_PTR(err); 503 return ERR_PTR(err);
492} 504}
493 505
494static void mlxsw_sp_fib_destroy(struct mlxsw_sp_fib *fib) 506static void mlxsw_sp_fib_destroy(struct mlxsw_sp *mlxsw_sp,
507 struct mlxsw_sp_fib *fib)
495{ 508{
509 mlxsw_sp_vr_lpm_tree_unbind(mlxsw_sp, fib);
510 mlxsw_sp_lpm_tree_put(mlxsw_sp, fib->lpm_tree);
496 WARN_ON(!list_empty(&fib->node_list)); 511 WARN_ON(!list_empty(&fib->node_list));
497 WARN_ON(fib->lpm_tree);
498 rhashtable_destroy(&fib->ht); 512 rhashtable_destroy(&fib->ht);
499 kfree(fib); 513 kfree(fib);
500} 514}
@@ -581,6 +595,9 @@ mlxsw_sp_lpm_tree_create(struct mlxsw_sp *mlxsw_sp,
581 goto err_left_struct_set; 595 goto err_left_struct_set;
582 memcpy(&lpm_tree->prefix_usage, prefix_usage, 596 memcpy(&lpm_tree->prefix_usage, prefix_usage,
583 sizeof(lpm_tree->prefix_usage)); 597 sizeof(lpm_tree->prefix_usage));
598 memset(&lpm_tree->prefix_ref_count, 0,
599 sizeof(lpm_tree->prefix_ref_count));
600 lpm_tree->ref_count = 1;
584 return lpm_tree; 601 return lpm_tree;
585 602
586err_left_struct_set: 603err_left_struct_set:
@@ -607,8 +624,10 @@ mlxsw_sp_lpm_tree_get(struct mlxsw_sp *mlxsw_sp,
607 if (lpm_tree->ref_count != 0 && 624 if (lpm_tree->ref_count != 0 &&
608 lpm_tree->proto == proto && 625 lpm_tree->proto == proto &&
609 mlxsw_sp_prefix_usage_eq(&lpm_tree->prefix_usage, 626 mlxsw_sp_prefix_usage_eq(&lpm_tree->prefix_usage,
610 prefix_usage)) 627 prefix_usage)) {
628 mlxsw_sp_lpm_tree_hold(lpm_tree);
611 return lpm_tree; 629 return lpm_tree;
630 }
612 } 631 }
613 return mlxsw_sp_lpm_tree_create(mlxsw_sp, prefix_usage, proto); 632 return mlxsw_sp_lpm_tree_create(mlxsw_sp, prefix_usage, proto);
614} 633}
@@ -629,9 +648,10 @@ static void mlxsw_sp_lpm_tree_put(struct mlxsw_sp *mlxsw_sp,
629 648
630static int mlxsw_sp_lpm_init(struct mlxsw_sp *mlxsw_sp) 649static int mlxsw_sp_lpm_init(struct mlxsw_sp *mlxsw_sp)
631{ 650{
651 struct mlxsw_sp_prefix_usage req_prefix_usage = {{ 0 } };
632 struct mlxsw_sp_lpm_tree *lpm_tree; 652 struct mlxsw_sp_lpm_tree *lpm_tree;
633 u64 max_trees; 653 u64 max_trees;
634 int i; 654 int err, i;
635 655
636 if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_LPM_TREES)) 656 if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_LPM_TREES))
637 return -EIO; 657 return -EIO;
@@ -649,11 +669,42 @@ static int mlxsw_sp_lpm_init(struct mlxsw_sp *mlxsw_sp)
649 lpm_tree->id = i + MLXSW_SP_LPM_TREE_MIN; 669 lpm_tree->id = i + MLXSW_SP_LPM_TREE_MIN;
650 } 670 }
651 671
672 lpm_tree = mlxsw_sp_lpm_tree_get(mlxsw_sp, &req_prefix_usage,
673 MLXSW_SP_L3_PROTO_IPV4);
674 if (IS_ERR(lpm_tree)) {
675 err = PTR_ERR(lpm_tree);
676 goto err_ipv4_tree_get;
677 }
678 mlxsw_sp->router->lpm.proto_trees[MLXSW_SP_L3_PROTO_IPV4] = lpm_tree;
679
680 lpm_tree = mlxsw_sp_lpm_tree_get(mlxsw_sp, &req_prefix_usage,
681 MLXSW_SP_L3_PROTO_IPV6);
682 if (IS_ERR(lpm_tree)) {
683 err = PTR_ERR(lpm_tree);
684 goto err_ipv6_tree_get;
685 }
686 mlxsw_sp->router->lpm.proto_trees[MLXSW_SP_L3_PROTO_IPV6] = lpm_tree;
687
652 return 0; 688 return 0;
689
690err_ipv6_tree_get:
691 lpm_tree = mlxsw_sp->router->lpm.proto_trees[MLXSW_SP_L3_PROTO_IPV4];
692 mlxsw_sp_lpm_tree_put(mlxsw_sp, lpm_tree);
693err_ipv4_tree_get:
694 kfree(mlxsw_sp->router->lpm.trees);
695 return err;
653} 696}
654 697
655static void mlxsw_sp_lpm_fini(struct mlxsw_sp *mlxsw_sp) 698static void mlxsw_sp_lpm_fini(struct mlxsw_sp *mlxsw_sp)
656{ 699{
700 struct mlxsw_sp_lpm_tree *lpm_tree;
701
702 lpm_tree = mlxsw_sp->router->lpm.proto_trees[MLXSW_SP_L3_PROTO_IPV6];
703 mlxsw_sp_lpm_tree_put(mlxsw_sp, lpm_tree);
704
705 lpm_tree = mlxsw_sp->router->lpm.proto_trees[MLXSW_SP_L3_PROTO_IPV4];
706 mlxsw_sp_lpm_tree_put(mlxsw_sp, lpm_tree);
707
657 kfree(mlxsw_sp->router->lpm.trees); 708 kfree(mlxsw_sp->router->lpm.trees);
658} 709}
659 710
@@ -745,10 +796,10 @@ static struct mlxsw_sp_vr *mlxsw_sp_vr_create(struct mlxsw_sp *mlxsw_sp,
745 NL_SET_ERR_MSG(extack, "spectrum: Exceeded number of supported virtual routers"); 796 NL_SET_ERR_MSG(extack, "spectrum: Exceeded number of supported virtual routers");
746 return ERR_PTR(-EBUSY); 797 return ERR_PTR(-EBUSY);
747 } 798 }
748 vr->fib4 = mlxsw_sp_fib_create(vr, MLXSW_SP_L3_PROTO_IPV4); 799 vr->fib4 = mlxsw_sp_fib_create(mlxsw_sp, vr, MLXSW_SP_L3_PROTO_IPV4);
749 if (IS_ERR(vr->fib4)) 800 if (IS_ERR(vr->fib4))
750 return ERR_CAST(vr->fib4); 801 return ERR_CAST(vr->fib4);
751 vr->fib6 = mlxsw_sp_fib_create(vr, MLXSW_SP_L3_PROTO_IPV6); 802 vr->fib6 = mlxsw_sp_fib_create(mlxsw_sp, vr, MLXSW_SP_L3_PROTO_IPV6);
752 if (IS_ERR(vr->fib6)) { 803 if (IS_ERR(vr->fib6)) {
753 err = PTR_ERR(vr->fib6); 804 err = PTR_ERR(vr->fib6);
754 goto err_fib6_create; 805 goto err_fib6_create;
@@ -763,21 +814,22 @@ static struct mlxsw_sp_vr *mlxsw_sp_vr_create(struct mlxsw_sp *mlxsw_sp,
763 return vr; 814 return vr;
764 815
765err_mr_table_create: 816err_mr_table_create:
766 mlxsw_sp_fib_destroy(vr->fib6); 817 mlxsw_sp_fib_destroy(mlxsw_sp, vr->fib6);
767 vr->fib6 = NULL; 818 vr->fib6 = NULL;
768err_fib6_create: 819err_fib6_create:
769 mlxsw_sp_fib_destroy(vr->fib4); 820 mlxsw_sp_fib_destroy(mlxsw_sp, vr->fib4);
770 vr->fib4 = NULL; 821 vr->fib4 = NULL;
771 return ERR_PTR(err); 822 return ERR_PTR(err);
772} 823}
773 824
774static void mlxsw_sp_vr_destroy(struct mlxsw_sp_vr *vr) 825static void mlxsw_sp_vr_destroy(struct mlxsw_sp *mlxsw_sp,
826 struct mlxsw_sp_vr *vr)
775{ 827{
776 mlxsw_sp_mr_table_destroy(vr->mr4_table); 828 mlxsw_sp_mr_table_destroy(vr->mr4_table);
777 vr->mr4_table = NULL; 829 vr->mr4_table = NULL;
778 mlxsw_sp_fib_destroy(vr->fib6); 830 mlxsw_sp_fib_destroy(mlxsw_sp, vr->fib6);
779 vr->fib6 = NULL; 831 vr->fib6 = NULL;
780 mlxsw_sp_fib_destroy(vr->fib4); 832 mlxsw_sp_fib_destroy(mlxsw_sp, vr->fib4);
781 vr->fib4 = NULL; 833 vr->fib4 = NULL;
782} 834}
783 835
@@ -793,12 +845,12 @@ static struct mlxsw_sp_vr *mlxsw_sp_vr_get(struct mlxsw_sp *mlxsw_sp, u32 tb_id,
793 return vr; 845 return vr;
794} 846}
795 847
796static void mlxsw_sp_vr_put(struct mlxsw_sp_vr *vr) 848static void mlxsw_sp_vr_put(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_vr *vr)
797{ 849{
798 if (!vr->rif_count && list_empty(&vr->fib4->node_list) && 850 if (!vr->rif_count && list_empty(&vr->fib4->node_list) &&
799 list_empty(&vr->fib6->node_list) && 851 list_empty(&vr->fib6->node_list) &&
800 mlxsw_sp_mr_table_empty(vr->mr4_table)) 852 mlxsw_sp_mr_table_empty(vr->mr4_table))
801 mlxsw_sp_vr_destroy(vr); 853 mlxsw_sp_vr_destroy(mlxsw_sp, vr);
802} 854}
803 855
804static bool 856static bool
@@ -809,7 +861,7 @@ mlxsw_sp_vr_lpm_tree_should_replace(struct mlxsw_sp_vr *vr,
809 861
810 if (!mlxsw_sp_vr_is_used(vr)) 862 if (!mlxsw_sp_vr_is_used(vr))
811 return false; 863 return false;
812 if (fib->lpm_tree && fib->lpm_tree->id == tree_id) 864 if (fib->lpm_tree->id == tree_id)
813 return true; 865 return true;
814 return false; 866 return false;
815} 867}
@@ -839,14 +891,13 @@ static int mlxsw_sp_vrs_lpm_tree_replace(struct mlxsw_sp *mlxsw_sp,
839 struct mlxsw_sp_fib *fib, 891 struct mlxsw_sp_fib *fib,
840 struct mlxsw_sp_lpm_tree *new_tree) 892 struct mlxsw_sp_lpm_tree *new_tree)
841{ 893{
842 struct mlxsw_sp_lpm_tree *old_tree = fib->lpm_tree;
843 enum mlxsw_sp_l3proto proto = fib->proto; 894 enum mlxsw_sp_l3proto proto = fib->proto;
895 struct mlxsw_sp_lpm_tree *old_tree;
844 u8 old_id, new_id = new_tree->id; 896 u8 old_id, new_id = new_tree->id;
845 struct mlxsw_sp_vr *vr; 897 struct mlxsw_sp_vr *vr;
846 int i, err; 898 int i, err;
847 899
848 if (!old_tree) 900 old_tree = mlxsw_sp->router->lpm.proto_trees[proto];
849 goto no_replace;
850 old_id = old_tree->id; 901 old_id = old_tree->id;
851 902
852 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) { 903 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 goto err_tree_replace; 911 goto err_tree_replace;
861 } 912 }
862 913
914 memcpy(new_tree->prefix_ref_count, old_tree->prefix_ref_count,
915 sizeof(new_tree->prefix_ref_count));
916 mlxsw_sp->router->lpm.proto_trees[proto] = new_tree;
917 mlxsw_sp_lpm_tree_put(mlxsw_sp, old_tree);
918
863 return 0; 919 return 0;
864 920
865err_tree_replace: 921err_tree_replace:
@@ -871,36 +927,6 @@ err_tree_replace:
871 old_tree); 927 old_tree);
872 } 928 }
873 return err; 929 return err;
874
875no_replace:
876 fib->lpm_tree = new_tree;
877 mlxsw_sp_lpm_tree_hold(new_tree);
878 err = mlxsw_sp_vr_lpm_tree_bind(mlxsw_sp, fib, new_tree->id);
879 if (err) {
880 mlxsw_sp_lpm_tree_put(mlxsw_sp, new_tree);
881 fib->lpm_tree = NULL;
882 return err;
883 }
884 return 0;
885}
886
887static void
888mlxsw_sp_vrs_prefixes(struct mlxsw_sp *mlxsw_sp,
889 enum mlxsw_sp_l3proto proto,
890 struct mlxsw_sp_prefix_usage *req_prefix_usage)
891{
892 int i;
893
894 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) {
895 struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[i];
896 struct mlxsw_sp_fib *fib = mlxsw_sp_vr_fib(vr, proto);
897 unsigned char prefix;
898
899 if (!mlxsw_sp_vr_is_used(vr))
900 continue;
901 mlxsw_sp_prefix_usage_for_each(prefix, &fib->prefix_usage)
902 mlxsw_sp_prefix_usage_set(req_prefix_usage, prefix);
903 }
904} 930}
905 931
906static int mlxsw_sp_vrs_init(struct mlxsw_sp *mlxsw_sp) 932static 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} 4227}
4202 4228
4203static int mlxsw_sp_fib_lpm_tree_link(struct mlxsw_sp *mlxsw_sp, 4229static int mlxsw_sp_fib_lpm_tree_link(struct mlxsw_sp *mlxsw_sp,
4204 struct mlxsw_sp_fib *fib,
4205 struct mlxsw_sp_fib_node *fib_node) 4230 struct mlxsw_sp_fib_node *fib_node)
4206{ 4231{
4207 struct mlxsw_sp_prefix_usage req_prefix_usage = {{ 0 } }; 4232 struct mlxsw_sp_prefix_usage req_prefix_usage;
4233 struct mlxsw_sp_fib *fib = fib_node->fib;
4208 struct mlxsw_sp_lpm_tree *lpm_tree; 4234 struct mlxsw_sp_lpm_tree *lpm_tree;
4209 int err; 4235 int err;
4210 4236
4211 /* Since the tree is shared between all virtual routers we must 4237 lpm_tree = mlxsw_sp->router->lpm.proto_trees[fib->proto];
4212 * make sure it contains all the required prefix lengths. This 4238 if (lpm_tree->prefix_ref_count[fib_node->key.prefix_len] != 0)
4213 * can be computed by either adding the new prefix length to the 4239 goto out;
4214 * existing prefix usage of a bound tree, or by aggregating the
4215 * prefix lengths across all virtual routers and adding the new
4216 * one as well.
4217 */
4218 if (fib->lpm_tree)
4219 mlxsw_sp_prefix_usage_cpy(&req_prefix_usage,
4220 &fib->lpm_tree->prefix_usage);
4221 else
4222 mlxsw_sp_vrs_prefixes(mlxsw_sp, fib->proto, &req_prefix_usage);
4223 mlxsw_sp_prefix_usage_set(&req_prefix_usage, fib_node->key.prefix_len);
4224 4240
4241 mlxsw_sp_prefix_usage_cpy(&req_prefix_usage, &lpm_tree->prefix_usage);
4242 mlxsw_sp_prefix_usage_set(&req_prefix_usage, fib_node->key.prefix_len);
4225 lpm_tree = mlxsw_sp_lpm_tree_get(mlxsw_sp, &req_prefix_usage, 4243 lpm_tree = mlxsw_sp_lpm_tree_get(mlxsw_sp, &req_prefix_usage,
4226 fib->proto); 4244 fib->proto);
4227 if (IS_ERR(lpm_tree)) 4245 if (IS_ERR(lpm_tree))
4228 return PTR_ERR(lpm_tree); 4246 return PTR_ERR(lpm_tree);
4229 4247
4230 if (fib->lpm_tree && fib->lpm_tree->id == lpm_tree->id)
4231 return 0;
4232
4233 err = mlxsw_sp_vrs_lpm_tree_replace(mlxsw_sp, fib, lpm_tree); 4248 err = mlxsw_sp_vrs_lpm_tree_replace(mlxsw_sp, fib, lpm_tree);
4234 if (err) 4249 if (err)
4235 return err; 4250 goto err_lpm_tree_replace;
4236 4251
4252out:
4253 lpm_tree->prefix_ref_count[fib_node->key.prefix_len]++;
4237 return 0; 4254 return 0;
4238}
4239 4255
4240static void mlxsw_sp_fib_lpm_tree_unlink(struct mlxsw_sp *mlxsw_sp, 4256err_lpm_tree_replace:
4241 struct mlxsw_sp_fib *fib) 4257 mlxsw_sp_lpm_tree_put(mlxsw_sp, lpm_tree);
4242{ 4258 return err;
4243 if (!mlxsw_sp_prefix_usage_none(&fib->prefix_usage))
4244 return;
4245 mlxsw_sp_vr_lpm_tree_unbind(mlxsw_sp, fib);
4246 mlxsw_sp_lpm_tree_put(mlxsw_sp, fib->lpm_tree);
4247 fib->lpm_tree = NULL;
4248} 4259}
4249 4260
4250static void mlxsw_sp_fib_node_prefix_inc(struct mlxsw_sp_fib_node *fib_node) 4261static void mlxsw_sp_fib_lpm_tree_unlink(struct mlxsw_sp *mlxsw_sp,
4262 struct mlxsw_sp_fib_node *fib_node)
4251{ 4263{
4252 unsigned char prefix_len = fib_node->key.prefix_len; 4264 struct mlxsw_sp_lpm_tree *lpm_tree = fib_node->fib->lpm_tree;
4265 struct mlxsw_sp_prefix_usage req_prefix_usage;
4253 struct mlxsw_sp_fib *fib = fib_node->fib; 4266 struct mlxsw_sp_fib *fib = fib_node->fib;
4267 int err;
4254 4268
4255 if (fib->prefix_ref_count[prefix_len]++ == 0) 4269 if (--lpm_tree->prefix_ref_count[fib_node->key.prefix_len] != 0)
4256 mlxsw_sp_prefix_usage_set(&fib->prefix_usage, prefix_len); 4270 return;
4257} 4271 /* Try to construct a new LPM tree from the current prefix usage
4272 * minus the unused one. If we fail, continue using the old one.
4273 */
4274 mlxsw_sp_prefix_usage_cpy(&req_prefix_usage, &lpm_tree->prefix_usage);
4275 mlxsw_sp_prefix_usage_clear(&req_prefix_usage,
4276 fib_node->key.prefix_len);
4277 lpm_tree = mlxsw_sp_lpm_tree_get(mlxsw_sp, &req_prefix_usage,
4278 fib->proto);
4279 if (IS_ERR(lpm_tree))
4280 return;
4258 4281
4259static void mlxsw_sp_fib_node_prefix_dec(struct mlxsw_sp_fib_node *fib_node) 4282 err = mlxsw_sp_vrs_lpm_tree_replace(mlxsw_sp, fib, lpm_tree);
4260{ 4283 if (err)
4261 unsigned char prefix_len = fib_node->key.prefix_len; 4284 goto err_lpm_tree_replace;
4262 struct mlxsw_sp_fib *fib = fib_node->fib;
4263 4285
4264 if (--fib->prefix_ref_count[prefix_len] == 0) 4286 return;
4265 mlxsw_sp_prefix_usage_clear(&fib->prefix_usage, prefix_len); 4287
4288err_lpm_tree_replace:
4289 mlxsw_sp_lpm_tree_put(mlxsw_sp, lpm_tree);
4266} 4290}
4267 4291
4268static int mlxsw_sp_fib_node_init(struct mlxsw_sp *mlxsw_sp, 4292static 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 return err; 4300 return err;
4277 fib_node->fib = fib; 4301 fib_node->fib = fib;
4278 4302
4279 err = mlxsw_sp_fib_lpm_tree_link(mlxsw_sp, fib, fib_node); 4303 err = mlxsw_sp_fib_lpm_tree_link(mlxsw_sp, fib_node);
4280 if (err) 4304 if (err)
4281 goto err_fib_lpm_tree_link; 4305 goto err_fib_lpm_tree_link;
4282 4306
4283 mlxsw_sp_fib_node_prefix_inc(fib_node);
4284
4285 return 0; 4307 return 0;
4286 4308
4287err_fib_lpm_tree_link: 4309err_fib_lpm_tree_link:
@@ -4295,8 +4317,7 @@ static void mlxsw_sp_fib_node_fini(struct mlxsw_sp *mlxsw_sp,
4295{ 4317{
4296 struct mlxsw_sp_fib *fib = fib_node->fib; 4318 struct mlxsw_sp_fib *fib = fib_node->fib;
4297 4319
4298 mlxsw_sp_fib_node_prefix_dec(fib_node); 4320 mlxsw_sp_fib_lpm_tree_unlink(mlxsw_sp, fib_node);
4299 mlxsw_sp_fib_lpm_tree_unlink(mlxsw_sp, fib);
4300 fib_node->fib = NULL; 4321 fib_node->fib = NULL;
4301 mlxsw_sp_fib_node_remove(fib, fib_node); 4322 mlxsw_sp_fib_node_remove(fib, fib_node);
4302} 4323}
@@ -4335,7 +4356,7 @@ mlxsw_sp_fib_node_get(struct mlxsw_sp *mlxsw_sp, u32 tb_id, const void *addr,
4335err_fib_node_init: 4356err_fib_node_init:
4336 mlxsw_sp_fib_node_destroy(fib_node); 4357 mlxsw_sp_fib_node_destroy(fib_node);
4337err_fib_node_create: 4358err_fib_node_create:
4338 mlxsw_sp_vr_put(vr); 4359 mlxsw_sp_vr_put(mlxsw_sp, vr);
4339 return ERR_PTR(err); 4360 return ERR_PTR(err);
4340} 4361}
4341 4362
@@ -4348,7 +4369,7 @@ static void mlxsw_sp_fib_node_put(struct mlxsw_sp *mlxsw_sp,
4348 return; 4369 return;
4349 mlxsw_sp_fib_node_fini(mlxsw_sp, fib_node); 4370 mlxsw_sp_fib_node_fini(mlxsw_sp, fib_node);
4350 mlxsw_sp_fib_node_destroy(fib_node); 4371 mlxsw_sp_fib_node_destroy(fib_node);
4351 mlxsw_sp_vr_put(vr); 4372 mlxsw_sp_vr_put(mlxsw_sp, vr);
4352} 4373}
4353 4374
4354static struct mlxsw_sp_fib4_entry * 4375static struct mlxsw_sp_fib4_entry *
@@ -5371,7 +5392,7 @@ static void mlxsw_sp_router_fibmr_del(struct mlxsw_sp *mlxsw_sp,
5371 return; 5392 return;
5372 5393
5373 mlxsw_sp_mr_route4_del(vr->mr4_table, men_info->mfc); 5394 mlxsw_sp_mr_route4_del(vr->mr4_table, men_info->mfc);
5374 mlxsw_sp_vr_put(vr); 5395 mlxsw_sp_vr_put(mlxsw_sp, vr);
5375} 5396}
5376 5397
5377static int 5398static int
@@ -5408,7 +5429,7 @@ mlxsw_sp_router_fibmr_vif_del(struct mlxsw_sp *mlxsw_sp,
5408 return; 5429 return;
5409 5430
5410 mlxsw_sp_mr_vif_del(vr->mr4_table, ven_info->vif_index); 5431 mlxsw_sp_mr_vif_del(vr->mr4_table, ven_info->vif_index);
5411 mlxsw_sp_vr_put(vr); 5432 mlxsw_sp_vr_put(mlxsw_sp, vr);
5412} 5433}
5413 5434
5414static int mlxsw_sp_router_set_abort_trap(struct mlxsw_sp *mlxsw_sp) 5435static int mlxsw_sp_router_set_abort_trap(struct mlxsw_sp *mlxsw_sp)
@@ -6057,7 +6078,7 @@ err_fid_get:
6057err_rif_alloc: 6078err_rif_alloc:
6058err_rif_index_alloc: 6079err_rif_index_alloc:
6059 vr->rif_count--; 6080 vr->rif_count--;
6060 mlxsw_sp_vr_put(vr); 6081 mlxsw_sp_vr_put(mlxsw_sp, vr);
6061 return ERR_PTR(err); 6082 return ERR_PTR(err);
6062} 6083}
6063 6084
@@ -6080,7 +6101,7 @@ void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif)
6080 mlxsw_sp_fid_put(fid); 6101 mlxsw_sp_fid_put(fid);
6081 kfree(rif); 6102 kfree(rif);
6082 vr->rif_count--; 6103 vr->rif_count--;
6083 mlxsw_sp_vr_put(vr); 6104 mlxsw_sp_vr_put(mlxsw_sp, vr);
6084} 6105}
6085 6106
6086static void 6107static void
@@ -6870,7 +6891,7 @@ mlxsw_sp_rif_ipip_lb_configure(struct mlxsw_sp_rif *rif)
6870 return 0; 6891 return 0;
6871 6892
6872err_loopback_op: 6893err_loopback_op:
6873 mlxsw_sp_vr_put(ul_vr); 6894 mlxsw_sp_vr_put(mlxsw_sp, ul_vr);
6874 return err; 6895 return err;
6875} 6896}
6876 6897
@@ -6884,7 +6905,7 @@ static void mlxsw_sp_rif_ipip_lb_deconfigure(struct mlxsw_sp_rif *rif)
6884 mlxsw_sp_rif_ipip_lb_op(lb_rif, ul_vr, false); 6905 mlxsw_sp_rif_ipip_lb_op(lb_rif, ul_vr, false);
6885 6906
6886 --ul_vr->rif_count; 6907 --ul_vr->rif_count;
6887 mlxsw_sp_vr_put(ul_vr); 6908 mlxsw_sp_vr_put(mlxsw_sp, ul_vr);
6888} 6909}
6889 6910
6890static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_ipip_lb_ops = { 6911static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_ipip_lb_ops = {