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