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

Similar to ipv4, add helpers for accessing fib6_nh data and convert
existing users.

Signed-off-by: David Ahern <dsah...@gmail.com>
---
 include/net/ip6_fib.h       | 11 ----------
 include/net/ip6_route.h     |  2 ++
 include/net/nexthop.h       | 40 +++++++++++++++++++++++++++++++++++
 include/trace/events/fib6.h |  2 +-
 net/core/filter.c           | 11 +++++++---
 net/ipv6/route.c            | 51 ++++++++++++++++++++++++++-------------------
 6 files changed, 81 insertions(+), 36 deletions(-)

diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h
index 9526eef711d5..1f04a26e4c65 100644
--- a/include/net/ip6_fib.h
+++ b/include/net/ip6_fib.h
@@ -424,17 +424,6 @@ static inline void fib6_nh_release(struct fib6_nh *fib6_nh)
        lwtstate_put(fib6_nh->nh_lwtstate);
 }
 
-static inline struct net_device *fib6_info_nh_dev(const struct fib6_info *f6i)
-{
-       return f6i->fib6_nh->nh_dev;
-}
-
-static inline
-struct lwtunnel_state *fib6_info_nh_lwt(const struct fib6_info *f6i)
-{
-       return f6i->fib6_nh->nh_lwtstate;
-}
-
 void inet6_rt_notify(int event, struct fib6_info *rt, struct nl_info *info,
                     unsigned int flags);
 
diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
index b1ca637acb2a..0cdfe176c530 100644
--- a/include/net/ip6_route.h
+++ b/include/net/ip6_route.h
@@ -2,6 +2,8 @@
 #ifndef _NET_IP6_ROUTE_H
 #define _NET_IP6_ROUTE_H
 
+#include <net/nexthop.h>
+
 struct route_info {
        __u8                    type;
        __u8                    length;
diff --git a/include/net/nexthop.h b/include/net/nexthop.h
index c149fe8394ab..dae1518af3f3 100644
--- a/include/net/nexthop.h
+++ b/include/net/nexthop.h
@@ -160,6 +160,46 @@ static inline __be32 fib_info_nh_gw(struct fib_info *fi)
        return fib_nh ? fib_nh->nh_gw : 0;
 }
 
+/* IPv6 variants
+ */
+static inline struct fib6_nh *nexthop_fib6_nh(struct nexthop *nh)
+{
+       struct nh_info *nhi;
+
+       nhi = rcu_dereference(nh->nh_info);
+       if (nhi->family == AF_INET6)
+               return &nhi->fib6_nh;
+
+       return NULL;
+}
+
+static inline struct fib6_nh *fib6_info_nh(struct fib6_info *f6i)
+{
+       return f6i->fib6_nh;
+}
+
+static inline struct net_device *fib6_info_nh_dev(struct fib6_info *f6i)
+{
+       struct fib6_nh *fib6_nh = fib6_info_nh(f6i);
+
+       return fib6_nh ? fib6_nh->nh_dev : NULL;
+}
+
+static inline struct in6_addr *fib6_info_nh_gw(struct fib6_info *f6i)
+{
+       struct fib6_nh *fib6_nh = fib6_info_nh(f6i);
+
+       return fib6_nh ? &fib6_nh->nh_gw : NULL;
+}
+
+static inline
+struct lwtunnel_state *fib6_info_nh_lwt(struct fib6_info *f6i)
+{
+       struct fib6_nh *fib6_nh = fib6_info_nh(f6i);
+
+       return fib6_nh ? fib6_nh->nh_lwtstate : NULL;
+}
+
 int fib_check_nexthop(struct fib_info *fi, struct fib_config *cfg,
                      struct netlink_ext_ack *extack);
 
diff --git a/include/trace/events/fib6.h b/include/trace/events/fib6.h
index 037df3d2be0b..4e5e36cc35b9 100644
--- a/include/trace/events/fib6.h
+++ b/include/trace/events/fib6.h
@@ -36,7 +36,7 @@ TRACE_EVENT(fib6_table_lookup,
        ),
 
        TP_fast_assign(
-               struct fib6_nh *fib6_nh = f6i->fib6_nh;
+               struct fib6_nh *fib6_nh = fib6_info_nh(f6i);
                struct in6_addr *in6;
 
                __entry->tb_id = table->tb6_id;
diff --git a/net/core/filter.c b/net/core/filter.c
index bc979edf06ca..4d227fae69c8 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -4340,6 +4340,7 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct 
bpf_fib_lookup *params,
 {
        struct in6_addr *src = (struct in6_addr *) params->ipv6_src;
        struct in6_addr *dst = (struct in6_addr *) params->ipv6_dst;
+       struct fib6_nh *fib6_nh;
        struct neighbour *neigh;
        struct net_device *dev;
        struct inet6_dev *idev;
@@ -4428,13 +4429,17 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct 
bpf_fib_lookup *params,
                        return BPF_FIB_LKUP_RET_FRAG_NEEDED;
        }
 
-       if (f6i->fib6_nh->nh_lwtstate)
+       fib6_nh = fib6_info_nh(f6i);
+       if (!fib6_nh)
+               return BPF_FIB_LKUP_RET_NOT_FWDED;
+
+       if (fib6_nh->nh_lwtstate)
                return BPF_FIB_LKUP_RET_UNSUPP_LWT;
 
        if (f6i->fib6_flags & RTF_GATEWAY)
-               *dst = f6i->fib6_nh->nh_gw;
+               *dst = fib6_nh->nh_gw;
 
-       dev = f6i->fib6_nh->nh_dev;
+       dev = fib6_nh->nh_dev;
        params->rt_metric = f6i->fib6_metric;
 
        /* xdp and cls_bpf programs are run in RCU-bh so rcu_read_lock_bh is
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 5792f57fdb91..2c140ce95eb4 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -533,8 +533,8 @@ static void rt6_probe(struct fib6_info *rt)
        if (!rt || !(rt->fib6_flags & RTF_GATEWAY))
                return;
 
-       nh_gw = &rt->fib6_nh->nh_gw;
-       dev = rt->fib6_nh->nh_dev;
+       nh_gw = fib6_info_nh_gw(rt);
+       dev = fib6_info_nh_dev(rt);
        rcu_read_lock_bh();
        neigh = __ipv6_neigh_lookup_noref(dev, nh_gw);
        if (neigh) {
@@ -580,9 +580,9 @@ static inline void rt6_probe(struct fib6_info *rt)
  */
 static inline int rt6_check_dev(struct fib6_info *rt, int oif)
 {
-       const struct net_device *dev = rt->fib6_nh->nh_dev;
+       const struct net_device *dev = fib6_info_nh_dev(rt);
 
-       if (!oif || dev->ifindex == oif)
+       if (!oif || (dev && dev->ifindex == oif))
                return 2;
        return 0;
 }
@@ -590,6 +590,8 @@ static inline int rt6_check_dev(struct fib6_info *rt, int 
oif)
 static inline enum rt6_nud_state rt6_check_neigh(struct fib6_info *rt)
 {
        enum rt6_nud_state ret = RT6_NUD_FAIL_HARD;
+       const struct in6_addr *nh_gw = fib6_info_nh_gw(rt);
+       struct net_device *dev = fib6_info_nh_dev(rt);
        struct neighbour *neigh;
 
        if (rt->fib6_flags & RTF_NONEXTHOP ||
@@ -597,8 +599,7 @@ static inline enum rt6_nud_state rt6_check_neigh(struct 
fib6_info *rt)
                return RT6_NUD_SUCCEED;
 
        rcu_read_lock_bh();
-       neigh = __ipv6_neigh_lookup_noref(rt->fib6_nh->nh_dev,
-                                         &rt->fib6_nh->nh_gw);
+       neigh = __ipv6_neigh_lookup_noref(dev, nh_gw);
        if (neigh) {
                read_lock(&neigh->lock);
                if (neigh->nud_state & NUD_VALID)
@@ -638,12 +639,12 @@ static int rt6_score_route(struct fib6_info *rt, int oif, 
int strict)
 }
 
 /* called with rc_read_lock held */
-// TO-DO: if (!f6i->nh)
 static inline bool fib6_ignore_linkdown(const struct fib6_info *f6i)
 {
-       const struct net_device *dev = fib6_info_nh_dev(f6i);
+       const struct net_device *dev;
        bool rc = false;
 
+       dev = f6i->fib6_nh->nh_dev;
        if (dev) {
                const struct inet6_dev *idev = __in6_dev_get(dev);
 
@@ -869,7 +870,7 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
 /* called with rcu_lock held */
 static struct net_device *ip6_rt_get_dev_rcu(struct fib6_info *rt)
 {
-       struct net_device *dev = rt->fib6_nh->nh_dev;
+       struct net_device *dev = fib6_info_nh_dev(rt);
 
        if (rt->fib6_flags & (RTF_LOCAL | RTF_ANYCAST)) {
                /* for copies of local routes, dst->dev needs to be the
@@ -947,6 +948,8 @@ static void ip6_rt_init_dst_reject(struct rt6_info *rt, 
struct fib6_info *ort)
 
 static void ip6_rt_init_dst(struct rt6_info *rt, struct fib6_info *ort)
 {
+       struct lwtunnel_state *lws;
+
        rt->dst.flags |= fib6_info_dst_flags(ort);
 
        if (ort->fib6_flags & RTF_REJECT) {
@@ -965,8 +968,9 @@ static void ip6_rt_init_dst(struct rt6_info *rt, struct 
fib6_info *ort)
                rt->dst.input = ip6_forward;
        }
 
-       if (ort->fib6_nh->nh_lwtstate) {
-               rt->dst.lwtstate = lwtstate_get(ort->fib6_nh->nh_lwtstate);
+       lws = fib6_info_nh_lwt(ort);
+       if (lws) {
+               rt->dst.lwtstate = lwtstate_get(lws);
                lwtunnel_set_redirect(&rt->dst);
        }
 
@@ -985,19 +989,20 @@ static void rt6_set_from(struct rt6_info *rt, struct 
fib6_info *from)
 static void ip6_rt_copy_init(struct rt6_info *rt, struct fib6_info *ort)
 {
        struct net_device *dev = fib6_info_nh_dev(ort);
+       struct fib6_nh *fib6_nh = fib6_info_nh(ort);
 
        ip6_rt_init_dst(rt, ort);
 
        rt->rt6i_dst = ort->fib6_dst;
        rt->rt6i_idev = dev ? in6_dev_get(dev) : NULL;
-       rt->rt6i_gateway = ort->fib6_nh->nh_gw;
+       rt->rt6i_gateway = fib6_nh->nh_gw;
        rt->rt6i_flags = ort->fib6_flags;
        rt6_set_from(rt, ort);
 #ifdef CONFIG_IPV6_SUBTREES
        rt->rt6i_src = ort->fib6_src;
 #endif
        rt->rt6i_prefsrc = ort->fib6_prefsrc;
-       rt->dst.lwtstate = lwtstate_get(ort->fib6_nh->nh_lwtstate);
+       rt->dst.lwtstate = lwtstate_get(fib6_nh->nh_lwtstate);
 }
 
 static struct fib6_node* fib6_backtrack(struct fib6_node *fn,
@@ -1039,7 +1044,7 @@ static bool ip6_hold_safe(struct net *net, struct 
rt6_info **prt,
 static struct rt6_info *ip6_create_rt_rcu(struct fib6_info *rt)
 {
        unsigned short flags = fib6_info_dst_flags(rt);
-       struct net_device *dev = rt->fib6_nh->nh_dev;
+       struct net_device *dev = fib6_info_nh_dev(rt);
        struct rt6_info *nrt;
 
        if (!fib6_info_hold_safe(rt))
@@ -1392,8 +1397,9 @@ __rt6_find_exception_rcu(struct rt6_exception_bucket 
**bucket,
        return NULL;
 }
 
-static unsigned int fib6_mtu(const struct fib6_info *rt)
+static unsigned int fib6_mtu(struct fib6_info *rt)
 {
+       struct lwtunnel_state *lws = fib6_info_nh_lwt(rt);
        unsigned int mtu;
 
        if (rt->fib6_pmtu) {
@@ -1410,7 +1416,7 @@ static unsigned int fib6_mtu(const struct fib6_info *rt)
 
        mtu = min_t(unsigned int, mtu, IP6_MAX_MTU);
 
-       return mtu - lwtunnel_headroom(rt->fib6_nh->nh_lwtstate, mtu);
+       return mtu - lwtunnel_headroom(lws, mtu);
 }
 
 static int rt6_insert_exception(struct rt6_info *nrt,
@@ -2454,7 +2460,9 @@ static struct rt6_info *__ip6_route_redirect(struct net 
*net,
        fn = fib6_node_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
 restart:
        for_each_fib6_node_rt_rcu(fn) {
-               if (rt->fib6_nh->nh_flags & RTNH_F_DEAD)
+               struct fib6_nh *fib6_nh = fib6_info_nh(rt);
+
+               if (fib6_nh->nh_flags & RTNH_F_DEAD)
                        continue;
                if (fib6_check_expired(rt))
                        continue;
@@ -2462,14 +2470,14 @@ static struct rt6_info *__ip6_route_redirect(struct net 
*net,
                        break;
                if (!(rt->fib6_flags & RTF_GATEWAY))
                        continue;
-               if (fl6->flowi6_oif != rt->fib6_nh->nh_dev->ifindex)
+               if (fl6->flowi6_oif != fib6_nh->nh_dev->ifindex)
                        continue;
                /* rt_cache's gateway might be different from its 'parent'
                 * in the case of an ip redirect.
                 * So we keep searching in the exception table if the gateway
                 * is different.
                 */
-               if (!ipv6_addr_equal(&rdfl->gateway, &rt->fib6_nh->nh_gw)) {
+               if (!ipv6_addr_equal(&rdfl->gateway, &fib6_nh->nh_gw)) {
                        rt_cache = rt6_find_cached_rt(rt,
                                                      &fl6->daddr,
                                                      &fl6->saddr);
@@ -3804,8 +3812,9 @@ static int fib6_remove_prefsrc(struct fib6_info *rt, void 
*arg)
        struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev;
        struct net *net = ((struct arg_dev_net_ip *)arg)->net;
        struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr;
+       struct net_device *nh_dev = fib6_info_nh_dev(rt);
 
-       if (((void *)rt->fib6_nh->nh_dev == dev || !dev) &&
+       if ((nh_dev == dev || !dev) &&
            rt != net->ipv6.fib6_null_entry &&
            ipv6_addr_equal(addr, &rt->fib6_prefsrc.addr)) {
                spin_lock_bh(&rt6_exception_lock);
@@ -4127,7 +4136,7 @@ static int rt6_mtu_change_route(struct fib6_info *rt, 
void *p_arg)
           Since RFC 1981 doesn't include administrative MTU increase
           update PMTU increase is a MUST. (i.e. jumbo frame)
         */
-       if (rt->fib6_nh->nh_dev == arg->dev &&
+       if (fib6_info_nh_dev(rt) == arg->dev &&
            !fib6_metric_locked(rt, RTAX_MTU)) {
                u32 mtu = rt->fib6_pmtu;
 
-- 
2.11.0

Reply via email to