summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorJarno Rajahalme <jrajahalme@nicira.com>2015-07-06 11:45:54 -0700
committerJarno Rajahalme <jrajahalme@nicira.com>2015-07-06 11:46:34 -0700
commitbd53aa1723a007415d26fdd8fb7da05acc06aad0 (patch)
treecdff83f858e77eee3f8052e71d0fc6b646f4f3df /lib
parent8be0036745ecda6325e27e87cdb1d23e3e3d5d34 (diff)
downloadopenvswitch-bd53aa1723a007415d26fdd8fb7da05acc06aad0.tar.gz
classifier: Make versioning more explicit.
Now that struct cls_match has 'add_version' the 'version' in cls_match was largely redundant. Remove 'version' from struct cls_rule, and add it to function prototypes that need it. This makes versioning more explicit (or less indirect) in the API. Suggested-by: Ben Pfaff <blp@nicira.com> Signed-off-by: Jarno Rajahalme <jrajahalme@nicira.com> Acked-by: Ben Pfaff <blp@nicira.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/classifier.c120
-rw-r--r--lib/classifier.h36
-rw-r--r--lib/ovs-router.c8
-rw-r--r--lib/tnl-ports.c4
4 files changed, 78 insertions, 90 deletions
diff --git a/lib/classifier.c b/lib/classifier.c
index db6a16916..a8a4780f6 100644
--- a/lib/classifier.c
+++ b/lib/classifier.c
@@ -87,7 +87,7 @@ cls_conjunction_set_alloc(struct cls_match *match,
}
static struct cls_match *
-cls_match_alloc(const struct cls_rule *rule,
+cls_match_alloc(const struct cls_rule *rule, cls_version_t version,
const struct cls_conjunction conj[], size_t n)
{
int count = count_1bits(rule->match.flow.map);
@@ -99,9 +99,9 @@ cls_match_alloc(const struct cls_rule *rule,
ovsrcu_init(&cls_match->next, NULL);
*CONST_CAST(const struct cls_rule **, &cls_match->cls_rule) = rule;
*CONST_CAST(int *, &cls_match->priority) = rule->priority;
- *CONST_CAST(cls_version_t *, &cls_match->add_version) = rule->version;
- atomic_init(&cls_match->remove_version, rule->version); /* Initially
- invisible. */
+ *CONST_CAST(cls_version_t *, &cls_match->add_version) = version;
+ atomic_init(&cls_match->remove_version, version); /* Initially
+ * invisible. */
miniflow_clone_inline(CONST_CAST(struct miniflow *, &cls_match->flow),
&rule->match.flow, count);
ovsrcu_set_hidden(&cls_match->conj_set,
@@ -163,12 +163,10 @@ static bool mask_prefix_bits_set(const struct flow_wildcards *,
/* cls_rule. */
static inline void
-cls_rule_init__(struct cls_rule *rule, unsigned int priority,
- cls_version_t version)
+cls_rule_init__(struct cls_rule *rule, unsigned int priority)
{
rculist_init(&rule->node);
*CONST_CAST(int *, &rule->priority) = priority;
- *CONST_CAST(cls_version_t *, &rule->version) = version;
rule->cls_match = NULL;
}
@@ -181,41 +179,29 @@ cls_rule_init__(struct cls_rule *rule, unsigned int priority,
* Clients should not use priority INT_MIN. (OpenFlow uses priorities between
* 0 and UINT16_MAX, inclusive.) */
void
-cls_rule_init(struct cls_rule *rule, const struct match *match, int priority,
- cls_version_t version)
+cls_rule_init(struct cls_rule *rule, const struct match *match, int priority)
{
- cls_rule_init__(rule, priority, version);
+ cls_rule_init__(rule, priority);
minimatch_init(CONST_CAST(struct minimatch *, &rule->match), match);
}
/* Same as cls_rule_init() for initialization from a "struct minimatch". */
void
cls_rule_init_from_minimatch(struct cls_rule *rule,
- const struct minimatch *match, int priority,
- cls_version_t version)
+ const struct minimatch *match, int priority)
{
- cls_rule_init__(rule, priority, version);
+ cls_rule_init__(rule, priority);
minimatch_clone(CONST_CAST(struct minimatch *, &rule->match), match);
}
-/* Initializes 'dst' as a copy of 'src', but with 'version'.
- *
- * The caller must eventually destroy 'dst' with cls_rule_destroy(). */
-void
-cls_rule_clone_in_version(struct cls_rule *dst, const struct cls_rule *src,
- cls_version_t version)
-{
- cls_rule_init__(dst, src->priority, version);
- minimatch_clone(CONST_CAST(struct minimatch *, &dst->match), &src->match);
-}
-
/* Initializes 'dst' as a copy of 'src'.
*
* The caller must eventually destroy 'dst' with cls_rule_destroy(). */
void
cls_rule_clone(struct cls_rule *dst, const struct cls_rule *src)
{
- cls_rule_clone_in_version(dst, src, src->version);
+ cls_rule_init__(dst, src->priority);
+ minimatch_clone(CONST_CAST(struct minimatch *, &dst->match), &src->match);
}
/* Initializes 'dst' with the data in 'src', destroying 'src'.
@@ -226,7 +212,7 @@ cls_rule_clone(struct cls_rule *dst, const struct cls_rule *src)
void
cls_rule_move(struct cls_rule *dst, struct cls_rule *src)
{
- cls_rule_init__(dst, src->priority, src->version);
+ cls_rule_init__(dst, src->priority);
minimatch_move(CONST_CAST(struct minimatch *, &dst->match),
CONST_CAST(struct minimatch *, &src->match));
}
@@ -312,7 +298,7 @@ cls_rule_make_invisible_in_version(const struct cls_rule *rule,
cls_match_set_remove_version(rule->cls_match, remove_version);
}
-/* This undoes the change made by cls_rule_make_invisible_after_version().
+/* This undoes the change made by cls_rule_make_invisible_in_version().
*
* 'rule' must be in a classifier. */
void
@@ -572,14 +558,15 @@ subtable_replace_head_rule(struct classifier *cls OVS_UNUSED,
cmap_replace(&subtable->rules, &head->cmap_node, &new->cmap_node, hash);
}
-/* Inserts 'rule' into 'cls'. Until 'rule' is removed from 'cls', the caller
- * must not modify or free it.
+/* Inserts 'rule' into 'cls' in 'version'. Until 'rule' is removed from 'cls',
+ * the caller must not modify or free it.
*
* If 'cls' already contains an identical rule (including wildcards, values of
- * fixed fields, and priority), replaces the old rule by 'rule' and returns the
- * rule that was replaced. The caller takes ownership of the returned rule and
- * is thus responsible for destroying it with cls_rule_destroy(), after RCU
- * grace period has passed (see ovsrcu_postpone()).
+ * fixed fields, and priority) that is visible in 'version', replaces the old
+ * rule by 'rule' and returns the rule that was replaced. The caller takes
+ * ownership of the returned rule and is thus responsible for destroying it
+ * with cls_rule_destroy(), after RCU grace period has passed (see
+ * ovsrcu_postpone()).
*
* Returns NULL if 'cls' does not contain a rule with an identical key, after
* inserting the new rule. In this case, no rules are displaced by the new
@@ -588,6 +575,7 @@ subtable_replace_head_rule(struct classifier *cls OVS_UNUSED,
*/
const struct cls_rule *
classifier_replace(struct classifier *cls, const struct cls_rule *rule,
+ cls_version_t version,
const struct cls_conjunction *conjs, size_t n_conjs)
{
struct cls_match *new;
@@ -601,7 +589,7 @@ classifier_replace(struct classifier *cls, const struct cls_rule *rule,
int i;
/* 'new' is initially invisible to lookups. */
- new = cls_match_alloc(rule, conjs, n_conjs);
+ new = cls_match_alloc(rule, version, conjs, n_conjs);
CONST_CAST(struct cls_rule *, rule)->cls_match = new;
@@ -773,10 +761,11 @@ classifier_replace(struct classifier *cls, const struct cls_rule *rule,
* such a rule. */
void
classifier_insert(struct classifier *cls, const struct cls_rule *rule,
- const struct cls_conjunction conj[], size_t n_conj)
+ cls_version_t version, const struct cls_conjunction conj[],
+ size_t n_conj)
{
const struct cls_rule *displaced_rule
- = classifier_replace(cls, rule, conj, n_conj);
+ = classifier_replace(cls, rule, version, conj, n_conj);
ovs_assert(!displaced_rule);
}
@@ -1292,12 +1281,13 @@ classifier_lookup(const struct classifier *cls, cls_version_t version,
}
/* Finds and returns a rule in 'cls' with exactly the same priority and
- * matching criteria as 'target', and that is visible in 'target->version.
+ * matching criteria as 'target', and that is visible in 'version'.
* Only one such rule may ever exist. Returns a null pointer if 'cls' doesn't
* contain an exact match. */
const struct cls_rule *
classifier_find_rule_exactly(const struct classifier *cls,
- const struct cls_rule *target)
+ const struct cls_rule *target,
+ cls_version_t version)
{
const struct cls_match *head, *rule;
const struct cls_subtable *subtable;
@@ -1318,7 +1308,7 @@ classifier_find_rule_exactly(const struct classifier *cls,
break; /* Not found. */
}
if (rule->priority == target->priority
- && cls_match_visible_in_version(rule, target->version)) {
+ && cls_match_visible_in_version(rule, version)) {
return rule->cls_rule;
}
}
@@ -1337,16 +1327,16 @@ classifier_find_match_exactly(const struct classifier *cls,
const struct cls_rule *retval;
struct cls_rule cr;
- cls_rule_init(&cr, target, priority, version);
- retval = classifier_find_rule_exactly(cls, &cr);
+ cls_rule_init(&cr, target, priority);
+ retval = classifier_find_rule_exactly(cls, &cr, version);
cls_rule_destroy(&cr);
return retval;
}
-/* Checks if 'target' would overlap any other rule in 'cls'. Two rules are
- * considered to overlap if both rules have the same priority and a packet
- * could match both, and if both rules are visible in the same version.
+/* Checks if 'target' would overlap any other rule in 'cls' in 'version'. Two
+ * rules are considered to overlap if both rules have the same priority and a
+ * packet could match both, and if both rules are visible in the same version.
*
* A trivial example of overlapping rules is two rules matching disjoint sets
* of fields. E.g., if one rule matches only on port number, while another only
@@ -1354,7 +1344,7 @@ classifier_find_match_exactly(const struct classifier *cls,
* dl_type could match both, if the rules also have the same priority. */
bool
classifier_rule_overlaps(const struct classifier *cls,
- const struct cls_rule *target)
+ const struct cls_rule *target, cls_version_t version)
{
struct cls_subtable *subtable;
@@ -1371,8 +1361,7 @@ classifier_rule_overlaps(const struct classifier *cls,
if (rule->priority == target->priority
&& miniflow_equal_in_minimask(&target->match.flow,
&rule->match.flow, &mask)
- && cls_match_visible_in_version(rule->cls_match,
- target->version)) {
+ && cls_match_visible_in_version(rule->cls_match, version)) {
return true;
}
}
@@ -1424,17 +1413,15 @@ cls_rule_is_loose_match(const struct cls_rule *rule,
/* Iteration. */
-/* Rule may only match a target if it is visible in target's version. For NULL
- * target we only return rules that are not invisible in any version. */
static bool
-rule_matches(const struct cls_rule *rule, const struct cls_rule *target)
+rule_matches(const struct cls_rule *rule, const struct cls_rule *target,
+ cls_version_t version)
{
- /* Iterators never see duplicate rules with the same priority. */
- return target
- ? (miniflow_equal_in_minimask(&rule->match.flow, &target->match.flow,
- &target->match.mask)
- && cls_match_visible_in_version(rule->cls_match, target->version))
- : !cls_match_is_eventually_invisible(rule->cls_match);
+ /* Rule may only match a target if it is visible in target's version. */
+ return cls_match_visible_in_version(rule->cls_match, version)
+ && (!target || miniflow_equal_in_minimask(&rule->match.flow,
+ &target->match.flow,
+ &target->match.mask));
}
static const struct cls_rule *
@@ -1446,7 +1433,7 @@ search_subtable(const struct cls_subtable *subtable,
const struct cls_rule *rule;
RCULIST_FOR_EACH (rule, node, &subtable->rules_list) {
- if (rule_matches(rule, cursor->target)) {
+ if (rule_matches(rule, cursor->target, cursor->version)) {
return rule;
}
}
@@ -1455,27 +1442,26 @@ search_subtable(const struct cls_subtable *subtable,
}
/* Initializes 'cursor' for iterating through rules in 'cls', and returns the
- * first matching cls_rule via '*pnode', or NULL if there are no matches.
+ * cursor.
*
- * - If 'target' is null, or if the 'target' is a catchall target and the
- * target's version is CLS_MAX_VERSION, the cursor will visit every rule
- * in 'cls' that is not invisible in any version.
+ * - If 'target' is null, or if the 'target' is a catchall target, the
+ * cursor will visit every rule in 'cls' that is visible in 'version'.
*
* - If 'target' is nonnull, the cursor will visit each 'rule' in 'cls'
* such that cls_rule_is_loose_match(rule, target) returns true and that
- * the rule is visible in 'target->version'.
+ * the rule is visible in 'version'.
*
* Ignores target->priority. */
struct cls_cursor
-cls_cursor_start(const struct classifier *cls, const struct cls_rule *target)
+cls_cursor_start(const struct classifier *cls, const struct cls_rule *target,
+ cls_version_t version)
{
struct cls_cursor cursor;
struct cls_subtable *subtable;
cursor.cls = cls;
- cursor.target = target && (!cls_rule_is_catchall(target)
- || target->version != CLS_MAX_VERSION)
- ? target : NULL;
+ cursor.target = target && !cls_rule_is_catchall(target) ? target : NULL;
+ cursor.version = version;
cursor.rule = NULL;
/* Find first rule. */
@@ -1502,7 +1488,7 @@ cls_cursor_next(struct cls_cursor *cursor)
rule = cursor->rule;
subtable = cursor->subtable;
RCULIST_FOR_EACH_CONTINUE (rule, node, &subtable->rules_list) {
- if (rule_matches(rule, cursor->target)) {
+ if (rule_matches(rule, cursor->target, cursor->version)) {
return rule;
}
}
diff --git a/lib/classifier.h b/lib/classifier.h
index 8bbc7366b..5ffe756b1 100644
--- a/lib/classifier.h
+++ b/lib/classifier.h
@@ -357,18 +357,14 @@ struct cls_conjunction {
struct cls_rule {
struct rculist node; /* In struct cls_subtable 'rules_list'. */
const int priority; /* Larger numbers are higher priorities. */
- const cls_version_t version; /* Version in which the rule was added. */
struct cls_match *cls_match; /* NULL if not in a classifier. */
const struct minimatch match; /* Matching rule. */
};
-void cls_rule_init(struct cls_rule *, const struct match *, int priority,
- cls_version_t);
+void cls_rule_init(struct cls_rule *, const struct match *, int priority);
void cls_rule_init_from_minimatch(struct cls_rule *, const struct minimatch *,
- int priority, cls_version_t);
+ int priority);
void cls_rule_clone(struct cls_rule *, const struct cls_rule *);
-void cls_rule_clone_in_version(struct cls_rule *, const struct cls_rule *,
- cls_version_t);
void cls_rule_move(struct cls_rule *dst, struct cls_rule *src);
void cls_rule_destroy(struct cls_rule *);
@@ -395,9 +391,11 @@ bool classifier_set_prefix_fields(struct classifier *,
const enum mf_field_id *trie_fields,
unsigned int n_trie_fields);
void classifier_insert(struct classifier *, const struct cls_rule *,
- const struct cls_conjunction *, size_t n_conjunctions);
+ cls_version_t, const struct cls_conjunction *,
+ size_t n_conjunctions);
const struct cls_rule *classifier_replace(struct classifier *,
const struct cls_rule *,
+ cls_version_t,
const struct cls_conjunction *,
size_t n_conjunctions);
const struct cls_rule *classifier_remove(struct classifier *,
@@ -411,9 +409,10 @@ const struct cls_rule *classifier_lookup(const struct classifier *,
cls_version_t, struct flow *,
struct flow_wildcards *);
bool classifier_rule_overlaps(const struct classifier *,
- const struct cls_rule *);
+ const struct cls_rule *, cls_version_t);
const struct cls_rule *classifier_find_rule_exactly(const struct classifier *,
- const struct cls_rule *);
+ const struct cls_rule *,
+ cls_version_t);
const struct cls_rule *classifier_find_match_exactly(const struct classifier *,
const struct match *,
int priority,
@@ -437,18 +436,20 @@ struct cls_cursor {
const struct classifier *cls;
const struct cls_subtable *subtable;
const struct cls_rule *target;
+ cls_version_t version; /* Version to iterate. */
struct pvector_cursor subtables;
const struct cls_rule *rule;
};
-struct cls_cursor cls_cursor_start(const struct classifier *cls,
- const struct cls_rule *target);
+struct cls_cursor cls_cursor_start(const struct classifier *,
+ const struct cls_rule *target,
+ cls_version_t);
void cls_cursor_advance(struct cls_cursor *);
#define CLS_FOR_EACH(RULE, MEMBER, CLS) \
- CLS_FOR_EACH_TARGET(RULE, MEMBER, CLS, NULL)
-#define CLS_FOR_EACH_TARGET(RULE, MEMBER, CLS, TARGET) \
- for (struct cls_cursor cursor__ = cls_cursor_start(CLS, TARGET); \
+ CLS_FOR_EACH_TARGET(RULE, MEMBER, CLS, NULL, CLS_MAX_VERSION)
+#define CLS_FOR_EACH_TARGET(RULE, MEMBER, CLS, TARGET, VERSION) \
+ for (struct cls_cursor cursor__ = cls_cursor_start(CLS, TARGET, VERSION); \
(cursor__.rule \
? (INIT_CONTAINER(RULE, cursor__.rule, MEMBER), \
cls_cursor_advance(&cursor__), \
@@ -456,9 +457,6 @@ void cls_cursor_advance(struct cls_cursor *);
: false); \
)
-#ifdef __cplusplus
-}
-#endif
static inline void
classifier_defer(struct classifier *cls)
@@ -472,4 +470,8 @@ classifier_publish(struct classifier *cls)
cls->publish = true;
pvector_publish(&cls->subtables);
}
+
+#ifdef __cplusplus
+}
+#endif
#endif /* classifier.h */
diff --git a/lib/ovs-router.c b/lib/ovs-router.c
index 532487e8f..df55bb4f0 100644
--- a/lib/ovs-router.c
+++ b/lib/ovs-router.c
@@ -116,10 +116,10 @@ ovs_router_insert__(uint8_t priority, ovs_be32 ip_dst, uint8_t plen,
p->plen = plen;
p->priority = priority;
/* Longest prefix matches first. */
- cls_rule_init(&p->cr, &match, priority, CLS_MIN_VERSION);
+ cls_rule_init(&p->cr, &match, priority);
ovs_mutex_lock(&mutex);
- cr = classifier_replace(&cls, &p->cr, NULL, 0);
+ cr = classifier_replace(&cls, &p->cr, CLS_MIN_VERSION, NULL, 0);
ovs_mutex_unlock(&mutex);
if (cr) {
@@ -145,10 +145,10 @@ rt_entry_delete(uint8_t priority, ovs_be32 ip_dst, uint8_t plen)
rt_init_match(&match, ip_dst, plen);
- cls_rule_init(&rule, &match, priority, CLS_MIN_VERSION);
+ cls_rule_init(&rule, &match, priority);
/* Find the exact rule. */
- cr = classifier_find_rule_exactly(&cls, &rule);
+ cr = classifier_find_rule_exactly(&cls, &rule, CLS_MAX_VERSION);
if (cr) {
/* Remove it. */
ovs_mutex_lock(&mutex);
diff --git a/lib/tnl-ports.c b/lib/tnl-ports.c
index 35dd0a5a7..9a87b7432 100644
--- a/lib/tnl-ports.c
+++ b/lib/tnl-ports.c
@@ -94,11 +94,11 @@ tnl_port_map_insert(odp_port_t port, ovs_be16 udp_port, const char dev_name[])
match.wc.masks.nw_frag = 0xff; /* XXX: No fragments support. */
match.wc.masks.tp_dst = OVS_BE16_MAX;
- cls_rule_init(&p->cr, &match, 0, CLS_MIN_VERSION); /* Priority == 0. */
+ cls_rule_init(&p->cr, &match, 0); /* Priority == 0. */
ovs_refcount_init(&p->ref_cnt);
ovs_strlcpy(p->dev_name, dev_name, sizeof p->dev_name);
- classifier_insert(&cls, &p->cr, NULL, 0);
+ classifier_insert(&cls, &p->cr, CLS_MIN_VERSION, NULL, 0);
}
ovs_mutex_unlock(&mutex);
}