ipv4: introduce rt_uses_gateway
authorJulian Anastasov <ja@ssi.bg>
Mon, 8 Oct 2012 11:41:18 +0000 (11:41 +0000)
committerDavid S. Miller <davem@davemloft.net>
Mon, 8 Oct 2012 21:42:36 +0000 (17:42 -0400)
Add new flag to remember when route is via gateway.
We will use it to allow rt_gateway to contain address of
directly connected host for the cases when DST_NOCACHE is
used or when the NH exception caches per-destination route
without DST_NOCACHE flag, i.e. when routes are not used for
other destinations. By this way we force the neighbour
resolving to work with the routed destination but we
can use different address in the packet, feature needed
for IPVS-DR where original packet for virtual IP is routed
via route to real IP.

Signed-off-by: Julian Anastasov <ja@ssi.bg>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/route.h
net/ipv4/inet_connection_sock.c
net/ipv4/ip_forward.c
net/ipv4/ip_output.c
net/ipv4/route.c
net/ipv4/xfrm4_policy.c

index da22243d27600cd66b5fb70da61f5cadc05d5468..bc40b633a5c4dc0e763c5c8c4ff123135160dc04 100644 (file)
@@ -48,7 +48,8 @@ struct rtable {
        int                     rt_genid;
        unsigned int            rt_flags;
        __u16                   rt_type;
-       __u16                   rt_is_input;
+       __u8                    rt_is_input;
+       __u8                    rt_uses_gateway;
 
        int                     rt_iif;
 
index f0c5b9c1a95714e2e206cf6cd178a90626271fcc..d34ce2972c8f90bca6809342aab5451c9138241e 100644 (file)
@@ -406,7 +406,7 @@ struct dst_entry *inet_csk_route_req(struct sock *sk,
        rt = ip_route_output_flow(net, fl4, sk);
        if (IS_ERR(rt))
                goto no_route;
-       if (opt && opt->opt.is_strictroute && rt->rt_gateway)
+       if (opt && opt->opt.is_strictroute && rt->rt_uses_gateway)
                goto route_err;
        return &rt->dst;
 
@@ -442,7 +442,7 @@ struct dst_entry *inet_csk_route_child_sock(struct sock *sk,
        rt = ip_route_output_flow(net, fl4, sk);
        if (IS_ERR(rt))
                goto no_route;
-       if (opt && opt->opt.is_strictroute && rt->rt_gateway)
+       if (opt && opt->opt.is_strictroute && rt->rt_uses_gateway)
                goto route_err;
        rcu_read_unlock();
        return &rt->dst;
index 7f35ac26a71a33d0f5ce1a32c5952814882999d6..694de3b7aebfede6073433201e1200cf72008997 100644 (file)
@@ -85,7 +85,7 @@ int ip_forward(struct sk_buff *skb)
 
        rt = skb_rtable(skb);
 
-       if (opt->is_strictroute && rt->rt_gateway)
+       if (opt->is_strictroute && rt->rt_uses_gateway)
                goto sr_failed;
 
        if (unlikely(skb->len > dst_mtu(&rt->dst) && !skb_is_gso(skb) &&
index 24a29a39e9a885dfa96300067fd37154b0875f53..6537a408a4fb451d906b574def4746c064399fd9 100644 (file)
@@ -193,7 +193,7 @@ static inline int ip_finish_output2(struct sk_buff *skb)
        }
 
        rcu_read_lock_bh();
-       nexthop = rt->rt_gateway ? rt->rt_gateway : ip_hdr(skb)->daddr;
+       nexthop = (__force u32) rt_nexthop(rt, ip_hdr(skb)->daddr);
        neigh = __ipv4_neigh_lookup_noref(dev, nexthop);
        if (unlikely(!neigh))
                neigh = __neigh_create(&arp_tbl, &nexthop, dev, false);
@@ -371,7 +371,7 @@ int ip_queue_xmit(struct sk_buff *skb, struct flowi *fl)
        skb_dst_set_noref(skb, &rt->dst);
 
 packet_routed:
-       if (inet_opt && inet_opt->opt.is_strictroute && rt->rt_gateway)
+       if (inet_opt && inet_opt->opt.is_strictroute && rt->rt_uses_gateway)
                goto no_route;
 
        /* OK, we know where to send it, allocate and build IP header. */
index 5b0180f11b20f0dc44bc0a1c528d2ad683b666be..3a116cb0991af6e06fcecab8f6da221ad11be65c 100644 (file)
@@ -1126,7 +1126,7 @@ static unsigned int ipv4_mtu(const struct dst_entry *dst)
        mtu = dst->dev->mtu;
 
        if (unlikely(dst_metric_locked(dst, RTAX_MTU))) {
-               if (rt->rt_gateway && mtu > 576)
+               if (rt->rt_uses_gateway && mtu > 576)
                        mtu = 576;
        }
 
@@ -1177,7 +1177,9 @@ static bool rt_bind_exception(struct rtable *rt, struct fib_nh_exception *fnhe,
                if (fnhe->fnhe_gw) {
                        rt->rt_flags |= RTCF_REDIRECTED;
                        rt->rt_gateway = fnhe->fnhe_gw;
-               }
+                       rt->rt_uses_gateway = 1;
+               } else if (!rt->rt_gateway)
+                       rt->rt_gateway = daddr;
 
                orig = rcu_dereference(fnhe->fnhe_rth);
                rcu_assign_pointer(fnhe->fnhe_rth, rt);
@@ -1186,13 +1188,6 @@ static bool rt_bind_exception(struct rtable *rt, struct fib_nh_exception *fnhe,
 
                fnhe->fnhe_stamp = jiffies;
                ret = true;
-       } else {
-               /* Routes we intend to cache in nexthop exception have
-                * the DST_NOCACHE bit clear.  However, if we are
-                * unsuccessful at storing this route into the cache
-                * we really need to set it.
-                */
-               rt->dst.flags |= DST_NOCACHE;
        }
        spin_unlock_bh(&fnhe_lock);
 
@@ -1215,15 +1210,8 @@ static bool rt_cache_route(struct fib_nh *nh, struct rtable *rt)
        if (prev == orig) {
                if (orig)
                        rt_free(orig);
-       } else {
-               /* Routes we intend to cache in the FIB nexthop have
-                * the DST_NOCACHE bit clear.  However, if we are
-                * unsuccessful at storing this route into the cache
-                * we really need to set it.
-                */
-               rt->dst.flags |= DST_NOCACHE;
+       } else
                ret = false;
-       }
 
        return ret;
 }
@@ -1284,8 +1272,10 @@ static void rt_set_nexthop(struct rtable *rt, __be32 daddr,
        if (fi) {
                struct fib_nh *nh = &FIB_RES_NH(*res);
 
-               if (nh->nh_gw && nh->nh_scope == RT_SCOPE_LINK)
+               if (nh->nh_gw && nh->nh_scope == RT_SCOPE_LINK) {
                        rt->rt_gateway = nh->nh_gw;
+                       rt->rt_uses_gateway = 1;
+               }
                dst_init_metrics(&rt->dst, fi->fib_metrics, true);
 #ifdef CONFIG_IP_ROUTE_CLASSID
                rt->dst.tclassid = nh->nh_tclassid;
@@ -1294,8 +1284,18 @@ static void rt_set_nexthop(struct rtable *rt, __be32 daddr,
                        cached = rt_bind_exception(rt, fnhe, daddr);
                else if (!(rt->dst.flags & DST_NOCACHE))
                        cached = rt_cache_route(nh, rt);
-       }
-       if (unlikely(!cached))
+               if (unlikely(!cached)) {
+                       /* Routes we intend to cache in nexthop exception or
+                        * FIB nexthop have the DST_NOCACHE bit clear.
+                        * However, if we are unsuccessful at storing this
+                        * route into the cache we really need to set it.
+                        */
+                       rt->dst.flags |= DST_NOCACHE;
+                       if (!rt->rt_gateway)
+                               rt->rt_gateway = daddr;
+                       rt_add_uncached_list(rt);
+               }
+       } else
                rt_add_uncached_list(rt);
 
 #ifdef CONFIG_IP_ROUTE_CLASSID
@@ -1363,6 +1363,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
        rth->rt_iif     = 0;
        rth->rt_pmtu    = 0;
        rth->rt_gateway = 0;
+       rth->rt_uses_gateway = 0;
        INIT_LIST_HEAD(&rth->rt_uncached);
        if (our) {
                rth->dst.input= ip_local_deliver;
@@ -1432,7 +1433,6 @@ static int __mkroute_input(struct sk_buff *skb,
                return -EINVAL;
        }
 
-
        err = fib_validate_source(skb, saddr, daddr, tos, FIB_RES_OIF(*res),
                                  in_dev->dev, in_dev, &itag);
        if (err < 0) {
@@ -1488,6 +1488,7 @@ static int __mkroute_input(struct sk_buff *skb,
        rth->rt_iif     = 0;
        rth->rt_pmtu    = 0;
        rth->rt_gateway = 0;
+       rth->rt_uses_gateway = 0;
        INIT_LIST_HEAD(&rth->rt_uncached);
 
        rth->dst.input = ip_forward;
@@ -1658,6 +1659,7 @@ local_input:
        rth->rt_iif     = 0;
        rth->rt_pmtu    = 0;
        rth->rt_gateway = 0;
+       rth->rt_uses_gateway = 0;
        INIT_LIST_HEAD(&rth->rt_uncached);
        if (res.type == RTN_UNREACHABLE) {
                rth->dst.input= ip_error;
@@ -1826,6 +1828,7 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
        rth->rt_iif     = orig_oif ? : 0;
        rth->rt_pmtu    = 0;
        rth->rt_gateway = 0;
+       rth->rt_uses_gateway = 0;
        INIT_LIST_HEAD(&rth->rt_uncached);
 
        RT_CACHE_STAT_INC(out_slow_tot);
@@ -2104,6 +2107,7 @@ struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_or
                rt->rt_flags = ort->rt_flags;
                rt->rt_type = ort->rt_type;
                rt->rt_gateway = ort->rt_gateway;
+               rt->rt_uses_gateway = ort->rt_uses_gateway;
 
                INIT_LIST_HEAD(&rt->rt_uncached);
 
@@ -2182,7 +2186,7 @@ static int rt_fill_info(struct net *net,  __be32 dst, __be32 src,
                if (nla_put_be32(skb, RTA_PREFSRC, fl4->saddr))
                        goto nla_put_failure;
        }
-       if (rt->rt_gateway &&
+       if (rt->rt_uses_gateway &&
            nla_put_be32(skb, RTA_GATEWAY, rt->rt_gateway))
                goto nla_put_failure;
 
index 681ea2f413e2ff624c41b8301d0095cf46ac73d9..05c5ab8d983c462f75ab6143ca653669d36c1005 100644 (file)
@@ -91,6 +91,7 @@ static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
                                              RTCF_LOCAL);
        xdst->u.rt.rt_type = rt->rt_type;
        xdst->u.rt.rt_gateway = rt->rt_gateway;
+       xdst->u.rt.rt_uses_gateway = rt->rt_uses_gateway;
        xdst->u.rt.rt_pmtu = rt->rt_pmtu;
        INIT_LIST_HEAD(&xdst->u.rt.rt_uncached);