@@ -320,19 +320,6 @@ struct mlxsw_sp_prefix_usage {
320
320
#define mlxsw_sp_prefix_usage_for_each (prefix , prefix_usage ) \
321
321
for_each_set_bit(prefix, (prefix_usage)->b, MLXSW_SP_PREFIX_COUNT)
322
322
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
-
336
323
static bool
337
324
mlxsw_sp_prefix_usage_eq (struct mlxsw_sp_prefix_usage * prefix_usage1 ,
338
325
struct mlxsw_sp_prefix_usage * prefix_usage2 )
@@ -589,16 +576,14 @@ mlxsw_sp_lpm_tree_get(struct mlxsw_sp *mlxsw_sp,
589
576
lpm_tree -> proto == proto &&
590
577
mlxsw_sp_prefix_usage_eq (& lpm_tree -> prefix_usage ,
591
578
prefix_usage ))
592
- goto inc_ref_count ;
579
+ return lpm_tree ;
593
580
}
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
+ }
598
583
599
- inc_ref_count :
584
+ static void mlxsw_sp_lpm_tree_hold (struct mlxsw_sp_lpm_tree * lpm_tree )
585
+ {
600
586
lpm_tree -> ref_count ++ ;
601
- return lpm_tree ;
602
587
}
603
588
604
589
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)
750
735
vr -> fib4 = NULL ;
751
736
}
752
737
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
-
793
738
static struct mlxsw_sp_vr * mlxsw_sp_vr_get (struct mlxsw_sp * mlxsw_sp , u32 tb_id )
794
739
{
795
740
struct mlxsw_sp_vr * vr ;
@@ -808,6 +753,100 @@ static void mlxsw_sp_vr_put(struct mlxsw_sp_vr *vr)
808
753
mlxsw_sp_vr_destroy (vr );
809
754
}
810
755
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
+
811
850
static int mlxsw_sp_vrs_init (struct mlxsw_sp * mlxsw_sp )
812
851
{
813
852
struct mlxsw_sp_vr * vr ;
@@ -2586,6 +2625,67 @@ mlxsw_sp_fib_node_entry_is_first(const struct mlxsw_sp_fib_node *fib_node,
2586
2625
struct mlxsw_sp_fib_entry , list ) == fib_entry ;
2587
2626
}
2588
2627
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
+
2589
2689
static void mlxsw_sp_fib_node_prefix_inc (struct mlxsw_sp_fib_node * fib_node )
2590
2690
{
2591
2691
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,
2608
2708
struct mlxsw_sp_fib_node * fib_node ,
2609
2709
struct mlxsw_sp_fib * fib )
2610
2710
{
2611
- struct mlxsw_sp_prefix_usage req_prefix_usage ;
2612
- struct mlxsw_sp_lpm_tree * lpm_tree ;
2613
2711
int err ;
2614
2712
2615
2713
err = mlxsw_sp_fib_node_insert (fib , fib_node );
2616
2714
if (err )
2617
2715
return err ;
2618
2716
fib_node -> fib = fib ;
2619
2717
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 ;
2638
2721
2639
2722
mlxsw_sp_fib_node_prefix_inc (fib_node );
2640
2723
2641
2724
return 0 ;
2642
2725
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 :
2647
2727
fib_node -> fib = NULL ;
2648
2728
mlxsw_sp_fib_node_remove (fib , fib_node );
2649
2729
return err ;
@@ -2652,19 +2732,10 @@ static int mlxsw_sp_fib_node_init(struct mlxsw_sp *mlxsw_sp,
2652
2732
static void mlxsw_sp_fib_node_fini (struct mlxsw_sp * mlxsw_sp ,
2653
2733
struct mlxsw_sp_fib_node * fib_node )
2654
2734
{
2655
- struct mlxsw_sp_lpm_tree * lpm_tree = fib_node -> fib -> lpm_tree ;
2656
2735
struct mlxsw_sp_fib * fib = fib_node -> fib ;
2657
2736
2658
2737
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 );
2668
2739
fib_node -> fib = NULL ;
2669
2740
mlxsw_sp_fib_node_remove (fib , fib_node );
2670
2741
}
0 commit comments