46
46
#include <linux/if_bridge.h>
47
47
#include <linux/socket.h>
48
48
#include <linux/route.h>
49
+ #include <linux/gcd.h>
49
50
#include <net/netevent.h>
50
51
#include <net/neighbour.h>
51
52
#include <net/arp.h>
@@ -2204,6 +2205,8 @@ struct mlxsw_sp_nexthop {
2204
2205
unsigned char gw_addr [sizeof (struct in6_addr )];
2205
2206
int ifindex ;
2206
2207
int nh_weight ;
2208
+ int norm_nh_weight ;
2209
+ int num_adj_entries ;
2207
2210
struct mlxsw_sp_rif * rif ;
2208
2211
u8 should_offload :1 , /* set indicates this neigh is connected and
2209
2212
* should be put to KVD linear area of this group.
@@ -2233,6 +2236,7 @@ struct mlxsw_sp_nexthop_group {
2233
2236
u32 adj_index ;
2234
2237
u16 ecmp_size ;
2235
2238
u16 count ;
2239
+ int sum_norm_weight ;
2236
2240
struct mlxsw_sp_nexthop nexthops [0 ];
2237
2241
#define nh_rif nexthops[0].rif
2238
2242
};
@@ -2318,7 +2322,7 @@ int mlxsw_sp_nexthop_indexes(struct mlxsw_sp_nexthop *nh, u32 *p_adj_index,
2318
2322
if (nh_iter == nh )
2319
2323
break ;
2320
2324
if (nh_iter -> offloaded )
2321
- adj_hash_index ++ ;
2325
+ adj_hash_index += nh_iter -> num_adj_entries ;
2322
2326
}
2323
2327
2324
2328
* p_adj_hash_index = adj_hash_index ;
@@ -2601,8 +2605,8 @@ static int mlxsw_sp_adj_index_mass_update(struct mlxsw_sp *mlxsw_sp,
2601
2605
return 0 ;
2602
2606
}
2603
2607
2604
- int mlxsw_sp_nexthop_update (struct mlxsw_sp * mlxsw_sp , u32 adj_index ,
2605
- struct mlxsw_sp_nexthop * nh )
2608
+ static int __mlxsw_sp_nexthop_update (struct mlxsw_sp * mlxsw_sp , u32 adj_index ,
2609
+ struct mlxsw_sp_nexthop * nh )
2606
2610
{
2607
2611
struct mlxsw_sp_neigh_entry * neigh_entry = nh -> neigh_entry ;
2608
2612
char ratr_pl [MLXSW_REG_RATR_LEN ];
@@ -2619,16 +2623,50 @@ int mlxsw_sp_nexthop_update(struct mlxsw_sp *mlxsw_sp, u32 adj_index,
2619
2623
return mlxsw_reg_write (mlxsw_sp -> core , MLXSW_REG (ratr ), ratr_pl );
2620
2624
}
2621
2625
2622
- static int mlxsw_sp_nexthop_ipip_update (struct mlxsw_sp * mlxsw_sp ,
2623
- u32 adj_index ,
2624
- struct mlxsw_sp_nexthop * nh )
2626
+ int mlxsw_sp_nexthop_update (struct mlxsw_sp * mlxsw_sp , u32 adj_index ,
2627
+ struct mlxsw_sp_nexthop * nh )
2628
+ {
2629
+ int i ;
2630
+
2631
+ for (i = 0 ; i < nh -> num_adj_entries ; i ++ ) {
2632
+ int err ;
2633
+
2634
+ err = __mlxsw_sp_nexthop_update (mlxsw_sp , adj_index + i , nh );
2635
+ if (err )
2636
+ return err ;
2637
+ }
2638
+
2639
+ return 0 ;
2640
+ }
2641
+
2642
+ static int __mlxsw_sp_nexthop_ipip_update (struct mlxsw_sp * mlxsw_sp ,
2643
+ u32 adj_index ,
2644
+ struct mlxsw_sp_nexthop * nh )
2625
2645
{
2626
2646
const struct mlxsw_sp_ipip_ops * ipip_ops ;
2627
2647
2628
2648
ipip_ops = mlxsw_sp -> router -> ipip_ops_arr [nh -> ipip_entry -> ipipt ];
2629
2649
return ipip_ops -> nexthop_update (mlxsw_sp , adj_index , nh -> ipip_entry );
2630
2650
}
2631
2651
2652
+ static int mlxsw_sp_nexthop_ipip_update (struct mlxsw_sp * mlxsw_sp ,
2653
+ u32 adj_index ,
2654
+ struct mlxsw_sp_nexthop * nh )
2655
+ {
2656
+ int i ;
2657
+
2658
+ for (i = 0 ; i < nh -> num_adj_entries ; i ++ ) {
2659
+ int err ;
2660
+
2661
+ err = __mlxsw_sp_nexthop_ipip_update (mlxsw_sp , adj_index + i ,
2662
+ nh );
2663
+ if (err )
2664
+ return err ;
2665
+ }
2666
+
2667
+ return 0 ;
2668
+ }
2669
+
2632
2670
static int
2633
2671
mlxsw_sp_nexthop_group_update (struct mlxsw_sp * mlxsw_sp ,
2634
2672
struct mlxsw_sp_nexthop_group * nh_grp ,
@@ -2663,7 +2701,7 @@ mlxsw_sp_nexthop_group_update(struct mlxsw_sp *mlxsw_sp,
2663
2701
nh -> update = 0 ;
2664
2702
nh -> offloaded = 1 ;
2665
2703
}
2666
- adj_index ++ ;
2704
+ adj_index += nh -> num_adj_entries ;
2667
2705
}
2668
2706
return 0 ;
2669
2707
}
@@ -2761,17 +2799,65 @@ static int mlxsw_sp_fix_adj_grp_size(struct mlxsw_sp *mlxsw_sp,
2761
2799
return 0 ;
2762
2800
}
2763
2801
2802
+ static void
2803
+ mlxsw_sp_nexthop_group_normalize (struct mlxsw_sp_nexthop_group * nh_grp )
2804
+ {
2805
+ int i , g = 0 , sum_norm_weight = 0 ;
2806
+ struct mlxsw_sp_nexthop * nh ;
2807
+
2808
+ for (i = 0 ; i < nh_grp -> count ; i ++ ) {
2809
+ nh = & nh_grp -> nexthops [i ];
2810
+
2811
+ if (!nh -> should_offload )
2812
+ continue ;
2813
+ if (g > 0 )
2814
+ g = gcd (nh -> nh_weight , g );
2815
+ else
2816
+ g = nh -> nh_weight ;
2817
+ }
2818
+
2819
+ for (i = 0 ; i < nh_grp -> count ; i ++ ) {
2820
+ nh = & nh_grp -> nexthops [i ];
2821
+
2822
+ if (!nh -> should_offload )
2823
+ continue ;
2824
+ nh -> norm_nh_weight = nh -> nh_weight / g ;
2825
+ sum_norm_weight += nh -> norm_nh_weight ;
2826
+ }
2827
+
2828
+ nh_grp -> sum_norm_weight = sum_norm_weight ;
2829
+ }
2830
+
2831
+ static void
2832
+ mlxsw_sp_nexthop_group_rebalance (struct mlxsw_sp_nexthop_group * nh_grp )
2833
+ {
2834
+ int total = nh_grp -> sum_norm_weight ;
2835
+ u16 ecmp_size = nh_grp -> ecmp_size ;
2836
+ int i , weight = 0 , lower_bound = 0 ;
2837
+
2838
+ for (i = 0 ; i < nh_grp -> count ; i ++ ) {
2839
+ struct mlxsw_sp_nexthop * nh = & nh_grp -> nexthops [i ];
2840
+ int upper_bound ;
2841
+
2842
+ if (!nh -> should_offload )
2843
+ continue ;
2844
+ weight += nh -> norm_nh_weight ;
2845
+ upper_bound = DIV_ROUND_CLOSEST (ecmp_size * weight , total );
2846
+ nh -> num_adj_entries = upper_bound - lower_bound ;
2847
+ lower_bound = upper_bound ;
2848
+ }
2849
+ }
2850
+
2764
2851
static void
2765
2852
mlxsw_sp_nexthop_group_refresh (struct mlxsw_sp * mlxsw_sp ,
2766
2853
struct mlxsw_sp_nexthop_group * nh_grp )
2767
2854
{
2855
+ u16 ecmp_size , old_ecmp_size ;
2768
2856
struct mlxsw_sp_nexthop * nh ;
2769
2857
bool offload_change = false;
2770
2858
u32 adj_index ;
2771
- u16 ecmp_size = 0 ;
2772
2859
bool old_adj_index_valid ;
2773
2860
u32 old_adj_index ;
2774
- u16 old_ecmp_size ;
2775
2861
int i ;
2776
2862
int err ;
2777
2863
@@ -2788,8 +2874,6 @@ mlxsw_sp_nexthop_group_refresh(struct mlxsw_sp *mlxsw_sp,
2788
2874
if (nh -> should_offload )
2789
2875
nh -> update = 1 ;
2790
2876
}
2791
- if (nh -> should_offload )
2792
- ecmp_size ++ ;
2793
2877
}
2794
2878
if (!offload_change ) {
2795
2879
/* Nothing was added or removed, so no need to reallocate. Just
@@ -2802,12 +2886,14 @@ mlxsw_sp_nexthop_group_refresh(struct mlxsw_sp *mlxsw_sp,
2802
2886
}
2803
2887
return ;
2804
2888
}
2805
- if (!ecmp_size )
2889
+ mlxsw_sp_nexthop_group_normalize (nh_grp );
2890
+ if (!nh_grp -> sum_norm_weight )
2806
2891
/* No neigh of this group is connected so we just set
2807
2892
* the trap and let everthing flow through kernel.
2808
2893
*/
2809
2894
goto set_trap ;
2810
2895
2896
+ ecmp_size = nh_grp -> sum_norm_weight ;
2811
2897
err = mlxsw_sp_fix_adj_grp_size (mlxsw_sp , & ecmp_size );
2812
2898
if (err )
2813
2899
/* No valid allocation size available. */
@@ -2827,6 +2913,7 @@ mlxsw_sp_nexthop_group_refresh(struct mlxsw_sp *mlxsw_sp,
2827
2913
nh_grp -> adj_index_valid = 1 ;
2828
2914
nh_grp -> adj_index = adj_index ;
2829
2915
nh_grp -> ecmp_size = ecmp_size ;
2916
+ mlxsw_sp_nexthop_group_rebalance (nh_grp );
2830
2917
err = mlxsw_sp_nexthop_group_update (mlxsw_sp , nh_grp , true);
2831
2918
if (err ) {
2832
2919
dev_warn (mlxsw_sp -> bus_info -> dev , "Failed to update neigh MAC in adjacency table.\n" );
0 commit comments