classifier: Add support for invisible flows.
authorJarno Rajahalme <jrajahalme@nicira.com>
Fri, 29 May 2015 18:28:38 +0000 (11:28 -0700)
committerJarno Rajahalme <jrajahalme@nicira.com>
Mon, 1 Jun 2015 20:24:09 +0000 (13:24 -0700)
This makes it possible to tentatively add flows to the classifier
without the datapath seeing them.

Signed-off-by: Jarno Rajahalme <jrajahalme@nicira.com>
Acked-by: Ben Pfaff <blp@nicira.com>
lib/classifier-private.h
lib/classifier.c
lib/classifier.h
ofproto/ofproto.c
utilities/ovs-ofctl.c

index 4eed9e4..a7edbe9 100644 (file)
@@ -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. */
index 68a3443..5344ca5 100644 (file)
@@ -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;
+}
+
 \f
 /* 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;
         }
index f9af33e..c38d922 100644 (file)
@@ -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
-
 \f
 static inline void
 classifier_defer(struct classifier *cls)
index 5c3b497..9c4e97d 100644 (file)
@@ -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);
index 3d61c4b..54a5bb8 100644 (file)
@@ -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