udp6: set rx_dst_cookie on rx_dst updates
authorPaolo Abeni <pabeni@redhat.com>
Fri, 25 Aug 2017 12:31:01 +0000 (14:31 +0200)
committerDavid S. Miller <davem@davemloft.net>
Sat, 26 Aug 2017 03:09:13 +0000 (20:09 -0700)
Currently, in the udp6 code, the dst cookie is not initialized/updated
concurrently with the RX dst used by early demux.

As a result, the dst_check() in the early_demux path always fails,
the rx dst cache is always invalidated, and we can't really
leverage significant gain from the demux lookup.

Fix it adding udp6 specific variant of sk_rx_dst_set() and use it
to set the dst cookie when the dst entry is really changed.

The issue is there since the introduction of early demux for ipv6.

Fixes: 5425077d73e0 ("net: ipv6: Add early demux handler for UDP unicast")
Acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/udp.h
net/ipv4/udp.c
net/ipv6/udp.c

index 586de4b811b5678c72a045a3ede9852164b9b3e2..626c2d8a70c59f51fb5b2558433d222b56610246 100644 (file)
@@ -260,7 +260,7 @@ static inline struct sk_buff *skb_recv_udp(struct sock *sk, unsigned int flags,
 }
 
 void udp_v4_early_demux(struct sk_buff *skb);
-void udp_sk_rx_dst_set(struct sock *sk, struct dst_entry *dst);
+bool udp_sk_rx_dst_set(struct sock *sk, struct dst_entry *dst);
 int udp_get_port(struct sock *sk, unsigned short snum,
                 int (*saddr_cmp)(const struct sock *,
                                  const struct sock *));
index cd1d044a7fa580f315af0fd81eb1bf425fd1f38c..a6dc48d76a2976e307763198abdc55ee196e995b 100644 (file)
@@ -1929,14 +1929,16 @@ drop:
 /* For TCP sockets, sk_rx_dst is protected by socket lock
  * For UDP, we use xchg() to guard against concurrent changes.
  */
-void udp_sk_rx_dst_set(struct sock *sk, struct dst_entry *dst)
+bool udp_sk_rx_dst_set(struct sock *sk, struct dst_entry *dst)
 {
        struct dst_entry *old;
 
        if (dst_hold_safe(dst)) {
                old = xchg(&sk->sk_rx_dst, dst);
                dst_release(old);
+               return old != dst;
        }
+       return false;
 }
 EXPORT_SYMBOL(udp_sk_rx_dst_set);
 
index 20039c8501eb9729619f4337a2757a2954163614..d6886228e1d05c4dd192f5fe431fdaca1ffadabd 100644 (file)
@@ -768,6 +768,15 @@ start_lookup:
        return 0;
 }
 
+static void udp6_sk_rx_dst_set(struct sock *sk, struct dst_entry *dst)
+{
+       if (udp_sk_rx_dst_set(sk, dst)) {
+               const struct rt6_info *rt = (const struct rt6_info *)dst;
+
+               inet6_sk(sk)->rx_dst_cookie = rt6_get_cookie(rt);
+       }
+}
+
 int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
                   int proto)
 {
@@ -817,7 +826,7 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
                int ret;
 
                if (unlikely(sk->sk_rx_dst != dst))
-                       udp_sk_rx_dst_set(sk, dst);
+                       udp6_sk_rx_dst_set(sk, dst);
 
                ret = udpv6_queue_rcv_skb(sk, skb);
                sock_put(sk);