mirror of
https://github.com/openvswitch/ovs
synced 2025-10-29 15:28:56 +00:00
Introduce sparse flows and masks, to reduce memory usage and improve speed.
A cls_rule is 324 bytes on i386 now. The cost of a flow table lookup is
currently proportional to this size, which is going to continue to grow.
However, the required cost of a flow table lookup, with the classifier that
we currently use, is only proportional to the number of bits that a rule
actually matches. This commit implements that optimization by replacing
the match inside "struct cls_rule" by a sparse representation.
This reduces struct cls_rule to 100 bytes on i386.
There is still some headroom for further optimization following this
commit:
- I suspect that adding an 'n' member to struct miniflow would make
miniflow operations faster, since popcount() has some cost.
- It's probably possible to replace the "struct minimatch" in cls_rule
by just a "struct miniflow", since the cls_rule's cls_table has a
copy of the minimask.
- Some of the miniflow operations aren't well-optimized.
Signed-off-by: Ben Pfaff <blp@nicira.com>
This commit is contained in:
74
lib/match.c
74
lib/match.c
@@ -773,3 +773,77 @@ match_print(const struct match *match)
|
||||
puts(s);
|
||||
free(s);
|
||||
}
|
||||
|
||||
/* Initializes 'dst' as a copy of 'src'. The caller must eventually free 'dst'
|
||||
* with minimatch_destroy(). */
|
||||
void
|
||||
minimatch_init(struct minimatch *dst, const struct match *src)
|
||||
{
|
||||
miniflow_init(&dst->flow, &src->flow);
|
||||
minimask_init(&dst->mask, &src->wc);
|
||||
}
|
||||
|
||||
/* Initializes 'dst' as a copy of 'src'. The caller must eventually free 'dst'
|
||||
* with minimatch_destroy(). */
|
||||
void
|
||||
minimatch_clone(struct minimatch *dst, const struct minimatch *src)
|
||||
{
|
||||
miniflow_clone(&dst->flow, &src->flow);
|
||||
minimask_clone(&dst->mask, &src->mask);
|
||||
}
|
||||
|
||||
/* Frees any memory owned by 'match'. Does not free the storage in which
|
||||
* 'match' itself resides; the caller is responsible for that. */
|
||||
void
|
||||
minimatch_destroy(struct minimatch *match)
|
||||
{
|
||||
miniflow_destroy(&match->flow);
|
||||
minimask_destroy(&match->mask);
|
||||
}
|
||||
|
||||
/* Initializes 'dst' as a copy of 'src'. */
|
||||
void
|
||||
minimatch_expand(const struct minimatch *src, struct match *dst)
|
||||
{
|
||||
miniflow_expand(&src->flow, &dst->flow);
|
||||
minimask_expand(&src->mask, &dst->wc);
|
||||
}
|
||||
|
||||
/* Returns true if 'a' and 'b' match the same packets, false otherwise. */
|
||||
bool
|
||||
minimatch_equal(const struct minimatch *a, const struct minimatch *b)
|
||||
{
|
||||
return (miniflow_equal(&a->flow, &b->flow)
|
||||
&& minimask_equal(&a->mask, &b->mask));
|
||||
}
|
||||
|
||||
/* Returns a hash value for 'match', given 'basis'. */
|
||||
uint32_t
|
||||
minimatch_hash(const struct minimatch *match, uint32_t basis)
|
||||
{
|
||||
return miniflow_hash(&match->flow, minimask_hash(&match->mask, basis));
|
||||
}
|
||||
|
||||
/* Appends a string representation of 'match' to 's'. If 'priority' is
|
||||
* different from OFP_DEFAULT_PRIORITY, includes it in 's'. */
|
||||
void
|
||||
minimatch_format(const struct minimatch *match, struct ds *s,
|
||||
unsigned int priority)
|
||||
{
|
||||
struct match megamatch;
|
||||
|
||||
minimatch_expand(match, &megamatch);
|
||||
match_format(&megamatch, s, priority);
|
||||
}
|
||||
|
||||
/* Converts 'match' to a string and returns the string. If 'priority' is
|
||||
* different from OFP_DEFAULT_PRIORITY, includes it in the string. The caller
|
||||
* must free the string (with free()). */
|
||||
char *
|
||||
minimatch_to_string(const struct minimatch *match, unsigned int priority)
|
||||
{
|
||||
struct match megamatch;
|
||||
|
||||
minimatch_expand(match, &megamatch);
|
||||
return match_to_string(&megamatch, priority);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user