This makes it possible to tentatively add flows to the classifier without the datapath seeing them.
Signed-off-by: Jarno Rajahalme <jrajaha...@nicira.com> --- lib/classifier-private.h | 3 +- lib/classifier.c | 68 +++++++++++++++++++++++++++++++++++++--------- lib/classifier.h | 1 + ofproto/ofproto.c | 1 + utilities/ovs-ofctl.c | 1 + 5 files changed, 60 insertions(+), 14 deletions(-) diff --git a/lib/classifier-private.h b/lib/classifier-private.h index 4eed9e4..a7edbe9 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 68a3443..0cf42f6 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,17 @@ 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(). + */ +void cls_rule_make_visible(const struct cls_rule *rule) +{ + ovs_assert(rule->cls_match); /* Must be in a classifier. */ + + rule->cls_match->visible = true; +} + /* Initializes 'cls' as a classifier that initially contains no classification * rules. */ @@ -623,8 +648,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 +703,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 +719,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 +1229,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 +1693,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 +1803,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 f9af33e..77c4458 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); diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 67feee6..1fd7e12 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 3d61c4b..54a5bb8 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 -- 1.7.10.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev