summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/classifier-private.h3
-rw-r--r--lib/classifier.c67
-rw-r--r--lib/classifier.h2
-rw-r--r--ofproto/ofproto.c1
-rw-r--r--utilities/ovs-ofctl.c1
5 files changed, 59 insertions, 15 deletions
diff --git a/lib/classifier-private.h b/lib/classifier-private.h
index 4eed9e42f..a7edbe93b 100644
--- a/lib/classifier-private.h
+++ b/lib/classifier-private.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 Nicira, Inc.
+ * Copyright (c) 2014, 2015 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -79,6 +79,7 @@ struct cls_match {
* 'indices'. */
/* Accessed by all readers. */
struct cmap_node cmap_node; /* Within struct cls_subtable 'rules'. */
+ bool visible;
const struct cls_rule *cls_rule;
OVSRCU_TYPE(struct cls_conjunction_set *) conj_set;
const struct miniflow flow; /* Matching rule. Mask is in the subtable. */
diff --git a/lib/classifier.c b/lib/classifier.c
index 68a34437a..5344ca55c 100644
--- a/lib/classifier.c
+++ b/lib/classifier.c
@@ -99,6 +99,7 @@ cls_match_alloc(const struct cls_rule *rule,
rculist_init(&cls_match->list);
*CONST_CAST(const struct cls_rule **, &cls_match->cls_rule) = rule;
*CONST_CAST(int *, &cls_match->priority) = rule->priority;
+ cls_match->visible = false;
miniflow_clone_inline(CONST_CAST(struct miniflow *, &cls_match->flow),
&rule->match.flow, count);
ovsrcu_set_hidden(&cls_match->conj_set,
@@ -136,6 +137,19 @@ next_rule_in_list(const struct cls_match *rule)
return next->priority < rule->priority ? next : NULL;
}
+/* Return the next lower-priority rule in the list that is visible. */
+static inline const struct cls_match *
+next_visible_rule_in_list(const struct cls_match *rule)
+{
+ const struct cls_match *next = rule;
+
+ do {
+ next = next_rule_in_list(next);
+ } while (next && !next->visible);
+
+ return next;
+}
+
static inline struct cls_match *
next_rule_in_list_protected__(struct cls_match *rule)
{
@@ -301,6 +315,16 @@ cls_rule_is_catchall(const struct cls_rule *rule)
{
return minimask_is_catchall(&rule->match.mask);
}
+
+/* Rules inserted during classifier_defer() need to be made visible before
+ * calling classifier_publish().
+ *
+ * 'rule' must be in a classifier. */
+void cls_rule_make_visible(const struct cls_rule *rule)
+{
+ rule->cls_match->visible = true;
+}
+
/* Initializes 'cls' as a classifier that initially contains no classification
* rules. */
@@ -623,8 +647,6 @@ classifier_replace(struct classifier *cls, const struct cls_rule *rule,
new->partition = create_partition(cls, subtable, metadata);
}
- /* Make rule visible to lookups. */
-
/* Add new node to segment indices.
*
* Readers may find the rule in the indices before the rule is visible
@@ -680,7 +702,10 @@ classifier_replace(struct classifier *cls, const struct cls_rule *rule,
/* No change in subtable's max priority or max count. */
- /* Make rule visible to iterators. */
+ /* Make rule visible to lookups? */
+ new->visible = cls->publish;
+
+ /* Make rule visible to iterators (immediately). */
rculist_replace(CONST_CAST(struct rculist *, &rule->node),
&old->node);
@@ -693,7 +718,10 @@ classifier_replace(struct classifier *cls, const struct cls_rule *rule,
}
}
- /* Make rule visible to iterators. */
+ /* Make rule visible to lookups? */
+ new->visible = cls->publish;
+
+ /* Make rule visible to iterators (immediately). */
rculist_push_back(&subtable->rules_list,
CONST_CAST(struct rculist *, &rule->node));
@@ -1200,7 +1228,7 @@ classifier_lookup__(const struct classifier *cls, struct flow *flow,
}
/* Find next-lower-priority flow with identical flow match. */
- match = next_rule_in_list(soft[i]->match);
+ match = next_visible_rule_in_list(soft[i]->match);
if (match) {
soft[i] = ovsrcu_get(struct cls_conjunction_set *,
&match->conj_set);
@@ -1664,12 +1692,18 @@ static inline const struct cls_match *
find_match(const struct cls_subtable *subtable, const struct flow *flow,
uint32_t hash)
{
- const struct cls_match *rule;
+ const struct cls_match *head, *rule;
- CMAP_FOR_EACH_WITH_HASH (rule, cmap_node, hash, &subtable->rules) {
- if (miniflow_and_mask_matches_flow(&rule->flow, &subtable->mask,
- flow)) {
- return rule;
+ CMAP_FOR_EACH_WITH_HASH (head, cmap_node, hash, &subtable->rules) {
+ if (OVS_LIKELY(miniflow_and_mask_matches_flow(&head->flow,
+ &subtable->mask,
+ flow))) {
+ /* Return highest priority rule that is visible. */
+ FOR_EACH_RULE_IN_LIST(rule, head) {
+ if (OVS_LIKELY(rule->visible)) {
+ return rule;
+ }
+ }
}
}
@@ -1768,10 +1802,17 @@ find_match_wc(const struct cls_subtable *subtable, const struct flow *flow,
* (Rare) hash collisions may cause us to miss the opportunity for this
* optimization. */
if (!cmap_node_next(inode)) {
- ASSIGN_CONTAINER(rule, inode - i, index_nodes);
- if (miniflow_and_mask_matches_flow_wc(&rule->flow, &subtable->mask,
+ const struct cls_match *head;
+
+ ASSIGN_CONTAINER(head, inode - i, index_nodes);
+ if (miniflow_and_mask_matches_flow_wc(&head->flow, &subtable->mask,
flow, wc)) {
- return rule;
+ /* Return highest priority rule that is visible. */
+ FOR_EACH_RULE_IN_LIST(rule, head) {
+ if (OVS_LIKELY(rule->visible)) {
+ return rule;
+ }
+ }
}
return NULL;
}
diff --git a/lib/classifier.h b/lib/classifier.h
index f9af33e32..c38d92200 100644
--- a/lib/classifier.h
+++ b/lib/classifier.h
@@ -285,6 +285,7 @@ void cls_rule_format(const struct cls_rule *, struct ds *);
bool cls_rule_is_catchall(const struct cls_rule *);
bool cls_rule_is_loose_match(const struct cls_rule *rule,
const struct minimatch *criteria);
+void cls_rule_make_visible(const struct cls_rule *rule);
/* Constructor/destructor. Must run single-threaded. */
void classifier_init(struct classifier *, const uint8_t *flow_segments);
@@ -358,7 +359,6 @@ void cls_cursor_advance(struct cls_cursor *);
#ifdef __cplusplus
}
#endif
-
static inline void
classifier_defer(struct classifier *cls)
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index 5c3b49773..9c4e97d27 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -4431,6 +4431,7 @@ add_flow(struct ofproto *ofproto, struct ofputil_flow_mod *fm,
ofproto_rule_unref(rule);
return error;
}
+ cls_rule_make_visible(&rule->cr);
classifier_publish(&table->cls);
learned_cookies_inc(ofproto, actions);
diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
index 3d61c4b8a..54a5bb8d0 100644
--- a/utilities/ovs-ofctl.c
+++ b/utilities/ovs-ofctl.c
@@ -2403,6 +2403,7 @@ fte_insert(struct classifier *cls, const struct match *match,
ovsrcu_postpone(fte_free, old);
}
+ cls_rule_make_visible(&fte->rule);
}
/* Reads the flows in 'filename' as flow table entries in 'cls' for the version