inet: Add a 2nd listener hashtable (port+addr)
authorMartin KaFai Lau <kafai@fb.com>
Fri, 1 Dec 2017 20:52:31 +0000 (12:52 -0800)
committerDavid S. Miller <davem@davemloft.net>
Sun, 3 Dec 2017 15:18:28 +0000 (10:18 -0500)
commit61b7c691c7317529375f90f0a81a331990b1ec1b
tree1f2dd502ca0f17197df85b240432bd87c0d2bde7
parentf0b1e64c1331dd8a2f0c30fcd0838db6cb406098
inet: Add a 2nd listener hashtable (port+addr)

The current listener hashtable is hashed by port only.
When a process is listening at many IP addresses with the same port (e.g.
[IP1]:443, [IP2]:443... [IPN]:443), the inet[6]_lookup_listener()
performance is degraded to a link list.  It is prone to syn attack.

UDP had a similar issue and a second hashtable was added to resolve it.

This patch adds a second hashtable for the listener's sockets.
The second hashtable is hashed by port and address.

It cannot reuse the existing skc_portaddr_node which is shared
with skc_bind_node.  TCP listener needs to use skc_bind_node.
Instead, this patch adds a hlist_node 'icsk_listen_portaddr_node' to
the inet_connection_sock which the listener (like TCP) also belongs to.

The new portaddr hashtable may need two lookup (First by IP:PORT.
Second by INADDR_ANY:PORT if the IP:PORT is a not found).   Hence,
it implements a similar cut off as UDP such that it will only consult the
new portaddr hashtable if the current port-only hashtable has >10
sk in the link-list.

lhash2 and lhash2_mask are added to 'struct inet_hashinfo'.  I take
this chance to plug a 4 bytes hole.  It is done by first moving
the existing bind_bucket_cachep up and then add the new
(int lhash2_mask, *lhash2) after the existing bhash_size.

Signed-off-by: Martin KaFai Lau <kafai@fb.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/inet_connection_sock.h
include/net/inet_hashtables.h
net/ipv4/inet_hashtables.c
net/ipv6/inet6_hashtables.c