ipv6: Use fib6_result for fib_lookups
Subsystems (6)
David Ahern
maintainerv2 cover ipv6: Use fib6_result for fib_lookups
From: David Ahern <[email protected]>
Add fib6_result as a single data structure to hold results from a fib lookup. IPv6 currently has everything in 1 data structure - a fib6_info, but with nexthop objects the fib6_nh can be in a nexthop or a nexthop can be a blackhole which affects the fib6_type and flags (REJECT).
v2
- fixed 2 bugs in patch12:
i. checking return from fib6_table_lookup in fib6_lookup ii. call to fib6_rule_saddr in fib6_rule_action_alt should use res->nh
David Ahern (13):
ipv6: Rename fib6_multipath_select and pass fib6_result
ipv6: Pass fib6_result to rt6_find_cached_rt
ipv6: Pass fib6_result to ip6_rt_cache_alloc
ipv6: Pass fib6_result to ip6_create_rt_rcu
ipv6: Pass fib6_result to pcpu route functions
ipv6: Pass fib6_result to ip6_rt_get_dev_rcu and ip6_rt_copy_init
ipv6: Pass fib6_result to rt6_insert_exception
ipv6: Pass fib6_result to ip6_mtu_from_fib6 and fib6_mtu
ipv6: Pass fib6_result to rt6_device_match
ipv6: Pass fib6_result to rt6_select and find_rr_leaf
ipv6: Pass fib6_result to fib6_table_lookup tracepoint
ipv6: Pass fib6_result to fib lookups
ipv6: Add fib6_type and fib6_flags to fib6_result
include/net/ip6_fib.h | 24 ++- include/net/ip6_route.h | 5 +- include/net/ipv6_stubs.h | 25 ++- include/trace/events/fib6.h | 16 +- net/core/filter.c | 56 +++--- net/ipv6/addrconf_core.c | 29 +-- net/ipv6/af_inet6.c | 2 +- net/ipv6/fib6_rules.c | 34 ++-- net/ipv6/ip6_fib.c | 7 +- net/ipv6/route.c | 443 +++++++++++++++++++++++++------------------- 10 files changed, 348 insertions(+), 293 deletions(-)
Signature · 1 line
2.11.0
David Ahern
maintainerPATCH v2 1/13 ipv6: Rename fib6_multipath_select and pass fib6_result
From: David Ahern <[email protected]>
Add 'struct fib6_result' to hold the fib entry and fib6_nh from a fib lookup as separate entries, similar to what IPv4 now has with fib_result.
Rename fib6_multipath_select to fib6_select_path, pass fib6_result to it, and set f6i and nh in the result once a path selection is done. Call fib6_select_path unconditionally for path selection which means moving the sibling and oif check to fib6_select_path. To handle the two different call paths (2 only call multipath_select if flowi6_oif == 0 and the other always calls it), add a new have_oif_match that controls the sibling walk if relevant.
Update callers of fib6_multipath_select accordingly and have them use the fib6_info and fib6_nh from the result.
This is needed for multipath nexthop objects where a single f6i can point to multiple fib6_nh (similar to IPv4).
--- include/net/ip6_fib.h | 13 ++++++---- include/net/ipv6_stubs.h | 9 +++---- net/core/filter.c | 34 +++++++++++++------------- net/ipv6/addrconf_core.c | 11 ++++----- net/ipv6/af_inet6.c | 2 +- net/ipv6/route.c | 63 +++++++++++++++++++++++++----------------------- 6 files changed, 68 insertions(+), 64 deletions(-)
include/net/ip6_fib.h +8 -5
@@ -190,6 +190,11 @@ struct rt6_info {unsigned short rt6i_nfheader_len; }; +struct fib6_result { +struct fib6_nh *nh; +struct fib6_info *f6i; +}; +#define for_each_fib6_node_rt_rcu (fn) \ for (rt = rcu_dereference((fn)->leaf); rt; \ rt = rcu_dereference(rt->fib6_next))
@@ -391,11 +396,9 @@ struct fib6_info *fib6_lookup(struct net *net, int oif, struct flowi6 *fl6,struct fib6_info *fib6_table_lookup (struct net *net,struct fib6_table *table,int oif,struct flowi6 *fl6,int strict); -struct fib6_info *fib6_multipath_select (const struct net *net, -struct fib6_info *match, -struct flowi6 *fl6,int oif, -const struct sk_buff *skb,int strict); - +void fib6_select_path (const struct net *net,struct fib6_result *res, +struct flowi6 *fl6,int oif,bool have_oif_match, +const struct sk_buff *skb,int strict);struct fib6_node *fib6_node_lookup (struct fib6_node *root,const struct in6_addr *daddr,const struct in6_addr *saddr);
include/net/ipv6_stubs.h +4 -5
@@ -14,6 +14,7 @@struct fib6_info ;struct fib6_nh ;struct fib6_config ; +struct fib6_result ;/* This is ugly, ideally these symbols should be built * into the core kernel.
@@ -34,11 +35,9 @@ struct ipv6_stub {struct fib6_table *table, int oif, struct flowi6 *fl6, int flags); -struct fib6_info *(*fib6_multipath_select)(const struct net *net, -struct fib6_info *f6i, -struct flowi6 *fl6,int oif, -const struct sk_buff *skb, -int strict); +void (*fib6_select_path)(const struct net *net,struct fib6_result *res, +struct flowi6 *fl6,int oif,bool oif_match, +const struct sk_buff *skb,int strict);u32 (*ip6_mtu_from_fib6)(struct fib6_info *f6i,struct in6_addr *daddr,struct in6_addr *saddr);
net/core/filter.c +17 -17
@@ -4677,9 +4677,9 @@ 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 neighbour *neigh; +struct fib6_result res;struct net_device *dev;struct inet6_dev *idev; -struct fib6_info *f6i;struct flowi6 fl6;int strict =0 ;int oif;
@@ -4724,21 +4724,23 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params,if (unlikely (!tb))return BPF_FIB_LKUP_RET_NOT_FWDED ; - f6i = ipv6_stub->fib6_table_lookup (net, tb, oif, &fl6, strict); + res.f6i = ipv6_stub->fib6_table_lookup (net, tb, oif, &fl6, + strict); }else { fl6.flowi6_mark =0 ; fl6.flowi6_secid =0 ; fl6.flowi6_tun_key.tun_id =0 ; fl6.flowi6_uid =sock_net_uid (net,NULL ); - f6i = ipv6_stub->fib6_lookup (net, oif, &fl6, strict); + res.f6i = ipv6_stub->fib6_lookup (net, oif, &fl6, strict); } -if (unlikely (IS_ERR_OR_NULL (f6i) || f6i == net->ipv6.fib6_null_entry)) +if (unlikely (IS_ERR_OR_NULL (res.f6i) || + res.f6i == net->ipv6.fib6_null_entry))return BPF_FIB_LKUP_RET_NOT_FWDED ; -if (unlikely (f6i->fib6_flags &RTF_REJECT )) { -switch (f6i->fib6_type) { +if (unlikely (res.f6i->fib6_flags &RTF_REJECT )) { +switch (res.f6i->fib6_type) {case RTN_BLACKHOLE :return BPF_FIB_LKUP_RET_BLACKHOLE ;case RTN_UNREACHABLE :
@@ -4750,28 +4752,26 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params, } } -if (f6i->fib6_type !=RTN_UNICAST ) +if (res.f6i->fib6_type !=RTN_UNICAST )return BPF_FIB_LKUP_RET_NOT_FWDED ; -if (f6i->fib6_nsiblings && fl6.flowi6_oif ==0 ) - f6i = ipv6_stub->fib6_multipath_select (net, f6i, &fl6, - fl6.flowi6_oif,NULL , - strict); + ipv6_stub->fib6_select_path (net, &res, &fl6, fl6.flowi6_oif, + fl6.flowi6_oif !=0 ,NULL , strict);if (check_mtu) { - mtu = ipv6_stub->ip6_mtu_from_fib6 (f6i, dst, src); + mtu = ipv6_stub->ip6_mtu_from_fib6 (res.f6i, dst, src);if (params->tot_len > mtu)return BPF_FIB_LKUP_RET_FRAG_NEEDED ; } -if (f6i->fib6_nh.fib_nh_lws) +if (res.nh->fib_nh_lws)return BPF_FIB_LKUP_RET_UNSUPP_LWT ; -if (f6i->fib6_nh.fib_nh_gw_family) - *dst = f6i->fib6_nh.fib_nh_gw6; +if (res.nh->fib_nh_gw_family) + *dst = res.nh->fib_nh_gw6; - dev = f6i->fib6_nh.fib_nh_dev; - params->rt_metric = f6i->fib6_metric; + dev = res.nh->fib_nh_dev; + params->rt_metric = res.f6i->fib6_metric;/* xdp and cls_bpf programs are run in RCU-bh so rcu_read_lock_bh is * not needed here.
net/ipv6/addrconf_core.c +5 -6
@@ -158,12 +158,11 @@ eafnosupport_fib6_lookup(struct net *net, int oif, struct flowi6 *fl6,return NULL ; } -static struct fib6_info * -eafnosupport_fib6_multipath_select (const struct net *net,struct fib6_info *f6i, -struct flowi6 *fl6,int oif, -const struct sk_buff *skb,int strict) +static void +eafnosupport_fib6_select_path (const struct net *net,struct fib6_result *res, +struct flowi6 *fl6,int oif,bool have_oif_match, +const struct sk_buff *skb,int strict) { -return f6i; } static u32
@@ -187,7 +186,7 @@ const struct ipv6_stub *ipv6_stub __read_mostly = &(struct ipv6_stub) { .fib6_get_table = eafnosupport_fib6_get_table, .fib6_table_lookup = eafnosupport_fib6_table_lookup, .fib6_lookup = eafnosupport_fib6_lookup, - .fib6_multipath_select = eafnosupport_fib6_multipath_select, + .fib6_select_path = eafnosupport_fib6_select_path, .ip6_mtu_from_fib6 = eafnosupport_ip6_mtu_from_fib6, .fib6_nh_init = eafnosupport_fib6_nh_init, };
net/ipv6/af_inet6.c +1 -1
@@ -917,7 +917,7 @@ static const struct ipv6_stub ipv6_stub_impl = { .fib6_get_table = fib6_get_table, .fib6_table_lookup = fib6_table_lookup, .fib6_lookup = fib6_lookup, - .fib6_multipath_select = fib6_multipath_select, + .fib6_select_path = fib6_select_path, .ip6_mtu_from_fib6 = ip6_mtu_from_fib6, .fib6_nh_init = fib6_nh_init, .fib6_nh_release = fib6_nh_release,
net/ipv6/route.c +33 -30
151 lines not on this page · raw message
Signature · 1 line
2.11.0
David Ahern
maintainerPATCH v2 2/13 ipv6: Pass fib6_result to rt6_find_cached_rt
In reply to David AhernFrom: David Ahern <[email protected]>
Simplify rt6_find_cached_rt for the fast path cases and pass fib6_result to rt6_find_cached_rt. Rename the local return variable to ret to maintain consisting with fib6_result name.
Update the comment in rt6_find_cached_rt to reference the new names in a fib6_info vs the old name when fib entries were an rt6_info.
--- net/ipv6/route.c | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-)
net/ipv6/route.c +21 -14
@@ -110,7 +110,7 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb, struct in6_addr *dest, struct in6_addr *src, int iif, int type, u32 portid, u32 seq, unsigned int flags); -static struct rt6_info *rt6_find_cached_rt (struct fib6_info *rt, +static struct rt6_info *rt6_find_cached_rt (const struct fib6_result *res,struct in6_addr *daddr,struct in6_addr *saddr);
@@ -1098,7 +1098,7 @@ static struct rt6_info *ip6_pol_route_lookup(struct net *net, fl6->flowi6_oif != 0, skb, flags);/* Search through exception table */ - rt =rt6_find_cached_rt (res.f6i, &fl6->daddr, &fl6->saddr); + rt =rt6_find_cached_rt (&res, &fl6->daddr, &fl6->saddr);if (rt) {if (ip6_hold_safe (net, &rt))dst_use_noref (&rt->dst, jiffies);
@@ -1538,33 +1538,33 @@ void rt6_flush_exceptions(struct fib6_info *rt)/* Find cached rt in the hash table inside passed in rt * Caller has to hold rcu_read_lock() */ -static struct rt6_info *rt6_find_cached_rt (struct fib6_info *rt, +static struct rt6_info *rt6_find_cached_rt (const struct fib6_result *res,struct in6_addr *daddr,struct in6_addr *saddr) {struct rt6_exception_bucket *bucket;struct in6_addr *src_key =NULL ;struct rt6_exception *rt6_ex; -struct rt6_info *res =NULL ; +struct rt6_info *ret =NULL ; - bucket =rcu_dereference (rt->rt6i_exception_bucket); + bucket =rcu_dereference (res->f6i->rt6i_exception_bucket);#ifdef CONFIG_IPV6_SUBTREES -/* rt6i_src.plen != 0 indicates rt is in subtree +/* fib6i_src.plen != 0 indicates f6i is in subtree * and exception table is indexed by a hash of -* both rt6i_dst and rt6i_src. +* both fib6_dst and fib6_src. * Otherwise, the exception table is indexed by -* a hash of only rt6i_dst. +* a hash of only fib6_dst. */ -if (rt->fib6_src.plen) +if (res->f6i->fib6_src.plen) src_key = saddr;#endif rt6_ex =__rt6_find_exception_rcu (&bucket, daddr, src_key);if (rt6_ex && !rt6_check_expired (rt6_ex->rt6i)) - res = rt6_ex->rt6i; + ret = rt6_ex->rt6i; -return res; +return ret; }/* Remove the passed in cached rt from the hash table that contains it */
@@ -1869,7 +1869,7 @@ struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,fib6_select_path (net, &res, fl6, oif, false, skb, strict);/*Search through exception table */ - rt =rt6_find_cached_rt (res.f6i, &fl6->daddr, &fl6->saddr); + rt =rt6_find_cached_rt (&res, &fl6->daddr, &fl6->saddr);if (rt) {if (ip6_hold_safe (net, &rt))dst_use_noref (&rt->dst, jiffies);
@@ -2426,9 +2426,12 @@ static bool ip6_redirect_nh_match(struct fib6_info *f6i,* is different. */ if (!ipv6_addr_equal (gw, &nh->fib_nh_gw6)) { +struct fib6_result res = { + .f6i = f6i, + };struct rt6_info *rt_cache; - rt_cache =rt6_find_cached_rt (f6i, &fl6->daddr, &fl6->saddr); + rt_cache =rt6_find_cached_rt (&res, &fl6->daddr, &fl6->saddr);if (rt_cache &&ipv6_addr_equal (gw, &rt_cache->rt6i_gateway)) { *ret = rt_cache;
@@ -3307,9 +3310,13 @@ static int ip6_route_del(struct fib6_config *cfg,struct fib6_nh *nh;if (cfg->fc_flags &RTF_CACHE ) { +struct fib6_result res = { + .f6i = rt, + };int rc; - rt_cache =rt6_find_cached_rt (rt, &cfg->fc_dst, + rt_cache =rt6_find_cached_rt (&res, + &cfg->fc_dst, &cfg->fc_src);if (rt_cache) { rc =ip6_del_cached_rt (rt_cache, cfg);
Signature · 1 line
2.11.0
David Ahern
maintainerPATCH v2 3/13 ipv6: Pass fib6_result to ip6_rt_cache_alloc
In reply to David AhernFrom: David Ahern <[email protected]>
Change ip6_rt_cache_alloc to take a fib6_result over a fib6_info.
Since ip6_rt_cache_alloc is only the caller, update the rt6_is_gw_or_nonexthop helper to take fib6_result.
--- net/ipv6/route.c | 46 +++++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 21 deletions(-)
net/ipv6/route.c +25 -21
@@ -784,9 +784,10 @@ static struct fib6_info *rt6_select(struct net *net, struct fib6_node *fn,return match ? match : net->ipv6.fib6_null_entry; } -static bool rt6_is_gw_or_nonexthop (const struct fib6_info *rt) +static bool rt6_is_gw_or_nonexthop (const struct fib6_result *res) { -return (rt->fib6_flags &RTF_NONEXTHOP ) || rt->fib6_nh.fib_nh_gw_family; +return (res->f6i->fib6_flags &RTF_NONEXTHOP ) || + res->nh->fib_nh_gw_family; }#ifdef CONFIG_IPV6_ROUTE_INFO
@@ -1174,10 +1175,11 @@ int ip6_ins_rt(struct net *net, struct fib6_info *rt)return __ip6_ins_rt (rt, &info,NULL ); } -static struct rt6_info *ip6_rt_cache_alloc (struct fib6_info *ort, +static struct rt6_info *ip6_rt_cache_alloc (const struct fib6_result *res,const struct in6_addr *daddr,const struct in6_addr *saddr) { +struct fib6_info *f6i = res->f6i;struct net_device *dev;struct rt6_info *rt;
@@ -1185,25 +1187,25 @@ static struct rt6_info *ip6_rt_cache_alloc(struct fib6_info *ort,* Clone the route. */ -if (!fib6_info_hold_safe (ort)) +if (!fib6_info_hold_safe (f6i))return NULL ; - dev =ip6_rt_get_dev_rcu (ort); + dev =ip6_rt_get_dev_rcu (f6i); rt =ip6_dst_alloc (dev_net (dev), dev,0 );if (!rt) { -fib6_info_release (ort); +fib6_info_release (f6i);return NULL ; } -ip6_rt_copy_init (rt, ort); +ip6_rt_copy_init (rt, res->f6i); rt->rt6i_flags |=RTF_CACHE ; rt->dst.flags |=DST_HOST ; rt->rt6i_dst.addr = *daddr; rt->rt6i_dst.plen =128 ; -if (!rt6_is_gw_or_nonexthop (ort)) { -if (ort->fib6_dst.plen !=128 && -ipv6_addr_equal (&ort->fib6_dst.addr, daddr)) +if (!rt6_is_gw_or_nonexthop (res)) { +if (f6i->fib6_dst.plen !=128 && +ipv6_addr_equal (&f6i->fib6_dst.addr, daddr)) rt->rt6i_flags |=RTF_ANYCAST ;#ifdef CONFIG_IPV6_SUBTREES if (rt->rt6i_src.plen && saddr) {
@@ -1885,7 +1887,7 @@ struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,*/ struct rt6_info *uncached_rt; - uncached_rt =ip6_rt_cache_alloc (res.f6i, &fl6->daddr,NULL ); + uncached_rt =ip6_rt_cache_alloc (&res, &fl6->daddr,NULL );rcu_read_unlock ();
@@ -2329,15 +2331,16 @@ static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,if (rt6->rt6i_flags &RTF_CACHE )rt6_update_exception_stamp_rt (rt6); }else if (daddr) { -struct fib6_info *from; +struct fib6_result res = {};struct rt6_info *nrt6;rcu_read_lock (); - from =rcu_dereference (rt6->from); - nrt6 =ip6_rt_cache_alloc (from, daddr, saddr); + res.f6i =rcu_dereference (rt6->from); + res.nh = &res.f6i->fib6_nh; + nrt6 =ip6_rt_cache_alloc (&res, daddr, saddr);if (nrt6) {rt6_do_update_pmtu (nrt6, mtu); -if (rt6_insert_exception (nrt6, from)) +if (rt6_insert_exception (nrt6, res.f6i))dst_release_immediate (&nrt6->dst); }rcu_read_unlock ();
@@ -3360,10 +3363,10 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu {struct netevent_redirect netevent;struct rt6_info *rt, *nrt =NULL ; +struct fib6_result res = {};struct ndisc_options ndopts;struct inet6_dev *in6_dev;struct neighbour *neigh; -struct fib6_info *from;struct rd_msg *msg;int optlen, on_link;u8 *lladdr;
@@ -3446,14 +3449,15 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu NDISC_REDIRECT, &ndopts);rcu_read_lock (); - from =rcu_dereference (rt->from); + res.f6i =rcu_dereference (rt->from);/* This fib6_info_hold() is safe here because we hold reference to rt * and rt already holds reference to fib6_info. */ -fib6_info_hold (from); +fib6_info_hold (res.f6i);rcu_read_unlock (); - nrt =ip6_rt_cache_alloc (from, &msg->dest,NULL ); + res.nh = &res.f6i->fib6_nh; + nrt =ip6_rt_cache_alloc (&res, &msg->dest,NULL );if (!nrt) goto out;
@@ -3467,7 +3471,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu* a cached route because rt6_insert_exception() will * takes care of it */ -if (rt6_insert_exception (nrt, from)) { +if (rt6_insert_exception (nrt, res.f6i)) {dst_release_immediate (&nrt->dst); goto out; }
@@ -3479,7 +3483,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bucall_netevent_notifiers (NETEVENT_REDIRECT , &netevent); out: -fib6_info_release (from); +fib6_info_release (res.f6i);neigh_release (neigh); }
Signature · 1 line
2.11.0
David Ahern
maintainerPATCH v2 4/13 ipv6: Pass fib6_result to ip6_create_rt_rcu
In reply to David AhernFrom: David Ahern <[email protected]>
Change ip6_create_rt_rcu to take fib6_result over a fib6_info.
--- net/ipv6/route.c | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-)
net/ipv6/route.c +21 -16
@@ -1038,22 +1038,24 @@ static bool ip6_hold_safe(struct net *net, struct rt6_info **prt) }/* called with rcu_lock held */ -static struct rt6_info *ip6_create_rt_rcu (struct fib6_info *rt) +static struct rt6_info *ip6_create_rt_rcu (const struct fib6_result *res) { -unsigned short flags =fib6_info_dst_flags (rt); -struct net_device *dev = rt->fib6_nh.fib_nh_dev; +struct net_device *dev = res->nh->fib_nh_dev; +struct fib6_info *f6i = res->f6i; +unsigned short flags;struct rt6_info *nrt; -if (!fib6_info_hold_safe (rt)) +if (!fib6_info_hold_safe (f6i)) goto fallback; + flags =fib6_info_dst_flags (f6i); nrt =ip6_dst_alloc (dev_net (dev), dev, flags);if (!nrt) { -fib6_info_release (rt); +fib6_info_release (f6i); goto fallback; } -ip6_rt_copy_init (nrt, rt); +ip6_rt_copy_init (nrt, f6i);return nrt; fallback:
@@ -1104,7 +1106,7 @@ static struct rt6_info *ip6_pol_route_lookup(struct net *net,if (ip6_hold_safe (net, &rt))dst_use_noref (&rt->dst, jiffies); }else { - rt =ip6_create_rt_rcu (res.f6i); + rt =ip6_create_rt_rcu (&res); } out:
@@ -2413,12 +2415,13 @@ void ip6_sk_dst_store_flow(struct sock *sk, struct dst_entry *dst, NULL); } -static bool ip6_redirect_nh_match (struct fib6_info *f6i, -struct fib6_nh *nh, +static bool ip6_redirect_nh_match (const struct fib6_result *res,struct flowi6 *fl6,const struct in6_addr *gw,struct rt6_info **ret) { +const struct fib6_nh *nh = res->nh; +if (nh->fib_nh_flags &RTNH_F_DEAD || !nh->fib_nh_gw_family || fl6->flowi6_oif != nh->fib_nh_dev->ifindex)return false;
@@ -2429,12 +2432,9 @@ static bool ip6_redirect_nh_match(struct fib6_info *f6i,* is different. */ if (!ipv6_addr_equal (gw, &nh->fib_nh_gw6)) { -struct fib6_result res = { - .f6i = f6i, - };struct rt6_info *rt_cache; - rt_cache =rt6_find_cached_rt (&res, &fl6->daddr, &fl6->saddr); + rt_cache =rt6_find_cached_rt (res, &fl6->daddr, &fl6->saddr);if (rt_cache &&ipv6_addr_equal (gw, &rt_cache->rt6i_gateway)) { *ret = rt_cache;
@@ -2459,6 +2459,7 @@ 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_info *rt;struct fib6_node *fn;
@@ -2476,12 +2477,14 @@ 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) { + 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 (rt, &rt->fib6_nh, fl6, - &rdfl->gateway, &ret)) +if (ip6_redirect_nh_match (&res, fl6, &rdfl->gateway, &ret)) goto out; }
@@ -2498,11 +2501,13 @@ static struct rt6_info *__ip6_route_redirect(struct net *net, goto restart; } + res.f6i = rt; + res.nh = &rt->fib6_nh; out:if (ret)ip6_hold_safe (net, &ret);else - ret =ip6_create_rt_rcu (rt); + ret =ip6_create_rt_rcu (&res);rcu_read_unlock ();
Signature · 1 line
2.11.0
David Ahern
maintainerPATCH v2 5/13 ipv6: Pass fib6_result to pcpu route functions
In reply to David AhernFrom: David Ahern <[email protected]>
Update ip6_rt_pcpu_alloc, rt6_get_pcpu_route and rt6_make_pcpu_route to a fib6_result over a fib6_info.
--- net/ipv6/route.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-)
net/ipv6/route.c +14 -13
@@ -1220,34 +1220,35 @@ static struct rt6_info *ip6_rt_cache_alloc(const struct fib6_result *res,return rt; } -static struct rt6_info *ip6_rt_pcpu_alloc (struct fib6_info *rt) +static struct rt6_info *ip6_rt_pcpu_alloc (const struct fib6_result *res) { -unsigned short flags =fib6_info_dst_flags (rt); +struct fib6_info *f6i = res->f6i; +unsigned short flags =fib6_info_dst_flags (f6i);struct net_device *dev;struct rt6_info *pcpu_rt; -if (!fib6_info_hold_safe (rt)) +if (!fib6_info_hold_safe (f6i))return NULL ;rcu_read_lock (); - dev =ip6_rt_get_dev_rcu (rt); + dev =ip6_rt_get_dev_rcu (f6i); pcpu_rt =ip6_dst_alloc (dev_net (dev), dev, flags);rcu_read_unlock ();if (!pcpu_rt) { -fib6_info_release (rt); +fib6_info_release (f6i);return NULL ; } -ip6_rt_copy_init (pcpu_rt, rt); +ip6_rt_copy_init (pcpu_rt, f6i); pcpu_rt->rt6i_flags |=RTF_PCPU ;return pcpu_rt; }/* It should be called with rcu_read_lock() acquired */ -static struct rt6_info *rt6_get_pcpu_route (struct fib6_info *rt) +static struct rt6_info *rt6_get_pcpu_route (const struct fib6_result *res) {struct rt6_info *pcpu_rt, **p; - p =this_cpu_ptr (rt->rt6i_pcpu); + p =this_cpu_ptr (res->f6i->rt6i_pcpu); pcpu_rt = *p;if (pcpu_rt)
@@ -1257,18 +1258,18 @@ static struct rt6_info *rt6_get_pcpu_route(struct fib6_info *rt) }static struct rt6_info *rt6_make_pcpu_route (struct net *net, -struct fib6_info *rt) +const struct fib6_result *res) {struct rt6_info *pcpu_rt, *prev, **p; - pcpu_rt =ip6_rt_pcpu_alloc (rt); + pcpu_rt =ip6_rt_pcpu_alloc (res);if (!pcpu_rt) {dst_hold (&net->ipv6.ip6_null_entry->dst);return net->ipv6.ip6_null_entry; }dst_hold (&pcpu_rt->dst); - p =this_cpu_ptr (rt->rt6i_pcpu); + p =this_cpu_ptr (res->f6i->rt6i_pcpu); prev =cmpxchg (p,NULL , pcpu_rt);BUG_ON (prev);
@@ -1911,10 +1912,10 @@ struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,struct rt6_info *pcpu_rt;local_bh_disable (); - pcpu_rt =rt6_get_pcpu_route (res.f6i); + pcpu_rt =rt6_get_pcpu_route (&res);if (!pcpu_rt) - pcpu_rt =rt6_make_pcpu_route (net, res.f6i); + pcpu_rt =rt6_make_pcpu_route (net, &res);local_bh_enable ();rcu_read_unlock ();
Signature · 1 line
2.11.0
David Ahern
maintainerPATCH v2 6/13 ipv6: Pass fib6_result to ip6_rt_get_dev_rcu and ip6_rt_copy_init
In reply to David AhernFrom: David Ahern <[email protected]>
Now that all callers are update to have a fib6_result, pass it down to ip6_rt_get_dev_rcu, ip6_rt_copy_init, and ip6_rt_init_dst.
In the process, change ort to f6i in ip6_rt_copy_init to make it clear it is a reference to a fib6_info.
--- net/ipv6/route.c | 49 +++++++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 22 deletions(-)
net/ipv6/route.c +27 -22
@@ -871,17 +871,18 @@ 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) +static struct net_device *ip6_rt_get_dev_rcu (const struct fib6_result *res) { -struct net_device *dev = rt->fib6_nh.fib_nh_dev; +struct net_device *dev = res->nh->fib_nh_dev; +const struct fib6_info *f6i = res->f6i; -if (rt->fib6_flags & (RTF_LOCAL |RTF_ANYCAST )) { +if (f6i->fib6_flags & (RTF_LOCAL |RTF_ANYCAST )) {/* for copies of local routes, dst->dev needs to be the * device if it is a master device, the master device if * device is enslaved, and the loopback as the default */ if (netif_is_l3_slave (dev) && - !rt6_need_strict (&rt->fib6_dst.addr)) + !rt6_need_strict (&f6i->fib6_dst.addr)) dev =l3mdev_master_dev_rcu (dev);else if (!netif_is_l3_master (dev)) dev =dev_net (dev)->loopback_dev;
@@ -949,8 +950,10 @@ 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) +static void ip6_rt_init_dst (struct rt6_info *rt,const struct fib6_result *res) { +struct fib6_info *ort = res->f6i; +if (ort->fib6_flags &RTF_REJECT ) {ip6_rt_init_dst_reject (rt, ort);return ;
@@ -967,8 +970,8 @@ static void ip6_rt_init_dst(struct rt6_info *rt, struct fib6_info *ort) rt->dst.input = ip6_forward; } -if (ort->fib6_nh.fib_nh_lws) { - rt->dst.lwtstate =lwtstate_get (ort->fib6_nh.fib_nh_lws); +if (res->nh->fib_nh_lws) { + rt->dst.lwtstate =lwtstate_get (res->nh->fib_nh_lws);lwtunnel_set_redirect (&rt->dst); }
@@ -983,23 +986,25 @@ static void rt6_set_from(struct rt6_info *rt, struct fib6_info *from)ip_dst_init_metrics (&rt->dst, from->fib6_metrics); } -/* Caller must already hold reference to @ort */ -static void ip6_rt_copy_init (struct rt6_info *rt,struct fib6_info *ort) +/* Caller must already hold reference to f6i in result */ +static void ip6_rt_copy_init (struct rt6_info *rt,const struct fib6_result *res) { -struct net_device *dev =fib6_info_nh_dev (ort); +const struct fib6_nh *nh = res->nh; +const struct net_device *dev = nh->fib_nh_dev; +struct fib6_info *f6i = res->f6i; -ip6_rt_init_dst (rt, ort); +ip6_rt_init_dst (rt, res); - rt->rt6i_dst = ort->fib6_dst; + rt->rt6i_dst = f6i->fib6_dst; rt->rt6i_idev = dev ?in6_dev_get (dev) :NULL ; - rt->rt6i_flags = ort->fib6_flags; -if (ort->fib6_nh.fib_nh_gw_family) { - rt->rt6i_gateway = ort->fib6_nh.fib_nh_gw6; + rt->rt6i_flags = f6i->fib6_flags; +if (nh->fib_nh_gw_family) { + rt->rt6i_gateway = nh->fib_nh_gw6; rt->rt6i_flags |=RTF_GATEWAY ; } -rt6_set_from (rt, ort); +rt6_set_from (rt, f6i);#ifdef CONFIG_IPV6_SUBTREES - rt->rt6i_src = ort->fib6_src; + rt->rt6i_src = f6i->fib6_src;#endif }
@@ -1055,7 +1060,7 @@ static struct rt6_info *ip6_create_rt_rcu(const struct fib6_result *res) goto fallback; } -ip6_rt_copy_init (nrt, f6i); +ip6_rt_copy_init (nrt, res);return nrt; fallback:
@@ -1192,14 +1197,14 @@ static struct rt6_info *ip6_rt_cache_alloc(const struct fib6_result *res,if (!fib6_info_hold_safe (f6i))return NULL ; - dev =ip6_rt_get_dev_rcu (f6i); + dev =ip6_rt_get_dev_rcu (res); rt =ip6_dst_alloc (dev_net (dev), dev,0 );if (!rt) {fib6_info_release (f6i);return NULL ; } -ip6_rt_copy_init (rt, res->f6i); +ip6_rt_copy_init (rt, res); rt->rt6i_flags |=RTF_CACHE ; rt->dst.flags |=DST_HOST ; rt->rt6i_dst.addr = *daddr;
@@ -1231,14 +1236,14 @@ static struct rt6_info *ip6_rt_pcpu_alloc(const struct fib6_result *res)return NULL ;rcu_read_lock (); - dev =ip6_rt_get_dev_rcu (f6i); + dev =ip6_rt_get_dev_rcu (res); pcpu_rt =ip6_dst_alloc (dev_net (dev), dev, flags);rcu_read_unlock ();if (!pcpu_rt) {fib6_info_release (f6i);return NULL ; } -ip6_rt_copy_init (pcpu_rt, f6i); +ip6_rt_copy_init (pcpu_rt, res); pcpu_rt->rt6i_flags |=RTF_PCPU ;return pcpu_rt; }
Signature · 1 line
2.11.0
David Ahern
maintainerPATCH v2 7/13 ipv6: Pass fib6_result to rt6_insert_exception
In reply to David AhernFrom: David Ahern <[email protected]>
Update rt6_insert_exception to take a fib6_result over a fib6_info. Change ort to f6i from the fib6_result and rename to better reflect what it references (a fib6_info).
Since this function is already getting changed, update the comments to reference fib6_info variables rather than the older rt6_info.
--- net/ipv6/route.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-)
net/ipv6/route.c +17 -16
@@ -1439,22 +1439,23 @@ static unsigned int fib6_mtu(const struct fib6_info *rt) }static int rt6_insert_exception (struct rt6_info *nrt, -struct fib6_info *ort) +const struct fib6_result *res) {struct net *net =dev_net (nrt->dst.dev);struct rt6_exception_bucket *bucket;struct in6_addr *src_key =NULL ;struct rt6_exception *rt6_ex; +struct fib6_info *f6i = res->f6i;int err =0 ;spin_lock_bh (&rt6_exception_lock); -if (ort->exception_bucket_flushed) { +if (f6i->exception_bucket_flushed) { err = -EINVAL ; goto out; } - bucket =rcu_dereference_protected (ort->rt6i_exception_bucket, + bucket =rcu_dereference_protected (f6i->rt6i_exception_bucket,lockdep_is_held (&rt6_exception_lock));if (!bucket) { bucket = kcalloc(FIB6_EXCEPTION_BUCKET_SIZE, sizeof(*bucket),
@@ -1463,24 +1464,24 @@ static int rt6_insert_exception(struct rt6_info *nrt, err = -ENOMEM ; goto out; } -rcu_assign_pointer (ort->rt6i_exception_bucket, bucket); +rcu_assign_pointer (f6i->rt6i_exception_bucket, bucket); }#ifdef CONFIG_IPV6_SUBTREES -/* rt6i_src.plen != 0 indicates ort is in subtree +/* fib6_src.plen != 0 indicates f6i is in subtree * and exception table is indexed by a hash of -* both rt6i_dst and rt6i_src. +* both fib6_dst and fib6_src. * Otherwise, the exception table is indexed by -* a hash of only rt6i_dst. +* a hash of only fib6_dst. */ -if (ort->fib6_src.plen) +if (f6i->fib6_src.plen) src_key = &nrt->rt6i_src.addr;#endif -/* rt6_mtu_change() might lower mtu on ort. +/* rt6_mtu_change() might lower mtu on f6i. * Only insert this exception route if its mtu -* is less than ort's mtu value. +* is less than f6i's mtu value. */ -if (dst_metric_raw (&nrt->dst,RTAX_MTU ) >=fib6_mtu (ort)) { +if (dst_metric_raw (&nrt->dst,RTAX_MTU ) >=fib6_mtu (res->f6i)) { err = -EINVAL ; goto out; }
@@ -1509,9 +1510,9 @@ static int rt6_insert_exception(struct rt6_info *nrt,/* Update fn->fn_sernum to invalidate all cached dst */ if (!err) { -spin_lock_bh (&ort->fib6_table->tb6_lock); -fib6_update_sernum (net, ort); -spin_unlock_bh (&ort->fib6_table->tb6_lock); +spin_lock_bh (&f6i->fib6_table->tb6_lock); +fib6_update_sernum (net, f6i); +spin_unlock_bh (&f6i->fib6_table->tb6_lock);fib6_force_start_gc (net); }
@@ -2348,7 +2349,7 @@ static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk, nrt6 =ip6_rt_cache_alloc (&res, daddr, saddr);if (nrt6) {rt6_do_update_pmtu (nrt6, mtu); -if (rt6_insert_exception (nrt6, res.f6i)) +if (rt6_insert_exception (nrt6, &res))dst_release_immediate (&nrt6->dst); }rcu_read_unlock ();
@@ -3482,7 +3483,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu* a cached route because rt6_insert_exception() will * takes care of it */ -if (rt6_insert_exception (nrt, res.f6i)) { +if (rt6_insert_exception (nrt, &res)) {dst_release_immediate (&nrt->dst); goto out; }
Signature · 1 line
2.11.0
David Ahern
maintainerPATCH v2 8/13 ipv6: Pass fib6_result to ip6_mtu_from_fib6 and fib6_mtu
In reply to David AhernFrom: David Ahern <[email protected]>
Change ip6_mtu_from_fib6 and fib6_mtu to take a fib6_result over a fib6_info. Update both to use the fib6_nh from fib6_result.
Since the signature of ip6_mtu_from_fib6 is already changing, add const to daddr and saddr.
--- include/net/ip6_route.h | 5 +++-- include/net/ipv6_stubs.h | 5 +++-- net/core/filter.c | 2 +- net/ipv6/addrconf_core.c | 5 +++-- net/ipv6/route.c | 26 +++++++++++++++----------- 5 files changed, 25 insertions(+), 18 deletions(-)
include/net/ip6_route.h +3 -2
@@ -302,8 +302,9 @@ static inline unsigned int ip6_dst_mtu_forward(const struct dst_entry *dst)return mtu; } -u32 ip6_mtu_from_fib6 (struct fib6_info *f6i,struct in6_addr *daddr, -struct in6_addr *saddr); +u32 ip6_mtu_from_fib6 (const struct fib6_result *res, +const struct in6_addr *daddr, +const struct in6_addr *saddr); struct neighbour *ip6_neigh_lookup(const struct in6_addr *gw, struct net_device *dev, struct sk_buff *skb,
include/net/ipv6_stubs.h +3 -2
@@ -38,8 +38,9 @@ struct ipv6_stub {void (*fib6_select_path)(const struct net *net,struct fib6_result *res,struct flowi6 *fl6,int oif,bool oif_match,const struct sk_buff *skb,int strict); -u32 (*ip6_mtu_from_fib6)(struct fib6_info *f6i,struct in6_addr *daddr, -struct in6_addr *saddr); +u32 (*ip6_mtu_from_fib6)(const struct fib6_result *res, +const struct in6_addr *daddr, +const struct in6_addr *saddr); int (*fib6_nh_init)(struct net *net, struct fib6_nh *fib6_nh, struct fib6_config *cfg, gfp_t gfp_flags,
net/core/filter.c +1 -1
@@ -4759,7 +4759,7 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params, fl6.flowi6_oif != 0, NULL, strict);if (check_mtu) { - mtu = ipv6_stub->ip6_mtu_from_fib6 (res.f6i, dst, src); + mtu = ipv6_stub->ip6_mtu_from_fib6 (&res, dst, src);if (params->tot_len > mtu)return BPF_FIB_LKUP_RET_FRAG_NEEDED ; }
net/ipv6/addrconf_core.c +3 -2
@@ -166,8 +166,9 @@ eafnosupport_fib6_select_path(const struct net *net, struct fib6_result *res, }static u32 -eafnosupport_ip6_mtu_from_fib6 (struct fib6_info *f6i,struct in6_addr *daddr, -struct in6_addr *saddr) +eafnosupport_ip6_mtu_from_fib6 (const struct fib6_result *res, +const struct in6_addr *daddr, +const struct in6_addr *saddr) {return 0 ; }
net/ipv6/route.c +15 -11
@@ -1417,14 +1417,15 @@ __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 (const struct fib6_result *res) { +const struct fib6_nh *nh = res->nh;unsigned int mtu; -if (rt->fib6_pmtu) { - mtu = rt->fib6_pmtu; +if (res->f6i->fib6_pmtu) { + mtu = res->f6i->fib6_pmtu; }else { -struct net_device *dev =fib6_info_nh_dev (rt); +struct net_device *dev = nh->fib_nh_dev;struct inet6_dev *idev;rcu_read_lock ();
@@ -1435,7 +1436,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.fib_nh_lws, mtu); +return mtu -lwtunnel_headroom (nh->fib_nh_lws, mtu); } static int rt6_insert_exception(struct rt6_info *nrt,
@@ -1481,7 +1482,7 @@ static int rt6_insert_exception(struct rt6_info *nrt,* Only insert this exception route if its mtu * is less than f6i's mtu value. */ -if (dst_metric_raw (&nrt->dst,RTAX_MTU ) >=fib6_mtu (res->f6i)) { +if (dst_metric_raw (&nrt->dst,RTAX_MTU ) >=fib6_mtu (res)) { err = -EINVAL ; goto out; }
@@ -2636,12 +2637,15 @@ static unsigned int ip6_mtu(const struct dst_entry *dst)* based on ip6_dst_mtu_forward and exception logic of * rt6_find_cached_rt; called with rcu_read_lock */ -u32 ip6_mtu_from_fib6 (struct fib6_info *f6i,struct in6_addr *daddr, -struct in6_addr *saddr) +u32 ip6_mtu_from_fib6 (const struct fib6_result *res, +const struct in6_addr *daddr, +const struct in6_addr *saddr) {struct rt6_exception_bucket *bucket; +const struct fib6_nh *nh = res->nh; +struct fib6_info *f6i = res->f6i; +const struct in6_addr *src_key;struct rt6_exception *rt6_ex; -struct in6_addr *src_key;struct inet6_dev *idev;u32 mtu =0 ;
@@ -2663,7 +2667,7 @@ u32 ip6_mtu_from_fib6(struct fib6_info *f6i, struct in6_addr *daddr, mtu =dst_metric_raw (&rt6_ex->rt6i->dst,RTAX_MTU );if (likely (!mtu)) { -struct net_device *dev =fib6_info_nh_dev (f6i); +struct net_device *dev = nh->fib_nh_dev; mtu =IPV6_MIN_MTU ; idev =__in6_dev_get (dev);
@@ -2673,7 +2677,7 @@ u32 ip6_mtu_from_fib6(struct fib6_info *f6i, struct in6_addr *daddr, mtu = min_t(unsigned int, mtu, IP6_MAX_MTU); out: -return mtu -lwtunnel_headroom (fib6_info_nh_lwt (f6i), mtu); +return mtu -lwtunnel_headroom (nh->fib_nh_lws, mtu); } struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
Signature · 1 line
2.11.0
David Ahern
maintainerPATCH v2 9/13 ipv6: Pass fib6_result to rt6_device_match
In reply to David AhernFrom: David Ahern <[email protected]>
Pass fib6_result to rt6_device_match with f6i set. rt6_device_match updates f6i in the result if it finds a better match and sets nh.
--- net/ipv6/route.c | 49 ++++++++++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 19 deletions(-)
net/ipv6/route.c +30 -19
@@ -491,29 +491,40 @@ static bool __rt6_device_match(struct net *net, const struct fib6_nh *nh,return false; } -static inline struct fib6_info *rt6_device_match (struct net *net, -struct fib6_info *rt, -const struct in6_addr *saddr, -int oif, -int flags) +static void rt6_device_match (struct net *net,struct fib6_result *res, +const struct in6_addr *saddr,int oif,int flags) { -const struct fib6_nh *nh; -struct fib6_info *sprt; +struct fib6_info *f6i = res->f6i; +struct fib6_info *spf6i; +struct fib6_nh *nh; -if (!oif &&ipv6_addr_any (saddr) && - !(rt->fib6_nh.fib_nh_flags &RTNH_F_DEAD )) -return rt; +if (!oif &&ipv6_addr_any (saddr)) { + nh = &f6i->fib6_nh; +if (!(nh->fib_nh_flags &RTNH_F_DEAD )) { + res->nh = nh; +return ; + } + } -for (sprt = rt; sprt; sprt =rcu_dereference (sprt->fib6_next)) { - nh = &sprt->fib6_nh; -if (__rt6_device_match (net, nh, saddr, oif, flags)) -return sprt; +for (spf6i = f6i; spf6i; spf6i =rcu_dereference (spf6i->fib6_next)) { + nh = &spf6i->fib6_nh; +if (__rt6_device_match (net, nh, saddr, oif, flags)) { + res->f6i = spf6i; + res->nh = nh; + } } -if (oif && flags &RT6_LOOKUP_F_IFACE ) -return net->ipv6.fib6_null_entry; +if (oif && flags &RT6_LOOKUP_F_IFACE ) { + res->f6i = net->ipv6.fib6_null_entry; + res->nh = &res->f6i->fib6_nh; +return ; + } -return rt->fib6_nh.fib_nh_flags &RTNH_F_DEAD ? net->ipv6.fib6_null_entry : rt; + res->nh = &f6i->fib6_nh; +if (res->nh->fib_nh_flags &RTNH_F_DEAD ) { + res->f6i = net->ipv6.fib6_null_entry; + res->nh = &res->f6i->fib6_nh; + } }#ifdef CONFIG_IPV6_ROUTER_PREF
@@ -1089,8 +1100,8 @@ static struct rt6_info *ip6_pol_route_lookup(struct net *net,if (!res.f6i) res.f6i = net->ipv6.fib6_null_entry;else - res.f6i =rt6_device_match (net, res.f6i, &fl6->saddr, - fl6->flowi6_oif, flags); +rt6_device_match (net, &res, &fl6->saddr, fl6->flowi6_oif, + flags);if (res.f6i == net->ipv6.fib6_null_entry) { fn =fib6_backtrack (fn, &fl6->saddr);
Signature · 1 line
2.11.0
David Ahern
maintainerPATCH v2 10/13 ipv6: Pass fib6_result to rt6_select and find_rr_leaf
In reply to David AhernFrom: David Ahern <[email protected]>
Pass fib6_result to rt6_select. Instead of returning the fib entry, it will set f6i and nh based on the lookup.
find_rr_leaf is changed to remove the match option in favor of taking fib6_result and having __find_rr_leaf set f6i in the result.
In the process, update fib6_info references in __find_rr_leaf to f6i names.
--- net/ipv6/route.c | 82 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 43 insertions(+), 39 deletions(-)
net/ipv6/route.c +43 -39
@@ -695,66 +695,68 @@ static bool find_match(struct fib6_nh *nh, u32 fib6_flags,return rc; } -static void __find_rr_leaf (struct fib6_info *rt_start, +static void __find_rr_leaf (struct fib6_info *f6i_start,struct fib6_info *nomatch,u32 metric, -struct fib6_info **match,struct fib6_info **cont, +struct fib6_result *res,struct fib6_info **cont,int oif,int strict,bool *do_rr,int *mpri) { -struct fib6_info *rt; +struct fib6_info *f6i; -for (rt = rt_start; - rt && rt != nomatch; - rt =rcu_dereference (rt->fib6_next)) { +for (f6i = f6i_start; + f6i && f6i != nomatch; + f6i =rcu_dereference (f6i->fib6_next)) {struct fib6_nh *nh; -if (cont && rt->fib6_metric != metric) { - *cont = rt; +if (cont && f6i->fib6_metric != metric) { + *cont = f6i;return ; } -if (fib6_check_expired (rt)) +if (fib6_check_expired (f6i))continue ; - nh = &rt->fib6_nh; -if (find_match (nh, rt->fib6_flags, oif, strict, mpri, do_rr)) - *match = rt; + nh = &f6i->fib6_nh; +if (find_match (nh, f6i->fib6_flags, oif, strict, mpri, do_rr)) { + res->f6i = f6i; + res->nh = nh; + } } } -static struct fib6_info *find_rr_leaf (struct fib6_node *fn, -struct fib6_info *leaf, -struct fib6_info *rr_head, -u32 metric,int oif,int strict, -bool *do_rr) +static void find_rr_leaf (struct fib6_node *fn,struct fib6_info *leaf, +struct fib6_info *rr_head,int oif,int strict, +bool *do_rr,struct fib6_result *res) { -struct fib6_info *match =NULL , *cont =NULL ; +u32 metric = rr_head->fib6_metric; +struct fib6_info *cont =NULL ;int mpri =-1 ; -__find_rr_leaf (rr_head,NULL , metric, &match, &cont, +__find_rr_leaf (rr_head,NULL , metric, res, &cont, oif, strict, do_rr, &mpri); -__find_rr_leaf (leaf, rr_head, metric, &match, &cont, +__find_rr_leaf (leaf, rr_head, metric, res, &cont, oif, strict, do_rr, &mpri); -if (match || !cont) -return match; +if (res->f6i || !cont) +return ; -__find_rr_leaf (cont,NULL , metric, &match,NULL , +__find_rr_leaf (cont,NULL , metric, res,NULL , oif, strict, do_rr, &mpri); - -return match; } -static struct fib6_info *rt6_select (struct net *net,struct fib6_node *fn, -int oif,int strict) +static void rt6_select (struct net *net,struct fib6_node *fn,int oif, +struct fib6_result *res,int strict) {struct fib6_info *leaf =rcu_dereference (fn->leaf); -struct fib6_info *match, *rt0; +struct fib6_info *rt0;bool do_rr = false;int key_plen; +/* make sure this function or its helpers sets f6i */ + res->f6i =NULL ; +if (!leaf || leaf == net->ipv6.fib6_null_entry) -return net->ipv6.fib6_null_entry; + goto out; rt0 =rcu_dereference (fn->rr_ptr);if (!rt0)
@@ -771,11 +773,9 @@ static struct fib6_info *rt6_select(struct net *net, struct fib6_node *fn, key_plen = rt0->fib6_src.plen;#endif if (fn->fn_bit != key_plen) -return net->ipv6.fib6_null_entry; - - match =find_rr_leaf (fn, leaf, rt0, rt0->fib6_metric, oif, strict, - &do_rr); + goto out; +find_rr_leaf (fn, leaf, rt0, oif, strict, &do_rr, res);if (do_rr) {struct fib6_info *next =rcu_dereference (rt0->fib6_next);
@@ -792,7 +792,11 @@ static struct fib6_info *rt6_select(struct net *net, struct fib6_node *fn, } } -return match ? match : net->ipv6.fib6_null_entry; +out: +if (!res->f6i) { + res->f6i = net->ipv6.fib6_null_entry; + res->nh = &res->f6i->fib6_nh; + } }static bool rt6_is_gw_or_nonexthop (const struct fib6_result *res)
@@ -1839,7 +1843,7 @@ struct fib6_info *fib6_table_lookup(struct net *net, struct fib6_table *table, int oif, struct flowi6 *fl6, int strict) { struct fib6_node *fn, *saved_fn; -struct fib6_info *f6i; +struct fib6_result res; fn =fib6_node_lookup (&table->tb6_root, &fl6->daddr, &fl6->saddr); saved_fn = fn;
@@ -1848,8 +1852,8 @@ struct fib6_info *fib6_table_lookup(struct net *net, struct fib6_table *table, oif =0 ; redo_rt6_select: - f6i =rt6_select (net, fn, oif, strict); -if (f6i == net->ipv6.fib6_null_entry) { +rt6_select (net, fn, oif, &res, strict); +if (res.f6i == net->ipv6.fib6_null_entry) { fn =fib6_backtrack (fn, &fl6->saddr);if (fn) goto redo_rt6_select;
@@ -1861,9 +1865,9 @@ struct fib6_info *fib6_table_lookup(struct net *net, struct fib6_table *table, } } -trace_fib6_table_lookup (net, f6i, table, fl6); +trace_fib6_table_lookup (net, res.f6i, table, fl6); -return f6i; +return res.f6i; } struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
Signature · 1 line
2.11.0
David Ahern
maintainerPATCH v2 11/13 ipv6: Pass fib6_result to fib6_table_lookup tracepoint
In reply to David AhernFrom: David Ahern <[email protected]>
Change fib6_table_lookup tracepoint to take the fib6_result and use the fib6_info and fib6_nh from it.
--- include/trace/events/fib6.h | 16 ++++++++-------- net/ipv6/route.c | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-)
include/trace/events/fib6.h +8 -8
@@ -12,10 +12,10 @@ TRACE_EVENT(fib6_table_lookup, - TP_PROTO(const struct net *net, const struct fib6_info *f6i, + TP_PROTO(const struct net *net, const struct fib6_result *res, struct fib6_table *table, const struct flowi6 *flp), - TP_ARGS(net, f6i, table, flp), + TP_ARGS(net, res, table, flp), TP_STRUCT__entry( __field( u32, tb_id )
@@ -39,7 +39,7 @@ TRACE_EVENT(fib6_table_lookup,struct in6_addr *in6; __entry->tb_id = table->tb6_id; - __entry->err =ip6_rt_type_to_error (f6i->fib6_type); + __entry->err =ip6_rt_type_to_error (res->f6i->fib6_type); __entry->oif = flp->flowi6_oif; __entry->iif = flp->flowi6_iif; __entry->tos =ip6_tclass (flp->flowlabel);
@@ -62,20 +62,20 @@ TRACE_EVENT(fib6_table_lookup, __entry->dport =0 ; } -if (f6i->fib6_nh.fib_nh_dev) { -__assign_str (name, f6i->fib6_nh.fib_nh_dev); +if (res->nh && res->nh->fib_nh_dev) { +__assign_str (name, res->nh->fib_nh_dev); }else {__assign_str (name,"-" ); } -if (f6i == net->ipv6.fib6_null_entry) { +if (res->f6i == net->ipv6.fib6_null_entry) {struct in6_addr in6_zero = {}; in6 = (struct in6_addr *)__entry->gw; *in6 = in6_zero; - }else if (f6i) { + }else if (res->nh) { in6 = (struct in6_addr *)__entry->gw; - *in6 = f6i->fib6_nh.fib_nh_gw6; + *in6 = res->nh->fib_nh_gw6; } ),
net/ipv6/route.c +3 -3
@@ -1130,7 +1130,7 @@ static struct rt6_info *ip6_pol_route_lookup(struct net *net, } out: -trace_fib6_table_lookup (net, res.f6i, table, fl6); +trace_fib6_table_lookup (net, &res, table, fl6);rcu_read_unlock ();
@@ -1865,7 +1865,7 @@ struct fib6_info *fib6_table_lookup(struct net *net, struct fib6_table *table, } } -trace_fib6_table_lookup (net, res.f6i, table, fl6); +trace_fib6_table_lookup (net, &res, table, fl6);return res.f6i; }
@@ -2534,7 +2534,7 @@ static struct rt6_info *__ip6_route_redirect(struct net *net,rcu_read_unlock (); -trace_fib6_table_lookup (net, rt, table, fl6); +trace_fib6_table_lookup (net, &res, table, fl6);return ret; };
Signature · 1 line
2.11.0
David Ahern
maintainerPATCH v2 12/13 ipv6: Pass fib6_result to fib lookups
In reply to David AhernFrom: David Ahern <[email protected]>
Change fib6_lookup and fib6_table_lookup to take a fib6_result and set f6i and nh rather than returning a fib6_info. For now both always return 0.
A later patch set can make these more like the IPv4 counterparts and return EINVAL, EACCESS, etc based on fib6_type.
--- include/net/ip6_fib.h | 9 +++++---- include/net/ipv6_stubs.h | 11 +++++------ net/core/filter.c | 10 +++++----- net/ipv6/addrconf_core.c | 13 +++++++------ net/ipv6/fib6_rules.c | 34 +++++++++++++--------------------- net/ipv6/ip6_fib.c | 7 ++++--- net/ipv6/route.c | 15 +++++++-------- 7 files changed, 46 insertions(+), 53 deletions(-)
include/net/ip6_fib.h +5 -4
@@ -389,12 +389,13 @@ struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6,/* called with rcu lock held; can return error pointer * caller needs to select path */ -struct fib6_info *fib6_lookup (struct net *net,int oif,struct flowi6 *fl6, -int flags); +int fib6_lookup (struct net *net,int oif,struct flowi6 *fl6, +struct fib6_result *res,int flags);/* called with rcu lock held; caller needs to select path */ -struct fib6_info *fib6_table_lookup (struct net *net,struct fib6_table *table, -int oif,struct flowi6 *fl6,int strict); +int fib6_table_lookup (struct net *net,struct fib6_table *table, +int oif,struct flowi6 *fl6,struct fib6_result *res, +int strict); void fib6_select_path(const struct net *net, struct fib6_result *res, struct flowi6 *fl6, int oif, bool have_oif_match,
include/net/ipv6_stubs.h +5 -6
@@ -29,12 +29,11 @@ struct ipv6_stub {int (*ipv6_route_input)(struct sk_buff *skb);struct fib6_table *(*fib6_get_table)(struct net *net,u32 id); -struct fib6_info *(*fib6_lookup)(struct net *net,int oif, -struct flowi6 *fl6,int flags); -struct fib6_info *(*fib6_table_lookup)(struct net *net, -struct fib6_table *table, -int oif,struct flowi6 *fl6, -int flags); +int (*fib6_lookup)(struct net *net,int oif,struct flowi6 *fl6, +struct fib6_result *res,int flags); +int (*fib6_table_lookup)(struct net *net,struct fib6_table *table, +int oif,struct flowi6 *fl6, +struct fib6_result *res,int flags);void (*fib6_select_path)(const struct net *net,struct fib6_result *res,struct flowi6 *fl6,int oif,bool oif_match,const struct sk_buff *skb,int strict);
net/core/filter.c +5 -5
@@ -4682,7 +4682,7 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params,struct inet6_dev *idev;struct flowi6 fl6;int strict =0 ; -int oif; +int oif, err;u32 mtu;/* link local addresses are never forwarded */
@@ -4724,18 +4724,18 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params,if (unlikely (!tb))return BPF_FIB_LKUP_RET_NOT_FWDED ; - res.f6i = ipv6_stub->fib6_table_lookup (net, tb, oif, &fl6, - strict); + err = ipv6_stub->fib6_table_lookup (net, tb, oif, &fl6, &res, + strict); }else { fl6.flowi6_mark =0 ; fl6.flowi6_secid =0 ; fl6.flowi6_tun_key.tun_id =0 ; fl6.flowi6_uid =sock_net_uid (net,NULL ); - res.f6i = ipv6_stub->fib6_lookup (net, oif, &fl6, strict); + err = ipv6_stub->fib6_lookup (net, oif, &fl6, &res, strict); } -if (unlikely (IS_ERR_OR_NULL (res.f6i) || +if (unlikely (err ||IS_ERR_OR_NULL (res.f6i) || res.f6i == net->ipv6.fib6_null_entry))return BPF_FIB_LKUP_RET_NOT_FWDED ;
net/ipv6/addrconf_core.c +7 -6
@@ -144,18 +144,19 @@ static struct fib6_table *eafnosupport_fib6_get_table(struct net *net, u32 id)return NULL ; } -static struct fib6_info * +static int eafnosupport_fib6_table_lookup (struct net *net,struct fib6_table *table, -int oif,struct flowi6 *fl6,int flags) +int oif,struct flowi6 *fl6, +struct fib6_result *res,int flags) { -return NULL ; +return -EAFNOSUPPORT ; } -static struct fib6_info * +static int eafnosupport_fib6_lookup (struct net *net,int oif,struct flowi6 *fl6, -int flags) +struct fib6_result *res,int flags) { -return NULL ; +return -EAFNOSUPPORT ; } static void
net/ipv6/fib6_rules.c +13 -21
@@ -61,16 +61,16 @@ unsigned int fib6_rules_seq_read(struct net *net) }/* called with rcu lock held; no reference taken on fib6_info */ -struct fib6_info *fib6_lookup (struct net *net,int oif,struct flowi6 *fl6, -int flags) +int fib6_lookup (struct net *net,int oif,struct flowi6 *fl6, +struct fib6_result *res,int flags) { -struct fib6_info *f6i;int err;if (net->ipv6.fib6_has_custom_rules) {struct fib_lookup_arg arg = { .lookup_ptr = fib6_table_lookup, .lookup_data = &oif, + .result = res, .flags =FIB_LOOKUP_NOREF , };
@@ -78,19 +78,15 @@ struct fib6_info *fib6_lookup(struct net *net, int oif, struct flowi6 *fl6, err =fib_rules_lookup (net->ipv6.fib6_rules_ops,flowi6_to_flowi (fl6), flags, &arg); -if (err) -return ERR_PTR (err); - - f6i = arg.result ? : net->ipv6.fib6_null_entry; }else { - f6i =fib6_table_lookup (net, net->ipv6.fib6_local_tbl, - oif, fl6, flags); -if (!f6i || f6i == net->ipv6.fib6_null_entry) - f6i =fib6_table_lookup (net, net->ipv6.fib6_main_tbl, - oif, fl6, flags); + err =fib6_table_lookup (net, net->ipv6.fib6_local_tbl, oif, + fl6, res, flags); +if (err || res->f6i == net->ipv6.fib6_null_entry) + err =fib6_table_lookup (net, net->ipv6.fib6_main_tbl, + oif, fl6, res, flags); } -return f6i; +return err; } struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6,
@@ -157,10 +153,10 @@ static int fib6_rule_saddr(struct net *net, struct fib_rule *rule, int flags,static int fib6_rule_action_alt (struct fib_rule *rule,struct flowi *flp,int flags,struct fib_lookup_arg *arg) { +struct fib6_result *res = arg->result;struct flowi6 *flp6 = &flp->u.ip6;struct net *net = rule->fr_net;struct fib6_table *table; -struct fib6_info *f6i;int err = -EAGAIN , *oif;u32 tb_id;
@@ -182,14 +178,10 @@ static int fib6_rule_action_alt(struct fib_rule *rule, struct flowi *flp,return -EAGAIN ; oif = (int *)arg->lookup_data; - f6i =fib6_table_lookup (net, table, *oif, flp6, flags); -if (f6i != net->ipv6.fib6_null_entry) { + err =fib6_table_lookup (net, table, *oif, flp6, res, flags); +if (!err && res->f6i != net->ipv6.fib6_null_entry) err =fib6_rule_saddr (net, rule, flags, flp6, -fib6_info_nh_dev (f6i)); - -if (likely (!err)) - arg->result = f6i; - } + res->nh->fib_nh_dev);return err; }
net/ipv6/ip6_fib.c +4 -3
@@ -354,10 +354,11 @@ struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6, }/* called with rcu lock held; no reference taken on fib6_info */ -struct fib6_info *fib6_lookup (struct net *net,int oif,struct flowi6 *fl6, -int flags) +int fib6_lookup (struct net *net,int oif,struct flowi6 *fl6, +struct fib6_result *res,int flags) { -return fib6_table_lookup (net, net->ipv6.fib6_main_tbl, oif, fl6, flags); +return fib6_table_lookup (net, net->ipv6.fib6_main_tbl, oif, fl6, + res, flags); }static void __net_init fib6_tables_init (struct net *net)
net/ipv6/route.c +7 -8
@@ -1839,11 +1839,10 @@ void rt6_age_exceptions(struct fib6_info *rt, }/* must be called with rcu lock held */ -struct fib6_info *fib6_table_lookup (struct net *net,struct fib6_table *table, -int oif,struct flowi6 *fl6,int strict) +int fib6_table_lookup (struct net *net,struct fib6_table *table,int oif, +struct flowi6 *fl6,struct fib6_result *res,int strict) {struct fib6_node *fn, *saved_fn; -struct fib6_result res; fn =fib6_node_lookup (&table->tb6_root, &fl6->daddr, &fl6->saddr); saved_fn = fn;
@@ -1852,8 +1851,8 @@ struct fib6_info *fib6_table_lookup(struct net *net, struct fib6_table *table, oif =0 ; redo_rt6_select: -rt6_select (net, fn, oif, &res, strict); -if (res.f6i == net->ipv6.fib6_null_entry) { +rt6_select (net, fn, oif, res, strict); +if (res->f6i == net->ipv6.fib6_null_entry) { fn =fib6_backtrack (fn, &fl6->saddr);if (fn) goto redo_rt6_select;
@@ -1865,9 +1864,9 @@ struct fib6_info *fib6_table_lookup(struct net *net, struct fib6_table *table, } } -trace_fib6_table_lookup (net, &res, table, fl6); +trace_fib6_table_lookup (net, res, table, fl6); -return res.f6i; +return 0 ; } struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
@@ -1885,7 +1884,7 @@ struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,rcu_read_lock (); - res.f6i =fib6_table_lookup (net, table, oif, fl6, strict); +fib6_table_lookup (net, table, oif, fl6, &res, strict);if (res.f6i == net->ipv6.fib6_null_entry) { rt = net->ipv6.ip6_null_entry;rcu_read_unlock ();
Signature · 1 line
2.11.0
David Ahern
maintainerPATCH v2 13/13 ipv6: Add fib6_type and fib6_flags to fib6_result
In reply to David AhernFrom: David Ahern <[email protected]>
Add the fib6_flags and fib6_type to fib6_result. Update the lookup helpers to set them and update post fib lookup users to use the version from the result.
This allows nexthop objects to have blackhole nexthop.
--- include/net/ip6_fib.h | 2 ++ include/trace/events/fib6.h | 2 +- net/core/filter.c | 26 +++++++++---------- net/ipv6/route.c | 61 +++++++++++++++++++++++++++------------------ 4 files changed, 52 insertions(+), 39 deletions(-)
include/net/ip6_fib.h +2 -0
@@ -193,6 +193,8 @@ struct rt6_info {struct fib6_result {struct fib6_nh *nh;struct fib6_info *f6i; +u32 fib6_flags; +u8 fib6_type; };#define for_each_fib6_node_rt_rcu (fn) \
include/trace/events/fib6.h +1 -1
@@ -39,7 +39,7 @@ TRACE_EVENT(fib6_table_lookup,struct in6_addr *in6; __entry->tb_id = table->tb6_id; - __entry->err =ip6_rt_type_to_error (res->f6i->fib6_type); + __entry->err =ip6_rt_type_to_error (res->fib6_type); __entry->oif = flp->flowi6_oif; __entry->iif = flp->flowi6_iif; __entry->tos =ip6_tclass (flp->flowlabel);
net/core/filter.c +12 -14
@@ -4739,21 +4739,19 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params, res.f6i == net->ipv6.fib6_null_entry))return BPF_FIB_LKUP_RET_NOT_FWDED ; -if (unlikely (res.f6i->fib6_flags &RTF_REJECT )) { -switch (res.f6i->fib6_type) { -case RTN_BLACKHOLE : -return BPF_FIB_LKUP_RET_BLACKHOLE ; -case RTN_UNREACHABLE : -return BPF_FIB_LKUP_RET_UNREACHABLE ; -case RTN_PROHIBIT : -return BPF_FIB_LKUP_RET_PROHIBIT ; -default : -return BPF_FIB_LKUP_RET_NOT_FWDED ; - } - } - -if (res.f6i->fib6_type !=RTN_UNICAST ) +switch (res.fib6_type) { +/* only unicast is forwarded */ +case RTN_UNICAST : +break ; +case RTN_BLACKHOLE : +return BPF_FIB_LKUP_RET_BLACKHOLE ; +case RTN_UNREACHABLE : +return BPF_FIB_LKUP_RET_UNREACHABLE ; +case RTN_PROHIBIT : +return BPF_FIB_LKUP_RET_PROHIBIT ; +default :return BPF_FIB_LKUP_RET_NOT_FWDED ; + } ipv6_stub->fib6_select_path (net, &res, &fl6, fl6.flowi6_oif, fl6.flowi6_oif !=0 ,NULL , strict);
net/ipv6/route.c +37 -24
154 lines not on this page · raw message
Signature · 1 line
2.11.0
David Miller
maintainerFrom: David Ahern <[email protected]>
Date: Tue, 16 Apr 2019 14:35:58 -0700
Quoted 11 lines
From: David Ahern <[email protected]>
Add
fib6_resultas a single data structure to hold results from a fib lookup. IPv6 currently has everything in 1 data structure - afib6_info, but with nexthop objects thefib6_nhcan be in a nexthop or a nexthop can be a blackhole which affects thefib6_typeand flags (REJECT).v2
- fixed 2 bugs in patch12:
i. checking return fromfib6_table_lookupinfib6_lookupii. call tofib6_rule_saddrinfib6_rule_action_altshould useres->nh
Looks good, series applied.
Thanks David.