net: use dst_confirm_neigh for UDP, RAW, ICMP, L2TP
authorJulian Anastasov <ja@ssi.bg>
Mon, 6 Feb 2017 21:14:16 +0000 (23:14 +0200)
committerDavid S. Miller <davem@davemloft.net>
Tue, 7 Feb 2017 18:07:47 +0000 (13:07 -0500)
When same struct dst_entry can be used for many different
neighbours we can not use it for pending confirmations.

The datagram protocols can use MSG_CONFIRM to confirm the
neighbour. When used with MSG_PROBE we do not reach the
code where neighbour is confirmed, so we have to do the
same slow lookup by using the dst_confirm_neigh() helper.
When MSG_PROBE is not used, ip_append_data/ip6_append_data
will set the skb flag dst_pending_confirm.

Reported-by: YueHaibing <yuehaibing@huawei.com>
Fixes: 5110effee8fd ("net: Do delayed neigh confirmation.")
Fixes: f2bb4bedf35d ("ipv4: Cache output routes in fib_info nexthops.")
Signed-off-by: Julian Anastasov <ja@ssi.bg>
Acked-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ipv4/ip_output.c
net/ipv4/ping.c
net/ipv4/raw.c
net/ipv4/udp.c
net/ipv6/ip6_output.c
net/ipv6/raw.c
net/ipv6/route.c
net/ipv6/udp.c
net/l2tp/l2tp_ip6.c

