diff options
-rw-r--r-- | include/net/inet6_hashtables.h | 70 | ||||
-rw-r--r-- | net/ipv6/inet6_hashtables.c | 80 |
2 files changed, 83 insertions, 67 deletions
diff --git a/include/net/inet6_hashtables.h b/include/net/inet6_hashtables.h index 25f708ff020e..59f0c83d55a2 100644 --- a/include/net/inet6_hashtables.h +++ b/include/net/inet6_hashtables.h | |||
@@ -48,31 +48,7 @@ static inline int inet6_sk_ehashfn(const struct sock *sk) | |||
48 | return inet6_ehashfn(laddr, lport, faddr, fport); | 48 | return inet6_ehashfn(laddr, lport, faddr, fport); |
49 | } | 49 | } |
50 | 50 | ||
51 | static inline void __inet6_hash(struct inet_hashinfo *hashinfo, | 51 | extern void __inet6_hash(struct inet_hashinfo *hashinfo, struct sock *sk); |
52 | struct sock *sk) | ||
53 | { | ||
54 | struct hlist_head *list; | ||
55 | rwlock_t *lock; | ||
56 | |||
57 | BUG_TRAP(sk_unhashed(sk)); | ||
58 | |||
59 | if (sk->sk_state == TCP_LISTEN) { | ||
60 | list = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)]; | ||
61 | lock = &hashinfo->lhash_lock; | ||
62 | inet_listen_wlock(hashinfo); | ||
63 | } else { | ||
64 | unsigned int hash; | ||
65 | sk->sk_hash = hash = inet6_sk_ehashfn(sk); | ||
66 | hash &= (hashinfo->ehash_size - 1); | ||
67 | list = &hashinfo->ehash[hash].chain; | ||
68 | lock = &hashinfo->ehash[hash].lock; | ||
69 | write_lock(lock); | ||
70 | } | ||
71 | |||
72 | __sk_add_node(sk, list); | ||
73 | sock_prot_inc_use(sk->sk_prot); | ||
74 | write_unlock(lock); | ||
75 | } | ||
76 | 52 | ||
77 | /* | 53 | /* |
78 | * Sockets in TCP_CLOSE state are _always_ taken out of the hash, so | 54 | * Sockets in TCP_CLOSE state are _always_ taken out of the hash, so |
@@ -80,52 +56,12 @@ static inline void __inet6_hash(struct inet_hashinfo *hashinfo, | |||
80 | * | 56 | * |
81 | * The sockhash lock must be held as a reader here. | 57 | * The sockhash lock must be held as a reader here. |
82 | */ | 58 | */ |
83 | static inline struct sock * | 59 | extern struct sock *__inet6_lookup_established(struct inet_hashinfo *hashinfo, |
84 | __inet6_lookup_established(struct inet_hashinfo *hashinfo, | ||
85 | const struct in6_addr *saddr, | 60 | const struct in6_addr *saddr, |
86 | const u16 sport, | 61 | const u16 sport, |
87 | const struct in6_addr *daddr, | 62 | const struct in6_addr *daddr, |
88 | const u16 hnum, | 63 | const u16 hnum, |
89 | const int dif) | 64 | const int dif); |
90 | { | ||
91 | struct sock *sk; | ||
92 | const struct hlist_node *node; | ||
93 | const __u32 ports = INET_COMBINED_PORTS(sport, hnum); | ||
94 | /* Optimize here for direct hit, only listening connections can | ||
95 | * have wildcards anyways. | ||
96 | */ | ||
97 | unsigned int hash = inet6_ehashfn(daddr, hnum, saddr, sport); | ||
98 | struct inet_ehash_bucket *head = inet_ehash_bucket(hashinfo, hash); | ||
99 | |||
100 | prefetch(head->chain.first); | ||
101 | read_lock(&head->lock); | ||
102 | sk_for_each(sk, node, &head->chain) { | ||
103 | /* For IPV6 do the cheaper port and family tests first. */ | ||
104 | if (INET6_MATCH(sk, hash, saddr, daddr, ports, dif)) | ||
105 | goto hit; /* You sunk my battleship! */ | ||
106 | } | ||
107 | /* Must check for a TIME_WAIT'er before going to listener hash. */ | ||
108 | sk_for_each(sk, node, &(head + hashinfo->ehash_size)->chain) { | ||
109 | const struct inet_timewait_sock *tw = inet_twsk(sk); | ||
110 | |||
111 | if(*((__u32 *)&(tw->tw_dport)) == ports && | ||
112 | sk->sk_family == PF_INET6) { | ||
113 | const struct inet6_timewait_sock *tw6 = inet6_twsk(sk); | ||
114 | |||
115 | if (ipv6_addr_equal(&tw6->tw_v6_daddr, saddr) && | ||
116 | ipv6_addr_equal(&tw6->tw_v6_rcv_saddr, daddr) && | ||
117 | (!sk->sk_bound_dev_if || sk->sk_bound_dev_if == dif)) | ||
118 | goto hit; | ||
119 | } | ||
120 | } | ||
121 | read_unlock(&head->lock); | ||
122 | return NULL; | ||
123 | |||
124 | hit: | ||
125 | sock_hold(sk); | ||
126 | read_unlock(&head->lock); | ||
127 | return sk; | ||
128 | } | ||
129 | 65 | ||
130 | extern struct sock *inet6_lookup_listener(struct inet_hashinfo *hashinfo, | 66 | extern struct sock *inet6_lookup_listener(struct inet_hashinfo *hashinfo, |
131 | const struct in6_addr *daddr, | 67 | const struct in6_addr *daddr, |
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index bb8ffb8a14c5..2ae84c961678 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c | |||
@@ -23,6 +23,86 @@ | |||
23 | #include <net/inet6_hashtables.h> | 23 | #include <net/inet6_hashtables.h> |
24 | #include <net/ip.h> | 24 | #include <net/ip.h> |
25 | 25 | ||
26 | void __inet6_hash(struct inet_hashinfo *hashinfo, | ||
27 | struct sock *sk) | ||
28 | { | ||
29 | struct hlist_head *list; | ||
30 | rwlock_t *lock; | ||
31 | |||
32 | BUG_TRAP(sk_unhashed(sk)); | ||
33 | |||
34 | if (sk->sk_state == TCP_LISTEN) { | ||
35 | list = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)]; | ||
36 | lock = &hashinfo->lhash_lock; | ||
37 | inet_listen_wlock(hashinfo); | ||
38 | } else { | ||
39 | unsigned int hash; | ||
40 | sk->sk_hash = hash = inet6_sk_ehashfn(sk); | ||
41 | hash &= (hashinfo->ehash_size - 1); | ||
42 | list = &hashinfo->ehash[hash].chain; | ||
43 | lock = &hashinfo->ehash[hash].lock; | ||
44 | write_lock(lock); | ||
45 | } | ||
46 | |||
47 | __sk_add_node(sk, list); | ||
48 | sock_prot_inc_use(sk->sk_prot); | ||
49 | write_unlock(lock); | ||
50 | } | ||
51 | EXPORT_SYMBOL(__inet6_hash); | ||
52 | |||
53 | /* | ||
54 | * Sockets in TCP_CLOSE state are _always_ taken out of the hash, so | ||
55 | * we need not check it for TCP lookups anymore, thanks Alexey. -DaveM | ||
56 | * | ||
57 | * The sockhash lock must be held as a reader here. | ||
58 | */ | ||
59 | struct sock *__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 | unsigned int hash = inet6_ehashfn(daddr, hnum, saddr, sport); | ||
73 | struct inet_ehash_bucket *head = inet_ehash_bucket(hashinfo, hash); | ||
74 | |||
75 | prefetch(head->chain.first); | ||
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, hash, 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 inet6_timewait_sock *tw6 = inet6_twsk(sk); | ||
89 | |||
90 | if (ipv6_addr_equal(&tw6->tw_v6_daddr, saddr) && | ||
91 | ipv6_addr_equal(&tw6->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 | EXPORT_SYMBOL(__inet6_lookup_established); | ||
105 | |||
26 | struct sock *inet6_lookup_listener(struct inet_hashinfo *hashinfo, | 106 | struct sock *inet6_lookup_listener(struct inet_hashinfo *hashinfo, |
27 | const struct in6_addr *daddr, | 107 | const struct in6_addr *daddr, |
28 | const unsigned short hnum, const int dif) | 108 | const unsigned short hnum, const int dif) |