[ovs-dev] [next2 7/7] ofproto: Make rule construction and destruction more symmetric.

Ben Pfaff blp at nicira.com
Tue Apr 26 20:51:31 UTC 2011


Before, ->rule_construct() both created the rule and inserted into the
flow table, but ->rule_destruct() only destroyed the rule.  This makes
->rule_destruct() also remove the rule from the flow table.
---
 lib/classifier.c        |   20 +++++++++++++++++++-
 lib/classifier.h        |    3 ++-
 ofproto/ofproto-dpif.c  |   25 ++++++++++---------------
 ofproto/ofproto.c       |   30 +++++++++---------------------
 ofproto/private.h       |   25 ++++++++++++-------------
 tests/test-classifier.c |   12 ++++++------
 utilities/ovs-ofctl.c   |    2 +-
 7 files changed, 59 insertions(+), 58 deletions(-)

diff --git a/lib/classifier.c b/lib/classifier.c
index 42a2169..013de32 100644
--- a/lib/classifier.c
+++ b/lib/classifier.c
@@ -692,7 +692,7 @@ classifier_count(const struct classifier *cls)
  * rule, even rules that cannot have any effect because the new rule matches a
  * superset of their flows and has higher priority. */
 struct cls_rule *
-classifier_insert(struct classifier *cls, struct cls_rule *rule)
+classifier_replace(struct classifier *cls, struct cls_rule *rule)
 {
     struct cls_rule *old_rule;
     struct cls_table *table;
@@ -710,6 +710,24 @@ classifier_insert(struct classifier *cls, struct cls_rule *rule)
     return old_rule;
 }
 
+/* Inserts 'rule' into 'cls'.  Until 'rule' is removed from 'cls', the caller
+ * must not modify or free it.
+ *
+ * 'cls' must not contain an identical rule (including wildcards, values of
+ * fixed fields, and priority).  Use classifier_find_rule_exactly() to find
+ * such a rule.
+ *
+ * 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
+ * rule, even rules that cannot have any effect because the new rule matches a
+ * superset of their flows and has higher priority. */
+void
+classifier_insert(struct classifier *cls, struct cls_rule *rule)
+{
+    struct cls_rule *displaced_rule = classifier_replace(cls, rule);
+    assert(!displaced_rule);
+}
+
 /* Removes 'rule' from 'cls'.  It is the caller's responsibility to free
  * 'rule', if this is desirable. */
 void
diff --git a/lib/classifier.h b/lib/classifier.h
index d3121bf..08e2c0d 100644
--- a/lib/classifier.h
+++ b/lib/classifier.h
@@ -121,7 +121,8 @@ void classifier_init(struct classifier *);
 void classifier_destroy(struct classifier *);
 bool classifier_is_empty(const struct classifier *);
 int classifier_count(const struct classifier *);
-struct cls_rule *classifier_insert(struct classifier *, struct cls_rule *);
+void classifier_insert(struct classifier *, struct cls_rule *);
+struct cls_rule *classifier_replace(struct classifier *, struct cls_rule *);
 void classifier_remove(struct classifier *, struct cls_rule *);
 struct cls_rule *classifier_lookup(const struct classifier *,
                                    const struct flow *);
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index baaa19b..f163ff4 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -2442,7 +2442,7 @@ rule_construct(struct rule *rule_)
 {
     struct rule_dpif *rule = rule_dpif_cast(rule_);
     struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto);
-    struct cls_rule *displaced_rule;
+    struct rule_dpif *old_rule;
     int error;
 
     error = validate_actions(rule->up.actions, rule->up.n_actions,
@@ -2451,15 +2451,19 @@ rule_construct(struct rule *rule_)
         return error;
     }
 
+    old_rule = rule_dpif_cast(rule_from_cls_rule(classifier_find_rule_exactly(
+                                                     &ofproto->up.cls,
+                                                     &rule->up.cr)));
+    if (old_rule) {
+        ofproto_rule_destroy(&old_rule->up);
+    }
+
     rule->used = rule->up.created;
     rule->packet_count = 0;
     rule->byte_count = 0;
     list_init(&rule->facets);
+    classifier_insert(&ofproto->up.cls, &rule->up.cr);
 
-    displaced_rule = classifier_insert(&ofproto->up.cls, &rule->up.cr);
-    if (displaced_rule) {
-        ofproto_rule_destroy(rule_from_cls_rule(displaced_rule));
-    }
     ofproto->need_revalidate = true;
 
     return 0;
@@ -2472,19 +2476,11 @@ rule_destruct(struct rule *rule_)
     struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto);
     struct facet *facet, *next_facet;
 
+    classifier_remove(&ofproto->up.cls, &rule->up.cr);
     LIST_FOR_EACH_SAFE (facet, next_facet, list_node, &rule->facets) {
         facet_revalidate(ofproto, facet);
     }
