OSDN Git Service

ipv6: Handle all fib6_nh in a nexthop in __ip6_route_redirect
authorDavid Ahern <dsahern@gmail.com>
Sat, 8 Jun 2019 21:53:29 +0000 (14:53 -0700)
committerDavid S. Miller <davem@davemloft.net>
Mon, 10 Jun 2019 17:44:56 +0000 (10:44 -0700)
Add a hook in __ip6_route_redirect to handle a nexthop struct in a
fib6_info. Use nexthop_for_each_fib6_nh and fib6_nh_redirect_match
to call ip6_redirect_nh_match for each fib6_nh looking for a match.

Signed-off-by: David Ahern <dsahern@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ipv6/route.c

index dadb160..06498f6 100644 (file)
@@ -2789,6 +2789,21 @@ static bool ip6_redirect_nh_match(const struct fib6_result *res,
        return true;
 }
 
+struct fib6_nh_rd_arg {
+       struct fib6_result      *res;
+       struct flowi6           *fl6;
+       const struct in6_addr   *gw;
+       struct rt6_info         **ret;
+};
+
+static int fib6_nh_redirect_match(struct fib6_nh *nh, void *_arg)
+{
+       struct fib6_nh_rd_arg *arg = _arg;
+
+       arg->res->nh = nh;
+       return ip6_redirect_nh_match(arg->res, arg->fl6, arg->gw, arg->ret);
+}
+
 /* Handle redirects */
 struct ip6rd_flowi {
        struct flowi6 fl6;
@@ -2804,6 +2819,12 @@ static struct rt6_info *__ip6_route_redirect(struct net *net,
        struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl6;
        struct rt6_info *ret = NULL;
        struct fib6_result res = {};
+       struct fib6_nh_rd_arg arg = {
+               .res = &res,
+               .fl6 = fl6,
+               .gw  = &rdfl->gateway,
+               .ret = &ret
+       };
        struct fib6_info *rt;
        struct fib6_node *fn;
 
@@ -2828,14 +2849,24 @@ static struct rt6_info *__ip6_route_redirect(struct net *net,
 restart:
        for_each_fib6_node_rt_rcu(fn) {
                res.f6i = rt;
-               res.nh = rt->fib6_nh;
-
                if (fib6_check_expired(rt))
                        continue;
                if (rt->fib6_flags & RTF_REJECT)
                        break;
-               if (ip6_redirect_nh_match(&res, fl6, &rdfl->gateway, &ret))
-                       goto out;
+               if (unlikely(rt->nh)) {
+                       if (nexthop_is_blackhole(rt->nh))
+                               continue;
+                       /* on match, res->nh is filled in and potentially ret */
+                       if (nexthop_for_each_fib6_nh(rt->nh,
+                                                    fib6_nh_redirect_match,
+                                                    &arg))
+                               goto out;
+               } else {
+                       res.nh = rt->fib6_nh;
+                       if (ip6_redirect_nh_match(&res, fl6, &rdfl->gateway,
+                                                 &ret))
+                               goto out;
+               }
        }
 
        if (!rt)