Skip to content

Commit

Permalink
net: Handle different key sizes between address families in flow cache
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
dpward authored and davem330 committed Sep 16, 2011
1 parent 728871b commit aa1c366
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 14 deletions.
19 changes: 19 additions & 0 deletions include/net/flow.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#ifndef _NET_FLOW_H
#define _NET_FLOW_H

#include <linux/socket.h>
#include <linux/in6.h>
#include <linux/atomic.h>

Expand Down Expand Up @@ -161,6 +162,24 @@ static inline struct flowi *flowidn_to_flowi(struct flowidn *fldn)
return container_of(fldn, struct flowi, u.dn);
}

typedef unsigned long flow_compare_t;

static inline size_t flow_key_size(u16 family)
{
switch (family) {
case AF_INET:
BUILD_BUG_ON(sizeof(struct flowi4) % sizeof(flow_compare_t));
return sizeof(struct flowi4) / sizeof(flow_compare_t);
case AF_INET6:
BUILD_BUG_ON(sizeof(struct flowi6) % sizeof(flow_compare_t));
return sizeof(struct flowi6) / sizeof(flow_compare_t);
case AF_DECnet:
BUILD_BUG_ON(sizeof(struct flowidn) % sizeof(flow_compare_t));
return sizeof(struct flowidn) / sizeof(flow_compare_t);
}
return 0;
}

#define FLOW_DIR_IN 0
#define FLOW_DIR_OUT 1
#define FLOW_DIR_FWD 2
Expand Down
31 changes: 17 additions & 14 deletions net/core/flow.c
Original file line number Diff line number Diff line change
Expand Up @@ -173,29 +173,26 @@ static void flow_new_hash_rnd(struct flow_cache *fc,

static u32 flow_hash_code(struct flow_cache *fc,
struct flow_cache_percpu *fcp,
const struct flowi *key)
const struct flowi *key,
size_t keysize)
{
const u32 *k = (const u32 *) key;
const u32 length = keysize * sizeof(flow_compare_t) / sizeof(u32);

return jhash2(k, (sizeof(*key) / sizeof(u32)), fcp->hash_rnd)
return jhash2(k, length, fcp->hash_rnd)
& (flow_cache_hash_size(fc) - 1);
}

typedef unsigned long flow_compare_t;

/* I hear what you're saying, use memcmp. But memcmp cannot make
* important assumptions that we can here, such as alignment and
* constant size.
* important assumptions that we can here, such as alignment.
*/
static int flow_key_compare(const struct flowi *key1, const struct flowi *key2)
static int flow_key_compare(const struct flowi *key1, const struct flowi *key2,
size_t keysize)
{
const flow_compare_t *k1, *k1_lim, *k2;
const int n_elem = sizeof(struct flowi) / sizeof(flow_compare_t);

BUILD_BUG_ON(sizeof(struct flowi) % sizeof(flow_compare_t));

k1 = (const flow_compare_t *) key1;
k1_lim = k1 + n_elem;
k1_lim = k1 + keysize;

k2 = (const flow_compare_t *) key2;

Expand All @@ -216,13 +213,19 @@ flow_cache_lookup(struct net *net, const struct flowi *key, u16 family, u8 dir,
struct flow_cache_entry *fle, *tfle;
struct hlist_node *entry;
struct flow_cache_object *flo;
size_t keysize;
unsigned int hash;

local_bh_disable();
fcp = this_cpu_ptr(fc->percpu);

fle = NULL;
flo = NULL;

keysize = flow_key_size(family);
if (!keysize)
goto nocache;

/* Packet really early in init? Making flow_cache_init a
* pre-smp initcall would solve this. --RR */
if (!fcp->hash_table)
Expand All @@ -231,12 +234,12 @@ flow_cache_lookup(struct net *net, const struct flowi *key, u16 family, u8 dir,
if (fcp->hash_rnd_recalc)
flow_new_hash_rnd(fc, fcp);

hash = flow_hash_code(fc, fcp, key);
hash = flow_hash_code(fc, fcp, key, keysize);
hlist_for_each_entry(tfle, entry, &fcp->hash_table[hash], u.hlist) {
if (tfle->net == net &&
tfle->family == family &&
tfle->dir == dir &&
flow_key_compare(key, &tfle->key) == 0) {
flow_key_compare(key, &tfle->key, keysize) == 0) {
fle = tfle;
break;
}
Expand All @@ -251,7 +254,7 @@ flow_cache_lookup(struct net *net, const struct flowi *key, u16 family, u8 dir,
fle->net = net;
fle->family = family;
fle->dir = dir;
memcpy(&fle->key, key, sizeof(*key));
memcpy(&fle->key, key, keysize * sizeof(flow_compare_t));
fle->object = NULL;
hlist_add_head(&fle->u.hlist, &fcp->hash_table[hash]);
fcp->hash_count++;
Expand Down

0 comments on commit aa1c366

Please sign in to comment.