From: David Ahern <dsah...@gmail.com>

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 <dsah...@gmail.com>
---
 net/ipv6/route.c | 39 +++++++++++++++++++++++++++++++++++----
 1 file changed, 35 insertions(+), 4 deletions(-)

diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 49d58ad9f76e..fbbceca19e50 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -2800,6 +2800,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;
@@ -2815,6 +2830,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;
 
@@ -2839,14 +2860,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)
-- 
2.11.0

Reply via email to