diff options
Diffstat (limited to 'net/ipv4/route.c')
| -rw-r--r-- | net/ipv4/route.c | 67 | 
1 files changed, 49 insertions, 18 deletions
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 49cc1c1df1ba..299e247b2032 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -128,10 +128,11 @@ static int ip_rt_redirect_silence __read_mostly	= ((HZ / 50) << (9 + 1));  static int ip_rt_error_cost __read_mostly	= HZ;  static int ip_rt_error_burst __read_mostly	= 5 * HZ;  static int ip_rt_mtu_expires __read_mostly	= 10 * 60 * HZ; -static int ip_rt_min_pmtu __read_mostly		= 512 + 20 + 20; +static u32 ip_rt_min_pmtu __read_mostly		= 512 + 20 + 20;  static int ip_rt_min_advmss __read_mostly	= 256;  static int ip_rt_gc_timeout __read_mostly	= RT_GC_TIMEOUT; +  /*   *	Interface to generic destination cache.   */ @@ -633,6 +634,7 @@ static inline u32 fnhe_hashfun(__be32 daddr)  static void fill_route_from_fnhe(struct rtable *rt, struct fib_nh_exception *fnhe)  {  	rt->rt_pmtu = fnhe->fnhe_pmtu; +	rt->rt_mtu_locked = fnhe->fnhe_mtu_locked;  	rt->dst.expires = fnhe->fnhe_expires;  	if (fnhe->fnhe_gw) { @@ -643,7 +645,7 @@ static void fill_route_from_fnhe(struct rtable *rt, struct fib_nh_exception *fnh  }  static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw, -				  u32 pmtu, unsigned long expires) +				  u32 pmtu, bool lock, unsigned long expires)  {  	struct fnhe_hash_bucket *hash;  	struct fib_nh_exception *fnhe; @@ -680,8 +682,10 @@ static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw,  			fnhe->fnhe_genid = genid;  		if (gw)  			fnhe->fnhe_gw = gw; -		if (pmtu) +		if (pmtu) {  			fnhe->fnhe_pmtu = pmtu; +			fnhe->fnhe_mtu_locked = lock; +		}  		fnhe->fnhe_expires = max(1UL, expires);  		/* Update all cached dsts too */  		rt = rcu_dereference(fnhe->fnhe_rth_input); @@ -705,6 +709,7 @@ static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw,  		fnhe->fnhe_daddr = daddr;  		fnhe->fnhe_gw = gw;  		fnhe->fnhe_pmtu = pmtu; +		fnhe->fnhe_mtu_locked = lock;  		fnhe->fnhe_expires = expires;  		/* Exception created; mark the cached routes for the nexthop @@ -786,7 +791,8 @@ static void __ip_do_redirect(struct rtable *rt, struct sk_buff *skb, struct flow  				struct fib_nh *nh = &FIB_RES_NH(res);  				update_or_create_fnhe(nh, fl4->daddr, new_gw, -						0, jiffies + ip_rt_gc_timeout); +						0, false, +						jiffies + ip_rt_gc_timeout);  			}  			if (kill_route)  				rt->dst.obsolete = DST_OBSOLETE_KILL; @@ -930,14 +936,23 @@ out_put_peer:  static int ip_error(struct sk_buff *skb)  { -	struct in_device *in_dev = __in_dev_get_rcu(skb->dev);  	struct rtable *rt = skb_rtable(skb); +	struct net_device *dev = skb->dev; +	struct in_device *in_dev;  	struct inet_peer *peer;  	unsigned long now;  	struct net *net;  	bool send;  	int code; +	if (netif_is_l3_master(skb->dev)) { +		dev = __dev_get_by_index(dev_net(skb->dev), IPCB(skb)->iif); +		if (!dev) +			goto out; +	} + +	in_dev = __in_dev_get_rcu(dev); +  	/* IP on this device is disabled. */  	if (!in_dev)  		goto out; @@ -999,15 +1014,18 @@ static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu)  {  	struct dst_entry *dst = &rt->dst;  	struct fib_result res; +	bool lock = false; -	if (dst_metric_locked(dst, RTAX_MTU)) +	if (ip_mtu_locked(dst))  		return;  	if (ipv4_mtu(dst) < mtu)  		return; -	if (mtu < ip_rt_min_pmtu) +	if (mtu < ip_rt_min_pmtu) { +		lock = true;  		mtu = ip_rt_min_pmtu; +	}  	if (rt->rt_pmtu == mtu &&  	    time_before(jiffies, dst->expires - ip_rt_mtu_expires / 2)) @@ -1017,7 +1035,7 @@ static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu)  	if (fib_lookup(dev_net(dst->dev), fl4, &res, 0) == 0) {  		struct fib_nh *nh = &FIB_RES_NH(res); -		update_or_create_fnhe(nh, fl4->daddr, 0, mtu, +		update_or_create_fnhe(nh, fl4->daddr, 0, mtu, lock,  				      jiffies + ip_rt_mtu_expires);  	}  	rcu_read_unlock(); @@ -1270,7 +1288,7 @@ static unsigned int ipv4_mtu(const struct dst_entry *dst)  	mtu = READ_ONCE(dst->dev->mtu); -	if (unlikely(dst_metric_locked(dst, RTAX_MTU))) { +	if (unlikely(ip_mtu_locked(dst))) {  		if (rt->rt_uses_gateway && mtu > 576)  			mtu = 576;  	} @@ -1383,7 +1401,7 @@ struct uncached_list {  static DEFINE_PER_CPU_ALIGNED(struct uncached_list, rt_uncached_list); -static void rt_add_uncached_list(struct rtable *rt) +void rt_add_uncached_list(struct rtable *rt)  {  	struct uncached_list *ul = raw_cpu_ptr(&rt_uncached_list); @@ -1394,14 +1412,8 @@ static void rt_add_uncached_list(struct rtable *rt)  	spin_unlock_bh(&ul->lock);  } -static void ipv4_dst_destroy(struct dst_entry *dst) +void rt_del_uncached_list(struct rtable *rt)  { -	struct dst_metrics *p = (struct dst_metrics *)DST_METRICS_PTR(dst); -	struct rtable *rt = (struct rtable *) dst; - -	if (p != &dst_default_metrics && refcount_dec_and_test(&p->refcnt)) -		kfree(p); -  	if (!list_empty(&rt->rt_uncached)) {  		struct uncached_list *ul = rt->rt_uncached_list; @@ -1411,6 +1423,17 @@ static void ipv4_dst_destroy(struct dst_entry *dst)  	}  } +static void ipv4_dst_destroy(struct dst_entry *dst) +{ +	struct dst_metrics *p = (struct dst_metrics *)DST_METRICS_PTR(dst); +	struct rtable *rt = (struct rtable *)dst; + +	if (p != &dst_default_metrics && refcount_dec_and_test(&p->refcnt)) +		kfree(p); + +	rt_del_uncached_list(rt); +} +  void rt_flush_dev(struct net_device *dev)  {  	struct net *net = dev_net(dev); @@ -1506,6 +1529,7 @@ struct rtable *rt_dst_alloc(struct net_device *dev,  		rt->rt_is_input = 0;  		rt->rt_iif = 0;  		rt->rt_pmtu = 0; +		rt->rt_mtu_locked = 0;  		rt->rt_gateway = 0;  		rt->rt_uses_gateway = 0;  		rt->rt_table_id = 0; @@ -1826,6 +1850,8 @@ int fib_multipath_hash(const struct fib_info *fi, const struct flowi4 *fl4,  				return skb_get_hash_raw(skb) >> 1;  			memset(&hash_keys, 0, sizeof(hash_keys));  			skb_flow_dissect_flow_keys(skb, &keys, flag); + +			hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;  			hash_keys.addrs.v4addrs.src = keys.addrs.v4addrs.src;  			hash_keys.addrs.v4addrs.dst = keys.addrs.v4addrs.dst;  			hash_keys.ports.src = keys.ports.src; @@ -2529,6 +2555,7 @@ struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_or  		rt->rt_is_input = ort->rt_is_input;  		rt->rt_iif = ort->rt_iif;  		rt->rt_pmtu = ort->rt_pmtu; +		rt->rt_mtu_locked = ort->rt_mtu_locked;  		rt->rt_genid = rt_genid_ipv4(net);  		rt->rt_flags = ort->rt_flags; @@ -2631,6 +2658,8 @@ static int rt_fill_info(struct net *net,  __be32 dst, __be32 src, u32 table_id,  	memcpy(metrics, dst_metrics_ptr(&rt->dst), sizeof(metrics));  	if (rt->rt_pmtu && expires)  		metrics[RTAX_MTU - 1] = rt->rt_pmtu; +	if (rt->rt_mtu_locked && expires) +		metrics[RTAX_LOCK - 1] |= BIT(RTAX_MTU);  	if (rtnetlink_put_metrics(skb, metrics) < 0)  		goto nla_put_failure; @@ -2816,6 +2845,7 @@ void ip_rt_multicast_event(struct in_device *in_dev)  static int ip_rt_gc_interval __read_mostly  = 60 * HZ;  static int ip_rt_gc_min_interval __read_mostly	= HZ / 2;  static int ip_rt_gc_elasticity __read_mostly	= 8; +static int ip_min_valid_pmtu __read_mostly	= IPV4_MIN_MTU;  static int ipv4_sysctl_rtcache_flush(struct ctl_table *__ctl, int write,  					void __user *buffer, @@ -2931,7 +2961,8 @@ static struct ctl_table ipv4_route_table[] = {  		.data		= &ip_rt_min_pmtu,  		.maxlen		= sizeof(int),  		.mode		= 0644, -		.proc_handler	= proc_dointvec, +		.proc_handler	= proc_dointvec_minmax, +		.extra1		= &ip_min_valid_pmtu,  	},  	{  		.procname	= "min_adv_mss",  | 