-}
-
-static void
-rule_remove(struct rule *rule_)
-{
-    struct rule_dpif *rule = rule_dpif_cast(rule_);
-    struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto);
-
     ofproto->need_revalidate = true;
-    classifier_remove(&ofproto->up.cls, &rule->up.cr);
 }
 
 static void
@@ -3867,7 +3863,6 @@ const struct ofproto_class ofproto_dpif_class = {
     rule_construct,
     rule_destruct,
     rule_dealloc,
-    rule_remove,
     rule_get_stats,
     rule_execute,
     rule_modify_actions,
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index 028a50a..7f3ea6b 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -78,7 +78,6 @@ static void ofproto_flush_flows__(struct ofproto *);
 
 static void ofproto_rule_destroy__(struct rule *);
 static void ofproto_rule_send_removed(struct rule *, uint8_t reason);
-static void ofproto_rule_remove(struct rule *);
 
 static void handle_openflow(struct ofconn *, struct ofpbuf *);
 
@@ -882,9 +881,7 @@ ofproto_delete_flow(struct ofproto *ofproto, const struct cls_rule *target)
 
     rule = rule_from_cls_rule(classifier_find_rule_exactly(&ofproto->cls,
                                                            target));
-    if (rule) {
-        ofproto_rule_remove(rule);
-    }
+    ofproto_rule_destroy(rule);
 }
 
 static void
@@ -901,7 +898,7 @@ ofproto_flush_flows__(struct ofproto *ofproto)
 
     cls_cursor_init(&cursor, &ofproto->cls, NULL);
     CLS_CURSOR_FOR_EACH_SAFE (rule, next_rule, cr, &cursor) {
-        ofproto_rule_remove(rule);
+        ofproto_rule_destroy(rule);
     }
 }
 
@@ -1261,14 +1258,14 @@ ofproto_rule_destroy__(struct rule *rule)
     rule->ofproto->ofproto_class->rule_dealloc(rule);
 }
 
-/* Destroys 'rule' and removes it from the datapath.
- *
- * The caller must have already removed 'rule' from the classifier. */
+/* Destroys 'rule' and removes it from the flow table and the datapath. */
 void
 ofproto_rule_destroy(struct rule *rule)
 {
-    rule->ofproto->ofproto_class->rule_destruct(rule);
-    ofproto_rule_destroy__(rule);
+    if (rule) {
+        rule->ofproto->ofproto_class->rule_destruct(rule);
+        ofproto_rule_destroy__(rule);
+    }
 }
 
 /* Returns true if 'rule' has an OpenFlow OFPAT_OUTPUT or OFPAT_ENQUEUE action
@@ -1317,15 +1314,6 @@ rule_execute(struct rule *rule, uint16_t in_port, struct ofpbuf *packet)
     return rule->ofproto->ofproto_class->rule_execute(rule, &flow, packet);
 }
 
-/* Removes 'rule' from 'ofproto' and free up the associated memory.  Removes
- * 'rule' from the classifier.  */
-void
-ofproto_rule_remove(struct rule *rule)
-{
-    rule->ofproto->ofproto_class->rule_remove(rule);
-    ofproto_rule_destroy(rule);
-}
-
 /* Returns true if 'rule' should be hidden from the controller.
  *
  * Rules with priority higher than UINT16_MAX are set up by ofproto itself
@@ -2353,7 +2341,7 @@ delete_flow(struct rule *rule, ovs_be16 out_port)
     }
 
     ofproto_rule_send_removed(rule, OFPRR_DELETE);
-    ofproto_rule_remove(rule);
+    ofproto_rule_destroy(rule);
 }
 
 static void
@@ -2387,7 +2375,7 @@ ofproto_rule_expire(struct rule *rule, uint8_t reason)
 {
     assert(reason == OFPRR_HARD_TIMEOUT || reason == OFPRR_IDLE_TIMEOUT);
     ofproto_rule_send_removed(rule, reason);
-    ofproto_rule_remove(rule);
+    ofproto_rule_destroy(rule);
 }
 
 static int
diff --git a/ofproto/private.h b/ofproto/private.h
index cbf2c2e..c6c18f1 100644
--- a/ofproto/private.h
+++ b/ofproto/private.h
@@ -472,32 +472,31 @@ struct ofproto_class {
      * flow table:
      *
      *   - If there was already a rule with exactly the same matching criteria
-     *     and priority in the classifier, then it should remove that rule from
-     *     the classifier and destroy it (with ofproto_rule_destroy()).
+     *     and priority in the classifier, then it should destroy it (with
+     *     ofproto_rule_destroy()).
+     *
+     *     To the greatest extent possible, the old rule should be destroyed
+     *     only if inserting the new rule succeeds; that is, ->rule_construct()
+     *     should be transactional.
+     *
+     *     The function classifier_find_rule_exactly() can locate such a rule.
      *
      *   - Insert the new rule into the ofproto's 'cls' classifier, and into
      *     the datapath flow table.
      *
-     *     (The function classifier_insert() both inserts a rule into the
-     *     classifier and removes any rule with identical matching criteria, so
-     *     this single call implements parts of both steps above.)
+     *     The function classifier_insert() inserts a rule into the classifier.
      *
      * Other than inserting 'rule->cr' into the classifier, ->rule_construct()
      * should not modify any base members of struct rule.
      *
-     * When ->rule_destruct() is called, 'rule' has already been removed from
-     * the classifier and the datapath flow table (by calling ->rule_remove()),
-     * so ->rule_destruct() should not duplicate that behavior. */
+     * ->rule_destruct() should remove 'rule' from the ofproto's 'cls'
+     * classifier (e.g. with classifier_remove()) and from the datapath flow
+     * table. */
     struct rule *(*rule_alloc)(void);
     int (*rule_construct)(struct rule *rule);
     void (*rule_destruct)(struct rule *rule);
     void (*rule_dealloc)(struct rule *rule);
 
