* __inet_hash_connect port_offset parameter
@ 2015-05-27 15:25 Crestez Dan Leonard
2015-05-27 16:18 ` Eric Dumazet
0 siblings, 1 reply; 5+ messages in thread
From: Crestez Dan Leonard @ 2015-05-27 15:25 UTC (permalink / raw)
To: netdev
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
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: __inet_hash_connect port_offset parameter
2015-05-27 15:25 __inet_hash_connect port_offset parameter Crestez Dan Leonard
@ 2015-05-27 16:18 ` Eric Dumazet
2015-05-27 16:30 ` Eric Dumazet
0 siblings, 1 reply; 5+ messages in thread
From: Eric Dumazet @ 2015-05-27 16:18 UTC (permalink / raw)
To: Crestez Dan Leonard; +Cc: netdev
On Wed, 2015-05-27 at 18:25 +0300, Crestez Dan Leonard wrote:
> 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.
OK. Not a big deal I guess.
> - 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;
> - 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
>
> 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 ?
https://patchwork.ozlabs.org/patch/476002/
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: __inet_hash_connect port_offset parameter
2015-05-27 16:18 ` Eric Dumazet
@ 2015-05-27 16:30 ` Eric Dumazet
2015-05-27 17:46 ` [PATCH net-next] tcp: connect() from bound sockets can be faster Eric Dumazet
0 siblings, 1 reply; 5+ messages in thread
From: Eric Dumazet @ 2015-05-27 16:30 UTC (permalink / raw)
To: Crestez Dan Leonard; +Cc: netdev
On Wed, 2015-05-27 at 09:18 -0700, Eric Dumazet wrote:
> On Wed, 2015-05-27 at 18:25 +0300, Crestez Dan Leonard wrote:
> > 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.
>
> OK. Not a big deal I guess.
Patch for IPv4 would be :
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
index 185efef0f1251ba9d45fabb3ed51777a8be097a6..be4bac368b6bfb8a1eca429cce415da99adc5515 100644
--- a/net/ipv4/inet_hashtables.c
+++ b/net/ipv4/inet_hashtables.c
@@ -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);
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH net-next] tcp: connect() from bound sockets can be faster
2015-05-27 16:30 ` Eric Dumazet
@ 2015-05-27 17:46 ` Eric Dumazet
2015-05-27 18:31 ` David Miller
0 siblings, 1 reply; 5+ messages in thread
From: Eric Dumazet @ 2015-05-27 17:46 UTC (permalink / raw)
To: Crestez Dan Leonard, David Miller; +Cc: netdev
From: Eric Dumazet <edumazet@google.com>
__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 <cdleonard@gmail.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
net/ipv4/inet_hashtables.c | 9 +++++++--
net/ipv6/inet6_hashtables.c | 8 ++++++--
2 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
index 185efef0f1251ba9d45fabb3ed51777a8be097a6..e36942f0725d2e2d15f8d248b19a34c3487528ef 100644
--- a/net/ipv4/inet_hashtables.c
+++ b/net/ipv4/inet_hashtables.c
@@ -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);
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c
index 871641bc1ed4eb5b8f5f554c9efb75f2419fe5b6..b4fd96de97e61627003eff220e10bdd05a899e28 100644
--- a/net/ipv6/inet6_hashtables.c
+++ b/net/ipv6/inet6_hashtables.c
@@ -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);
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH net-next] tcp: connect() from bound sockets can be faster
2015-05-27 17:46 ` [PATCH net-next] tcp: connect() from bound sockets can be faster Eric Dumazet
@ 2015-05-27 18:31 ` David Miller
0 siblings, 0 replies; 5+ messages in thread
From: David Miller @ 2015-05-27 18:31 UTC (permalink / raw)
To: eric.dumazet; +Cc: cdleonard, netdev
From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Wed, 27 May 2015 10:46:02 -0700
> From: Eric Dumazet <edumazet@google.com>
>
> __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 <cdleonard@gmail.com>
> Signed-off-by: Eric Dumazet <edumazet@google.com>
Looks great, applied, thanks Eric!
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2015-05-27 18:31 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-05-27 15:25 __inet_hash_connect port_offset parameter Crestez Dan Leonard
2015-05-27 16:18 ` Eric Dumazet
2015-05-27 16:30 ` Eric Dumazet
2015-05-27 17:46 ` [PATCH net-next] tcp: connect() from bound sockets can be faster Eric Dumazet
2015-05-27 18:31 ` David Miller
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).