diff options
Diffstat (limited to 'net/ipv4/route.c')
| -rw-r--r-- | net/ipv4/route.c | 323 | 
1 files changed, 167 insertions, 156 deletions
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 99e6e4bb1c7..6a83840b16a 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -424,7 +424,7 @@ static int rt_cache_seq_show(struct seq_file *seq, void *v)  			dst_metric(&r->dst, RTAX_WINDOW),  			(int)((dst_metric(&r->dst, RTAX_RTT) >> 3) +  			      dst_metric(&r->dst, RTAX_RTTVAR)), -			r->rt_tos, +			r->rt_key_tos,  			r->dst.hh ? atomic_read(&r->dst.hh->hh_refcnt) : -1,  			r->dst.hh ? (r->dst.hh->hh_output ==  				       dev_queue_xmit) : 0, @@ -724,7 +724,7 @@ static inline int compare_keys(struct rtable *rt1, struct rtable *rt2)  	return (((__force u32)rt1->rt_key_dst ^ (__force u32)rt2->rt_key_dst) |  		((__force u32)rt1->rt_key_src ^ (__force u32)rt2->rt_key_src) |  		(rt1->rt_mark ^ rt2->rt_mark) | -		(rt1->rt_tos ^ rt2->rt_tos) | +		(rt1->rt_key_tos ^ rt2->rt_key_tos) |  		(rt1->rt_oif ^ rt2->rt_oif) |  		(rt1->rt_iif ^ rt2->rt_iif)) == 0;  } @@ -1349,7 +1349,7 @@ static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst)  						rt_genid(dev_net(dst->dev)));  #if RT_CACHE_DEBUG >= 1  			printk(KERN_DEBUG "ipv4_negative_advice: redirect to %pI4/%02x dropped\n", -				&rt->rt_dst, rt->rt_tos); +				&rt->rt_dst, rt->rt_key_tos);  #endif  			rt_del(hash, rt);  			ret = NULL; @@ -1507,7 +1507,7 @@ static inline unsigned short guess_mtu(unsigned short old_mtu)  	return 68;  } -unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph, +unsigned short ip_rt_frag_needed(struct net *net, const struct iphdr *iph,  				 unsigned short new_mtu,  				 struct net_device *dev)  { @@ -1710,7 +1710,7 @@ void ip_rt_get_source(u8 *addr, struct rtable *rt)  		struct flowi4 fl4 = {  			.daddr = rt->rt_key_dst,  			.saddr = rt->rt_key_src, -			.flowi4_tos = rt->rt_tos, +			.flowi4_tos = rt->rt_key_tos,  			.flowi4_oif = rt->rt_oif,  			.flowi4_iif = rt->rt_iif,  			.flowi4_mark = rt->rt_mark, @@ -1767,7 +1767,7 @@ static unsigned int ipv4_default_mtu(const struct dst_entry *dst)  	return mtu;  } -static void rt_init_metrics(struct rtable *rt, const struct flowi4 *oldflp4, +static void rt_init_metrics(struct rtable *rt, const struct flowi4 *fl4,  			    struct fib_info *fi)  {  	struct inet_peer *peer; @@ -1776,7 +1776,7 @@ static void rt_init_metrics(struct rtable *rt, const struct flowi4 *oldflp4,  	/* If a peer entry exists for this destination, we must hook  	 * it up in order to get at cached metrics.  	 */ -	if (oldflp4 && (oldflp4->flowi4_flags & FLOWI_FLAG_PRECOW_METRICS)) +	if (fl4 && (fl4->flowi4_flags & FLOWI_FLAG_PRECOW_METRICS))  		create = 1;  	rt->peer = peer = inet_getpeer_v4(rt->rt_dst, create); @@ -1803,7 +1803,7 @@ static void rt_init_metrics(struct rtable *rt, const struct flowi4 *oldflp4,  	}  } -static void rt_set_nexthop(struct rtable *rt, const struct flowi4 *oldflp4, +static void rt_set_nexthop(struct rtable *rt, const struct flowi4 *fl4,  			   const struct fib_result *res,  			   struct fib_info *fi, u16 type, u32 itag)  { @@ -1813,7 +1813,7 @@ static void rt_set_nexthop(struct rtable *rt, const struct flowi4 *oldflp4,  		if (FIB_RES_GW(*res) &&  		    FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK)  			rt->rt_gateway = FIB_RES_GW(*res); -		rt_init_metrics(rt, oldflp4, fi); +		rt_init_metrics(rt, fl4, fi);  #ifdef CONFIG_IP_ROUTE_CLASSID  		dst->tclassid = FIB_RES_NH(*res).nh_tclassid;  #endif @@ -1830,20 +1830,15 @@ static void rt_set_nexthop(struct rtable *rt, const struct flowi4 *oldflp4,  #endif  	set_class_tag(rt, itag);  #endif -	rt->rt_type = type;  } -static struct rtable *rt_dst_alloc(bool nopolicy, bool noxfrm) +static struct rtable *rt_dst_alloc(struct net_device *dev, +				   bool nopolicy, bool noxfrm)  { -	struct rtable *rt = dst_alloc(&ipv4_dst_ops, 1); -	if (rt) { -		rt->dst.obsolete = -1; - -		rt->dst.flags = DST_HOST | -			(nopolicy ? DST_NOPOLICY : 0) | -			(noxfrm ? DST_NOXFRM : 0); -	} -	return rt; +	return dst_alloc(&ipv4_dst_ops, dev, 1, -1, +			 DST_HOST | +			 (nopolicy ? DST_NOPOLICY : 0) | +			 (noxfrm ? DST_NOXFRM : 0));  }  /* called in rcu_read_lock() section */ @@ -1871,36 +1866,38 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,  			goto e_inval;  		spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK);  	} else { -		err = fib_validate_source(saddr, 0, tos, 0, dev, &spec_dst, -					  &itag, 0); +		err = fib_validate_source(skb, saddr, 0, tos, 0, dev, &spec_dst, +					  &itag);  		if (err < 0)  			goto e_err;  	} -	rth = rt_dst_alloc(IN_DEV_CONF_GET(in_dev, NOPOLICY), false); +	rth = rt_dst_alloc(init_net.loopback_dev, +			   IN_DEV_CONF_GET(in_dev, NOPOLICY), false);  	if (!rth)  		goto e_nobufs; +#ifdef CONFIG_IP_ROUTE_CLASSID +	rth->dst.tclassid = itag; +#endif  	rth->dst.output = ip_rt_bug;  	rth->rt_key_dst	= daddr; -	rth->rt_dst	= daddr; -	rth->rt_tos	= tos; -	rth->rt_mark    = skb->mark;  	rth->rt_key_src	= saddr; +	rth->rt_genid	= rt_genid(dev_net(dev)); +	rth->rt_flags	= RTCF_MULTICAST; +	rth->rt_type	= RTN_MULTICAST; +	rth->rt_key_tos	= tos; +	rth->rt_dst	= daddr;  	rth->rt_src	= saddr; -#ifdef CONFIG_IP_ROUTE_CLASSID -	rth->dst.tclassid = itag; -#endif  	rth->rt_route_iif = dev->ifindex;  	rth->rt_iif	= dev->ifindex; -	rth->dst.dev	= init_net.loopback_dev; -	dev_hold(rth->dst.dev);  	rth->rt_oif	= 0; +	rth->rt_mark    = skb->mark;  	rth->rt_gateway	= daddr;  	rth->rt_spec_dst= spec_dst; -	rth->rt_genid	= rt_genid(dev_net(dev)); -	rth->rt_flags	= RTCF_MULTICAST; -	rth->rt_type	= RTN_MULTICAST; +	rth->rt_peer_genid = 0; +	rth->peer = NULL; +	rth->fi = NULL;  	if (our) {  		rth->dst.input= ip_local_deliver;  		rth->rt_flags |= RTCF_LOCAL; @@ -1981,8 +1978,8 @@ static int __mkroute_input(struct sk_buff *skb,  	} -	err = fib_validate_source(saddr, daddr, tos, FIB_RES_OIF(*res), -				  in_dev->dev, &spec_dst, &itag, skb->mark); +	err = fib_validate_source(skb, saddr, daddr, tos, FIB_RES_OIF(*res), +				  in_dev->dev, &spec_dst, &itag);  	if (err < 0) {  		ip_handle_martian_source(in_dev->dev, in_dev, skb, daddr,  					 saddr); @@ -2013,7 +2010,8 @@ static int __mkroute_input(struct sk_buff *skb,  		}  	} -	rth = rt_dst_alloc(IN_DEV_CONF_GET(in_dev, NOPOLICY), +	rth = rt_dst_alloc(out_dev->dev, +			   IN_DEV_CONF_GET(in_dev, NOPOLICY),  			   IN_DEV_CONF_GET(out_dev, NOXFRM));  	if (!rth) {  		err = -ENOBUFS; @@ -2021,27 +2019,28 @@ static int __mkroute_input(struct sk_buff *skb,  	}  	rth->rt_key_dst	= daddr; -	rth->rt_dst	= daddr; -	rth->rt_tos	= tos; -	rth->rt_mark    = skb->mark;  	rth->rt_key_src	= saddr; +	rth->rt_genid = rt_genid(dev_net(rth->dst.dev)); +	rth->rt_flags = flags; +	rth->rt_type = res->type; +	rth->rt_key_tos	= tos; +	rth->rt_dst	= daddr;  	rth->rt_src	= saddr; -	rth->rt_gateway	= daddr;  	rth->rt_route_iif = in_dev->dev->ifindex;  	rth->rt_iif 	= in_dev->dev->ifindex; -	rth->dst.dev	= (out_dev)->dev; -	dev_hold(rth->dst.dev);  	rth->rt_oif 	= 0; +	rth->rt_mark    = skb->mark; +	rth->rt_gateway	= daddr;  	rth->rt_spec_dst= spec_dst; +	rth->rt_peer_genid = 0; +	rth->peer = NULL; +	rth->fi = NULL;  	rth->dst.input = ip_forward;  	rth->dst.output = ip_output; -	rth->rt_genid = rt_genid(dev_net(rth->dst.dev));  	rt_set_nexthop(rth, NULL, res, res->fi, res->type, itag); -	rth->rt_flags = flags; -  	*result = rth;  	err = 0;   cleanup: @@ -2150,9 +2149,9 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,  		goto brd_input;  	if (res.type == RTN_LOCAL) { -		err = fib_validate_source(saddr, daddr, tos, +		err = fib_validate_source(skb, saddr, daddr, tos,  					  net->loopback_dev->ifindex, -					  dev, &spec_dst, &itag, skb->mark); +					  dev, &spec_dst, &itag);  		if (err < 0)  			goto martian_source_keep_err;  		if (err) @@ -2176,8 +2175,8 @@ brd_input:  	if (ipv4_is_zeronet(saddr))  		spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK);  	else { -		err = fib_validate_source(saddr, 0, tos, 0, dev, &spec_dst, -					  &itag, skb->mark); +		err = fib_validate_source(skb, saddr, 0, tos, 0, dev, &spec_dst, +					  &itag);  		if (err < 0)  			goto martian_source_keep_err;  		if (err) @@ -2188,36 +2187,42 @@ brd_input:  	RT_CACHE_STAT_INC(in_brd);  local_input: -	rth = rt_dst_alloc(IN_DEV_CONF_GET(in_dev, NOPOLICY), false); +	rth = rt_dst_alloc(net->loopback_dev, +			   IN_DEV_CONF_GET(in_dev, NOPOLICY), false);  	if (!rth)  		goto e_nobufs; +	rth->dst.input= ip_local_deliver;  	rth->dst.output= ip_rt_bug; -	rth->rt_genid = rt_genid(net); +#ifdef CONFIG_IP_ROUTE_CLASSID +	rth->dst.tclassid = itag; +#endif  	rth->rt_key_dst	= daddr; -	rth->rt_dst	= daddr; -	rth->rt_tos	= tos; -	rth->rt_mark    = skb->mark;  	rth->rt_key_src	= saddr; +	rth->rt_genid = rt_genid(net); +	rth->rt_flags 	= flags|RTCF_LOCAL; +	rth->rt_type	= res.type; +	rth->rt_key_tos	= tos; +	rth->rt_dst	= daddr;  	rth->rt_src	= saddr;  #ifdef CONFIG_IP_ROUTE_CLASSID  	rth->dst.tclassid = itag;  #endif  	rth->rt_route_iif = dev->ifindex;  	rth->rt_iif	= dev->ifindex; -	rth->dst.dev	= net->loopback_dev; -	dev_hold(rth->dst.dev); +	rth->rt_oif	= 0; +	rth->rt_mark    = skb->mark;  	rth->rt_gateway	= daddr;  	rth->rt_spec_dst= spec_dst; -	rth->dst.input= ip_local_deliver; -	rth->rt_flags 	= flags|RTCF_LOCAL; +	rth->rt_peer_genid = 0; +	rth->peer = NULL; +	rth->fi = NULL;  	if (res.type == RTN_UNREACHABLE) {  		rth->dst.input= ip_error;  		rth->dst.error= -err;  		rth->rt_flags 	&= ~RTCF_LOCAL;  	} -	rth->rt_type	= res.type;  	hash = rt_hash(daddr, saddr, fl4.flowi4_iif, rt_genid(net));  	rth = rt_intern_hash(hash, rth, skb, fl4.flowi4_iif);  	err = 0; @@ -2288,7 +2293,7 @@ int ip_route_input_common(struct sk_buff *skb, __be32 daddr, __be32 saddr,  		     ((__force u32)rth->rt_key_src ^ (__force u32)saddr) |  		     (rth->rt_iif ^ iif) |  		     rth->rt_oif | -		     (rth->rt_tos ^ tos)) == 0 && +		     (rth->rt_key_tos ^ tos)) == 0 &&  		    rth->rt_mark == skb->mark &&  		    net_eq(dev_net(rth->dst.dev), net) &&  		    !rt_is_expired(rth)) { @@ -2349,12 +2354,12 @@ EXPORT_SYMBOL(ip_route_input_common);  /* called with rcu_read_lock() */  static struct rtable *__mkroute_output(const struct fib_result *res,  				       const struct flowi4 *fl4, -				       const struct flowi4 *oldflp4, -				       struct net_device *dev_out, +				       __be32 orig_daddr, __be32 orig_saddr, +				       int orig_oif, struct net_device *dev_out,  				       unsigned int flags)  {  	struct fib_info *fi = res->fi; -	u32 tos = RT_FL_TOS(oldflp4); +	u32 tos = RT_FL_TOS(fl4);  	struct in_device *in_dev;  	u16 type = res->type;  	struct rtable *rth; @@ -2381,8 +2386,8 @@ static struct rtable *__mkroute_output(const struct fib_result *res,  		fi = NULL;  	} else if (type == RTN_MULTICAST) {  		flags |= RTCF_MULTICAST | RTCF_LOCAL; -		if (!ip_check_mc_rcu(in_dev, oldflp4->daddr, oldflp4->saddr, -				     oldflp4->flowi4_proto)) +		if (!ip_check_mc_rcu(in_dev, fl4->daddr, fl4->saddr, +				     fl4->flowi4_proto))  			flags &= ~RTCF_LOCAL;  		/* If multicast route do not exist use  		 * default one, but do not gateway in this case. @@ -2392,29 +2397,31 @@ static struct rtable *__mkroute_output(const struct fib_result *res,  			fi = NULL;  	} -	rth = rt_dst_alloc(IN_DEV_CONF_GET(in_dev, NOPOLICY), +	rth = rt_dst_alloc(dev_out, +			   IN_DEV_CONF_GET(in_dev, NOPOLICY),  			   IN_DEV_CONF_GET(in_dev, NOXFRM));  	if (!rth)  		return ERR_PTR(-ENOBUFS); -	rth->rt_key_dst	= oldflp4->daddr; -	rth->rt_tos	= tos; -	rth->rt_key_src	= oldflp4->saddr; -	rth->rt_oif	= oldflp4->flowi4_oif; -	rth->rt_mark    = oldflp4->flowi4_mark; +	rth->dst.output = ip_output; + +	rth->rt_key_dst	= orig_daddr; +	rth->rt_key_src	= orig_saddr; +	rth->rt_genid = rt_genid(dev_net(dev_out)); +	rth->rt_flags	= flags; +	rth->rt_type	= type; +	rth->rt_key_tos	= tos;  	rth->rt_dst	= fl4->daddr;  	rth->rt_src	= fl4->saddr;  	rth->rt_route_iif = 0; -	rth->rt_iif	= oldflp4->flowi4_oif ? : dev_out->ifindex; -	/* get references to the devices that are to be hold by the routing -	   cache entry */ -	rth->dst.dev	= dev_out; -	dev_hold(dev_out); +	rth->rt_iif	= orig_oif ? : dev_out->ifindex; +	rth->rt_oif	= orig_oif; +	rth->rt_mark    = fl4->flowi4_mark;  	rth->rt_gateway = fl4->daddr;  	rth->rt_spec_dst= fl4->saddr; - -	rth->dst.output=ip_output; -	rth->rt_genid = rt_genid(dev_net(dev_out)); +	rth->rt_peer_genid = 0; +	rth->peer = NULL; +	rth->fi = NULL;  	RT_CACHE_STAT_INC(out_slow_tot); @@ -2432,7 +2439,7 @@ static struct rtable *__mkroute_output(const struct fib_result *res,  #ifdef CONFIG_IP_MROUTE  		if (type == RTN_MULTICAST) {  			if (IN_DEV_MFORWARD(in_dev) && -			    !ipv4_is_local_multicast(oldflp4->daddr)) { +			    !ipv4_is_local_multicast(fl4->daddr)) {  				rth->dst.input = ip_mr_input;  				rth->dst.output = ip_mc_output;  			} @@ -2440,9 +2447,8 @@ static struct rtable *__mkroute_output(const struct fib_result *res,  #endif  	} -	rt_set_nexthop(rth, oldflp4, res, fi, type, 0); +	rt_set_nexthop(rth, fl4, res, fi, type, 0); -	rth->rt_flags = flags;  	return rth;  } @@ -2451,36 +2457,37 @@ static struct rtable *__mkroute_output(const struct fib_result *res,   * called with rcu_read_lock();   */ -static struct rtable *ip_route_output_slow(struct net *net, -					   const struct flowi4 *oldflp4) +static struct rtable *ip_route_output_slow(struct net *net, struct flowi4 *fl4)  { -	u32 tos	= RT_FL_TOS(oldflp4); -	struct flowi4 fl4; -	struct fib_result res; -	unsigned int flags = 0;  	struct net_device *dev_out = NULL; +	u32 tos	= RT_FL_TOS(fl4); +	unsigned int flags = 0; +	struct fib_result res;  	struct rtable *rth; +	__be32 orig_daddr; +	__be32 orig_saddr; +	int orig_oif;  	res.fi		= NULL;  #ifdef CONFIG_IP_MULTIPLE_TABLES  	res.r		= NULL;  #endif -	fl4.flowi4_oif = oldflp4->flowi4_oif; -	fl4.flowi4_iif = net->loopback_dev->ifindex; -	fl4.flowi4_mark = oldflp4->flowi4_mark; -	fl4.daddr = oldflp4->daddr; -	fl4.saddr = oldflp4->saddr; -	fl4.flowi4_tos = tos & IPTOS_RT_MASK; -	fl4.flowi4_scope = ((tos & RTO_ONLINK) ? -			RT_SCOPE_LINK : RT_SCOPE_UNIVERSE); +	orig_daddr = fl4->daddr; +	orig_saddr = fl4->saddr; +	orig_oif = fl4->flowi4_oif; + +	fl4->flowi4_iif = net->loopback_dev->ifindex; +	fl4->flowi4_tos = tos & IPTOS_RT_MASK; +	fl4->flowi4_scope = ((tos & RTO_ONLINK) ? +			 RT_SCOPE_LINK : RT_SCOPE_UNIVERSE);  	rcu_read_lock(); -	if (oldflp4->saddr) { +	if (fl4->saddr) {  		rth = ERR_PTR(-EINVAL); -		if (ipv4_is_multicast(oldflp4->saddr) || -		    ipv4_is_lbcast(oldflp4->saddr) || -		    ipv4_is_zeronet(oldflp4->saddr)) +		if (ipv4_is_multicast(fl4->saddr) || +		    ipv4_is_lbcast(fl4->saddr) || +		    ipv4_is_zeronet(fl4->saddr))  			goto out;  		/* I removed check for oif == dev_out->oif here. @@ -2491,11 +2498,11 @@ static struct rtable *ip_route_output_slow(struct net *net,  		      of another iface. --ANK  		 */ -		if (oldflp4->flowi4_oif == 0 && -		    (ipv4_is_multicast(oldflp4->daddr) || -		     ipv4_is_lbcast(oldflp4->daddr))) { +		if (fl4->flowi4_oif == 0 && +		    (ipv4_is_multicast(fl4->daddr) || +		     ipv4_is_lbcast(fl4->daddr))) {  			/* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */ -			dev_out = __ip_dev_find(net, oldflp4->saddr, false); +			dev_out = __ip_dev_find(net, fl4->saddr, false);  			if (dev_out == NULL)  				goto out; @@ -2514,20 +2521,20 @@ static struct rtable *ip_route_output_slow(struct net *net,  			   Luckily, this hack is good workaround.  			 */ -			fl4.flowi4_oif = dev_out->ifindex; +			fl4->flowi4_oif = dev_out->ifindex;  			goto make_route;  		} -		if (!(oldflp4->flowi4_flags & FLOWI_FLAG_ANYSRC)) { +		if (!(fl4->flowi4_flags & FLOWI_FLAG_ANYSRC)) {  			/* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */ -			if (!__ip_dev_find(net, oldflp4->saddr, false)) +			if (!__ip_dev_find(net, fl4->saddr, false))  				goto out;  		}  	} -	if (oldflp4->flowi4_oif) { -		dev_out = dev_get_by_index_rcu(net, oldflp4->flowi4_oif); +	if (fl4->flowi4_oif) { +		dev_out = dev_get_by_index_rcu(net, fl4->flowi4_oif);  		rth = ERR_PTR(-ENODEV);  		if (dev_out == NULL)  			goto out; @@ -2537,37 +2544,37 @@ static struct rtable *ip_route_output_slow(struct net *net,  			rth = ERR_PTR(-ENETUNREACH);  			goto out;  		} -		if (ipv4_is_local_multicast(oldflp4->daddr) || -		    ipv4_is_lbcast(oldflp4->daddr)) { -			if (!fl4.saddr) -				fl4.saddr = inet_select_addr(dev_out, 0, -							     RT_SCOPE_LINK); +		if (ipv4_is_local_multicast(fl4->daddr) || +		    ipv4_is_lbcast(fl4->daddr)) { +			if (!fl4->saddr) +				fl4->saddr = inet_select_addr(dev_out, 0, +							      RT_SCOPE_LINK);  			goto make_route;  		} -		if (!fl4.saddr) { -			if (ipv4_is_multicast(oldflp4->daddr)) -				fl4.saddr = inet_select_addr(dev_out, 0, -							     fl4.flowi4_scope); -			else if (!oldflp4->daddr) -				fl4.saddr = inet_select_addr(dev_out, 0, -							     RT_SCOPE_HOST); +		if (fl4->saddr) { +			if (ipv4_is_multicast(fl4->daddr)) +				fl4->saddr = inet_select_addr(dev_out, 0, +							      fl4->flowi4_scope); +			else if (!fl4->daddr) +				fl4->saddr = inet_select_addr(dev_out, 0, +							      RT_SCOPE_HOST);  		}  	} -	if (!fl4.daddr) { -		fl4.daddr = fl4.saddr; -		if (!fl4.daddr) -			fl4.daddr = fl4.saddr = htonl(INADDR_LOOPBACK); +	if (!fl4->daddr) { +		fl4->daddr = fl4->saddr; +		if (!fl4->daddr) +			fl4->daddr = fl4->saddr = htonl(INADDR_LOOPBACK);  		dev_out = net->loopback_dev; -		fl4.flowi4_oif = net->loopback_dev->ifindex; +		fl4->flowi4_oif = net->loopback_dev->ifindex;  		res.type = RTN_LOCAL;  		flags |= RTCF_LOCAL;  		goto make_route;  	} -	if (fib_lookup(net, &fl4, &res)) { +	if (fib_lookup(net, fl4, &res)) {  		res.fi = NULL; -		if (oldflp4->flowi4_oif) { +		if (fl4->flowi4_oif) {  			/* Apparently, routing tables are wrong. Assume,  			   that the destination is on link. @@ -2586,9 +2593,9 @@ static struct rtable *ip_route_output_slow(struct net *net,  			   likely IPv6, but we do not.  			 */ -			if (fl4.saddr == 0) -				fl4.saddr = inet_select_addr(dev_out, 0, -							     RT_SCOPE_LINK); +			if (fl4->saddr == 0) +				fl4->saddr = inet_select_addr(dev_out, 0, +							      RT_SCOPE_LINK);  			res.type = RTN_UNICAST;  			goto make_route;  		} @@ -2597,42 +2604,45 @@ static struct rtable *ip_route_output_slow(struct net *net,  	}  	if (res.type == RTN_LOCAL) { -		if (!fl4.saddr) { +		if (!fl4->saddr) {  			if (res.fi->fib_prefsrc) -				fl4.saddr = res.fi->fib_prefsrc; +				fl4->saddr = res.fi->fib_prefsrc;  			else -				fl4.saddr = fl4.daddr; +				fl4->saddr = fl4->daddr;  		}  		dev_out = net->loopback_dev; -		fl4.flowi4_oif = dev_out->ifindex; +		fl4->flowi4_oif = dev_out->ifindex;  		res.fi = NULL;  		flags |= RTCF_LOCAL;  		goto make_route;  	}  #ifdef CONFIG_IP_ROUTE_MULTIPATH -	if (res.fi->fib_nhs > 1 && fl4.flowi4_oif == 0) +	if (res.fi->fib_nhs > 1 && fl4->flowi4_oif == 0)  		fib_select_multipath(&res);  	else  #endif -	if (!res.prefixlen && res.type == RTN_UNICAST && !fl4.flowi4_oif) +	if (!res.prefixlen && +	    res.table->tb_num_default > 1 && +	    res.type == RTN_UNICAST && !fl4->flowi4_oif)  		fib_select_default(&res); -	if (!fl4.saddr) -		fl4.saddr = FIB_RES_PREFSRC(net, res); +	if (!fl4->saddr) +		fl4->saddr = FIB_RES_PREFSRC(net, res);  	dev_out = FIB_RES_DEV(res); -	fl4.flowi4_oif = dev_out->ifindex; +	fl4->flowi4_oif = dev_out->ifindex;  make_route: -	rth = __mkroute_output(&res, &fl4, oldflp4, dev_out, flags); +	rth = __mkroute_output(&res, fl4, orig_daddr, orig_saddr, orig_oif, +			       dev_out, flags);  	if (!IS_ERR(rth)) {  		unsigned int hash; -		hash = rt_hash(oldflp4->daddr, oldflp4->saddr, oldflp4->flowi4_oif, +		hash = rt_hash(orig_daddr, orig_saddr, orig_oif,  			       rt_genid(dev_net(dev_out))); -		rth = rt_intern_hash(hash, rth, NULL, oldflp4->flowi4_oif); +		rth = rt_intern_hash(hash, rth, NULL, orig_oif);  	}  out: @@ -2640,7 +2650,7 @@ out:  	return rth;  } -struct rtable *__ip_route_output_key(struct net *net, const struct flowi4 *flp4) +struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *flp4)  {  	struct rtable *rth;  	unsigned int hash; @@ -2658,13 +2668,17 @@ struct rtable *__ip_route_output_key(struct net *net, const struct flowi4 *flp4)  		    rt_is_output_route(rth) &&  		    rth->rt_oif == flp4->flowi4_oif &&  		    rth->rt_mark == flp4->flowi4_mark && -		    !((rth->rt_tos ^ flp4->flowi4_tos) & +		    !((rth->rt_key_tos ^ flp4->flowi4_tos) &  			    (IPTOS_RT_MASK | RTO_ONLINK)) &&  		    net_eq(dev_net(rth->dst.dev), net) &&  		    !rt_is_expired(rth)) {  			dst_use(&rth->dst, jiffies);  			RT_CACHE_STAT_INC(out_hit);  			rcu_read_unlock_bh(); +			if (!flp4->saddr) +				flp4->saddr = rth->rt_src; +			if (!flp4->daddr) +				flp4->daddr = rth->rt_dst;  			return rth;  		}  		RT_CACHE_STAT_INC(out_hlist_search); @@ -2709,7 +2723,7 @@ static struct dst_ops ipv4_dst_blackhole_ops = {  struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_orig)  { -	struct rtable *rt = dst_alloc(&ipv4_dst_blackhole_ops, 1); +	struct rtable *rt = dst_alloc(&ipv4_dst_blackhole_ops, NULL, 1, 0, 0);  	struct rtable *ort = (struct rtable *) dst_orig;  	if (rt) { @@ -2726,7 +2740,7 @@ struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_or  		rt->rt_key_dst = ort->rt_key_dst;  		rt->rt_key_src = ort->rt_key_src; -		rt->rt_tos = ort->rt_tos; +		rt->rt_key_tos = ort->rt_key_tos;  		rt->rt_route_iif = ort->rt_route_iif;  		rt->rt_iif = ort->rt_iif;  		rt->rt_oif = ort->rt_oif; @@ -2762,15 +2776,10 @@ struct rtable *ip_route_output_flow(struct net *net, struct flowi4 *flp4,  	if (IS_ERR(rt))  		return rt; -	if (flp4->flowi4_proto) { -		if (!flp4->saddr) -			flp4->saddr = rt->rt_src; -		if (!flp4->daddr) -			flp4->daddr = rt->rt_dst; +	if (flp4->flowi4_proto)  		rt = (struct rtable *) xfrm_lookup(net, &rt->dst,  						   flowi4_to_flowi(flp4),  						   sk, 0); -	}  	return rt;  } @@ -2794,7 +2803,7 @@ static int rt_fill_info(struct net *net,  	r->rtm_family	 = AF_INET;  	r->rtm_dst_len	= 32;  	r->rtm_src_len	= 0; -	r->rtm_tos	= rt->rt_tos; +	r->rtm_tos	= rt->rt_key_tos;  	r->rtm_table	= RT_TABLE_MAIN;  	NLA_PUT_U32(skb, RTA_TABLE, RT_TABLE_MAIN);  	r->rtm_type	= rt->rt_type; @@ -2848,7 +2857,9 @@ static int rt_fill_info(struct net *net,  		if (ipv4_is_multicast(dst) && !ipv4_is_local_multicast(dst) &&  		    IPV4_DEVCONF_ALL(net, MC_FORWARDING)) { -			int err = ipmr_get_route(net, skb, r, nowait); +			int err = ipmr_get_route(net, skb, +						 rt->rt_src, rt->rt_dst, +						 r, nowait);  			if (err <= 0) {  				if (!nowait) {  					if (err == 0)  |