diff options
Diffstat (limited to 'net/ipv6/route.c')
| -rw-r--r-- | net/ipv6/route.c | 44 | 
1 files changed, 40 insertions, 4 deletions
| diff --git a/net/ipv6/route.c b/net/ipv6/route.c index c8bc9b4ac328..3c8834bc822d 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -62,6 +62,7 @@  #include <net/lwtunnel.h>  #include <net/ip_tunnels.h>  #include <net/l3mdev.h> +#include <trace/events/fib6.h>  #include <asm/uaccess.h> @@ -404,6 +405,14 @@ static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,  	}  } +static bool __rt6_check_expired(const struct rt6_info *rt) +{ +	if (rt->rt6i_flags & RTF_EXPIRES) +		return time_after(jiffies, rt->dst.expires); +	else +		return false; +} +  static bool rt6_check_expired(const struct rt6_info *rt)  {  	if (rt->rt6i_flags & RTF_EXPIRES) { @@ -515,7 +524,7 @@ static void rt6_probe_deferred(struct work_struct *w)  		container_of(w, struct __rt6_probe_work, work);  	addrconf_addr_solict_mult(&work->target, &mcaddr); -	ndisc_send_ns(work->dev, &work->target, &mcaddr, NULL, NULL); +	ndisc_send_ns(work->dev, &work->target, &mcaddr, NULL);  	dev_put(work->dev);  	kfree(work);  } @@ -857,6 +866,9 @@ restart:  	}  	dst_use(&rt->dst, jiffies);  	read_unlock_bh(&table->tb6_lock); + +	trace_fib6_table_lookup(net, rt, table->tb6_id, fl6); +  	return rt;  } @@ -1070,6 +1082,8 @@ redo_rt6_select:  		read_unlock_bh(&table->tb6_lock);  		rt6_dst_from_metrics_check(rt); + +		trace_fib6_table_lookup(net, rt, table->tb6_id, fl6);  		return rt;  	} else if (unlikely((fl6->flowi6_flags & FLOWI_FLAG_KNOWN_NH) &&  			    !(rt->rt6i_flags & RTF_GATEWAY))) { @@ -1093,6 +1107,8 @@ redo_rt6_select:  			uncached_rt = net->ipv6.ip6_null_entry;  		dst_hold(&uncached_rt->dst); + +		trace_fib6_table_lookup(net, uncached_rt, table->tb6_id, fl6);  		return uncached_rt;  	} else { @@ -1117,6 +1133,7 @@ redo_rt6_select:  			dst_release(&rt->dst);  		} +		trace_fib6_table_lookup(net, pcpu_rt, table->tb6_id, fl6);  		return pcpu_rt;  	} @@ -1252,7 +1269,8 @@ static struct dst_entry *rt6_check(struct rt6_info *rt, u32 cookie)  static struct dst_entry *rt6_dst_from_check(struct rt6_info *rt, u32 cookie)  { -	if (rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK && +	if (!__rt6_check_expired(rt) && +	    rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK &&  	    rt6_check((struct rt6_info *)(rt->dst.from), cookie))  		return &rt->dst;  	else @@ -1272,7 +1290,8 @@ static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)  	rt6_dst_from_metrics_check(rt); -	if ((rt->rt6i_flags & RTF_PCPU) || unlikely(dst->flags & DST_NOCACHE)) +	if (rt->rt6i_flags & RTF_PCPU || +	    (unlikely(dst->flags & DST_NOCACHE) && rt->dst.from))  		return rt6_dst_from_check(rt, cookie);  	else  		return rt6_check(rt, cookie); @@ -1322,6 +1341,12 @@ static void rt6_do_update_pmtu(struct rt6_info *rt, u32 mtu)  	rt6_update_expires(rt, net->ipv6.sysctl.ip6_rt_mtu_expires);  } +static bool rt6_cache_allowed_for_pmtu(const struct rt6_info *rt) +{ +	return !(rt->rt6i_flags & RTF_CACHE) && +		(rt->rt6i_flags & RTF_PCPU || rt->rt6i_node); +} +  static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,  				 const struct ipv6hdr *iph, u32 mtu)  { @@ -1335,7 +1360,7 @@ static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,  	if (mtu >= dst_mtu(dst))  		return; -	if (rt6->rt6i_flags & RTF_CACHE) { +	if (!rt6_cache_allowed_for_pmtu(rt6)) {  		rt6_do_update_pmtu(rt6, mtu);  	} else {  		const struct in6_addr *daddr, *saddr; @@ -1458,6 +1483,7 @@ out:  	read_unlock_bh(&table->tb6_lock); +	trace_fib6_table_lookup(net, rt, table->tb6_id, fl6);  	return rt;  }; @@ -2683,6 +2709,7 @@ static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {  	[RTA_PREF]              = { .type = NLA_U8 },  	[RTA_ENCAP_TYPE]	= { .type = NLA_U16 },  	[RTA_ENCAP]		= { .type = NLA_NESTED }, +	[RTA_EXPIRES]		= { .type = NLA_U32 },  };  static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, @@ -2783,6 +2810,15 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,  	if (tb[RTA_ENCAP_TYPE])  		cfg->fc_encap_type = nla_get_u16(tb[RTA_ENCAP_TYPE]); +	if (tb[RTA_EXPIRES]) { +		unsigned long timeout = addrconf_timeout_fixup(nla_get_u32(tb[RTA_EXPIRES]), HZ); + +		if (addrconf_finite_timeout(timeout)) { +			cfg->fc_expires = jiffies_to_clock_t(timeout * HZ); +			cfg->fc_flags |= RTF_EXPIRES; +		} +	} +  	err = 0;  errout:  	return err; | 
