From nobody Fri Sep 25 03:20:48 2026 Received: from sender6-of-o54.zoho.com (sender6-of-o54.zoho.com [165.173.180.54]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 95AD73914FA; Thu, 17 Sep 2026 09:26:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=165.173.180.54 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789637206; cv=pass; b=G7VIS6lNRLRkvVate8GsDp0dLu1MAsiIESt6hHxacKtvpEsCzSbdypTRhbUSEGpmDYoL+hs6FP/yucWuQg2fek1nS3kw88mkgOLf4bGgiT+lQG9n0orUzzhR5nC347n/BTtzyw1BXEXj96UBy8glHnTidV7HiJfF6ahZ6R+0sYA= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789637206; c=relaxed/simple; bh=Nq0pPKVX0rq4ZaB7Npr7GBIZ8LKGFla9qXq/w5+Ut0A=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=J4WnYofuwEu6hzkdXXBeYdRczcrA2otnEonlfjCIXzDXT4l3k4/MXbQCmIHwCYPwBhEIPEypi1TRWg1pN5Zn2Yle/D0pXgnh5FWiUBkFGjhL3sQGNvGCF0EWvgygjLuQBk2LHIA+lIQimay2FZpXmFPOOqMNFLMU3mfgYjlix98= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mpiricsoftware.com; spf=pass smtp.mailfrom=mpiricsoftware.com; dkim=fail (0-bit key) header.d=mpiricsoftware.com header.i=shardul.b@mpiricsoftware.com header.b=IpOsqbUk reason="key not found in DNS"; arc=pass smtp.client-ip=165.173.180.54 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mpiricsoftware.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mpiricsoftware.com Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="key not found in DNS" (0-bit key) header.d=mpiricsoftware.com header.i=shardul.b@mpiricsoftware.com header.b="IpOsqbUk" ARC-Seal: i=1; a=rsa-sha256; t=1789637157; cv=none; d=zohomail.com; s=zohoarc; b=NFpRg4Bhwbpxefzd4PdnHe7rESwq+LKnFtAkQYEu2d7PLd6Y5ZP9tS+y0PolzBEaR/nekTaj69AQHekBwSXcjHj7McHBj0KG96LtotH7Pb3QHv2uOTqZAYNC2I7nT0Eg0LUg9ij5YyfAGnnyeK+gozMpLCidfpTOpR+9SyqW8oo= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1789637157; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To; bh=l/ze8mgPcus8w05kTS+A3L1pCu9LxOEtnHesogqfgaM=; b=AHt6JC6SbBZ7+5fAWOQTXQJWdRunjThCmpXngge9ljqhS2h41jUAi0LVrZMf4AWP93oPG3aZA0RdyBXJVsvlZl3dF/FRNhroVtFmB9TqopU/xPyAQizPQDVQeS5cQVaHFKIOrfqRmpY3xaZdJRecSGUSa7nN8JxTC9VgCDbrFfc= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=mpiricsoftware.com; spf=pass smtp.mailfrom=shardul.b@mpiricsoftware.com; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1789637157; s=mpiric; d=mpiricsoftware.com; i=shardul.b@mpiricsoftware.com; h=From:From:Date:Date:Subject:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Message-Id:Message-Id:In-Reply-To:To:To:Cc:Cc:Reply-To; bh=l/ze8mgPcus8w05kTS+A3L1pCu9LxOEtnHesogqfgaM=; b=IpOsqbUky6rpp1bEbQQL9pJv3uvfVnO2E95XGOwXmNeA74KitsKasV/WJ7Xy+y5P H75GjxYieACsskbsz1V63znKqmZYD/Us+h2J3+yhCU/XA7gDlnrytSkZHR2HD/AtQ0P rZbQ/u6JuKdGJDo2Kt8aBtnTkgoP1tS8aYczhIms= Received: by smtp.zohomail.com with SMTPS id 1789637157030744.6273114838676; Thu, 17 Sep 2026 02:25:57 -0700 (PDT) From: Shardul Bankar Date: Thu, 17 Sep 2026 14:55:32 +0530 Subject: [PATCH net 1/2] udp: relocate a connected socket in the 4-tuple hash table on re-connect Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260917-udp_hash4_fix_v1-v1-1-718891af0d7a@mpiricsoftware.com> References: <20260917-udp_hash4_fix_v1-v1-0-718891af0d7a@mpiricsoftware.com> In-Reply-To: <20260917-udp_hash4_fix_v1-v1-0-718891af0d7a@mpiricsoftware.com> To: Willem de Bruijn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Philo Lu , Fred Chen , Yubing Qiu Cc: Kuniyuki Iwashima , Willem de Bruijn , Cambda Zhu , Janak Bhatt , Kalpan Jani , Shardul Bankar , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Shardul Bankar X-Mailer: b4 0.15.2 X-ZohoMailClient: External A connected UDP socket that connects again to a different peer is not re-filed in the 4-tuple hash table: sk binds to 127.0.0.1:21001 sk connects to 127.0.0.2:20001 // filed under hash(sk, peer1) sk connects to 127.0.0.3:20002 // still filed under hash(sk, peer1) packet from 127.0.0.3:20002 // hash(sk, peer2) misses, so the // lookup falls back to scoring the // hash2 chain for this address // and port udp_lib_hash4() returns early when the socket is already hashed, assuming ->rehash() relocates it. ->rehash() runs from __ip{4,6}_datagram_connect() only while the receive address is unset, which a second connect never is: the first connect assigns it, whether the socket was bound to a specific address or to the wildcard. commit 644f9108f3a5 ("udp: Make rehash4 independent in udp_lib_rehash()") added that early return and named connect(AF_UNSPEC) as the way around it. That workaround does not help a socket with both SOCK_BINDADDR_LOCK and SOCK_BINDPORT_LOCK set, because __udp_disconnect() skips ->rehash() for the first and ->unhash() for the second. Delivery is correct either way. Relocate the socket when the hash it is filed under differs from the one requested, which is what commit 78c91ae2c6de ("ipv4/udp: Add 4-tuple hash for connected socket") did before the early return became unconditional. It is done here under hslot->lock, which that version did not take, to match udp_lib_rehash() and udp_lib_unhash(). hslot2 is unchanged, so hash4_cnt needs no adjustment, as in udp_lib_rehash(). A first connect is unaffected, and IPv6 shares the code. With 500 sockets on the port, a re-connected socket measured 522,553 pps without this change and 2,055,078 with it. The UDP side was noted as remaining work in [1]. Link: https://lore.kernel.org/netdev/apnHqmYZQ4yzOP4N@v4bel/ [1] Fixes: 644f9108f3a5 ("udp: Make rehash4 independent in udp_lib_rehash()") Assisted-by: LLM Signed-off-by: Shardul Bankar Reviewed-by: Kuniyuki Iwashima --- net/ipv4/udp.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index bb8cfc62cb00..0fa3cdbdcc21 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -617,14 +617,23 @@ void udp_lib_hash4(struct sock *sk, u16 hash) struct net *net =3D sock_net(sk); struct udp_table *udptable; =20 - /* Connected udp socket can re-connect to another remote address, which - * will be handled by rehash. Thus no need to redo hash4 here. + udptable =3D net->ipv4.udp_table; + hslot =3D udp_hashslot(udptable, net, udp_sk(sk)->udp_port_hash); + + /* A connected socket can re-connect to another address. rehash() + * relocates it, but only runs when the local address changes, so a + * socket bound to a specific address would stay filed under the + * previous peer's hash. Move it here. */ - if (udp_hashed4(sk)) + if (udp_hashed4(sk)) { + if (udp_sk(sk)->udp_lrpa_hash !=3D hash) { + spin_lock_bh(&hslot->lock); + udp_rehash4(udptable, sk, hash); + spin_unlock_bh(&hslot->lock); + } return; + } =20 - udptable =3D net->ipv4.udp_table; - hslot =3D udp_hashslot(udptable, net, udp_sk(sk)->udp_port_hash); hslot2 =3D udp_hashslot2(udptable, udp_sk(sk)->udp_portaddr_hash); hslot4 =3D udp_hashslot4(udptable, hash); udp_sk(sk)->udp_lrpa_hash =3D hash; --=20 2.34.1 From nobody Fri Sep 25 03:20:48 2026 Received: from sender4-of-o54.zoho.com (sender4-of-o54.zoho.com [136.143.188.54]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 425F13F23CF; Thu, 17 Sep 2026 09:27:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.54 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789637232; cv=pass; b=Chd+hwfq39lm8H5W+mJliTrUcPoF87x419uHPwKUPRrxXvxUKslhS31bh8IpXmfPxAEtNYZvMtBMBbuLa0caXjkJYKnooiRyVdkZRt+ZXnJCXkNKaYX8cYyvv2SWzpncEihzhJ2dEhrY0yTH1hxQWK+982GQNp2zbPE8VhxVE0w= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789637232; c=relaxed/simple; bh=RMfpUzrNeHDlJNPLLvqSzyhwDsTSTz5ZhusnKzref8E=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Q7H3mTyQF6M7kW7kGJdG0tnjvO6IKVmPZpTNIKky4FEhQ/sS5T/IS5F6OzPGoYzKkbm0gQhKfVue3VbRJ+twB4W/p3zskGrt5BwmwkijuL3hsvSiZ7rf773PAfERy6riGO8Rt9k5MtJlHUg3sRXA3DsPbuQ6AMUTRgveVJy22Vg= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mpiricsoftware.com; spf=pass smtp.mailfrom=mpiricsoftware.com; dkim=fail (0-bit key) header.d=mpiricsoftware.com header.i=shardul.b@mpiricsoftware.com header.b=BmlSBb86 reason="key not found in DNS"; arc=pass smtp.client-ip=136.143.188.54 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mpiricsoftware.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mpiricsoftware.com Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="key not found in DNS" (0-bit key) header.d=mpiricsoftware.com header.i=shardul.b@mpiricsoftware.com header.b="BmlSBb86" ARC-Seal: i=1; a=rsa-sha256; t=1789637165; cv=none; d=zohomail.com; s=zohoarc; b=XzYLyu2KeCOebmukHSAh8pzMdvXD2Y0ib2lYGb1PCv8DKDlso28ADN+jjHtpUT6x7pnX/Iz1NOxibahDUcSbt7CbwD4A1ZXKy4h5DYeHJ8sU/Y9iobBYa8qIAqD/TJdAEFDgYURbbIPqbvYgtFDLAX3bgNNkvLlncbL81oaStO8= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1789637165; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To; bh=oGZD2THSIvgZ4FyKe8rXPnccrDB8Ijp2S5sc4lTYoLY=; b=HkqSd+M2vUMkzGI0nYzDCd/xA3yyr33iwJfXp5p8mnh+ExmWs5i88bb4EYKOeqzQkWLNr5Ekujh4C78EbWhVUpi8WkUeqicmIB2+gj6Ul0WTQ6danywOh+XYIgqEWvnCoKL3pE4WEE1fBoBDV54m2y0KCNz01hfABYNu9CsuuWs= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=mpiricsoftware.com; spf=pass smtp.mailfrom=shardul.b@mpiricsoftware.com; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1789637165; s=mpiric; d=mpiricsoftware.com; i=shardul.b@mpiricsoftware.com; h=From:From:Date:Date:Subject:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Message-Id:Message-Id:In-Reply-To:To:To:Cc:Cc:Reply-To; bh=oGZD2THSIvgZ4FyKe8rXPnccrDB8Ijp2S5sc4lTYoLY=; b=BmlSBb86tHDcEeWMpjU0UIY9xcAK+HmsekKlBg/I8OngkkbRAW919bgY+v7N6vay 20YCD1taMIAOGckw8o84YVlnq7Km7iJf843xEc+Pn9TYUHWXXY/ekJtS+km2baAUPtD +ntRY//qfDgzqUQa3unoVJ/rHFYX7++U3rMrxwRA= Received: by smtp.zohomail.com with SMTPS id 1789637163419124.35629496100057; Thu, 17 Sep 2026 02:26:03 -0700 (PDT) From: Shardul Bankar Date: Thu, 17 Sep 2026 14:55:33 +0530 Subject: [PATCH net 2/2] udp: remove a disconnected socket from the 4-tuple hash table Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260917-udp_hash4_fix_v1-v1-2-718891af0d7a@mpiricsoftware.com> References: <20260917-udp_hash4_fix_v1-v1-0-718891af0d7a@mpiricsoftware.com> In-Reply-To: <20260917-udp_hash4_fix_v1-v1-0-718891af0d7a@mpiricsoftware.com> To: Willem de Bruijn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Philo Lu , Fred Chen , Yubing Qiu Cc: Kuniyuki Iwashima , Willem de Bruijn , Cambda Zhu , Janak Bhatt , Kalpan Jani , Shardul Bankar , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Shardul Bankar X-Mailer: b4 0.15.2 X-ZohoMailClient: External A UDP socket bound to a specific address and port keeps its entry in the 4-tuple hash table after it is disconnected: sk binds to 127.0.0.1:21001 sk connects to 127.0.0.2:20001 // filed in the 4-tuple table sk disconnects, connect(AF_UNSPEC) // still filed, peer now 0.0.0.0:0 __udp_disconnect() takes a socket out of that table only as a side effect of ->rehash() or ->unhash(), and it skips ->rehash() when SOCK_BINDADDR_LOCK is set and ->unhash() when SOCK_BINDPORT_LOCK is set. commit 6996a2d2d0a6 ("udp: Unhash auto-bound connected sk from 4-tuple hash table when disconnected.") fixed the same end state for a wildcard-bound socket, by a path this one does not take. The entry is counted whether or not anything hits it. hash4_cnt on the hash2 slot stays raised for as long as the socket lives, so udp_has_hash4() keeps sending every packet for that address and port through the 4-tuple lookup first. On IPv6 it can also be hit. __udp_disconnect() does not clear sk_v6_daddr, so udp_v6_rehash() files the entry under the peer the socket was connected to with a zero dport, and inet6_match() compares that same field: a datagram from the former peer with a zero source port matches, and source port zero is accepted on receive. On IPv4 the peer is cleared, so a match would need a zero source address as well, which the routing layer rejects as martian. The stale sk_v6_daddr is a separate defect, not addressed here; removing the entry closes this path either way. The entry can also be relocated. __udp_disconnect() clears sk_bound_dev_if, so a subsequent SO_BINDTODEVICE calls ->rehash(), and because the receive address is still specific udp_lib_rehash() moves the entry instead of removing it, into the bucket that (rcv_saddr, num, 0, 0) hashes to -- a pure function of the address and port, so every socket reaching this state on one address and port collects in one bucket. The bucket cannot be chosen from outside, as udp_ehashfn() is seeded with a per-boot secret. This last one became reachable only with commit 644f9108f3a5 ("udp: Make rehash4 independent in udp_lib_rehash()"), which moved the hash4 handling out of a branch a disconnected socket does not take; the stale entry itself dates from the commit in Fixes. Take the socket out of the table before __udp_disconnect() runs, while it still matches how it was filed. This also reaches the wildcard case ahead of udp_lib_rehash()'s udp_unhash4() branch, leaving that branch unreachable from udp_disconnect(); removing it belongs in net-next. udp_disconnect() and udp_abort() are the only UDP entries into __udp_disconnect(), which is shared with raw, ping and l2tp sockets that are not struct udp_sock: ping_prot.obj_size is sizeof(struct inet_sock), so udp_hashed4() on one would read past the allocation. Fixes: 78c91ae2c6de ("ipv4/udp: Add 4-tuple hash for connected socket") Assisted-by: LLM Signed-off-by: Shardul Bankar Reviewed-by: Kuniyuki Iwashima --- net/ipv4/udp.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 0fa3cdbdcc21..b090bd1f59e8 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -2206,9 +2206,31 @@ int __udp_disconnect(struct sock *sk, int flags) } EXPORT_SYMBOL(__udp_disconnect); =20 +/* __udp_disconnect() takes a socket out of the 4-tuple hash table only via + * ->rehash() or ->unhash(), and neither runs for a socket bound to a + * specific address and port. Remove it here, before its peer is cleared. + */ +static void udp_unhash4_on_disconnect(struct sock *sk) +{ + struct net *net =3D sock_net(sk); + struct udp_table *udptable; + struct udp_hslot *hslot; + + if (!udp_hashed4(sk)) + return; + + udptable =3D net->ipv4.udp_table; + hslot =3D udp_hashslot(udptable, net, udp_sk(sk)->udp_port_hash); + + spin_lock_bh(&hslot->lock); + udp_unhash4(udptable, sk); + spin_unlock_bh(&hslot->lock); +} + int udp_disconnect(struct sock *sk, int flags) { lock_sock(sk); + udp_unhash4_on_disconnect(sk); __udp_disconnect(sk, flags); release_sock(sk); return 0; @@ -3140,6 +3162,7 @@ int udp_abort(struct sock *sk, int err) =20 sk->sk_err =3D err; sk_error_report(sk); + udp_unhash4_on_disconnect(sk); __udp_disconnect(sk, 0); =20 out: --=20 2.34.1