@@ -412,12 +412,37 @@ static bool rt6_check_expired(const struct rt6_info *rt)
412412 return false;
413413}
414414
415+ static struct fib6_info *
416+ rt6_multipath_first_sibling_rcu (const struct fib6_info * rt )
417+ {
418+ struct fib6_info * iter ;
419+ struct fib6_node * fn ;
420+
421+ fn = rcu_dereference (rt -> fib6_node );
422+ if (!fn )
423+ goto out ;
424+ iter = rcu_dereference (fn -> leaf );
425+ if (!iter )
426+ goto out ;
427+
428+ while (iter ) {
429+ if (iter -> fib6_metric == rt -> fib6_metric &&
430+ rt6_qualify_for_ecmp (iter ))
431+ return iter ;
432+ iter = rcu_dereference (iter -> fib6_next );
433+ }
434+
435+ out :
436+ return NULL ;
437+ }
438+
415439void fib6_select_path (const struct net * net , struct fib6_result * res ,
416440 struct flowi6 * fl6 , int oif , bool have_oif_match ,
417441 const struct sk_buff * skb , int strict )
418442{
419- struct fib6_info * match = res -> f6i ;
443+ struct fib6_info * first , * match = res -> f6i ;
420444 struct fib6_info * sibling ;
445+ int hash ;
421446
422447 if (!match -> nh && (!match -> fib6_nsiblings || have_oif_match ))
423448 goto out ;
@@ -440,16 +465,25 @@ void fib6_select_path(const struct net *net, struct fib6_result *res,
440465 return ;
441466 }
442467
443- if (fl6 -> mp_hash <= atomic_read (& match -> fib6_nh -> fib_nh_upper_bound ))
468+ first = rt6_multipath_first_sibling_rcu (match );
469+ if (!first )
444470 goto out ;
445471
446- list_for_each_entry_rcu (sibling , & match -> fib6_siblings ,
472+ hash = fl6 -> mp_hash ;
473+ if (hash <= atomic_read (& first -> fib6_nh -> fib_nh_upper_bound )) {
474+ if (rt6_score_route (first -> fib6_nh , first -> fib6_flags , oif ,
475+ strict ) >= 0 )
476+ match = first ;
477+ goto out ;
478+ }
479+
480+ list_for_each_entry_rcu (sibling , & first -> fib6_siblings ,
447481 fib6_siblings ) {
448482 const struct fib6_nh * nh = sibling -> fib6_nh ;
449483 int nh_upper_bound ;
450484
451485 nh_upper_bound = atomic_read (& nh -> fib_nh_upper_bound );
452- if (fl6 -> mp_hash > nh_upper_bound )
486+ if (hash > nh_upper_bound )
453487 continue ;
454488 if (rt6_score_route (nh , sibling -> fib6_flags , oif , strict ) < 0 )
455489 break ;
0 commit comments