Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

inet: create IPv6-equivalent inet_hash function

In order to support fast lookups for TCP sockets with SO_REUSEPORT,
the function that adds sockets to the listening hash set needs
to be able to check receive address equality. Since this equality
check is different for IPv4 and IPv6, we will need two different
socket hashing functions.

This patch adds inet6_hash identical to the existing inet_hash function
and updates the appropriate references. A following patch will
differentiate the two by passing different comparison functions to
__inet_hash.

Additionally, in order to use the IPv6 address equality function from
inet6_hashtables (which is compiled as a built-in object when IPv6 is
enabled) it also needs to be in a built-in object file as well. This
moves ipv6_rcv_saddr_equal into inet_hashtables to accomplish this.

Signed-off-by: Craig Gallek <kraig@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Craig Gallek and committed by
David S. Miller
496611d7 086c653f

+63 -46
+2
include/net/inet6_hashtables.h
··· 96 96 const struct in6_addr *saddr, const __be16 sport, 97 97 const struct in6_addr *daddr, const __be16 dport, 98 98 const int dif); 99 + 100 + int inet6_hash(struct sock *sk); 99 101 #endif /* IS_ENABLED(CONFIG_IPV6) */ 100 102 101 103 #define INET6_MATCH(__sk, __net, __saddr, __daddr, __ports, __dif) \
+1 -1
net/dccp/ipv6.c
··· 993 993 .sendmsg = dccp_sendmsg, 994 994 .recvmsg = dccp_recvmsg, 995 995 .backlog_rcv = dccp_v6_do_rcv, 996 - .hash = inet_hash, 996 + .hash = inet6_hash, 997 997 .unhash = inet_unhash, 998 998 .accept = inet_csk_accept, 999 999 .get_port = inet_csk_get_port,
+56
net/ipv6/inet6_hashtables.c
··· 274 274 __inet6_check_established); 275 275 } 276 276 EXPORT_SYMBOL_GPL(inet6_hash_connect); 277 + 278 + int inet6_hash(struct sock *sk) 279 + { 280 + if (sk->sk_state != TCP_CLOSE) { 281 + local_bh_disable(); 282 + __inet_hash(sk, NULL); 283 + local_bh_enable(); 284 + } 285 + 286 + return 0; 287 + } 288 + EXPORT_SYMBOL_GPL(inet6_hash); 289 + 290 + /* match_wildcard == true: IPV6_ADDR_ANY equals to any IPv6 addresses if IPv6 291 + * only, and any IPv4 addresses if not IPv6 only 292 + * match_wildcard == false: addresses must be exactly the same, i.e. 293 + * IPV6_ADDR_ANY only equals to IPV6_ADDR_ANY, 294 + * and 0.0.0.0 equals to 0.0.0.0 only 295 + */ 296 + int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2, 297 + bool match_wildcard) 298 + { 299 + const struct in6_addr *sk2_rcv_saddr6 = inet6_rcv_saddr(sk2); 300 + int sk2_ipv6only = inet_v6_ipv6only(sk2); 301 + int addr_type = ipv6_addr_type(&sk->sk_v6_rcv_saddr); 302 + int addr_type2 = sk2_rcv_saddr6 ? ipv6_addr_type(sk2_rcv_saddr6) : IPV6_ADDR_MAPPED; 303 + 304 + /* if both are mapped, treat as IPv4 */ 305 + if (addr_type == IPV6_ADDR_MAPPED && addr_type2 == IPV6_ADDR_MAPPED) { 306 + if (!sk2_ipv6only) { 307 + if (sk->sk_rcv_saddr == sk2->sk_rcv_saddr) 308 + return 1; 309 + if (!sk->sk_rcv_saddr || !sk2->sk_rcv_saddr) 310 + return match_wildcard; 311 + } 312 + return 0; 313 + } 314 + 315 + if (addr_type == IPV6_ADDR_ANY && addr_type2 == IPV6_ADDR_ANY) 316 + return 1; 317 + 318 + if (addr_type2 == IPV6_ADDR_ANY && match_wildcard && 319 + !(sk2_ipv6only && addr_type == IPV6_ADDR_MAPPED)) 320 + return 1; 321 + 322 + if (addr_type == IPV6_ADDR_ANY && match_wildcard && 323 + !(ipv6_only_sock(sk) && addr_type2 == IPV6_ADDR_MAPPED)) 324 + return 1; 325 + 326 + if (sk2_rcv_saddr6 && 327 + ipv6_addr_equal(&sk->sk_v6_rcv_saddr, sk2_rcv_saddr6)) 328 + return 1; 329 + 330 + return 0; 331 + } 332 + EXPORT_SYMBOL_GPL(ipv6_rcv_saddr_equal);
+1 -1
net/ipv6/tcp_ipv6.c
··· 1865 1865 .sendpage = tcp_sendpage, 1866 1866 .backlog_rcv = tcp_v6_do_rcv, 1867 1867 .release_cb = tcp_release_cb, 1868 - .hash = inet_hash, 1868 + .hash = inet6_hash, 1869 1869 .unhash = inet_unhash, 1870 1870 .get_port = inet_csk_get_port, 1871 1871 .enter_memory_pressure = tcp_enter_memory_pressure,
+1 -43
net/ipv6/udp.c
··· 37 37 #include <linux/slab.h> 38 38 #include <asm/uaccess.h> 39 39 40 + #include <net/addrconf.h> 40 41 #include <net/ndisc.h> 41 42 #include <net/protocol.h> 42 43 #include <net/transp_v6.h> ··· 76 75 77 76 return __inet6_ehashfn(lhash, lport, fhash, fport, 78 77 udp_ipv6_hash_secret + net_hash_mix(net)); 79 - } 80 - 81 - /* match_wildcard == true: IPV6_ADDR_ANY equals to any IPv6 addresses if IPv6 82 - * only, and any IPv4 addresses if not IPv6 only 83 - * match_wildcard == false: addresses must be exactly the same, i.e. 84 - * IPV6_ADDR_ANY only equals to IPV6_ADDR_ANY, 85 - * and 0.0.0.0 equals to 0.0.0.0 only 86 - */ 87 - int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2, 88 - bool match_wildcard) 89 - { 90 - const struct in6_addr *sk2_rcv_saddr6 = inet6_rcv_saddr(sk2); 91 - int sk2_ipv6only = inet_v6_ipv6only(sk2); 92 - int addr_type = ipv6_addr_type(&sk->sk_v6_rcv_saddr); 93 - int addr_type2 = sk2_rcv_saddr6 ? ipv6_addr_type(sk2_rcv_saddr6) : IPV6_ADDR_MAPPED; 94 - 95 - /* if both are mapped, treat as IPv4 */ 96 - if (addr_type == IPV6_ADDR_MAPPED && addr_type2 == IPV6_ADDR_MAPPED) { 97 - if (!sk2_ipv6only) { 98 - if (sk->sk_rcv_saddr == sk2->sk_rcv_saddr) 99 - return 1; 100 - if (!sk->sk_rcv_saddr || !sk2->sk_rcv_saddr) 101 - return match_wildcard; 102 - } 103 - return 0; 104 - } 105 - 106 - if (addr_type == IPV6_ADDR_ANY && addr_type2 == IPV6_ADDR_ANY) 107 - return 1; 108 - 109 - if (addr_type2 == IPV6_ADDR_ANY && match_wildcard && 110 - !(sk2_ipv6only && addr_type == IPV6_ADDR_MAPPED)) 111 - return 1; 112 - 113 - if (addr_type == IPV6_ADDR_ANY && match_wildcard && 114 - !(ipv6_only_sock(sk) && addr_type2 == IPV6_ADDR_MAPPED)) 115 - return 1; 116 - 117 - if (sk2_rcv_saddr6 && 118 - ipv6_addr_equal(&sk->sk_v6_rcv_saddr, sk2_rcv_saddr6)) 119 - return 1; 120 - 121 - return 0; 122 78 } 123 79 124 80 static u32 udp6_portaddr_hash(const struct net *net,
+2 -1
net/l2tp/l2tp_ip6.c
··· 25 25 #include <net/udp.h> 26 26 #include <net/inet_common.h> 27 27 #include <net/inet_hashtables.h> 28 + #include <net/inet6_hashtables.h> 28 29 #include <net/tcp_states.h> 29 30 #include <net/protocol.h> 30 31 #include <net/xfrm.h> ··· 719 718 .sendmsg = l2tp_ip6_sendmsg, 720 719 .recvmsg = l2tp_ip6_recvmsg, 721 720 .backlog_rcv = l2tp_ip6_backlog_recv, 722 - .hash = inet_hash, 721 + .hash = inet6_hash, 723 722 .unhash = inet_unhash, 724 723 .obj_size = sizeof(struct l2tp_ip6_sock), 725 724 #ifdef CONFIG_COMPAT