]>
Commit | Line | Data |
---|---|---|
10679586 | 1 | # This is a BitKeeper generated patch for the following project: |
2 | # Project Name: Linux kernel tree | |
3 | # This patch format is intended for GNU patch command version 2.5 or higher. | |
4 | # This patch includes the following deltas: | |
5 | # ChangeSet 1.1226 -> 1.1229 | |
6 | # include/linux/sysctl.h 1.23 -> 1.24 | |
7 | # net/ipv6/tcp_ipv6.c 1.23 -> 1.24 | |
8 | # net/ipv6/af_inet6.c 1.9 -> 1.10 | |
9 | # net/ipv4/af_inet.c 1.10 -> 1.11 | |
10 | # net/ipv4/ip_fragment.c 1.6 -> 1.8 | |
11 | # net/ipv6/reassembly.c 1.6 -> 1.7 | |
12 | # include/net/transp_v6.h 1.1 -> 1.2 | |
13 | # net/ipv4/sysctl_net_ipv4.c 1.8 -> 1.9 | |
14 | # | |
15 | # The following is the BitKeeper ChangeSet Log | |
16 | # -------------------------------------------- | |
17 | # 03/05/27 davem@nuts.ninka.net 1.1227 | |
18 | # [IPV4/IPV6]: Use Jenkins hash for fragment reassembly handling. | |
19 | # -------------------------------------------- | |
20 | # 03/05/27 davem@nuts.ninka.net 1.1228 | |
21 | # [IPV6]: Input full addresses into TCP_SYNQ hash function. | |
22 | # -------------------------------------------- | |
23 | # 03/05/28 davem@nuts.ninka.net 1.1229 | |
24 | # [IPV4]: Add sysctl to control ipfrag_secret_interval. | |
25 | # -------------------------------------------- | |
26 | # | |
27 | diff -Nru a/include/linux/sysctl.h b/include/linux/sysctl.h | |
28 | --- a/include/linux/sysctl.h Wed May 28 01:21:40 2003 | |
29 | +++ b/include/linux/sysctl.h Wed May 28 01:21:40 2003 | |
30 | @@ -295,7 +295,8 @@ | |
31 | NET_IPV4_NONLOCAL_BIND=88, | |
32 | NET_IPV4_ICMP_RATELIMIT=89, | |
33 | NET_IPV4_ICMP_RATEMASK=90, | |
34 | - NET_TCP_TW_REUSE=91 | |
35 | + NET_TCP_TW_REUSE=91, | |
36 | + NET_IPV4_IPFRAG_SECRET_INTERVAL=94 | |
37 | }; | |
38 | ||
39 | enum { | |
40 | diff -Nru a/include/net/transp_v6.h b/include/net/transp_v6.h | |
41 | --- a/include/net/transp_v6.h Wed May 28 01:21:40 2003 | |
42 | +++ b/include/net/transp_v6.h Wed May 28 01:21:40 2003 | |
43 | @@ -15,6 +15,8 @@ | |
44 | ||
45 | struct flowi; | |
46 | ||
47 | +extern void ipv6_frag_init(void); | |
48 | + | |
49 | extern void rawv6_init(void); | |
50 | extern void udpv6_init(void); | |
51 | extern void tcpv6_init(void); | |
52 | diff -Nru a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c | |
53 | --- a/net/ipv4/af_inet.c Wed May 28 01:21:40 2003 | |
54 | +++ b/net/ipv4/af_inet.c Wed May 28 01:21:40 2003 | |
55 | @@ -1100,6 +1100,7 @@ | |
56 | } | |
57 | } | |
58 | ||
59 | +extern void ipfrag_init(void); | |
60 | ||
61 | /* | |
62 | * Called by socket.c on kernel startup. | |
63 | @@ -1196,6 +1197,9 @@ | |
64 | proc_net_create ("tcp", 0, tcp_get_info); | |
65 | proc_net_create ("udp", 0, udp_get_info); | |
66 | #endif /* CONFIG_PROC_FS */ | |
67 | + | |
68 | + ipfrag_init(); | |
69 | + | |
70 | return 0; | |
71 | } | |
72 | module_init(inet_init); | |
73 | diff -Nru a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c | |
74 | --- a/net/ipv4/ip_fragment.c Wed May 28 01:21:40 2003 | |
75 | +++ b/net/ipv4/ip_fragment.c Wed May 28 01:21:40 2003 | |
76 | @@ -31,6 +31,8 @@ | |
77 | #include <linux/ip.h> | |
78 | #include <linux/icmp.h> | |
79 | #include <linux/netdevice.h> | |
80 | +#include <linux/jhash.h> | |
81 | +#include <linux/random.h> | |
82 | #include <net/sock.h> | |
83 | #include <net/ip.h> | |
84 | #include <net/icmp.h> | |
85 | @@ -97,6 +99,7 @@ | |
86 | /* Per-bucket lock is easy to add now. */ | |
87 | static struct ipq *ipq_hash[IPQ_HASHSZ]; | |
88 | static rwlock_t ipfrag_lock = RW_LOCK_UNLOCKED; | |
89 | +static u32 ipfrag_hash_rnd; | |
90 | int ip_frag_nqueues = 0; | |
91 | ||
92 | static __inline__ void __ipq_unlink(struct ipq *qp) | |
93 | @@ -116,21 +119,51 @@ | |
94 | write_unlock(&ipfrag_lock); | |
95 | } | |
96 | ||
97 | -/* | |
98 | - * Was: ((((id) >> 1) ^ (saddr) ^ (daddr) ^ (prot)) & (IPQ_HASHSZ - 1)) | |
99 | - * | |
100 | - * I see, I see evil hand of bigendian mafia. On Intel all the packets hit | |
101 | - * one hash bucket with this hash function. 8) | |
102 | - */ | |
103 | -static __inline__ unsigned int ipqhashfn(u16 id, u32 saddr, u32 daddr, u8 prot) | |
104 | +static unsigned int ipqhashfn(u16 id, u32 saddr, u32 daddr, u8 prot) | |
105 | { | |
106 | - unsigned int h = saddr ^ daddr; | |
107 | - | |
108 | - h ^= (h>>16)^id; | |
109 | - h ^= (h>>8)^prot; | |
110 | - return h & (IPQ_HASHSZ - 1); | |
111 | + return jhash_3words((u32)id << 16 | prot, saddr, daddr, | |
112 | + ipfrag_hash_rnd) & (IPQ_HASHSZ - 1); | |
113 | } | |
114 | ||
115 | +static struct timer_list ipfrag_secret_timer; | |
116 | +int sysctl_ipfrag_secret_interval = 10 * 60 * HZ; | |
117 | + | |
118 | +static void ipfrag_secret_rebuild(unsigned long dummy) | |
119 | +{ | |
120 | + unsigned long now = jiffies; | |
121 | + int i; | |
122 | + | |
123 | + write_lock(&ipfrag_lock); | |
124 | + get_random_bytes(&ipfrag_hash_rnd, sizeof(u32)); | |
125 | + for (i = 0; i < IPQ_HASHSZ; i++) { | |
126 | + struct ipq *q; | |
127 | + | |
128 | + q = ipq_hash[i]; | |
129 | + while (q) { | |
130 | + struct ipq *next = q->next; | |
131 | + unsigned int hval = ipqhashfn(q->id, q->saddr, | |
132 | + q->daddr, q->protocol); | |
133 | + | |
134 | + if (hval != i) { | |
135 | + /* Unlink. */ | |
136 | + if (q->next) | |
137 | + q->next->pprev = q->pprev; | |
138 | + *q->pprev = q->next; | |
139 | + | |
140 | + /* Relink to new hash chain. */ | |
141 | + if ((q->next = ipq_hash[hval]) != NULL) | |
142 | + q->next->pprev = &q->next; | |
143 | + ipq_hash[hval] = q; | |
144 | + q->pprev = &ipq_hash[hval]; | |
145 | + } | |
146 | + | |
147 | + q = next; | |
148 | + } | |
149 | + } | |
150 | + write_unlock(&ipfrag_lock); | |
151 | + | |
152 | + mod_timer(&ipfrag_secret_timer, now + sysctl_ipfrag_secret_interval); | |
153 | +} | |
154 | ||
155 | atomic_t ip_frag_mem = ATOMIC_INIT(0); /* Memory used for fragments */ | |
156 | ||
157 | @@ -630,4 +663,15 @@ | |
158 | IP_INC_STATS_BH(IpReasmFails); | |
159 | kfree_skb(skb); | |
160 | return NULL; | |
161 | +} | |
162 | + | |
163 | +void ipfrag_init(void) | |
164 | +{ | |
165 | + ipfrag_hash_rnd = (u32) ((num_physpages ^ (num_physpages>>7)) ^ | |
166 | + (jiffies ^ (jiffies >> 6))); | |
167 | + | |
168 | + init_timer(&ipfrag_secret_timer); | |
169 | + ipfrag_secret_timer.function = ipfrag_secret_rebuild; | |
170 | + ipfrag_secret_timer.expires = jiffies + sysctl_ipfrag_secret_interval; | |
171 | + add_timer(&ipfrag_secret_timer); | |
172 | } | |
173 | diff -Nru a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c | |
174 | --- a/net/ipv4/sysctl_net_ipv4.c Wed May 28 01:21:40 2003 | |
175 | +++ b/net/ipv4/sysctl_net_ipv4.c Wed May 28 01:21:40 2003 | |
176 | @@ -27,6 +27,7 @@ | |
177 | extern int sysctl_ipfrag_low_thresh; | |
178 | extern int sysctl_ipfrag_high_thresh; | |
179 | extern int sysctl_ipfrag_time; | |
180 | +extern int sysctl_ipfrag_secret_interval; | |
181 | ||
182 | /* From ip_output.c */ | |
183 | extern int sysctl_ip_dynaddr; | |
184 | @@ -225,6 +226,9 @@ | |
185 | &sysctl_icmp_ratemask, sizeof(int), 0644, NULL, &proc_dointvec}, | |
186 | {NET_TCP_TW_REUSE, "tcp_tw_reuse", | |
187 | &sysctl_tcp_tw_reuse, sizeof(int), 0644, NULL, &proc_dointvec}, | |
188 | + {NET_IPV4_IPFRAG_SECRET_INTERVAL, "ipfrag_secret_interval", | |
189 | + &sysctl_ipfrag_secret_interval, sizeof(int), 0644, NULL, &proc_dointvec_jiffies, | |
190 | + &sysctl_jiffies}, | |
191 | {0} | |
192 | }; | |
193 | ||
194 | diff -Nru a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c | |
195 | --- a/net/ipv6/af_inet6.c Wed May 28 01:21:40 2003 | |
196 | +++ b/net/ipv6/af_inet6.c Wed May 28 01:21:40 2003 | |
197 | @@ -671,6 +671,7 @@ | |
198 | ip6_flowlabel_init(); | |
199 | addrconf_init(); | |
200 | sit_init(); | |
201 | + ipv6_frag_init(); | |
202 | ||
203 | /* Init v6 transport protocols. */ | |
204 | udpv6_init(); | |
205 | diff -Nru a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c | |
206 | --- a/net/ipv6/reassembly.c Wed May 28 01:21:40 2003 | |
207 | +++ b/net/ipv6/reassembly.c Wed May 28 01:21:40 2003 | |
208 | @@ -37,6 +37,8 @@ | |
209 | #include <linux/in6.h> | |
210 | #include <linux/ipv6.h> | |
211 | #include <linux/icmpv6.h> | |
212 | +#include <linux/random.h> | |
213 | +#include <linux/jhash.h> | |
214 | ||
215 | #include <net/sock.h> | |
216 | #include <net/snmp.h> | |
217 | @@ -98,6 +100,7 @@ | |
218 | ||
219 | static struct frag_queue *ip6_frag_hash[IP6Q_HASHSZ]; | |
220 | static rwlock_t ip6_frag_lock = RW_LOCK_UNLOCKED; | |
221 | +static u32 ip6_frag_hash_rnd; | |
222 | int ip6_frag_nqueues = 0; | |
223 | ||
224 | static __inline__ void __fq_unlink(struct frag_queue *fq) | |
225 | @@ -117,16 +120,73 @@ | |
226 | write_unlock(&ip6_frag_lock); | |
227 | } | |
228 | ||
229 | -static __inline__ unsigned int ip6qhashfn(u32 id, struct in6_addr *saddr, | |
230 | - struct in6_addr *daddr) | |
231 | +static unsigned int ip6qhashfn(u32 id, struct in6_addr *saddr, | |
232 | + struct in6_addr *daddr) | |
233 | { | |
234 | - unsigned int h = saddr->s6_addr32[3] ^ daddr->s6_addr32[3] ^ id; | |
235 | + u32 a, b, c; | |
236 | ||
237 | - h ^= (h>>16); | |
238 | - h ^= (h>>8); | |
239 | - return h & (IP6Q_HASHSZ - 1); | |
240 | + a = saddr->s6_addr32[0]; | |
241 | + b = saddr->s6_addr32[1]; | |
242 | + c = saddr->s6_addr32[2]; | |
243 | + | |
244 | + a += JHASH_GOLDEN_RATIO; | |
245 | + b += JHASH_GOLDEN_RATIO; | |
246 | + c += ip6_frag_hash_rnd; | |
247 | + __jhash_mix(a, b, c); | |
248 | + | |
249 | + a += saddr->s6_addr32[3]; | |
250 | + b += daddr->s6_addr32[0]; | |
251 | + c += daddr->s6_addr32[1]; | |
252 | + __jhash_mix(a, b, c); | |
253 | + | |
254 | + a += daddr->s6_addr32[2]; | |
255 | + b += daddr->s6_addr32[3]; | |
256 | + c += id; | |
257 | + __jhash_mix(a, b, c); | |
258 | + | |
259 | + return c & (IP6Q_HASHSZ - 1); | |
260 | } | |
261 | ||
262 | +static struct timer_list ip6_frag_secret_timer; | |
263 | +static int ip6_frag_secret_interval = 10 * 60 * HZ; | |
264 | + | |
265 | +static void ip6_frag_secret_rebuild(unsigned long dummy) | |
266 | +{ | |
267 | + unsigned long now = jiffies; | |
268 | + int i; | |
269 | + | |
270 | + write_lock(&ip6_frag_lock); | |
271 | + get_random_bytes(&ip6_frag_hash_rnd, sizeof(u32)); | |
272 | + for (i = 0; i < IP6Q_HASHSZ; i++) { | |
273 | + struct frag_queue *q; | |
274 | + | |
275 | + q = ip6_frag_hash[i]; | |
276 | + while (q) { | |
277 | + struct frag_queue *next = q->next; | |
278 | + unsigned int hval = ip6qhashfn(q->id, | |
279 | + &q->saddr, | |
280 | + &q->daddr); | |
281 | + | |
282 | + if (hval != i) { | |
283 | + /* Unlink. */ | |
284 | + if (q->next) | |
285 | + q->next->pprev = q->pprev; | |
286 | + *q->pprev = q->next; | |
287 | + | |
288 | + /* Relink to new hash chain. */ | |
289 | + if ((q->next = ip6_frag_hash[hval]) != NULL) | |
290 | + q->next->pprev = &q->next; | |
291 | + ip6_frag_hash[hval] = q; | |
292 | + q->pprev = &ip6_frag_hash[hval]; | |
293 | + } | |
294 | + | |
295 | + q = next; | |
296 | + } | |
297 | + } | |
298 | + write_unlock(&ip6_frag_lock); | |
299 | + | |
300 | + mod_timer(&ip6_frag_secret_timer, now + ip6_frag_secret_interval); | |
301 | +} | |
302 | ||
303 | atomic_t ip6_frag_mem = ATOMIC_INIT(0); | |
304 | ||
305 | @@ -680,4 +740,15 @@ | |
306 | IP6_INC_STATS_BH(Ip6ReasmFails); | |
307 | kfree_skb(skb); | |
308 | return -1; | |
309 | +} | |
310 | + | |
311 | +void __init ipv6_frag_init(void) | |
312 | +{ | |
313 | + ip6_frag_hash_rnd = (u32) ((num_physpages ^ (num_physpages>>7)) ^ | |
314 | + (jiffies ^ (jiffies >> 6))); | |
315 | + | |
316 | + init_timer(&ip6_frag_secret_timer); | |
317 | + ip6_frag_secret_timer.function = ip6_frag_secret_rebuild; | |
318 | + ip6_frag_secret_timer.expires = jiffies + ip6_frag_secret_interval; | |
319 | + add_timer(&ip6_frag_secret_timer); | |
320 | } | |
321 | diff -Nru a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c | |
322 | --- a/net/ipv6/tcp_ipv6.c Wed May 28 01:21:40 2003 | |
323 | +++ b/net/ipv6/tcp_ipv6.c Wed May 28 01:21:40 2003 | |
324 | @@ -371,9 +371,22 @@ | |
325 | ||
326 | static u32 tcp_v6_synq_hash(struct in6_addr *raddr, u16 rport, u32 rnd) | |
327 | { | |
328 | - return (jhash_3words(raddr->s6_addr32[0] ^ raddr->s6_addr32[1], | |
329 | - raddr->s6_addr32[2] ^ raddr->s6_addr32[3], | |
330 | - (u32) rport, rnd) & (TCP_SYNQ_HSIZE - 1)); | |
331 | + u32 a, b, c; | |
332 | + | |
333 | + a = raddr->s6_addr32[0]; | |
334 | + b = raddr->s6_addr32[1]; | |
335 | + c = raddr->s6_addr32[2]; | |
336 | + | |
337 | + a += JHASH_GOLDEN_RATIO; | |
338 | + b += JHASH_GOLDEN_RATIO; | |
339 | + c += rnd; | |
340 | + __jhash_mix(a, b, c); | |
341 | + | |
342 | + a += raddr->s6_addr32[3]; | |
343 | + b += (u32) rport; | |
344 | + __jhash_mix(a, b, c); | |
345 | + | |
346 | + return c & (TCP_SYNQ_HSIZE - 1); | |
347 | } | |
348 | ||
349 | static struct open_request *tcp_v6_search_req(struct tcp_opt *tp, |