OSDN Git Service

ipv6: Use hash-threshold instead of modulo-N
authorIdo Schimmel <idosch@mellanox.com>
Tue, 9 Jan 2018 14:40:27 +0000 (16:40 +0200)
committerDavid S. Miller <davem@davemloft.net>
Wed, 10 Jan 2018 20:14:44 +0000 (15:14 -0500)
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>
net/ipv6/route.c

index 09e8e10..7837b8c 100644 (file)
@@ -455,7 +455,6 @@ static struct rt6_info *rt6_multipath_select(struct rt6_info *match,
                                             int strict)
 {
        struct rt6_info *sibling, *next_sibling;
-       int route_choosen;
 
        /* 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.
@@ -463,28 +462,19 @@ static struct rt6_info *rt6_multipath_select(struct rt6_info *match,
        if (!fl6->mp_hash)
                fl6->mp_hash = rt6_multipath_hash(fl6, NULL);
 
-       route_choosen = fl6->mp_hash % (match->rt6i_nsiblings + 1);
-       /* Don't change the route, if route_choosen == 0
-        * (siblings does not include ourself)
-        */
-       if (route_choosen)
-               list_for_each_entry_safe(sibling, next_sibling,
-                               &match->rt6i_siblings, rt6i_siblings) {
-                       route_choosen--;
-                       if (route_choosen == 0) {
-                               struct inet6_dev *idev = sibling->rt6i_idev;
-
-                               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;
-                       }
-               }
+       if (fl6->mp_hash <= atomic_read(&match->rt6i_nh_upper_bound))
+               return match;
+
+       list_for_each_entry_safe(sibling, next_sibling, &match->rt6i_siblings,
+                                rt6i_siblings) {
+               if (fl6->mp_hash > atomic_read(&sibling->rt6i_nh_upper_bound))
+                       continue;
+               if (rt6_score_route(sibling, oif, strict) < 0)
+                       break;
+               match = sibling;
+               break;
+       }
+
        return match;
 }