diff options
author | dpward <david.ward@ll.mit.edu> | 2011-09-05 12:47:24 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-09-16 17:47:28 -0400 |
commit | aa1c366e4febc7f5c2b84958a2dd7cd70e28f9d0 (patch) | |
tree | 336ecab3185913c78fb3ac81779a373e4d4ae5af /net | |
parent | 728871bc05afc8ff310b17dba3e57a2472792b13 (diff) |
net: Handle different key sizes between address families in flow cache
With the conversion of struct flowi to a union of AF-specific structs, some
operations on the flow cache need to account for the exact size of the key.
Signed-off-by: David Ward <david.ward@ll.mit.edu>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/core/flow.c | 31 |
1 files changed, 17 insertions, 14 deletions
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++; |