]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - net/ipv4/route.c
SUNRPC: Fix races between socket connection and destroy code
[mirror_ubuntu-bionic-kernel.git] / net / ipv4 / route.c
index e681b852ced1d0c0cde984496d832d9cf3f7fad2..5f4a5565ad8b32ef7d10619364a86713d52f38e0 100644 (file)
@@ -91,6 +91,7 @@
 #include <linux/slab.h>
 #include <linux/jhash.h>
 #include <net/dst.h>
+#include <net/dst_metadata.h>
 #include <net/net_namespace.h>
 #include <net/protocol.h>
 #include <net/ip.h>
 #include <net/tcp.h>
 #include <net/icmp.h>
 #include <net/xfrm.h>
+#include <net/lwtunnel.h>
 #include <net/netevent.h>
 #include <net/rtnetlink.h>
 #ifdef CONFIG_SYSCTL
 #include <linux/kmemleak.h>
 #endif
 #include <net/secure_seq.h>
+#include <net/ip_tunnels.h>
+#include <net/vrf.h>
 
 #define RT_FL_TOS(oldflp4) \
        ((oldflp4)->flowi4_tos & (IPTOS_RT_MASK | RTO_ONLINK))
@@ -834,6 +838,7 @@ void ip_rt_send_redirect(struct sk_buff *skb)
        struct inet_peer *peer;
        struct net *net;
        int log_martians;
+       int vif;
 
        rcu_read_lock();
        in_dev = __in_dev_get_rcu(rt->dst.dev);
@@ -842,10 +847,11 @@ void ip_rt_send_redirect(struct sk_buff *skb)
                return;
        }
        log_martians = IN_DEV_LOG_MARTIANS(in_dev);
+       vif = vrf_master_ifindex_rcu(rt->dst.dev);
        rcu_read_unlock();
 
        net = dev_net(rt->dst.dev);
-       peer = inet_getpeer_v4(net->ipv4.peers, ip_hdr(skb)->saddr, 1);
+       peer = inet_getpeer_v4(net->ipv4.peers, ip_hdr(skb)->saddr, vif, 1);
        if (!peer) {
                icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST,
                          rt_nexthop(rt, ip_hdr(skb)->daddr));
@@ -934,7 +940,8 @@ static int ip_error(struct sk_buff *skb)
                break;
        }
 
-       peer = inet_getpeer_v4(net->ipv4.peers, ip_hdr(skb)->saddr, 1);
+       peer = inet_getpeer_v4(net->ipv4.peers, ip_hdr(skb)->saddr,
+                              vrf_master_ifindex(skb->dev), 1);
 
        send = true;
        if (peer) {
@@ -1403,6 +1410,7 @@ static void rt_set_nexthop(struct rtable *rt, __be32 daddr,
 #ifdef CONFIG_IP_ROUTE_CLASSID
                rt->dst.tclassid = nh->nh_tclassid;
 #endif
+               rt->dst.lwtstate = lwtstate_get(nh->nh_lwtstate);
                if (unlikely(fnhe))
                        cached = rt_bind_exception(rt, fnhe, daddr);
                else if (!(rt->dst.flags & DST_NOCACHE))
@@ -1546,7 +1554,6 @@ static int __mkroute_input(struct sk_buff *skb,
        struct rtable *rth;
        int err;
        struct in_device *out_dev;
-       unsigned int flags = 0;
        bool do_cache;
        u32 itag = 0;
 
@@ -1610,7 +1617,7 @@ static int __mkroute_input(struct sk_buff *skb,
        }
 
        rth->rt_genid = rt_genid_ipv4(dev_net(rth->dst.dev));
-       rth->rt_flags = flags;
+       rth->rt_flags = 0;
        rth->rt_type = res->type;
        rth->rt_is_input = 1;
        rth->rt_iif     = 0;
@@ -1624,6 +1631,14 @@ static int __mkroute_input(struct sk_buff *skb,
        rth->dst.output = ip_output;
 
        rt_set_nexthop(rth, daddr, res, fnhe, res->fi, res->type, itag);
+       if (lwtunnel_output_redirect(rth->dst.lwtstate)) {
+               rth->dst.lwtstate->orig_output = rth->dst.output;
+               rth->dst.output = lwtunnel_output;
+       }
+       if (lwtunnel_input_redirect(rth->dst.lwtstate)) {
+               rth->dst.lwtstate->orig_input = rth->dst.input;
+               rth->dst.input = lwtunnel_input;
+       }
        skb_dst_set(skb, &rth->dst);
 out:
        err = 0;
@@ -1662,6 +1677,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
 {
        struct fib_result res;
        struct in_device *in_dev = __in_dev_get_rcu(dev);
+       struct ip_tunnel_info *tun_info;
        struct flowi4   fl4;
        unsigned int    flags = 0;
        u32             itag = 0;
@@ -1679,6 +1695,13 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
           by fib_lookup.
         */
 
+       tun_info = skb_tunnel_info(skb);
+       if (tun_info && !(tun_info->mode & IP_TUNNEL_INFO_TX))
+               fl4.flowi4_tun_key.tun_id = tun_info->key.tun_id;
+       else
+               fl4.flowi4_tun_key.tun_id = 0;
+       skb_dst_drop(skb);
+
        if (ipv4_is_multicast(saddr) || ipv4_is_lbcast(saddr))
                goto martian_source;
 
@@ -1710,7 +1733,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
         *      Now we are ready to route packet.
         */
        fl4.flowi4_oif = 0;
-       fl4.flowi4_iif = dev->ifindex;
+       fl4.flowi4_iif = vrf_master_ifindex_rcu(dev) ? : dev->ifindex;
        fl4.flowi4_mark = skb->mark;
        fl4.flowi4_tos = tos;
        fl4.flowi4_scope = RT_SCOPE_UNIVERSE;
@@ -1792,6 +1815,7 @@ local_input:
        rth->rt_gateway = 0;
        rth->rt_uses_gateway = 0;
        INIT_LIST_HEAD(&rth->rt_uncached);
+
        RT_CACHE_STAT_INC(in_slow_tot);
        if (res.type == RTN_UNREACHABLE) {
                rth->dst.input= ip_error;
@@ -1981,7 +2005,6 @@ add:
        rth->rt_gateway = 0;
        rth->rt_uses_gateway = 0;
        INIT_LIST_HEAD(&rth->rt_uncached);
-
        RT_CACHE_STAT_INC(out_slow_tot);
 
        if (flags & RTCF_LOCAL)
@@ -2004,6 +2027,8 @@ add:
        }
 
        rt_set_nexthop(rth, fl4->daddr, res, fnhe, fi, type, 0);
+       if (lwtunnel_output_redirect(rth->dst.lwtstate))
+               rth->dst.output = lwtunnel_output;
 
        return rth;
 }
@@ -2110,6 +2135,11 @@ struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *fl4)
                                fl4->saddr = inet_select_addr(dev_out, 0,
                                                              RT_SCOPE_HOST);
                }
+               if (netif_is_vrf(dev_out) &&
+                   !(fl4->flowi4_flags & FLOWI_FLAG_VRFSRC)) {
+                       rth = vrf_dev_get_rth(dev_out);
+                       goto out;
+               }
        }
 
        if (!fl4->daddr) {
@@ -2261,7 +2291,6 @@ struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_or
                rt->rt_uses_gateway = ort->rt_uses_gateway;
 
                INIT_LIST_HEAD(&rt->rt_uncached);
-
                dst_free(new);
        }