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

[INET6_HASHTABLES]: Move inet6_lookup functions to net/ipv6/inet6_hashtables.c

Doing this we allow tcp_diag to support IPV6 even if tcp_diag is compiled
statically and IPV6 is compiled as a module, removing the previous restriction
while not building any IPV6 code if it is not selected.

Now to work on the tcpdiag_register infrastructure and then to rename the whole
thing to inetdiag, reflecting its by then completely generic nature.

Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Arnaldo Carvalho de Melo and committed by
David S. Miller
5324a040 505cbfc5

+190 -157
+105 -1
include/net/inet6_hashtables.h
··· 14 14 #ifndef _INET6_HASHTABLES_H 15 15 #define _INET6_HASHTABLES_H 16 16 17 + #include <linux/config.h> 18 + 19 + #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) 20 + #include <linux/in6.h> 21 + #include <linux/ipv6.h> 17 22 #include <linux/types.h> 18 23 19 - struct in6_addr; 24 + #include <net/ipv6.h> 25 + 20 26 struct inet_hashinfo; 27 + 28 + /* I have no idea if this is a good hash for v6 or not. -DaveM */ 29 + static inline int inet6_ehashfn(const struct in6_addr *laddr, const u16 lport, 30 + const struct in6_addr *faddr, const u16 fport, 31 + const int ehash_size) 32 + { 33 + int hashent = (lport ^ fport); 34 + 35 + hashent ^= (laddr->s6_addr32[3] ^ faddr->s6_addr32[3]); 36 + hashent ^= hashent >> 16; 37 + hashent ^= hashent >> 8; 38 + return (hashent & (ehash_size - 1)); 39 + } 40 + 41 + static inline int inet6_sk_ehashfn(const struct sock *sk, const int ehash_size) 42 + { 43 + const struct inet_sock *inet = inet_sk(sk); 44 + const struct ipv6_pinfo *np = inet6_sk(sk); 45 + const struct in6_addr *laddr = &np->rcv_saddr; 46 + const struct in6_addr *faddr = &np->daddr; 47 + const __u16 lport = inet->num; 48 + const __u16 fport = inet->dport; 49 + return inet6_ehashfn(laddr, lport, faddr, fport, ehash_size); 50 + } 51 + 52 + /* 53 + * Sockets in TCP_CLOSE state are _always_ taken out of the hash, so 54 + * we need not check it for TCP lookups anymore, thanks Alexey. -DaveM 55 + * 56 + * The sockhash lock must be held as a reader here. 57 + */ 58 + static inline struct sock * 59 + __inet6_lookup_established(struct inet_hashinfo *hashinfo, 60 + const struct in6_addr *saddr, 61 + const u16 sport, 62 + const struct in6_addr *daddr, 63 + const u16 hnum, 64 + const int dif) 65 + { 66 + struct sock *sk; 67 + const struct hlist_node *node; 68 + const __u32 ports = INET_COMBINED_PORTS(sport, hnum); 69 + /* Optimize here for direct hit, only listening connections can 70 + * have wildcards anyways. 71 + */ 72 + const int hash = inet6_ehashfn(daddr, hnum, saddr, sport, 73 + hashinfo->ehash_size); 74 + struct inet_ehash_bucket *head = &hashinfo->ehash[hash]; 75 + 76 + read_lock(&head->lock); 77 + sk_for_each(sk, node, &head->chain) { 78 + /* For IPV6 do the cheaper port and family tests first. */ 79 + if (INET6_MATCH(sk, saddr, daddr, ports, dif)) 80 + goto hit; /* You sunk my battleship! */ 81 + } 82 + /* Must check for a TIME_WAIT'er before going to listener hash. */ 83 + sk_for_each(sk, node, &(head + hashinfo->ehash_size)->chain) { 84 + const struct inet_timewait_sock *tw = inet_twsk(sk); 85 + 86 + if(*((__u32 *)&(tw->tw_dport)) == ports && 87 + sk->sk_family == PF_INET6) { 88 + const struct tcp6_timewait_sock *tcp6tw = tcp6_twsk(sk); 89 + 90 + if (ipv6_addr_equal(&tcp6tw->tw_v6_daddr, saddr) && 91 + ipv6_addr_equal(&tcp6tw->tw_v6_rcv_saddr, daddr) && 92 + (!sk->sk_bound_dev_if || sk->sk_bound_dev_if == dif)) 93 + goto hit; 94 + } 95 + } 96 + read_unlock(&head->lock); 97 + return NULL; 98 + 99 + hit: 100 + sock_hold(sk); 101 + read_unlock(&head->lock); 102 + return sk; 103 + } 104 + 105 + extern struct sock *inet6_lookup_listener(struct inet_hashinfo *hashinfo, 106 + const struct in6_addr *daddr, 107 + const unsigned short hnum, 108 + const int dif); 109 + 110 + static inline struct sock *__inet6_lookup(struct inet_hashinfo *hashinfo, 111 + const struct in6_addr *saddr, 112 + const u16 sport, 113 + const struct in6_addr *daddr, 114 + const u16 hnum, 115 + const int dif) 116 + { 117 + struct sock *sk = __inet6_lookup_established(hashinfo, saddr, sport, 118 + daddr, hnum, dif); 119 + if (sk) 120 + return sk; 121 + 122 + return inet6_lookup_listener(hashinfo, daddr, hnum, dif); 123 + } 21 124 22 125 extern struct sock *inet6_lookup(struct inet_hashinfo *hashinfo, 23 126 const struct in6_addr *saddr, const u16 sport, 24 127 const struct in6_addr *daddr, const u16 dport, 25 128 const int dif); 129 + #endif /* defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) */ 26 130 #endif /* _INET6_HASHTABLES_H */
+1 -3
net/ipv4/Kconfig
··· 419 419 ---help--- 420 420 Support for TCP socket monitoring interface used by native Linux 421 421 tools such as ss. ss is included in iproute2, currently downloadable 422 - at <http://developer.osdl.org/dev/iproute2>. If you want IPv6 or DCCP 423 - support and have selected IPv6 or DCCP as a module, you need to build 424 - this as a module too. 422 + at <http://developer.osdl.org/dev/iproute2>. 425 423 426 424 If unsure, say Y. 427 425
+2
net/ipv6/Makefile
··· 23 23 obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o 24 24 25 25 obj-y += exthdrs_core.o 26 + 27 + obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_hashtables.o
+81
net/ipv6/inet6_hashtables.c
··· 1 + /* 2 + * INET An implementation of the TCP/IP protocol suite for the LINUX 3 + * operating system. INET is implemented using the BSD Socket 4 + * interface as the means of communication with the user level. 5 + * 6 + * Generic INET6 transport hashtables 7 + * 8 + * Authors: Lotsa people, from code originally in tcp 9 + * 10 + * This program is free software; you can redistribute it and/or 11 + * modify it under the terms of the GNU General Public License 12 + * as published by the Free Software Foundation; either version 13 + * 2 of the License, or (at your option) any later version. 14 + */ 15 + 16 + #include <linux/config.h> 17 + 18 + #include <linux/module.h> 19 + 20 + #include <net/inet_connection_sock.h> 21 + #include <net/inet_hashtables.h> 22 + #include <net/inet6_hashtables.h> 23 + 24 + struct sock *inet6_lookup_listener(struct inet_hashinfo *hashinfo, 25 + const struct in6_addr *daddr, 26 + const unsigned short hnum, const int dif) 27 + { 28 + struct sock *sk; 29 + const struct hlist_node *node; 30 + struct sock *result = NULL; 31 + int score, hiscore = 0; 32 + 33 + read_lock(&hashinfo->lhash_lock); 34 + sk_for_each(sk, node, &hashinfo->listening_hash[inet_lhashfn(hnum)]) { 35 + if (inet_sk(sk)->num == hnum && sk->sk_family == PF_INET6) { 36 + const struct ipv6_pinfo *np = inet6_sk(sk); 37 + 38 + score = 1; 39 + if (!ipv6_addr_any(&np->rcv_saddr)) { 40 + if (!ipv6_addr_equal(&np->rcv_saddr, daddr)) 41 + continue; 42 + score++; 43 + } 44 + if (sk->sk_bound_dev_if) { 45 + if (sk->sk_bound_dev_if != dif) 46 + continue; 47 + score++; 48 + } 49 + if (score == 3) { 50 + result = sk; 51 + break; 52 + } 53 + if (score > hiscore) { 54 + hiscore = score; 55 + result = sk; 56 + } 57 + } 58 + } 59 + if (result) 60 + sock_hold(result); 61 + read_unlock(&hashinfo->lhash_lock); 62 + return result; 63 + } 64 + 65 + EXPORT_SYMBOL_GPL(inet6_lookup_listener); 66 + 67 + struct sock *inet6_lookup(struct inet_hashinfo *hashinfo, 68 + const struct in6_addr *saddr, const u16 sport, 69 + const struct in6_addr *daddr, const u16 dport, 70 + const int dif) 71 + { 72 + struct sock *sk; 73 + 74 + local_bh_disable(); 75 + sk = __inet6_lookup(hashinfo, saddr, sport, daddr, ntohs(dport), dif); 76 + local_bh_enable(); 77 + 78 + return sk; 79 + } 80 + 81 + EXPORT_SYMBOL_GPL(inet6_lookup);
+1 -153
net/ipv6/tcp_ipv6.c
··· 47 47 48 48 #include <net/tcp.h> 49 49 #include <net/ndisc.h> 50 + #include <net/inet6_hashtables.h> 50 51 #include <net/ipv6.h> 51 52 #include <net/transp_v6.h> 52 53 #include <net/addrconf.h> ··· 75 74 76 75 static struct tcp_func ipv6_mapped; 77 76 static struct tcp_func ipv6_specific; 78 - 79 - /* I have no idea if this is a good hash for v6 or not. -DaveM */ 80 - static inline int inet6_ehashfn(const struct in6_addr *laddr, const u16 lport, 81 - const struct in6_addr *faddr, const u16 fport, 82 - const int ehash_size) 83 - { 84 - int hashent = (lport ^ fport); 85 - 86 - hashent ^= (laddr->s6_addr32[3] ^ faddr->s6_addr32[3]); 87 - hashent ^= hashent>>16; 88 - hashent ^= hashent>>8; 89 - return (hashent & (ehash_size - 1)); 90 - } 91 - 92 - static inline int inet6_sk_ehashfn(const struct sock *sk, const int ehash_size) 93 - { 94 - const struct inet_sock *inet = inet_sk(sk); 95 - const struct ipv6_pinfo *np = inet6_sk(sk); 96 - const struct in6_addr *laddr = &np->rcv_saddr; 97 - const struct in6_addr *faddr = &np->daddr; 98 - const __u16 lport = inet->num; 99 - const __u16 fport = inet->dport; 100 - return inet6_ehashfn(laddr, lport, faddr, fport, ehash_size); 101 - } 102 77 103 78 static inline int tcp_v6_bind_conflict(const struct sock *sk, 104 79 const struct inet_bind_bucket *tb) ··· 235 258 local_bh_enable(); 236 259 } 237 260 } 238 - 239 - static struct sock *inet6_lookup_listener(struct inet_hashinfo *hashinfo, 240 - const struct in6_addr *daddr, 241 - const unsigned short hnum, 242 - const int dif) 243 - { 244 - struct sock *sk; 245 - struct hlist_node *node; 246 - struct sock *result = NULL; 247 - int score, hiscore; 248 - 249 - hiscore=0; 250 - read_lock(&hashinfo->lhash_lock); 251 - sk_for_each(sk, node, &hashinfo->listening_hash[inet_lhashfn(hnum)]) { 252 - if (inet_sk(sk)->num == hnum && sk->sk_family == PF_INET6) { 253 - struct ipv6_pinfo *np = inet6_sk(sk); 254 - 255 - score = 1; 256 - if (!ipv6_addr_any(&np->rcv_saddr)) { 257 - if (!ipv6_addr_equal(&np->rcv_saddr, daddr)) 258 - continue; 259 - score++; 260 - } 261 - if (sk->sk_bound_dev_if) { 262 - if (sk->sk_bound_dev_if != dif) 263 - continue; 264 - score++; 265 - } 266 - if (score == 3) { 267 - result = sk; 268 - break; 269 - } 270 - if (score > hiscore) { 271 - hiscore = score; 272 - result = sk; 273 - } 274 - } 275 - } 276 - if (result) 277 - sock_hold(result); 278 - read_unlock(&hashinfo->lhash_lock); 279 - return result; 280 - } 281 - 282 - /* Sockets in TCP_CLOSE state are _always_ taken out of the hash, so 283 - * we need not check it for TCP lookups anymore, thanks Alexey. -DaveM 284 - * 285 - * The sockhash lock must be held as a reader here. 286 - */ 287 - 288 - static inline struct sock * 289 - __inet6_lookup_established(struct inet_hashinfo *hashinfo, 290 - const struct in6_addr *saddr, 291 - const u16 sport, 292 - const struct in6_addr *daddr, 293 - const u16 hnum, 294 - const int dif) 295 - { 296 - struct sock *sk; 297 - const struct hlist_node *node; 298 - const __u32 ports = INET_COMBINED_PORTS(sport, hnum); 299 - /* Optimize here for direct hit, only listening connections can 300 - * have wildcards anyways. 301 - */ 302 - const int hash = inet6_ehashfn(daddr, hnum, saddr, sport, 303 - hashinfo->ehash_size); 304 - struct inet_ehash_bucket *head = &hashinfo->ehash[hash]; 305 - 306 - read_lock(&head->lock); 307 - sk_for_each(sk, node, &head->chain) { 308 - /* For IPV6 do the cheaper port and family tests first. */ 309 - if (INET6_MATCH(sk, saddr, daddr, ports, dif)) 310 - goto hit; /* You sunk my battleship! */ 311 - } 312 - /* Must check for a TIME_WAIT'er before going to listener hash. */ 313 - sk_for_each(sk, node, &(head + hashinfo->ehash_size)->chain) { 314 - const struct inet_timewait_sock *tw = inet_twsk(sk); 315 - 316 - if(*((__u32 *)&(tw->tw_dport)) == ports && 317 - sk->sk_family == PF_INET6) { 318 - const struct tcp6_timewait_sock *tcp6tw = tcp6_twsk(sk); 319 - 320 - if (ipv6_addr_equal(&tcp6tw->tw_v6_daddr, saddr) && 321 - ipv6_addr_equal(&tcp6tw->tw_v6_rcv_saddr, daddr) && 322 - (!sk->sk_bound_dev_if || sk->sk_bound_dev_if == dif)) 323 - goto hit; 324 - } 325 - } 326 - read_unlock(&head->lock); 327 - return NULL; 328 - 329 - hit: 330 - sock_hold(sk); 331 - read_unlock(&head->lock); 332 - return sk; 333 - } 334 - 335 - 336 - static inline struct sock *__inet6_lookup(struct inet_hashinfo *hashinfo, 337 - const struct in6_addr *saddr, 338 - const u16 sport, 339 - const struct in6_addr *daddr, 340 - const u16 hnum, 341 - const int dif) 342 - { 343 - struct sock *sk = __inet6_lookup_established(hashinfo, saddr, sport, 344 - daddr, hnum, dif); 345 - if (sk) 346 - return sk; 347 - 348 - return inet6_lookup_listener(hashinfo, daddr, hnum, dif); 349 - } 350 - 351 - inline struct sock *inet6_lookup(struct inet_hashinfo *hashinfo, 352 - const struct in6_addr *saddr, const u16 sport, 353 - const struct in6_addr *daddr, const u16 dport, 354 - const int dif) 355 - { 356 - struct sock *sk; 357 - 358 - local_bh_disable(); 359 - sk = __inet6_lookup(hashinfo, saddr, sport, daddr, ntohs(dport), dif); 360 - local_bh_enable(); 361 - 362 - return sk; 363 - } 364 - 365 - EXPORT_SYMBOL_GPL(inet6_lookup); 366 - 367 261 368 262 /* 369 263 * Open request hash tables.