forked from mirrors/linux
		
	ipv6: Use hash-threshold instead of modulo-N
Now that each nexthop stores its region boundary in the multipath hash function's output space, we can use hash-threshold instead of modulo-N in multipath selection. This reduces the number of checks we need to perform during lookup, as dead and linkdown nexthops are assigned a negative region boundary. In addition, in contrast to modulo-N, only flows near region boundaries are affected when a nexthop is added or removed. Signed-off-by: Ido Schimmel <idosch@mellanox.com> Acked-by: David Ahern <dsahern@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									7696c06a18
								
							
						
					
					
						commit
						3d709f69a3
					
				
					 1 changed files with 12 additions and 22 deletions
				
			
		| 
						 | 
					@ -455,7 +455,6 @@ static struct rt6_info *rt6_multipath_select(struct rt6_info *match,
 | 
				
			||||||
					     int strict)
 | 
										     int strict)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rt6_info *sibling, *next_sibling;
 | 
						struct rt6_info *sibling, *next_sibling;
 | 
				
			||||||
	int route_choosen;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* We might have already computed the hash for ICMPv6 errors. In such
 | 
						/* We might have already computed the hash for ICMPv6 errors. In such
 | 
				
			||||||
	 * case it will always be non-zero. Otherwise now is the time to do it.
 | 
						 * case it will always be non-zero. Otherwise now is the time to do it.
 | 
				
			||||||
| 
						 | 
					@ -463,28 +462,19 @@ static struct rt6_info *rt6_multipath_select(struct rt6_info *match,
 | 
				
			||||||
	if (!fl6->mp_hash)
 | 
						if (!fl6->mp_hash)
 | 
				
			||||||
		fl6->mp_hash = rt6_multipath_hash(fl6, NULL);
 | 
							fl6->mp_hash = rt6_multipath_hash(fl6, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	route_choosen = fl6->mp_hash % (match->rt6i_nsiblings + 1);
 | 
						if (fl6->mp_hash <= atomic_read(&match->rt6i_nh_upper_bound))
 | 
				
			||||||
	/* Don't change the route, if route_choosen == 0
 | 
							return match;
 | 
				
			||||||
	 * (siblings does not include ourself)
 | 
					
 | 
				
			||||||
	 */
 | 
						list_for_each_entry_safe(sibling, next_sibling, &match->rt6i_siblings,
 | 
				
			||||||
	if (route_choosen)
 | 
									 rt6i_siblings) {
 | 
				
			||||||
		list_for_each_entry_safe(sibling, next_sibling,
 | 
							if (fl6->mp_hash > atomic_read(&sibling->rt6i_nh_upper_bound))
 | 
				
			||||||
				&match->rt6i_siblings, rt6i_siblings) {
 | 
								continue;
 | 
				
			||||||
			route_choosen--;
 | 
							if (rt6_score_route(sibling, oif, strict) < 0)
 | 
				
			||||||
			if (route_choosen == 0) {
 | 
								break;
 | 
				
			||||||
				struct inet6_dev *idev = sibling->rt6i_idev;
 | 
							match = sibling;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if (sibling->rt6i_nh_flags & RTNH_F_DEAD)
 | 
					 | 
				
			||||||
					break;
 | 
					 | 
				
			||||||
				if (sibling->rt6i_nh_flags & RTNH_F_LINKDOWN &&
 | 
					 | 
				
			||||||
				    idev->cnf.ignore_routes_with_linkdown)
 | 
					 | 
				
			||||||
					break;
 | 
					 | 
				
			||||||
				if (rt6_score_route(sibling, oif, strict) < 0)
 | 
					 | 
				
			||||||
					break;
 | 
					 | 
				
			||||||
				match = sibling;
 | 
					 | 
				
			||||||
				break;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	return match;
 | 
						return match;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue