[PATCH net-next v1] tcp/dccp: avoid parity split for socket-local bind range
From: <hidden>
Date: 2026-06-26 09:40:27
Subsystem:
networking [general], networking [tcp], the rest · Maintainers:
"David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Neal Cardwell, Linus Torvalds
From: luoxuanqiang <redacted> IP_LOCAL_PORT_RANGE lets applications override the netns ephemeral port range on a per-socket basis. __inet_hash_connect() already treats such a range as an explicit application partition and scans it with step 1 [1]. Do the same in inet_csk_find_open_port(): when a socket-local range is set, walk the whole selected range instead of first splitting it by parity. Keep the existing step-2 parity behavior for sockets using the netns range, so the default bind/connect separation remains unchanged. [1] https://lore.kernel.org/r/20231214192939.1962891-3-edumazet@google.com (local) Suggested-by: Eric Dumazet <edumazet@google.com> Signed-off-by: luoxuanqiang <redacted> --- net/ipv4/inet_connection_sock.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index 56902bba54838..ad8af70c92ca3 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c@@ -323,13 +323,16 @@ inet_csk_find_open_port(const struct sock *sk, struct inet_bind_bucket **tb_ret, struct inet_bind2_bucket *tb2; struct inet_bind_bucket *tb; u32 remaining, offset; + bool local_ports; bool relax = false; + int step; l3mdev = inet_sk_bound_l3mdev(sk); ports_exhausted: attempt_half = (sk->sk_reuse == SK_CAN_REUSE) ? 1 : 0; other_half_scan: - inet_sk_get_local_port_range(sk, &low, &high); + local_ports = inet_sk_get_local_port_range(sk, &low, &high); + step = local_ports ? 1 : 2; high++; /* [32768, 60999] -> [32768, 61000[ */ if (high - low < 4) attempt_half = 0;
@@ -342,18 +345,19 @@ inet_csk_find_open_port(const struct sock *sk, struct inet_bind_bucket **tb_ret, low = half; } remaining = high - low; - if (likely(remaining > 1)) + if (!local_ports && remaining > 1) remaining &= ~1U; offset = get_random_u32_below(remaining); /* __inet_hash_connect() favors ports having @low parity * We do the opposite to not pollute connect() users. */ - offset |= 1U; + if (!local_ports) + offset |= 1U; other_parity_scan: port = low + offset; - for (i = 0; i < remaining; i += 2, port += 2) { + for (i = 0; i < remaining; i += step, port += step) { if (unlikely(port >= high)) port -= remaining; if (inet_is_local_reserved_port(net, port))
@@ -384,9 +388,11 @@ inet_csk_find_open_port(const struct sock *sk, struct inet_bind_bucket **tb_ret, cond_resched(); } - offset--; - if (!(offset & 1)) - goto other_parity_scan; + if (!local_ports) { + offset--; + if (!(offset & 1)) + goto other_parity_scan; + } if (attempt_half == 1) { /* OK we now try the upper half of the range */
--
2.43.0