__inet_hash_connect port_offset parameter
Subsystems (3)
Hello,
I'm confused about the port_offset parameter to __inet_hash_connect.
When allocating the local port for an outgoing TCP connection the port search looks something like this:
static u32 hint;
u32 offset = hint + port_offset;
inet_get_local_port_range(net, &low, &high);
remaining = (high - low) + 1;
for (i = 1; i <= remaining; i++) {
port = low + (i + offset) % remaining;
/* check port is free */The port_offset is calculated for v4 and v6 based on a hash of src/dst addresses, presumably in order to improve security.
I see a few issues with this:
- The port_offset is calculated even if the local port was already assigned via bind. This wastes a few cycles.
- Keeping the last searched port as a static variable is a bad idea on multicore cpus. Starting a lot of connections to the same target will result in lock contention in the bind hash. This is probably only visible in highly synthetic tests.
- When doing a port search at bind() time the search starts from "prandom_32()". Is this "less secure" for port allocation? I bet most applications are not aware of this difference.
Wouldn't it be better to use the same local port search mechanism at both bind (inet_csk_get_port) and connect (__inet_hash_connect) time, based on starting from a random point? It would also make connecting slightly faster.
Regards,
Leonard
Quoted 17 lines · Crestez Dan Leonard
Hello,
I'm confused about the
port_offsetparameter to__inet_hash_connect.When allocating the local port for an outgoing TCP connection the port search looks something like this:
static u32 hint; u32 offset = hint + port_offset; inet_get_local_port_range(net, &low, &high); remaining = (high - low) + 1; for (i = 1; i <= remaining; i++) { port = low + (i + offset) % remaining; /* check port is free */
Quoted 6 lines
The
port_offsetis calculated for v4 and v6 based on a hash of src/dst addresses, presumably in order to improve security.I see a few issues with this:
- Theport_offsetis calculated even if the local port was already
assigned via bind. This wastes a few cycles.
OK. Not a big deal I guess.
Quoted 4 lines
- Keeping the last searched port as a static variable is a bad idea
on multicore cpus. Starting a lot of connections to the same target will result in lock contention in the bind hash. This is probably only visible in highly synthetic tests.
Not really. This is a hint only.
I have one patch adding an array of hints, but this does not change behavior if connecting to same target.
u32 key = port_offset % HINTS_SZ;
Quoted 3 lines
- When doing a port search at
bind()time the search starts from
"prandom_32()". Is this "less secure" for port allocation? I bet most applications are not aware of this difference.
I am afraid we need to keep a sequential search for ephemeral port selection.
This known behavior is described in RFC 6056
Quoted 5 lines
Wouldn't it be better to use the same local port search mechanism at both bind (
inet_csk_get_port) and connect (__inet_hash_connect) time, based on starting from a random point? It would also make connecting slightly faster.
Nope, bind() and connect() have different semantics.
The randomization is only good for bind(port=0) users.
Have you seen my proposal ?
Quoted 18 lines · Eric Dumazet
Quoted 17 lines · Crestez Dan Leonard
Hello,
I'm confused about the
port_offsetparameter to__inet_hash_connect.When allocating the local port for an outgoing TCP connection the port search looks something like this:
static u32 hint; u32 offset = hint + port_offset; inet_get_local_port_range(net, &low, &high); remaining = (high - low) + 1; for (i = 1; i <= remaining; i++) { port = low + (i + offset) % remaining; /* check port is free */
Quoted 8 lines
Quoted 6 lines
The
port_offsetis calculated for v4 and v6 based on a hash of src/dst addresses, presumably in order to improve security.I see a few issues with this:
- Theport_offsetis calculated even if the local port was already
assigned via bind. This wastes a few cycles.OK. Not a big deal I guess.
Patch for IPv4 would be :
net/ipv4/inet_hashtables.c +5 -1
@@ -594,7 +594,11 @@ out:int inet_hash_connect (struct inet_timewait_death_row *death_row,struct sock *sk) { -return __inet_hash_connect (death_row, sk,inet_sk_port_offset (sk), +u32 port_offset =0 ; + +if (!inet_sk (sk)->inet_num) + port_offset =inet_sk_port_offset (sk); +return __inet_hash_connect (death_row, sk, port_offset, __inet_check_established); }EXPORT_SYMBOL_GPL (inet_hash_connect);
PATCH 1/1 tcp: connect() from bound sockets can be faster
From: Eric Dumazet <[email protected]>
__inet_hash_connect() does not use its third argument (port_offset) if socket was already bound to a source port.
No need to perform useless but expensive md5 computations.
--- net/ipv4/inet_hashtables.c | 9 +++++++-- net/ipv6/inet6_hashtables.c | 8 ++++++-- 2 files changed, 13 insertions(+), 4 deletions(-)
net/ipv4/inet_hashtables.c +7 -2
@@ -394,9 +394,10 @@ not_unique:return -EADDRNOTAVAIL ; } -static inline u32 inet_sk_port_offset (const struct sock *sk) +static u32 inet_sk_port_offset (const struct sock *sk) {const struct inet_sock *inet =inet_sk (sk); +return secure_ipv4_port_ephemeral (inet->inet_rcv_saddr, inet->inet_daddr, inet->inet_dport);
@@ -594,7 +595,11 @@ out:int inet_hash_connect (struct inet_timewait_death_row *death_row,struct sock *sk) { -return __inet_hash_connect (death_row, sk,inet_sk_port_offset (sk), +u32 port_offset =0 ; + +if (!inet_sk (sk)->inet_num) + port_offset =inet_sk_port_offset (sk); +return __inet_hash_connect (death_row, sk, port_offset, __inet_check_established); }EXPORT_SYMBOL_GPL (inet_hash_connect);
net/ipv6/inet6_hashtables.c +6 -2
@@ -257,7 +257,7 @@ not_unique:return -EADDRNOTAVAIL ; } -static inline u32 inet6_sk_port_offset (const struct sock *sk) +static u32 inet6_sk_port_offset (const struct sock *sk) {const struct inet_sock *inet =inet_sk (sk);
@@ -269,7 +269,11 @@ static inline u32 inet6_sk_port_offset(const struct sock *sk)int inet6_hash_connect (struct inet_timewait_death_row *death_row,struct sock *sk) { -return __inet_hash_connect (death_row, sk,inet6_sk_port_offset (sk), +u32 port_offset =0 ; + +if (!inet_sk (sk)->inet_num) + port_offset =inet6_sk_port_offset (sk); +return __inet_hash_connect (death_row, sk, port_offset, __inet6_check_established); }EXPORT_SYMBOL_GPL (inet6_hash_connect);
David Miller
maintainerRe: [PATCH net-next] tcp: connect() from bound sockets can be faster
From: Eric Dumazet <[email protected]>
Date: Wed, 27 May 2015 10:46:02 -0700
Quoted 9 lines
From: Eric Dumazet <[email protected]>
__inet_hash_connect()does not use its third argument (port_offset) if socket was already bound to a source port.No need to perform useless but expensive md5 computations.
Reported-by Crestez Dan Leonard <[email protected]>Signed-off-by Eric Dumazet <[email protected]>
Looks great, applied, thanks Eric!