-    /* Removes 'rule' from 'rule->ofproto->cls' and from the datapath.
-     *
-     * 'rule' will be destructed, with ->rule_destruct(), soon after. */
-    void (*rule_remove)(struct rule *rule);
-
     /* Obtains statistics for 'rule', storing the number of packets that have
      * matched it in '*packet_count' and the number of bytes in those packets
      * in '*byte_count'. */
diff --git a/tests/test-classifier.c b/tests/test-classifier.c
index bb75dba..1cfd5cf 100644
--- a/tests/test-classifier.c
+++ b/tests/test-classifier.c
@@ -526,7 +526,7 @@ test_single_rule(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
         tcls_init(&tcls);
 
         tcls_rule = tcls_insert(&tcls, rule);
-        assert(!classifier_insert(&cls, &rule->cls_rule));
+        classifier_insert(&cls, &rule->cls_rule);
         check_tables(&cls, 1, 1, 0);
         compare_classifiers(&cls, &tcls);
 
@@ -562,7 +562,7 @@ test_rule_replacement(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
         classifier_init(&cls);
         tcls_init(&tcls);
         tcls_insert(&tcls, rule1);
-        assert(!classifier_insert(&cls, &rule1->cls_rule));
+        classifier_insert(&cls, &rule1->cls_rule);
         check_tables(&cls, 1, 1, 0);
         compare_classifiers(&cls, &tcls);
         tcls_destroy(&tcls);
@@ -570,7 +570,7 @@ test_rule_replacement(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
         tcls_init(&tcls);
         tcls_insert(&tcls, rule2);
         assert(test_rule_from_cls_rule(
-                   classifier_insert(&cls, &rule2->cls_rule)) == rule1);
+                   classifier_replace(&cls, &rule2->cls_rule)) == rule1);
         free(rule1);
         check_tables(&cls, 1, 1, 0);
         compare_classifiers(&cls, &tcls);
@@ -681,7 +681,7 @@ test_many_rules_in_one_list (int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 
                     tcls_rules[j] = tcls_insert(&tcls, rules[j]);
                     displaced_rule = test_rule_from_cls_rule(
-                        classifier_insert(&cls, &rules[j]->cls_rule));
+                        classifier_replace(&cls, &rules[j]->cls_rule));
                     if (pri_rules[pris[j]] >= 0) {
                         int k = pri_rules[pris[j]];
                         assert(displaced_rule != NULL);
@@ -781,7 +781,7 @@ test_many_rules_in_one_table(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 
             rules[i] = make_rule(wcf, priority, value_pats[i]);
             tcls_rules[i] = tcls_insert(&tcls, rules[i]);
-            assert(!classifier_insert(&cls, &rules[i]->cls_rule));
+            classifier_insert(&cls, &rules[i]->cls_rule);
 
             check_tables(&cls, 1, i + 1, 0);
             compare_classifiers(&cls, &tcls);
@@ -839,7 +839,7 @@ test_many_rules_in_n_tables(int n_tables)
             int value_pat = rand() & ((1u << CLS_N_FIELDS) - 1);
             rule = make_rule(wcf, priority, value_pat);
             tcls_insert(&tcls, rule);
-            assert(!classifier_insert(&cls, &rule->cls_rule));
+            classifier_insert(&cls, &rule->cls_rule);
             check_tables(&cls, -1, i + 1, -1);
             compare_classifiers(&cls, &tcls);
         }
diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
index 660fc3a..b829ac7 100644
--- a/utilities/ovs-ofctl.c
+++ b/utilities/ovs-ofctl.c
@@ -1000,7 +1000,7 @@ fte_insert(struct classifier *cls, const struct cls_rule *rule,
     fte->rule = *rule;
     fte->versions[index] = version;
 
-    old = fte_from_cls_rule(classifier_insert(cls, &fte->rule));
+    old = fte_from_cls_rule(classifier_replace(cls, &fte->rule));
     if (old) {
         fte_version_free(old->versions[index]);
         fte->versions[!index] = old->versions[!index];
-- 
1.7.4.4




More information about the dev mailing list