diff options
-rw-r--r-- | include/net/flow.h | 19 | ||||
-rw-r--r-- | net/core/flow.c | 31 |
2 files changed, 36 insertions, 14 deletions
diff --git a/include/net/flow.h b/include/net/flow.h index 2ec377d9ab9f..a09447749e2d 100644 --- a/include/net/flow.h +++ b/include/net/flow.h | |||
@@ -7,6 +7,7 @@ | |||
7 | #ifndef _NET_FLOW_H | 7 | #ifndef _NET_FLOW_H |
8 | #define _NET_FLOW_H | 8 | #define _NET_FLOW_H |
9 | 9 | ||
10 | #include <linux/socket.h> | ||
10 | #include <linux/in6.h> | 11 | #include <linux/in6.h> |
11 | #include <linux/atomic.h> | 12 | #include <linux/atomic.h> |
12 | 13 | ||
@@ -161,6 +162,24 @@ static inline struct flowi *flowidn_to_flowi(struct flowidn *fldn) | |||
161 | return container_of(fldn, struct flowi, u.dn); | 162 | return container_of(fldn, struct flowi, u.dn); |
162 | } | 163 | } |
163 | 164 | ||
165 | typedef unsigned long flow_compare_t; | ||
166 | |||
167 | static inline size_t flow_key_size(u16 family) | ||
168 | { | ||
169 | switch (family) { | ||
170 | case AF_INET: | ||
171 | BUILD_BUG_ON(sizeof(struct flowi4) % sizeof(flow_compare_t)); | ||
172 | return sizeof(struct flowi4) / sizeof(flow_compare_t); | ||
173 | case AF_INET6: | ||
174 | BUILD_BUG_ON(sizeof(struct flowi6) % sizeof(flow_compare_t)); | ||
175 | return sizeof(struct flowi6) / sizeof(flow_compare_t); | ||
176 | case AF_DECnet: | ||
177 | BUILD_BUG_ON(sizeof(struct flowidn) % sizeof(flow_compare_t)); | ||
178 | return sizeof(struct flowidn) / sizeof(flow_compare_t); | ||
179 | } | ||
180 | return 0; | ||
181 | } | ||
182 | |||
164 | #define FLOW_DIR_IN 0 | 183 | #define FLOW_DIR_IN 0 |
165 | #define FLOW_DIR_OUT 1 | 184 | #define FLOW_DIR_OUT 1 |
166 | #define FLOW_DIR_FWD 2 | 185 | #define FLOW_DIR_FWD 2 |
diff --git a/net/core/flow.c b/net/core/flow.c index 47b6d26c2afb..555a456efb07 100644 --- a/net/core/flow.c +++ b/net/core/flow.c | |||
@@ -173,29 +173,26 @@ static void flow_new_hash_rnd(struct flow_cache *fc, | |||
173 | 173 | ||
174 | static u32 flow_hash_code(struct flow_cache *fc, | 174 | static u32 flow_hash_code(struct flow_cache *fc, |
175 | struct flow_cache_percpu *fcp, | 175 | struct flow_cache_percpu *fcp, |
176 | const struct flowi *key) | 176 | const struct flowi *key, |
177 | size_t keysize) | ||
177 | { | 178 | { |
178 | const u32 *k = (const u32 *) key; | 179 | const u32 *k = (const u32 *) key; |
180 | const u32 length = keysize * sizeof(flow_compare_t) / sizeof(u32); | ||
179 | 181 | ||
180 | return jhash2(k, (sizeof(*key) / sizeof(u32)), fcp->hash_rnd) | 182 | return jhash2(k, length, fcp->hash_rnd) |
181 | & (flow_cache_hash_size(fc) - 1); | 183 | & (flow_cache_hash_size(fc) - 1); |
182 | } | 184 | } |
183 | 185 | ||
184 | typedef unsigned long flow_compare_t; | ||
185 | |||
186 | /* I hear what you're saying, use memcmp. But memcmp cannot make | 186 | /* I hear what you're saying, use memcmp. But memcmp cannot make |
187 | * important assumptions that we can here, such as alignment and | 187 | * important assumptions that we can here, such as alignment. |
188 | * constant size. | ||
189 | */ | 188 | */ |
190 | static int flow_key_compare(const struct flowi *key1, const struct flowi *key2) | 189 | static int flow_key_compare(const struct flowi *key1, const struct flowi *key2, |
190 | size_t keysize) | ||
191 | { | 191 | { |
192 | const flow_compare_t *k1, *k1_lim, *k2; | 192 | const flow_compare_t *k1, *k1_lim, *k2; |
193 | const int n_elem = sizeof(struct flowi) / sizeof(flow_compare_t); | ||
194 | |||
195 | BUILD_BUG_ON(sizeof(struct flowi) % sizeof(flow_compare_t)); | ||
196 | 193 | ||
197 | k1 = (const flow_compare_t *) key1; | 194 | k1 = (const flow_compare_t *) key1; |
198 | k1_lim = k1 + n_elem; | 195 | k1_lim = k1 + keysize; |
199 | 196 | ||
200 | k2 = (const flow_compare_t *) key2; | 197 | k2 = (const flow_compare_t *) key2; |
201 | 198 | ||
@@ -216,6 +213,7 @@ flow_cache_lookup(struct net *net, const struct flowi *key, u16 family, u8 dir, | |||
216 | struct flow_cache_entry *fle, *tfle; | 213 | struct flow_cache_entry *fle, *tfle; |
217 | struct hlist_node *entry; | 214 | struct hlist_node *entry; |
218 | struct flow_cache_object *flo; | 215 | struct flow_cache_object *flo; |
216 | size_t keysize; | ||
219 | unsigned int hash; | 217 | unsigned int hash; |
220 | 218 | ||
221 | local_bh_disable(); | 219 | local_bh_disable(); |
@@ -223,6 +221,11 @@ flow_cache_lookup(struct net *net, const struct flowi *key, u16 family, u8 dir, | |||
223 | 221 | ||
224 | fle = NULL; | 222 | fle = NULL; |
225 | flo = NULL; | 223 | flo = NULL; |
224 | |||
225 | keysize = flow_key_size(family); | ||
226 | if (!keysize) | ||
227 | goto nocache; | ||
228 | |||
226 | /* Packet really early in init? Making flow_cache_init a | 229 | /* Packet really early in init? Making flow_cache_init a |
227 | * pre-smp initcall would solve this. --RR */ | 230 | * pre-smp initcall would solve this. --RR */ |
228 | if (!fcp->hash_table) | 231 | if (!fcp->hash_table) |
@@ -231,12 +234,12 @@ flow_cache_lookup(struct net *net, const struct flowi *key, u16 family, u8 dir, | |||
231 | if (fcp->hash_rnd_recalc) | 234 | if (fcp->hash_rnd_recalc) |
232 | flow_new_hash_rnd(fc, fcp); | 235 | flow_new_hash_rnd(fc, fcp); |
233 | 236 | ||
234 | hash = flow_hash_code(fc, fcp, key); | 237 | hash = flow_hash_code(fc, fcp, key, keysize); |
235 | hlist_for_each_entry(tfle, entry, &fcp->hash_table[hash], u.hlist) { | 238 | hlist_for_each_entry(tfle, entry, &fcp->hash_table[hash], u.hlist) { |
236 | if (tfle->net == net && | 239 | if (tfle->net == net && |
237 | tfle->family == family && | 240 | tfle->family == family && |
238 | tfle->dir == dir && | 241 | tfle->dir == dir && |
239 | flow_key_compare(key, &tfle->key) == 0) { | 242 | flow_key_compare(key, &tfle->key, keysize) == 0) { |
240 | fle = tfle; | 243 | fle = tfle; |
241 | break; | 244 | break; |
242 | } | 245 | } |
@@ -251,7 +254,7 @@ flow_cache_lookup(struct net *net, const struct flowi *key, u16 family, u8 dir, | |||
251 | fle->net = net; | 254 | fle->net = net; |
252 | fle->family = family; | 255 | fle->family = family; |
253 | fle->dir = dir; | 256 | fle->dir = dir; |
254 | memcpy(&fle->key, key, sizeof(*key)); | 257 | memcpy(&fle->key, key, keysize * sizeof(flow_compare_t)); |
255 | fle->object = NULL; | 258 | fle->object = NULL; |
256 | hlist_add_head(&fle->u.hlist, &fcp->hash_table[hash]); | 259 | hlist_add_head(&fle->u.hlist, &fcp->hash_table[hash]); |
257 | fcp->hash_count++; | 260 | fcp->hash_count++; |