index c9fc32fa3272760ecce17841519753f892a1f66e..7a719f1ae55685346573c5ffe33cd1a8764f6422 100644 (file)
@@ -889,6 +889,9 @@ static inline int ip_ufo_append_data(struct sock *sk,
 
                skb->csum = 0;
 
+               if (flags & MSG_CONFIRM)
+                       skb_set_dst_pending_confirm(skb, 1);
+
                __skb_queue_tail(queue, skb);
        } else if (skb_is_gso(skb)) {
                goto append;
@@ -1089,6 +1092,9 @@ alloc_new_skb:
                        exthdrlen = 0;
                        csummode = CHECKSUM_NONE;
 
+                       if ((flags & MSG_CONFIRM) && !skb_prev)
+                               skb_set_dst_pending_confirm(skb, 1);
+
                        /*
                         * Put the packet on the pending queue.
                         */
index 592db6a3a0e92e86dac22ebc29f4e0209c074d38..6ee792d83d5befcac511470033ced09475a8f661 100644 (file)
@@ -848,7 +848,8 @@ out:
        return err;
 
 do_confirm:
-       dst_confirm(&rt->dst);
+       if (msg->msg_flags & MSG_PROBE)
+               dst_confirm_neigh(&rt->dst, &fl4.daddr);
        if (!(msg->msg_flags & MSG_PROBE) || len)
                goto back_from_confirm;
        err = 0;
index 4e49e5cb001ccd6824104af273bcbc40fc864ef7..8119e1f66e036ad2a8372bf24dd943c7d9631d8e 100644 (file)
@@ -383,6 +383,9 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4,
 
        sock_tx_timestamp(sk, sockc->tsflags, &skb_shinfo(skb)->tx_flags);
 
+       if (flags & MSG_CONFIRM)
+               skb_set_dst_pending_confirm(skb, 1);
+
        skb->transport_header = skb->network_header;
        err = -EFAULT;
        if (memcpy_from_msg(iph, msg, length))
@@ -666,7 +669,8 @@ out:
        return len;
 
 do_confirm:
-       dst_confirm(&rt->dst);
+       if (msg->msg_flags & MSG_PROBE)
+               dst_confirm_neigh(&rt->dst, &fl4.daddr);
        if (!(msg->msg_flags & MSG_PROBE) || len)
                goto back_from_confirm;
        err = 0;
index cf6ba33874013f009fa57ba7f9cbc7b678969cbd..4a1ba04565d11539d2be1fd6de968e826eb5cbce 100644 (file)
@@ -1101,7 +1101,8 @@ out:
        return err;
 
 do_confirm:
-       dst_confirm(&rt->dst);
+       if (msg->msg_flags & MSG_PROBE)
+               dst_confirm_neigh(&rt->dst, &fl4->daddr);
        if (!(msg->msg_flags&MSG_PROBE) || len)
                goto back_from_confirm;
        err = 0;
index 14d99fbf102e12b0952b97183689a65d219f4b3d..d299040613a036895081e4aab2bc7b42f67e823d 100644 (file)
@@ -1145,6 +1145,9 @@ static inline int ip6_ufo_append_data(struct sock *sk,
                skb->protocol = htons(ETH_P_IPV6);
                skb->csum = 0;
 
+               if (flags & MSG_CONFIRM)
+                       skb_set_dst_pending_confirm(skb, 1);
+
                __skb_queue_tail(queue, skb);
        } else if (skb_is_gso(skb)) {
                goto append;
@@ -1517,6 +1520,9 @@ alloc_new_skb:
                        exthdrlen = 0;
                        dst_exthdrlen = 0;
 
+                       if ((flags & MSG_CONFIRM) && !skb_prev)
+                               skb_set_dst_pending_confirm(skb, 1);
+
                        /*
                         * Put the packet on the pending queue
                         */
index ea89073c824747f185beb7da0f4aab6b74832149..f174e76e6505d4045e940c9fceef765d2aaa937d 100644 (file)
@@ -654,6 +654,9 @@ static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length,
 
        skb->ip_summed = CHECKSUM_NONE;
 
+       if (flags & MSG_CONFIRM)
+               skb_set_dst_pending_confirm(skb, 1);
+
        skb->transport_header = skb->network_header;
        err = memcpy_from_msg(iph, msg, length);
        if (err)
@@ -934,7 +937,8 @@ out:
        txopt_put(opt_to_free);
        return err < 0 ? err : len;
 do_confirm:
-       dst_confirm(dst);
+       if (msg->msg_flags & MSG_PROBE)
+               dst_confirm_neigh(dst, &fl6.daddr);
        if (!(msg->msg_flags & MSG_PROBE) || len)
                goto back_from_confirm;
        err = 0;
index 98b183f1bc8bf01fcdc9b9045249c3bc2747e739..f54f4265b37f291ea10c8f67a45a243d2095074c 100644 (file)
@@ -1381,6 +1381,7 @@ static bool rt6_cache_allowed_for_pmtu(const struct rt6_info *rt)
 static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
                                 const struct ipv6hdr *iph, u32 mtu)
 {
+       const struct in6_addr *daddr, *saddr;
        struct rt6_info *rt6 = (struct rt6_info *)dst;
 
        if (rt6->rt6i_flags & RTF_LOCAL)
@@ -1389,26 +1390,26 @@ static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
        if (dst_metric_locked(dst, RTAX_MTU))
                return;
 
-       dst_confirm(dst);
+       if (iph) {
+               daddr = &iph->daddr;
+               saddr = &iph->saddr;
+       } else if (sk) {
+               daddr = &sk->sk_v6_daddr;
+               saddr = &inet6_sk(sk)->saddr;
+       } else {
+               daddr = NULL;
+               saddr = NULL;
+       }
+       dst_confirm_neigh(dst, daddr);
        mtu = max_t(u32, mtu, IPV6_MIN_MTU);
        if (mtu >= dst_mtu(dst))
                return;
 
        if (!rt6_cache_allowed_for_pmtu(rt6)) {
                rt6_do_update_pmtu(rt6, mtu);
-       } else {
-               const struct in6_addr *daddr, *saddr;
+       } else if (daddr) {
                struct rt6_info *nrt6;
 
-               if (iph) {
-                       daddr = &iph->daddr;
-                       saddr = &iph->saddr;
-               } else if (sk) {
-                       daddr = &sk->sk_v6_daddr;
-                       saddr = &inet6_sk(sk)->saddr;
-               } else {
-                       return;
-               }
                nrt6 = ip6_rt_cache_alloc(rt6, daddr, saddr);
                if (nrt6) {
                        rt6_do_update_pmtu(nrt6, mtu);
@@ -2332,7 +2333,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
         * Look, redirects are sent only in response to data packets,
         * so that this nexthop apparently is reachable. --ANK
         */
-       dst_confirm(&rt->dst);
+       dst_confirm_neigh(&rt->dst, &ipv6_hdr(skb)->saddr);
 
        neigh = __neigh_lookup(&nd_tbl, &msg->target, skb->dev, 1);
        if (!neigh)
index b4c6516a3a0c159e7fa5d061202a66d9ccf2f671..51346fa70298a0864e3997a6c94845a5707fa305 100644 (file)
@@ -1308,7 +1308,8 @@ out:
        return err;
 
 do_confirm:
-       dst_confirm(dst);
+       if (msg->msg_flags & MSG_PROBE)
+               dst_confirm_neigh(dst, &fl6.daddr);
        if (!(msg->msg_flags&MSG_PROBE) || len)
                goto back_from_confirm;
        err = 0;
index 4b06eb415f6837321b4afdb23ac3dbd3877ebee2..734798a00ca03bb0b06363aa39964fbb252f7093 100644 (file)
@@ -658,7 +658,8 @@ out:
        return err < 0 ? err : len;
 
 do_confirm:
-       dst_confirm(dst);
+       if (msg->msg_flags & MSG_PROBE)
+               dst_confirm_neigh(dst, &fl6.daddr);
        if (!(msg->msg_flags & MSG_PROBE) || len)
                goto back_from_confirm;
        err = 0;