Commit f8126f1d authored by David S. Miller's avatar David S. Miller

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: default avatarDavid S. Miller <davem@davemloft.net>
Tested-by: default avatarVijay Subramanian <subramanian.vijay@gmail.com>
parent f1ce3062
...@@ -70,6 +70,13 @@ static inline bool rt_is_output_route(const struct rtable *rt) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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 ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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,8 +1085,9 @@ void ip_rt_get_source(u8 *addr, struct sk_buff *skb, struct rtable *rt) ...@@ -1085,8 +1085,9 @@ 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_SCOPE_UNIVERSE); rt_nexthop(rt, iph->daddr),
RT_SCOPE_UNIVERSE);
rcu_read_unlock(); rcu_read_unlock();
} }
memcpy(addr, &src, 4); memcpy(addr, &src, 4);
...@@ -1132,7 +1133,7 @@ static unsigned int ipv4_mtu(const struct dst_entry *dst) ...@@ -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, ...@@ -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, ...@@ -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; ...@@ -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, ...@@ -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, ...@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment