Skip to content

Commit

Permalink
lib/dpif-netdev: Integrate megaflow classifier.
Browse files Browse the repository at this point in the history
Megaflow inserts and removals are simplified:

- No need for classifier internal mutex, as dpif-netdev already has a
  'flow_mutex'.
- Number of memory allocations/frees can be halved.
- Lookup code path can rely on netdev_flow_key always having inline data.

This will also be easier to simplify further when moving to per-thread
megaflow classifiers in the future.

Signed-off-by: Jarno Rajahalme <[email protected]>
Acked-by: Alex Wang <[email protected]>
  • Loading branch information
Jarno Rajahalme committed Oct 17, 2014
1 parent 965f980 commit 0de8783
Show file tree
Hide file tree
Showing 5 changed files with 535 additions and 247 deletions.
109 changes: 0 additions & 109 deletions lib/classifier.c
Original file line number Diff line number Diff line change
Expand Up @@ -970,115 +970,6 @@ classifier_lookup(const struct classifier *cls, const struct flow *flow,
return best ? best->cls_rule : NULL;
}

/* Returns true if 'target' satisifies 'match', that is, if each bit for which
* 'match' specifies a particular value has the correct value in 'target'.
*
* 'flow' and 'mask' have the same mask! */
static bool
miniflow_and_mask_matches_miniflow(const struct miniflow *flow,
const struct minimask *mask,
const struct miniflow *target)
{
const uint32_t *flowp = miniflow_get_u32_values(flow);
const uint32_t *maskp = miniflow_get_u32_values(&mask->masks);
uint32_t target_u32;

MINIFLOW_FOR_EACH_IN_MAP(target_u32, target, mask->masks.map) {
if ((*flowp++ ^ target_u32) & *maskp++) {
return false;
}
}

return true;
}

/* For each miniflow in 'flows' performs a classifier lookup writing the result
* into the corresponding slot in 'rules'.
*
* This function is optimized for use in the userspace datapath and therefore
* does not implement a lot of features available in the standard
* classifier_lookup() function. Specifically, it does not implement
* priorities, instead returning any rule which matches the flow.
*
* Returns true if all flows found a corresponding rule. */
bool
classifier_lookup_miniflow_batch(const struct classifier *cls,
const struct miniflow *flows[],
struct cls_rule *rules[], const size_t cnt)
{
/* The batch size 16 was experimentally found faster than 8 or 32. */
typedef uint16_t map_type;
#define MAP_BITS (sizeof(map_type) * CHAR_BIT)

struct cls_subtable *subtable;
const int n_maps = DIV_ROUND_UP(cnt, MAP_BITS);

#if !defined(__CHECKER__) && !defined(_WIN32)
map_type maps[n_maps];
#else
map_type maps[DIV_ROUND_UP(CLASSIFIER_MAX_BATCH, MAP_BITS)];
ovs_assert(n_maps <= CLASSIFIER_MAX_BATCH);
#endif
BUILD_ASSERT_DECL(sizeof *maps * CHAR_BIT == MAP_BITS);

memset(maps, 0xff, sizeof maps);
if (cnt % MAP_BITS) {
maps[n_maps - 1] >>= MAP_BITS - cnt % MAP_BITS; /* Clear extra bits. */
}
memset(rules, 0, cnt * sizeof *rules);

PVECTOR_FOR_EACH (subtable, &cls->subtables) {
const struct miniflow **mfs = flows;
struct cls_rule **results = rules;
map_type remains = 0;
int m;

BUILD_ASSERT_DECL(sizeof remains == sizeof *maps);

for (m = 0; m < n_maps; m++, mfs += MAP_BITS, results += MAP_BITS) {
uint32_t hashes[MAP_BITS];
const struct cmap_node *nodes[MAP_BITS];
unsigned long map = maps[m];
int i;

if (!map) {
continue; /* Skip empty ones. */
}

/* Compute hashes for the unfound flows. */
ULONG_FOR_EACH_1(i, map) {
hashes[i] = miniflow_hash_in_minimask(mfs[i], &subtable->mask,
0);
}
/* Lookup. */
map = cmap_find_batch(&subtable->rules, map, hashes, nodes);
/* Check results. */
ULONG_FOR_EACH_1(i, map) {
struct cls_match *rule;

CMAP_NODE_FOR_EACH (rule, cmap_node, nodes[i]) {
if (OVS_LIKELY(miniflow_and_mask_matches_miniflow(
&rule->flow, &subtable->mask,
mfs[i]))) {
results[i] = rule->cls_rule;
goto next;
}
}
ULONG_SET0(map, i); /* Did not match. */
next:
; /* Keep Sparse happy. */
}
maps[m] &= ~map; /* Clear the found rules. */
remains |= maps[m];
}
if (!remains) {
return true; /* All found. */
}
}
/* Some misses. */
return false;
}

/* Finds and returns a rule in 'cls' with exactly the same priority and
* matching criteria as 'target'. Returns a null pointer if 'cls' doesn't
* contain an exact match. */
Expand Down
5 changes: 0 additions & 5 deletions lib/classifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -295,11 +295,6 @@ struct cls_rule *classifier_remove(struct classifier *, struct cls_rule *);
struct cls_rule *classifier_lookup(const struct classifier *,
const struct flow *,
struct flow_wildcards *);
bool classifier_lookup_miniflow_batch(const struct classifier *cls,
const struct miniflow **flows,
struct cls_rule **rules,
const size_t cnt);
enum { CLASSIFIER_MAX_BATCH = 256 };
bool classifier_rule_overlaps(const struct classifier *,
const struct cls_rule *);

Expand Down
Loading

0 comments on commit 0de8783

Please sign in to comment.