diff options
Diffstat (limited to 'net/ipv4/route.c')
| -rw-r--r-- | net/ipv4/route.c | 39 | 
1 files changed, 26 insertions, 13 deletions
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index a770df2493d..cb562fdd9b9 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -90,6 +90,7 @@  #include <linux/jhash.h>  #include <linux/rcupdate.h>  #include <linux/times.h> +#include <linux/slab.h>  #include <net/dst.h>  #include <net/net_namespace.h>  #include <net/protocol.h> @@ -1097,7 +1098,7 @@ static int slow_chain_length(const struct rtable *head)  }  static int rt_intern_hash(unsigned hash, struct rtable *rt, -			  struct rtable **rp, struct sk_buff *skb) +			  struct rtable **rp, struct sk_buff *skb, int ifindex)  {  	struct rtable	*rth, **rthp;  	unsigned long	now; @@ -1212,11 +1213,16 @@ restart:  		    slow_chain_length(rt_hash_table[hash].chain) > rt_chain_length_max) {  			struct net *net = dev_net(rt->u.dst.dev);  			int num = ++net->ipv4.current_rt_cache_rebuild_count; -			if (!rt_caching(dev_net(rt->u.dst.dev))) { +			if (!rt_caching(net)) {  				printk(KERN_WARNING "%s: %d rebuilds is over limit, route caching disabled\n",  					rt->u.dst.dev->name, num);  			} -			rt_emergency_hash_rebuild(dev_net(rt->u.dst.dev)); +			rt_emergency_hash_rebuild(net); +			spin_unlock_bh(rt_hash_lock_addr(hash)); + +			hash = rt_hash(rt->fl.fl4_dst, rt->fl.fl4_src, +					ifindex, rt_genid(net)); +			goto restart;  		}  	} @@ -1441,7 +1447,7 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,  					dev_hold(rt->u.dst.dev);  				if (rt->idev)  					in_dev_hold(rt->idev); -				rt->u.dst.obsolete	= 0; +				rt->u.dst.obsolete	= -1;  				rt->u.dst.lastuse	= jiffies;  				rt->u.dst.path		= &rt->u.dst;  				rt->u.dst.neighbour	= NULL; @@ -1477,7 +1483,7 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,  							&netevent);  				rt_del(hash, rth); -				if (!rt_intern_hash(hash, rt, &rt, NULL)) +				if (!rt_intern_hash(hash, rt, &rt, NULL, rt->fl.oif))  					ip_rt_put(rt);  				goto do_next;  			} @@ -1506,11 +1512,12 @@ static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst)  	struct dst_entry *ret = dst;  	if (rt) { -		if (dst->obsolete) { +		if (dst->obsolete > 0) {  			ip_rt_put(rt);  			ret = NULL;  		} else if ((rt->rt_flags & RTCF_REDIRECTED) || -			   rt->u.dst.expires) { +			   (rt->u.dst.expires && +			    time_after_eq(jiffies, rt->u.dst.expires))) {  			unsigned hash = rt_hash(rt->fl.fl4_dst, rt->fl.fl4_src,  						rt->fl.oif,  						rt_genid(dev_net(dst->dev))); @@ -1726,7 +1733,9 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu)  static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie)  { -	return NULL; +	if (rt_is_expired((struct rtable *)dst)) +		return NULL; +	return dst;  }  static void ipv4_dst_destroy(struct dst_entry *dst) @@ -1888,7 +1897,8 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,  	if (!rth)  		goto e_nobufs; -	rth->u.dst.output= ip_rt_bug; +	rth->u.dst.output = ip_rt_bug; +	rth->u.dst.obsolete = -1;  	atomic_set(&rth->u.dst.__refcnt, 1);  	rth->u.dst.flags= DST_HOST; @@ -1927,7 +1937,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,  	in_dev_put(in_dev);  	hash = rt_hash(daddr, saddr, dev->ifindex, rt_genid(dev_net(dev))); -	return rt_intern_hash(hash, rth, NULL, skb); +	return rt_intern_hash(hash, rth, NULL, skb, dev->ifindex);  e_nobufs:  	in_dev_put(in_dev); @@ -2054,6 +2064,7 @@ static int __mkroute_input(struct sk_buff *skb,  	rth->fl.oif 	= 0;  	rth->rt_spec_dst= spec_dst; +	rth->u.dst.obsolete = -1;  	rth->u.dst.input = ip_forward;  	rth->u.dst.output = ip_output;  	rth->rt_genid = rt_genid(dev_net(rth->u.dst.dev)); @@ -2093,7 +2104,7 @@ static int ip_mkroute_input(struct sk_buff *skb,  	/* put it into the cache */  	hash = rt_hash(daddr, saddr, fl->iif,  		       rt_genid(dev_net(rth->u.dst.dev))); -	return rt_intern_hash(hash, rth, NULL, skb); +	return rt_intern_hash(hash, rth, NULL, skb, fl->iif);  }  /* @@ -2218,6 +2229,7 @@ local_input:  		goto e_nobufs;  	rth->u.dst.output= ip_rt_bug; +	rth->u.dst.obsolete = -1;  	rth->rt_genid = rt_genid(net);  	atomic_set(&rth->u.dst.__refcnt, 1); @@ -2249,7 +2261,7 @@ local_input:  	}  	rth->rt_type	= res.type;  	hash = rt_hash(daddr, saddr, fl.iif, rt_genid(net)); -	err = rt_intern_hash(hash, rth, NULL, skb); +	err = rt_intern_hash(hash, rth, NULL, skb, fl.iif);  	goto done;  no_route: @@ -2444,6 +2456,7 @@ static int __mkroute_output(struct rtable **result,  	rth->rt_spec_dst= fl->fl4_src;  	rth->u.dst.output=ip_output; +	rth->u.dst.obsolete = -1;  	rth->rt_genid = rt_genid(dev_net(dev_out));  	RT_CACHE_STAT_INC(out_slow_tot); @@ -2495,7 +2508,7 @@ static int ip_mkroute_output(struct rtable **rp,  	if (err == 0) {  		hash = rt_hash(oldflp->fl4_dst, oldflp->fl4_src, oldflp->oif,  			       rt_genid(dev_net(dev_out))); -		err = rt_intern_hash(hash, rth, rp, NULL); +		err = rt_intern_hash(hash, rth, rp, NULL, oldflp->oif);  	}  	return err;  |