mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	ipv4: Adjust semantics of rt->rt_gateway.
In order to allow prefixed routes, we have to adjust how rt_gateway is set and interpreted. The new interpretation is: 1) rt_gateway == 0, destination is on-link, nexthop is iph->daddr 2) rt_gateway != 0, destination requires a nexthop gateway Abstract the fetching of the proper nexthop value using a new inline helper, rt_nexthop(), as suggested by Joe Perches. Signed-off-by: David S. Miller <davem@davemloft.net> Tested-by: Vijay Subramanian <subramanian.vijay@gmail.com>
This commit is contained in:
		
							parent
							
								
									f1ce3062c5
								
							
						
					
					
						commit
						f8126f1d51
					
				
					 8 changed files with 25 additions and 17 deletions
				
			
		| 
						 | 
					@ -70,6 +70,13 @@ static inline bool rt_is_output_route(const struct rtable *rt)
 | 
				
			||||||
	return rt->rt_route_iif == 0;
 | 
						return rt->rt_route_iif == 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline __be32 rt_nexthop(const struct rtable *rt, __be32 daddr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (rt->rt_gateway)
 | 
				
			||||||
 | 
							return rt->rt_gateway;
 | 
				
			||||||
 | 
						return daddr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ip_rt_acct {
 | 
					struct ip_rt_acct {
 | 
				
			||||||
	__u32 	o_bytes;
 | 
						__u32 	o_bytes;
 | 
				
			||||||
	__u32 	o_packets;
 | 
						__u32 	o_packets;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -475,8 +475,7 @@ int arp_find(unsigned char *haddr, struct sk_buff *skb)
 | 
				
			||||||
		return 1;
 | 
							return 1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	paddr = skb_rtable(skb)->rt_gateway;
 | 
						paddr = rt_nexthop(skb_rtable(skb), ip_hdr(skb)->daddr);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (arp_set_predefined(inet_addr_type(dev_net(dev), paddr), haddr,
 | 
						if (arp_set_predefined(inet_addr_type(dev_net(dev), paddr), haddr,
 | 
				
			||||||
			       paddr, dev))
 | 
								       paddr, dev))
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -389,7 +389,7 @@ struct dst_entry *inet_csk_route_req(struct sock *sk,
 | 
				
			||||||
	rt = ip_route_output_flow(net, fl4, sk);
 | 
						rt = ip_route_output_flow(net, fl4, sk);
 | 
				
			||||||
	if (IS_ERR(rt))
 | 
						if (IS_ERR(rt))
 | 
				
			||||||
		goto no_route;
 | 
							goto no_route;
 | 
				
			||||||
	if (opt && opt->opt.is_strictroute && fl4->daddr != rt->rt_gateway)
 | 
						if (opt && opt->opt.is_strictroute && rt->rt_gateway)
 | 
				
			||||||
		goto route_err;
 | 
							goto route_err;
 | 
				
			||||||
	return &rt->dst;
 | 
						return &rt->dst;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -422,7 +422,7 @@ struct dst_entry *inet_csk_route_child_sock(struct sock *sk,
 | 
				
			||||||
	rt = ip_route_output_flow(net, fl4, sk);
 | 
						rt = ip_route_output_flow(net, fl4, sk);
 | 
				
			||||||
	if (IS_ERR(rt))
 | 
						if (IS_ERR(rt))
 | 
				
			||||||
		goto no_route;
 | 
							goto no_route;
 | 
				
			||||||
	if (opt && opt->opt.is_strictroute && fl4->daddr != rt->rt_gateway)
 | 
						if (opt && opt->opt.is_strictroute && rt->rt_gateway)
 | 
				
			||||||
		goto route_err;
 | 
							goto route_err;
 | 
				
			||||||
	return &rt->dst;
 | 
						return &rt->dst;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -766,7 +766,7 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (skb->protocol == htons(ETH_P_IP)) {
 | 
							if (skb->protocol == htons(ETH_P_IP)) {
 | 
				
			||||||
			rt = skb_rtable(skb);
 | 
								rt = skb_rtable(skb);
 | 
				
			||||||
			dst = rt->rt_gateway;
 | 
								dst = rt_nexthop(rt, old_iph->daddr);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
#if IS_ENABLED(CONFIG_IPV6)
 | 
					#if IS_ENABLED(CONFIG_IPV6)
 | 
				
			||||||
		else if (skb->protocol == htons(ETH_P_IPV6)) {
 | 
							else if (skb->protocol == htons(ETH_P_IPV6)) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -371,7 +371,7 @@ int ip_queue_xmit(struct sk_buff *skb, struct flowi *fl)
 | 
				
			||||||
	skb_dst_set_noref(skb, &rt->dst);
 | 
						skb_dst_set_noref(skb, &rt->dst);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
packet_routed:
 | 
					packet_routed:
 | 
				
			||||||
	if (inet_opt && inet_opt->opt.is_strictroute && fl4->daddr != rt->rt_gateway)
 | 
						if (inet_opt && inet_opt->opt.is_strictroute && rt->rt_gateway)
 | 
				
			||||||
		goto no_route;
 | 
							goto no_route;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* OK, we know where to send it, allocate and build IP header. */
 | 
						/* OK, we know where to send it, allocate and build IP header. */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -487,7 +487,7 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
 | 
				
			||||||
			dev->stats.tx_fifo_errors++;
 | 
								dev->stats.tx_fifo_errors++;
 | 
				
			||||||
			goto tx_error;
 | 
								goto tx_error;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		dst = rt->rt_gateway;
 | 
							dst = rt_nexthop(rt, old_iph->daddr);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rt = ip_route_output_ports(dev_net(dev), &fl4, NULL,
 | 
						rt = ip_route_output_ports(dev_net(dev), &fl4, NULL,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -52,7 +52,7 @@ masquerade_tg(struct sk_buff *skb, const struct xt_action_param *par)
 | 
				
			||||||
	struct nf_nat_ipv4_range newrange;
 | 
						struct nf_nat_ipv4_range newrange;
 | 
				
			||||||
	const struct nf_nat_ipv4_multi_range_compat *mr;
 | 
						const struct nf_nat_ipv4_multi_range_compat *mr;
 | 
				
			||||||
	const struct rtable *rt;
 | 
						const struct rtable *rt;
 | 
				
			||||||
	__be32 newsrc;
 | 
						__be32 newsrc, nh;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	NF_CT_ASSERT(par->hooknum == NF_INET_POST_ROUTING);
 | 
						NF_CT_ASSERT(par->hooknum == NF_INET_POST_ROUTING);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -70,7 +70,8 @@ masquerade_tg(struct sk_buff *skb, const struct xt_action_param *par)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mr = par->targinfo;
 | 
						mr = par->targinfo;
 | 
				
			||||||
	rt = skb_rtable(skb);
 | 
						rt = skb_rtable(skb);
 | 
				
			||||||
	newsrc = inet_select_addr(par->out, rt->rt_gateway, RT_SCOPE_UNIVERSE);
 | 
						nh = rt_nexthop(rt, ip_hdr(skb)->daddr);
 | 
				
			||||||
 | 
						newsrc = inet_select_addr(par->out, nh, RT_SCOPE_UNIVERSE);
 | 
				
			||||||
	if (!newsrc) {
 | 
						if (!newsrc) {
 | 
				
			||||||
		pr_info("%s ate my IP address\n", par->out->name);
 | 
							pr_info("%s ate my IP address\n", par->out->name);
 | 
				
			||||||
		return NF_DROP;
 | 
							return NF_DROP;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1085,7 +1085,8 @@ void ip_rt_get_source(u8 *addr, struct sk_buff *skb, struct rtable *rt)
 | 
				
			||||||
		if (fib_lookup(dev_net(rt->dst.dev), &fl4, &res) == 0)
 | 
							if (fib_lookup(dev_net(rt->dst.dev), &fl4, &res) == 0)
 | 
				
			||||||
			src = FIB_RES_PREFSRC(dev_net(rt->dst.dev), res);
 | 
								src = FIB_RES_PREFSRC(dev_net(rt->dst.dev), res);
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
			src = inet_select_addr(rt->dst.dev, rt->rt_gateway,
 | 
								src = inet_select_addr(rt->dst.dev,
 | 
				
			||||||
 | 
										       rt_nexthop(rt, iph->daddr),
 | 
				
			||||||
					       RT_SCOPE_UNIVERSE);
 | 
										       RT_SCOPE_UNIVERSE);
 | 
				
			||||||
		rcu_read_unlock();
 | 
							rcu_read_unlock();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -1132,7 +1133,7 @@ static unsigned int ipv4_mtu(const struct dst_entry *dst)
 | 
				
			||||||
	mtu = dst->dev->mtu;
 | 
						mtu = dst->dev->mtu;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (unlikely(dst_metric_locked(dst, RTAX_MTU))) {
 | 
						if (unlikely(dst_metric_locked(dst, RTAX_MTU))) {
 | 
				
			||||||
		if (rt->rt_gateway != 0 && mtu > 576)
 | 
							if (rt->rt_gateway && mtu > 576)
 | 
				
			||||||
			mtu = 576;
 | 
								mtu = 576;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1274,7 +1275,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
 | 
				
			||||||
	rth->rt_iif	= dev->ifindex;
 | 
						rth->rt_iif	= dev->ifindex;
 | 
				
			||||||
	rth->rt_oif	= 0;
 | 
						rth->rt_oif	= 0;
 | 
				
			||||||
	rth->rt_pmtu	= 0;
 | 
						rth->rt_pmtu	= 0;
 | 
				
			||||||
	rth->rt_gateway	= daddr;
 | 
						rth->rt_gateway	= 0;
 | 
				
			||||||
	rth->fi = NULL;
 | 
						rth->fi = NULL;
 | 
				
			||||||
	if (our) {
 | 
						if (our) {
 | 
				
			||||||
		rth->dst.input= ip_local_deliver;
 | 
							rth->dst.input= ip_local_deliver;
 | 
				
			||||||
| 
						 | 
					@ -1392,7 +1393,7 @@ static int __mkroute_input(struct sk_buff *skb,
 | 
				
			||||||
	rth->rt_iif 	= in_dev->dev->ifindex;
 | 
						rth->rt_iif 	= in_dev->dev->ifindex;
 | 
				
			||||||
	rth->rt_oif 	= 0;
 | 
						rth->rt_oif 	= 0;
 | 
				
			||||||
	rth->rt_pmtu	= 0;
 | 
						rth->rt_pmtu	= 0;
 | 
				
			||||||
	rth->rt_gateway	= daddr;
 | 
						rth->rt_gateway	= 0;
 | 
				
			||||||
	rth->fi = NULL;
 | 
						rth->fi = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rth->dst.input = ip_forward;
 | 
						rth->dst.input = ip_forward;
 | 
				
			||||||
| 
						 | 
					@ -1557,7 +1558,7 @@ out:	return err;
 | 
				
			||||||
	rth->rt_iif	= dev->ifindex;
 | 
						rth->rt_iif	= dev->ifindex;
 | 
				
			||||||
	rth->rt_oif	= 0;
 | 
						rth->rt_oif	= 0;
 | 
				
			||||||
	rth->rt_pmtu	= 0;
 | 
						rth->rt_pmtu	= 0;
 | 
				
			||||||
	rth->rt_gateway	= daddr;
 | 
						rth->rt_gateway	= 0;
 | 
				
			||||||
	rth->fi = NULL;
 | 
						rth->fi = NULL;
 | 
				
			||||||
	if (res.type == RTN_UNREACHABLE) {
 | 
						if (res.type == RTN_UNREACHABLE) {
 | 
				
			||||||
		rth->dst.input= ip_error;
 | 
							rth->dst.input= ip_error;
 | 
				
			||||||
| 
						 | 
					@ -1707,7 +1708,7 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
 | 
				
			||||||
	rth->rt_iif	= orig_oif ? : dev_out->ifindex;
 | 
						rth->rt_iif	= orig_oif ? : dev_out->ifindex;
 | 
				
			||||||
	rth->rt_oif	= orig_oif;
 | 
						rth->rt_oif	= orig_oif;
 | 
				
			||||||
	rth->rt_pmtu	= 0;
 | 
						rth->rt_pmtu	= 0;
 | 
				
			||||||
	rth->rt_gateway = fl4->daddr;
 | 
						rth->rt_gateway = 0;
 | 
				
			||||||
	rth->fi = NULL;
 | 
						rth->fi = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	RT_CACHE_STAT_INC(out_slow_tot);
 | 
						RT_CACHE_STAT_INC(out_slow_tot);
 | 
				
			||||||
| 
						 | 
					@ -2070,7 +2071,7 @@ static int rt_fill_info(struct net *net,  __be32 dst, __be32 src,
 | 
				
			||||||
		if (nla_put_be32(skb, RTA_PREFSRC, fl4->saddr))
 | 
							if (nla_put_be32(skb, RTA_PREFSRC, fl4->saddr))
 | 
				
			||||||
			goto nla_put_failure;
 | 
								goto nla_put_failure;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (fl4->daddr != rt->rt_gateway &&
 | 
						if (rt->rt_gateway &&
 | 
				
			||||||
	    nla_put_be32(skb, RTA_GATEWAY, rt->rt_gateway))
 | 
						    nla_put_be32(skb, RTA_GATEWAY, rt->rt_gateway))
 | 
				
			||||||
		goto nla_put_failure;
 | 
							goto nla_put_failure;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue