From: Eric Dumazet <eduma...@google.com> udp_dump_one() uses __udp4_lib_lookup() & __udp6_lib_lookup() which cannot properly handle the provided cookie when SO_REUSEPORT is used, as many sockets share the same 4-tuple
Instead, let's use the provided 64bit cookie to uniquely identify the socket. This will allow us to remove a check against skb being NULL in reuseport_select_sock(), as we no longer share __udp4_lib_lookup() & __udp6_lib_lookup() with packet processing path. We no longer need to export these two functions, and udp_diag IPv6 dependency can be removed. Signed-off-by: Eric Dumazet <eduma...@google.com> --- include/net/udp.h | 8 ------- net/ipv4/Kconfig | 2 - net/ipv4/udp.c | 8 +++---- net/ipv4/udp_diag.c | 44 ++++++++++++++++++------------------------ net/ipv6/udp.c | 3 -- 5 files changed, 25 insertions(+), 40 deletions(-) diff --git a/include/net/udp.h b/include/net/udp.h index 2842541e28e7..1e3bcadc2169 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -256,18 +256,10 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname, int (*push_pending_frames)(struct sock *)); struct sock *udp4_lib_lookup(struct net *net, __be32 saddr, __be16 sport, __be32 daddr, __be16 dport, int dif); -struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr, __be16 sport, - __be32 daddr, __be16 dport, int dif, - struct udp_table *tbl, struct sk_buff *skb); struct sock *udp6_lib_lookup(struct net *net, const struct in6_addr *saddr, __be16 sport, const struct in6_addr *daddr, __be16 dport, int dif); -struct sock *__udp6_lib_lookup(struct net *net, - const struct in6_addr *saddr, __be16 sport, - const struct in6_addr *daddr, __be16 dport, - int dif, struct udp_table *tbl, - struct sk_buff *skb); /* * SNMP statistics for UDP and UDP-Lite diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index c22920525e5d..ff9b81ff733a 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig @@ -430,7 +430,7 @@ config INET_TCP_DIAG config INET_UDP_DIAG tristate "UDP: socket monitoring interface" - depends on INET_DIAG && (IPV6 || IPV6=n) + depends on INET_DIAG default n ---help--- Support for UDP socket monitoring interface used by the ss tool. diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 835378365f25..6f58a9d86f41 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -551,9 +551,10 @@ found: /* UDP is nearly always wildcards out the wazoo, it makes no sense to try * harder than this. -DaveM */ -struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr, - __be16 sport, __be32 daddr, __be16 dport, - int dif, struct udp_table *udptable, struct sk_buff *skb) +static struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr, + __be16 sport, __be32 daddr, __be16 dport, + int dif, struct udp_table *udptable, + struct sk_buff *skb) { struct sock *sk, *result; struct hlist_nulls_node *node; @@ -638,7 +639,6 @@ found: rcu_read_unlock(); return result; } -EXPORT_SYMBOL_GPL(__udp4_lib_lookup); static inline struct sock *__udp4_lib_lookup_skb(struct sk_buff *skb, __be16 sport, __be16 dport, diff --git a/net/ipv4/udp_diag.c b/net/ipv4/udp_diag.c index df1966f3b6ec..09d0e1cffeb4 100644 --- a/net/ipv4/udp_diag.c +++ b/net/ipv4/udp_diag.c @@ -35,36 +35,30 @@ static int udp_dump_one(struct udp_table *tbl, struct sk_buff *in_skb, const struct nlmsghdr *nlh, const struct inet_diag_req_v2 *req) { - int err = -EINVAL; - struct sock *sk; + struct sock *aux, *sk = NULL; struct sk_buff *rep; struct net *net = sock_net(in_skb->sk); - - if (req->sdiag_family == AF_INET) - sk = __udp4_lib_lookup(net, - req->id.idiag_src[0], req->id.idiag_sport, - req->id.idiag_dst[0], req->id.idiag_dport, - req->id.idiag_if, tbl, NULL); -#if IS_ENABLED(CONFIG_IPV6) - else if (req->sdiag_family == AF_INET6) - sk = __udp6_lib_lookup(net, - (struct in6_addr *)req->id.idiag_src, - req->id.idiag_sport, - (struct in6_addr *)req->id.idiag_dst, - req->id.idiag_dport, - req->id.idiag_if, tbl, NULL); -#endif - else - goto out_nosk; - - err = -ENOENT; + unsigned short hnum = ntohs(req->id.idiag_dport); + unsigned int slot = udp_hashfn(net, hnum, tbl->mask); + struct udp_hslot *hslot = &tbl->hash[slot]; + struct hlist_nulls_node *node; + int err = -ENOENT; + + spin_lock_bh(&hslot->lock); + sk_nulls_for_each(aux, node, &hslot->head) { + if (net_eq(sock_net(aux), net) && + !sock_diag_check_cookie(aux, req->id.idiag_cookie) && + (req->sdiag_family == AF_UNSPEC || + req->sdiag_family == aux->sk_family)) { + sk = aux; + sock_hold(sk); + break; + } + } + spin_unlock_bh(&hslot->lock); if (!sk) goto out_nosk; - err = sock_diag_check_cookie(sk, req->id.idiag_cookie); - if (err) - goto out; - err = -ENOMEM; rep = nlmsg_new(sizeof(struct inet_diag_msg) + sizeof(struct inet_diag_meminfo) + 64, diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 56fcb55fda31..83bfd64cf37b 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -307,7 +307,7 @@ found: return result; } -struct sock *__udp6_lib_lookup(struct net *net, +static struct sock *__udp6_lib_lookup(struct net *net, const struct in6_addr *saddr, __be16 sport, const struct in6_addr *daddr, __be16 dport, int dif, struct udp_table *udptable, @@ -395,7 +395,6 @@ found: rcu_read_unlock(); return result; } -EXPORT_SYMBOL_GPL(__udp6_lib_lookup); static struct sock *__udp6_lib_lookup_skb(struct sk_buff *skb, __be16 sport, __be16 dport, -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html