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

[IPV6]: Generalise the tcp_v6_lookup routines

In the same way as was done with the v4 counterparts, this will be moved
to inet6_hashtables.c.

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
505cbfc5 b766b305

+122 -91
+5
include/linux/ipv6.h
··· 193 193 194 194 #define IP6CB(skb) ((struct inet6_skb_parm*)((skb)->cb)) 195 195 196 + static inline int inet6_iif(const struct sk_buff *skb) 197 + { 198 + return IP6CB(skb)->iif; 199 + } 200 + 196 201 struct tcp6_request_sock { 197 202 struct tcp_request_sock req; 198 203 struct in6_addr loc_addr;
+26
include/net/inet6_hashtables.h
··· 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 + * Authors: Lotsa people, from code originally in tcp 7 + * 8 + * This program is free software; you can redistribute it and/or 9 + * modify it under the terms of the GNU General Public License 10 + * as published by the Free Software Foundation; either version 11 + * 2 of the License, or (at your option) any later version. 12 + */ 13 + 14 + #ifndef _INET6_HASHTABLES_H 15 + #define _INET6_HASHTABLES_H 16 + 17 + #include <linux/types.h> 18 + 19 + struct in6_addr; 20 + struct inet_hashinfo; 21 + 22 + extern struct sock *inet6_lookup(struct inet_hashinfo *hashinfo, 23 + const struct in6_addr *saddr, const u16 sport, 24 + const struct in6_addr *daddr, const u16 dport, 25 + const int dif); 26 + #endif /* _INET6_HASHTABLES_H */
-3
net/ipv4/Kconfig
··· 425 425 426 426 If unsure, say Y. 427 427 428 - config IP_TCPDIAG_IPV6 429 - def_bool (IP_TCPDIAG=y && IPV6=y) || (IP_TCPDIAG=m && IPV6) 430 - 431 428 config IP_TCPDIAG_DCCP 432 429 def_bool (IP_TCPDIAG=y && IP_DCCP=y) || (IP_TCPDIAG=m && IP_DCCP) 433 430
+17 -23
net/ipv4/tcp_diag.c
··· 24 24 #include <net/tcp.h> 25 25 #include <net/ipv6.h> 26 26 #include <net/inet_common.h> 27 + #include <net/inet_connection_sock.h> 28 + #include <net/inet_hashtables.h> 29 + #include <net/inet_timewait_sock.h> 30 + #include <net/inet6_hashtables.h> 27 31 28 32 #include <linux/inet.h> 29 33 #include <linux/stddef.h> ··· 106 102 r->tcpdiag_wqueue = 0; 107 103 r->tcpdiag_uid = 0; 108 104 r->tcpdiag_inode = 0; 109 - #ifdef CONFIG_IP_TCPDIAG_IPV6 105 + #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) 110 106 if (r->tcpdiag_family == AF_INET6) { 111 107 const struct tcp6_timewait_sock *tcp6tw = tcp6_twsk(sk); 112 108 ··· 125 121 r->id.tcpdiag_src[0] = inet->rcv_saddr; 126 122 r->id.tcpdiag_dst[0] = inet->daddr; 127 123 128 - #ifdef CONFIG_IP_TCPDIAG_IPV6 124 + #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) 129 125 if (r->tcpdiag_family == AF_INET6) { 130 126 struct ipv6_pinfo *np = inet6_sk(sk); 131 127 ··· 200 196 return -1; 201 197 } 202 198 203 - #ifdef CONFIG_IP_TCPDIAG_IPV6 204 - extern struct sock *tcp_v6_lookup(struct in6_addr *saddr, u16 sport, 205 - struct in6_addr *daddr, u16 dport, 206 - int dif); 207 - #else 208 - static inline struct sock *tcp_v6_lookup(struct in6_addr *saddr, u16 sport, 209 - struct in6_addr *daddr, u16 dport, 210 - int dif) 211 - { 212 - return NULL; 213 - } 214 - #endif 215 - 216 199 static int tcpdiag_get_exact(struct sk_buff *in_skb, const struct nlmsghdr *nlh) 217 200 { 218 201 int err; ··· 216 225 req->id.tcpdiag_dport, req->id.tcpdiag_src[0], 217 226 req->id.tcpdiag_sport, req->id.tcpdiag_if); 218 227 } 219 - #ifdef CONFIG_IP_TCPDIAG_IPV6 228 + #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) 220 229 else if (req->tcpdiag_family == AF_INET6) { 221 - sk = tcp_v6_lookup((struct in6_addr*)req->id.tcpdiag_dst, req->id.tcpdiag_dport, 222 - (struct in6_addr*)req->id.tcpdiag_src, req->id.tcpdiag_sport, 223 - req->id.tcpdiag_if); 230 + sk = inet6_lookup(hashinfo, 231 + (struct in6_addr*)req->id.tcpdiag_dst, 232 + req->id.tcpdiag_dport, 233 + (struct in6_addr*)req->id.tcpdiag_src, 234 + req->id.tcpdiag_sport, 235 + req->id.tcpdiag_if); 224 236 } 225 237 #endif 226 238 else { ··· 434 440 struct inet_sock *inet = inet_sk(sk); 435 441 436 442 entry.family = sk->sk_family; 437 - #ifdef CONFIG_IP_TCPDIAG_IPV6 443 + #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) 438 444 if (entry.family == AF_INET6) { 439 445 struct ipv6_pinfo *np = inet6_sk(sk); 440 446 ··· 496 502 r->tcpdiag_wqueue = 0; 497 503 r->tcpdiag_uid = sock_i_uid(sk); 498 504 r->tcpdiag_inode = 0; 499 - #ifdef CONFIG_IP_TCPDIAG_IPV6 505 + #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) 500 506 if (r->tcpdiag_family == AF_INET6) { 501 507 ipv6_addr_copy((struct in6_addr *)r->id.tcpdiag_src, 502 508 &tcp6_rsk(req)->loc_addr); ··· 561 567 562 568 if (bc) { 563 569 entry.saddr = 564 - #ifdef CONFIG_IP_TCPDIAG_IPV6 570 + #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) 565 571 (entry.family == AF_INET6) ? 566 572 tcp6_rsk(req)->loc_addr.s6_addr32 : 567 573 #endif 568 574 &ireq->loc_addr; 569 575 entry.daddr = 570 - #ifdef CONFIG_IP_TCPDIAG_IPV6 576 + #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) 571 577 (entry.family == AF_INET6) ? 572 578 tcp6_rsk(req)->rmt_addr.s6_addr32 : 573 579 #endif
+74 -65
net/ipv6/tcp_ipv6.c
··· 76 76 static struct tcp_func ipv6_specific; 77 77 78 78 /* I have no idea if this is a good hash for v6 or not. -DaveM */ 79 - static __inline__ int tcp_v6_hashfn(struct in6_addr *laddr, u16 lport, 80 - struct in6_addr *faddr, u16 fport) 79 + static inline int inet6_ehashfn(const struct in6_addr *laddr, const u16 lport, 80 + const struct in6_addr *faddr, const u16 fport, 81 + const int ehash_size) 81 82 { 82 83 int hashent = (lport ^ fport); 83 84 84 85 hashent ^= (laddr->s6_addr32[3] ^ faddr->s6_addr32[3]); 85 86 hashent ^= hashent>>16; 86 87 hashent ^= hashent>>8; 87 - return (hashent & (tcp_hashinfo.ehash_size - 1)); 88 + return (hashent & (ehash_size - 1)); 88 89 } 89 90 90 - static __inline__ int tcp_v6_sk_hashfn(struct sock *sk) 91 + static inline int inet6_sk_ehashfn(const struct sock *sk, const int ehash_size) 91 92 { 92 - struct inet_sock *inet = inet_sk(sk); 93 - struct ipv6_pinfo *np = inet6_sk(sk); 94 - struct in6_addr *laddr = &np->rcv_saddr; 95 - struct in6_addr *faddr = &np->daddr; 96 - __u16 lport = inet->num; 97 - __u16 fport = inet->dport; 98 - return tcp_v6_hashfn(laddr, lport, faddr, fport); 93 + const struct inet_sock *inet = inet_sk(sk); 94 + const struct ipv6_pinfo *np = inet6_sk(sk); 95 + const struct in6_addr *laddr = &np->rcv_saddr; 96 + const struct in6_addr *faddr = &np->daddr; 97 + const __u16 lport = inet->num; 98 + const __u16 fport = inet->dport; 99 + return inet6_ehashfn(laddr, lport, faddr, fport, ehash_size); 99 100 } 100 101 101 102 static inline int tcp_v6_bind_conflict(const struct sock *sk, ··· 232 231 lock = &tcp_hashinfo.lhash_lock; 233 232 inet_listen_wlock(&tcp_hashinfo); 234 233 } else { 235 - sk->sk_hashent = tcp_v6_sk_hashfn(sk); 234 + sk->sk_hashent = inet6_sk_ehashfn(sk, tcp_hashinfo.ehash_size); 236 235 list = &tcp_hashinfo.ehash[sk->sk_hashent].chain; 237 236 lock = &tcp_hashinfo.ehash[sk->sk_hashent].lock; 238 237 write_lock(lock); ··· 259 258 } 260 259 } 261 260 262 - static struct sock *tcp_v6_lookup_listener(struct in6_addr *daddr, unsigned short hnum, int dif) 261 + static struct sock *inet6_lookup_listener(struct inet_hashinfo *hashinfo, 262 + const struct in6_addr *daddr, 263 + const unsigned short hnum, 264 + const int dif) 263 265 { 264 266 struct sock *sk; 265 267 struct hlist_node *node; ··· 270 266 int score, hiscore; 271 267 272 268 hiscore=0; 273 - read_lock(&tcp_hashinfo.lhash_lock); 274 - sk_for_each(sk, node, &tcp_hashinfo.listening_hash[inet_lhashfn(hnum)]) { 269 + read_lock(&hashinfo->lhash_lock); 270 + sk_for_each(sk, node, &hashinfo->listening_hash[inet_lhashfn(hnum)]) { 275 271 if (inet_sk(sk)->num == hnum && sk->sk_family == PF_INET6) { 276 272 struct ipv6_pinfo *np = inet6_sk(sk); 277 273 ··· 298 294 } 299 295 if (result) 300 296 sock_hold(result); 301 - read_unlock(&tcp_hashinfo.lhash_lock); 297 + read_unlock(&hashinfo->lhash_lock); 302 298 return result; 303 299 } 304 300 ··· 308 304 * The sockhash lock must be held as a reader here. 309 305 */ 310 306 311 - static inline struct sock *__tcp_v6_lookup_established(struct in6_addr *saddr, u16 sport, 312 - struct in6_addr *daddr, u16 hnum, 313 - int dif) 307 + static inline struct sock * 308 + __inet6_lookup_established(struct inet_hashinfo *hashinfo, 309 + const struct in6_addr *saddr, 310 + const u16 sport, 311 + const struct in6_addr *daddr, 312 + const u16 hnum, 313 + const int dif) 314 314 { 315 315 struct sock *sk; 316 316 const struct hlist_node *node; ··· 322 314 /* Optimize here for direct hit, only listening connections can 323 315 * have wildcards anyways. 324 316 */ 325 - const int hash = tcp_v6_hashfn(daddr, hnum, saddr, sport); 326 - struct inet_ehash_bucket *head = &tcp_hashinfo.ehash[hash]; 317 + const int hash = inet6_ehashfn(daddr, hnum, saddr, sport, 318 + hashinfo->ehash_size); 319 + struct inet_ehash_bucket *head = &hashinfo->ehash[hash]; 327 320 328 321 read_lock(&head->lock); 329 322 sk_for_each(sk, node, &head->chain) { ··· 333 324 goto hit; /* You sunk my battleship! */ 334 325 } 335 326 /* Must check for a TIME_WAIT'er before going to listener hash. */ 336 - sk_for_each(sk, node, &(head + tcp_hashinfo.ehash_size)->chain) { 327 + sk_for_each(sk, node, &(head + hashinfo->ehash_size)->chain) { 337 328 const struct inet_timewait_sock *tw = inet_twsk(sk); 338 329 339 330 if(*((__u32 *)&(tw->tw_dport)) == ports && ··· 356 347 } 357 348 358 349 359 - static inline struct sock *__tcp_v6_lookup(struct in6_addr *saddr, u16 sport, 360 - struct in6_addr *daddr, u16 hnum, 361 - int dif) 350 + static inline struct sock *__inet6_lookup(struct inet_hashinfo *hashinfo, 351 + const struct in6_addr *saddr, 352 + const u16 sport, 353 + const struct in6_addr *daddr, 354 + const u16 hnum, 355 + const int dif) 362 356 { 363 - struct sock *sk; 364 - 365 - sk = __tcp_v6_lookup_established(saddr, sport, daddr, hnum, dif); 366 - 357 + struct sock *sk = __inet6_lookup_established(hashinfo, saddr, sport, 358 + daddr, hnum, dif); 367 359 if (sk) 368 360 return sk; 369 361 370 - return tcp_v6_lookup_listener(daddr, hnum, dif); 362 + return inet6_lookup_listener(hashinfo, daddr, hnum, dif); 371 363 } 372 364 373 - inline struct sock *tcp_v6_lookup(struct in6_addr *saddr, u16 sport, 374 - struct in6_addr *daddr, u16 dport, 375 - int dif) 365 + inline struct sock *inet6_lookup(struct inet_hashinfo *hashinfo, 366 + const struct in6_addr *saddr, const u16 sport, 367 + const struct in6_addr *daddr, const u16 dport, 368 + const int dif) 376 369 { 377 370 struct sock *sk; 378 371 379 372 local_bh_disable(); 380 - sk = __tcp_v6_lookup(saddr, sport, daddr, ntohs(dport), dif); 373 + sk = __inet6_lookup(hashinfo, saddr, sport, daddr, ntohs(dport), dif); 381 374 local_bh_enable(); 382 375 383 376 return sk; 384 377 } 385 378 386 - EXPORT_SYMBOL_GPL(tcp_v6_lookup); 379 + EXPORT_SYMBOL_GPL(inet6_lookup); 387 380 388 381 389 382 /* ··· 465 454 } 466 455 } 467 456 468 - static int __tcp_v6_check_established(struct sock *sk, __u16 lport, 457 + static int __tcp_v6_check_established(struct sock *sk, const __u16 lport, 469 458 struct inet_timewait_sock **twp) 470 459 { 471 460 struct inet_sock *inet = inet_sk(sk); 472 - struct ipv6_pinfo *np = inet6_sk(sk); 473 - struct in6_addr *daddr = &np->rcv_saddr; 474 - struct in6_addr *saddr = &np->daddr; 475 - int dif = sk->sk_bound_dev_if; 461 + const struct ipv6_pinfo *np = inet6_sk(sk); 462 + const struct in6_addr *daddr = &np->rcv_saddr; 463 + const struct in6_addr *saddr = &np->daddr; 464 + const int dif = sk->sk_bound_dev_if; 476 465 const u32 ports = INET_COMBINED_PORTS(inet->dport, lport); 477 - const int hash = tcp_v6_hashfn(daddr, inet->num, saddr, inet->dport); 466 + const int hash = inet6_ehashfn(daddr, inet->num, saddr, inet->dport, 467 + tcp_hashinfo.ehash_size); 478 468 struct inet_ehash_bucket *head = &tcp_hashinfo.ehash[hash]; 479 469 struct sock *sk2; 480 470 const struct hlist_node *node; ··· 647 635 local_bh_enable(); 648 636 return ret; 649 637 } 650 - } 651 - 652 - static __inline__ int tcp_v6_iif(struct sk_buff *skb) 653 - { 654 - return IP6CB(skb)->iif; 655 638 } 656 639 657 640 static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, ··· 840 833 int type, int code, int offset, __u32 info) 841 834 { 842 835 struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data; 843 - struct tcphdr *th = (struct tcphdr *)(skb->data+offset); 836 + const struct tcphdr *th = (struct tcphdr *)(skb->data+offset); 844 837 struct ipv6_pinfo *np; 845 838 struct sock *sk; 846 839 int err; 847 840 struct tcp_sock *tp; 848 841 __u32 seq; 849 842 850 - sk = tcp_v6_lookup(&hdr->daddr, th->dest, &hdr->saddr, th->source, skb->dev->ifindex); 843 + sk = inet6_lookup(&tcp_hashinfo, &hdr->daddr, th->dest, &hdr->saddr, 844 + th->source, skb->dev->ifindex); 851 845 852 846 if (sk == NULL) { 853 847 ICMP6_INC_STATS_BH(__in6_dev_get(skb->dev), ICMP6_MIB_INERRORS); ··· 935 927 goto out; 936 928 937 929 req = tcp_v6_search_req(sk, &prev, th->dest, &hdr->daddr, 938 - &hdr->saddr, tcp_v6_iif(skb)); 930 + &hdr->saddr, inet6_iif(skb)); 939 931 if (!req) 940 932 goto out; 941 933 ··· 1146 1138 buff->csum); 1147 1139 1148 1140 fl.proto = IPPROTO_TCP; 1149 - fl.oif = tcp_v6_iif(skb); 1141 + fl.oif = inet6_iif(skb); 1150 1142 fl.fl_ip_dport = t1->dest; 1151 1143 fl.fl_ip_sport = t1->source; 1152 1144 ··· 1215 1207 buff->csum); 1216 1208 1217 1209 fl.proto = IPPROTO_TCP; 1218 - fl.oif = tcp_v6_iif(skb); 1210 + fl.oif = inet6_iif(skb); 1219 1211 fl.fl_ip_dport = t1->dest; 1220 1212 fl.fl_ip_sport = t1->source; 1221 1213 ··· 1253 1245 static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb) 1254 1246 { 1255 1247 struct request_sock *req, **prev; 1256 - struct tcphdr *th = skb->h.th; 1248 + const struct tcphdr *th = skb->h.th; 1257 1249 struct sock *nsk; 1258 1250 1259 1251 /* Find possible connection requests. */ 1260 1252 req = tcp_v6_search_req(sk, &prev, th->source, &skb->nh.ipv6h->saddr, 1261 - &skb->nh.ipv6h->daddr, tcp_v6_iif(skb)); 1253 + &skb->nh.ipv6h->daddr, inet6_iif(skb)); 1262 1254 if (req) 1263 1255 return tcp_check_req(sk, skb, req, prev); 1264 1256 1265 - nsk = __tcp_v6_lookup_established(&skb->nh.ipv6h->saddr, 1266 - th->source, 1267 - &skb->nh.ipv6h->daddr, 1268 - ntohs(th->dest), 1269 - tcp_v6_iif(skb)); 1257 + nsk = __inet6_lookup_established(&tcp_hashinfo, &skb->nh.ipv6h->saddr, 1258 + th->source, &skb->nh.ipv6h->daddr, 1259 + ntohs(th->dest), inet6_iif(skb)); 1270 1260 1271 1261 if (nsk) { 1272 1262 if (nsk->sk_state != TCP_TIME_WAIT) { ··· 1352 1346 /* So that link locals have meaning */ 1353 1347 if (!sk->sk_bound_dev_if && 1354 1348 ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL) 1355 - treq->iif = tcp_v6_iif(skb); 1349 + treq->iif = inet6_iif(skb); 1356 1350 1357 1351 if (isn == 0) 1358 1352 isn = tcp_v6_init_sequence(sk,skb); ··· 1417 1411 newsk->sk_backlog_rcv = tcp_v4_do_rcv; 1418 1412 newnp->pktoptions = NULL; 1419 1413 newnp->opt = NULL; 1420 - newnp->mcast_oif = tcp_v6_iif(skb); 1414 + newnp->mcast_oif = inet6_iif(skb); 1421 1415 newnp->mcast_hops = skb->nh.ipv6h->hop_limit; 1422 1416 1423 1417 /* ··· 1522 1516 skb_set_owner_r(newnp->pktoptions, newsk); 1523 1517 } 1524 1518 newnp->opt = NULL; 1525 - newnp->mcast_oif = tcp_v6_iif(skb); 1519 + newnp->mcast_oif = inet6_iif(skb); 1526 1520 newnp->mcast_hops = skb->nh.ipv6h->hop_limit; 1527 1521 1528 1522 /* Clone native IPv6 options from listening socket (if any) ··· 1697 1691 if (TCP_SKB_CB(opt_skb)->end_seq == tp->rcv_nxt && 1698 1692 !((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN))) { 1699 1693 if (np->rxopt.bits.rxinfo) 1700 - np->mcast_oif = tcp_v6_iif(opt_skb); 1694 + np->mcast_oif = inet6_iif(opt_skb); 1701 1695 if (np->rxopt.bits.rxhlim) 1702 1696 np->mcast_hops = opt_skb->nh.ipv6h->hop_limit; 1703 1697 if (ipv6_opt_accepted(sk, opt_skb)) { ··· 1752 1746 TCP_SKB_CB(skb)->flags = ipv6_get_dsfield(skb->nh.ipv6h); 1753 1747 TCP_SKB_CB(skb)->sacked = 0; 1754 1748 1755 - sk = __tcp_v6_lookup(&skb->nh.ipv6h->saddr, th->source, 1756 - &skb->nh.ipv6h->daddr, ntohs(th->dest), tcp_v6_iif(skb)); 1749 + sk = __inet6_lookup(&tcp_hashinfo, &skb->nh.ipv6h->saddr, th->source, 1750 + &skb->nh.ipv6h->daddr, ntohs(th->dest), 1751 + inet6_iif(skb)); 1757 1752 1758 1753 if (!sk) 1759 1754 goto no_tcp_socket; ··· 1825 1818 { 1826 1819 struct sock *sk2; 1827 1820 1828 - sk2 = tcp_v6_lookup_listener(&skb->nh.ipv6h->daddr, ntohs(th->dest), tcp_v6_iif(skb)); 1821 + sk2 = inet6_lookup_listener(&tcp_hashinfo, 1822 + &skb->nh.ipv6h->daddr, 1823 + ntohs(th->dest), inet6_iif(skb)); 1829 1824 if (sk2 != NULL) { 1830 1825 struct inet_timewait_sock *tw = inet_twsk(sk); 1831 1826 inet_twsk_deschedule(tw, &tcp_death_row);