]> git.pld-linux.org Git - packages/kernel.git/blame - linux-2.4.20-nethashfix2.patch
- obsolete
[packages/kernel.git] / linux-2.4.20-nethashfix2.patch
CommitLineData
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#
27diff -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 {
40diff -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);
52diff -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);
73diff -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 }
173diff -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
194diff -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();
205diff -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 }
321diff -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,
This page took 0.152815 seconds and 4 git commands to generate.