diff options
| author | dpward <david.ward@ll.mit.edu> | 2011-09-05 12:47:24 -0400 |
|---|---|---|
| committer | Herton Ronaldo Krzesinski <herton.krzesinski@canonical.com> | 2011-11-21 12:55:16 -0500 |
| commit | 21f65deaf30ccaae10f31469dfb09a876a180035 (patch) | |
| tree | 74240190cd7b5fe05ca8216eb5893d418d63c1ee /net/core | |
| parent | d2eb0a67b944bfdee762e19ccaf94bf1ab1db9d1 (diff) | |
net: Handle different key sizes between address families in flow cache
BugLink: http://bugs.launchpad.net/bugs/890952
commit aa1c366e4febc7f5c2b84958a2dd7cd70e28f9d0 upstream.
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>
Cc: Kim Phillips <kim.phillips@freescale.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Signed-off-by: Tim Gardner <tim.gardner@canonical.com>
Diffstat (limited to 'net/core')
| -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 990703b8863..a6bda2a514f 100644 --- a/net/core/flow.c +++ b/net/core/flow.c | |||
| @@ -172,29 +172,26 @@ static void flow_new_hash_rnd(struct flow_cache *fc, | |||
| 172 | 172 | ||
| 173 | static u32 flow_hash_code(struct flow_cache *fc, | 173 | static u32 flow_hash_code(struct flow_cache *fc, |
| 174 | struct flow_cache_percpu *fcp, | 174 | struct flow_cache_percpu *fcp, |
| 175 | const struct flowi *key) | 175 | const struct flowi *key, |
| 176 | size_t keysize) | ||
| 176 | { | 177 | { |
| 177 | const u32 *k = (const u32 *) key; | 178 | const u32 *k = (const u32 *) key; |
| 179 | const u32 length = keysize * sizeof(flow_compare_t) / sizeof(u32); | ||
| 178 | 180 | ||
| 179 | return jhash2(k, (sizeof(*key) / sizeof(u32)), fcp->hash_rnd) | 181 | return jhash2(k, length, fcp->hash_rnd) |
| 180 | & (flow_cache_hash_size(fc) - 1); | 182 | & (flow_cache_hash_size(fc) - 1); |
| 181 | } | 183 | } |
| 182 | 184 | ||
| 183 | typedef unsigned long flow_compare_t; | ||
| 184 | |||
| 185 | /* I hear what you're saying, use memcmp. But memcmp cannot make | 185 | /* I hear what you're saying, use memcmp. But memcmp cannot make |
| 186 | * important assumptions that we can here, such as alignment and | 186 | * important assumptions that we can here, such as alignment. |
| 187 | * constant size. | ||
| 188 | */ | 187 | */ |
| 189 | static int flow_key_compare(const struct flowi *key1, const struct flowi *key2) | 188 | static int flow_key_compare(const struct flowi *key1, const struct flowi *key2, |
| 189 | size_t keysize) | ||
| 190 | { | 190 | { |
| 191 | const flow_compare_t *k1, *k1_lim, *k2; | 191 | const flow_compare_t *k1, *k1_lim, *k2; |
| 192 | const int n_elem = sizeof(struct flowi) / sizeof(flow_compare_t); | ||
| 193 | |||
| 194 | BUILD_BUG_ON(sizeof(struct flowi) % sizeof(flow_compare_t)); | ||
| 195 | 192 | ||
| 196 | k1 = (const flow_compare_t *) key1; | 193 | k1 = (const flow_compare_t *) key1; |
| 197 | k1_lim = k1 + n_elem; | 194 | k1_lim = k1 + keysize; |
| 198 | 195 | ||
| 199 | k2 = (const flow_compare_t *) key2; | 196 | k2 = (const flow_compare_t *) key2; |
| 200 | 197 | ||
| @@ -215,6 +212,7 @@ flow_cache_lookup(struct net *net, const struct flowi *key, u16 family, u8 dir, | |||
| 215 | struct flow_cache_entry *fle, *tfle; | 212 | struct flow_cache_entry *fle, *tfle; |
| 216 | struct hlist_node *entry; | 213 | struct hlist_node *entry; |
| 217 | struct flow_cache_object *flo; | 214 | struct flow_cache_object *flo; |
| 215 | size_t keysize; | ||
| 218 | unsigned int hash; | 216 | unsigned int hash; |
| 219 | 217 | ||
| 220 | local_bh_disable(); | 218 | local_bh_disable(); |
| @@ -222,6 +220,11 @@ flow_cache_lookup(struct net *net, const struct flowi *key, u16 family, u8 dir, | |||
| 222 | 220 | ||
| 223 | fle = NULL; | 221 | fle = NULL; |
| 224 | flo = NULL; | 222 | flo = NULL; |
| 223 | |||
| 224 | keysize = flow_key_size(family); | ||
| 225 | if (!keysize) | ||
| 226 | goto nocache; | ||
| 227 | |||
| 225 | /* Packet really early in init? Making flow_cache_init a | 228 | /* Packet really early in init? Making flow_cache_init a |
| 226 | * pre-smp initcall would solve this. --RR */ | 229 | * pre-smp initcall would solve this. --RR */ |
| 227 | if (!fcp->hash_table) | 230 | if (!fcp->hash_table) |
| @@ -230,11 +233,11 @@ flow_cache_lookup(struct net *net, const struct flowi *key, u16 family, u8 dir, | |||
| 230 | if (fcp->hash_rnd_recalc) | 233 | if (fcp->hash_rnd_recalc) |
| 231 | flow_new_hash_rnd(fc, fcp); | 234 | flow_new_hash_rnd(fc, fcp); |
| 232 | 235 | ||
| 233 | hash = flow_hash_code(fc, fcp, key); | 236 | hash = flow_hash_code(fc, fcp, key, keysize); |
| 234 | hlist_for_each_entry(tfle, entry, &fcp->hash_table[hash], u.hlist) { | 237 | hlist_for_each_entry(tfle, entry, &fcp->hash_table[hash], u.hlist) { |
| 235 | if (tfle->family == family && | 238 | if (tfle->family == family && |
| 236 | tfle->dir == dir && | 239 | tfle->dir == dir && |
| 237 | flow_key_compare(key, &tfle->key) == 0) { | 240 | flow_key_compare(key, &tfle->key, keysize) == 0) { |
| 238 | fle = tfle; | 241 | fle = tfle; |
| 239 | break; | 242 | break; |
| 240 | } | 243 | } |
| @@ -248,7 +251,7 @@ flow_cache_lookup(struct net *net, const struct flowi *key, u16 family, u8 dir, | |||
| 248 | if (fle) { | 251 | if (fle) { |
| 249 | fle->family = family; | 252 | fle->family = family; |
| 250 | fle->dir = dir; | 253 | fle->dir = dir; |
| 251 | memcpy(&fle->key, key, sizeof(*key)); | 254 | memcpy(&fle->key, key, keysize * sizeof(flow_compare_t)); |
| 252 | fle->object = NULL; | 255 | fle->object = NULL; |
| 253 | hlist_add_head(&fle->u.hlist, &fcp->hash_table[hash]); | 256 | hlist_add_head(&fle->u.hlist, &fcp->hash_table[hash]); |
| 254 | fcp->hash_count++; | 257 | fcp->hash_count++; |
