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,
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)
{
{
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;
+}
+
\f
/* Initializes 'cls' as a classifier that initially contains no classification
* rules. */
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
/* 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);
}
}
- /* 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));
}
/* 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);
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;
+ }
+ }
}
}
* (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;
}