On Fri, 2016-12-09 at 19:47 -0800, Eric Dumazet wrote: > > Hmm... Is your ephemeral port range includes the port your load > balancing app is using ?
I suspect that you might have processes doing bind( port = 0) that are trapped into the bind_conflict() scan ? With 100,000 + timewaits there, this possibly hurts. Can you try the following loop breaker ? diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index d5d3ead0a6c31e42e8843d30f8c643324a91b8e9..74f0f5ee6a02c624edb0263b9ddd27813f68d0a5 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -51,7 +51,7 @@ int inet_csk_bind_conflict(const struct sock *sk, int reuse = sk->sk_reuse; int reuseport = sk->sk_reuseport; kuid_t uid = sock_i_uid((struct sock *)sk); - + unsigned int max_count; /* * Unlike other sk lookup places we do not check * for sk_net here, since _all_ the socks listed @@ -59,6 +59,7 @@ int inet_csk_bind_conflict(const struct sock *sk, * one this bucket belongs to. */ + max_count = relax ? ~0U : 100; sk_for_each_bound(sk2, &tb->owners) { if (sk != sk2 && !inet_v6_ipv6only(sk2) && @@ -84,6 +85,8 @@ int inet_csk_bind_conflict(const struct sock *sk, break; } } + if (--max_count == 0) + return 1; } return sk2 != NULL; } diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c index 1c86c478f578b49373e61a4c397f23f3dc7f3fc6..4f63d06e0d601da94eb3f2b35a988abd060e156c 100644 --- a/net/ipv6/inet6_connection_sock.c +++ b/net/ipv6/inet6_connection_sock.c @@ -35,12 +35,14 @@ int inet6_csk_bind_conflict(const struct sock *sk, int reuse = sk->sk_reuse; int reuseport = sk->sk_reuseport; kuid_t uid = sock_i_uid((struct sock *)sk); + unsigned int max_count; /* We must walk the whole port owner list in this case. -DaveM */ /* * See comment in inet_csk_bind_conflict about sock lookup * vs net namespaces issues. */ + max_count = relax ? ~0U : 100; sk_for_each_bound(sk2, &tb->owners) { if (sk != sk2 && (!sk->sk_bound_dev_if || @@ -61,6 +63,8 @@ int inet6_csk_bind_conflict(const struct sock *sk, ipv6_rcv_saddr_equal(sk, sk2, true)) break; } + if (--max_count == 0) + return 1; } return sk2 != NULL;