[ovs-dev] [PATCH 1/2] Optimize classifier by maintaining the priority of the highest priority rule in each table.

Jarno Rajahalme jarno.rajahalme at nsn.com
Thu Feb 7 22:06:22 UTC 2013


Signed-off-by: Jarno Rajahalme <jarno.rajahalme at nsn.com>
---
 lib/classifier.c        |   57 ++++++++++++++++++++++++++++++++++++++++-------
 lib/classifier.h        |    2 ++
 tests/test-classifier.c |   13 +++++++++++
 3 files changed, 64 insertions(+), 8 deletions(-)

diff --git a/lib/classifier.c b/lib/classifier.c
index 7192602..2ed0013 100644
--- a/lib/classifier.c
+++ b/lib/classifier.c
@@ -235,8 +235,21 @@ classifier_remove(struct classifier *cls, struct cls_rule *rule)
 
     if (--table->n_table_rules == 0) {
         destroy_table(cls, table);
-    }
+    } else if (rule->priority == table->max_priority
+               && --table->max_count == 0) {
+        /* Maintain table's max_priority */
+        struct cls_rule *head;
 
+        table->max_priority = 0;
+        HMAP_FOR_EACH (head, hmap_node, &table->rules) {
+            if (head->priority > table->max_priority) {
+                table->max_priority = head->priority;
+                table->max_count = 1;
+            } else if (head->priority == table->max_priority) {
+                ++table->max_count;
+            }
+        }
+    }
     cls->n_rules--;
 }
 
@@ -251,9 +264,14 @@ classifier_lookup(const struct classifier *cls, const struct flow *flow)
 
     best = NULL;
     HMAP_FOR_EACH (table, hmap_node, &cls->tables) {
-        struct cls_rule *rule = find_match(table, flow);
-        if (rule && (!best || rule->priority > best->priority)) {
-            best = rule;
+        /* Find only if there is hope.
+         * Would be even better to search the tables in the descending
+         * order of max_priority */
+        if (!best || table->max_priority > best->priority) {
+            struct cls_rule *rule = find_match(table, flow);
+            if (rule && (!best || rule->priority > best->priority)) {
+                best = rule;
+            }
         }
     }
     return best;
@@ -274,6 +292,10 @@ classifier_find_rule_exactly(const struct classifier *cls,
         return NULL;
     }
 
+    /* Skip if there is no hope */
+    if (target->priority > table->max_priority)
+        return NULL;
+
     head = find_equal(table, &target->match.flow,
                       miniflow_hash_in_minimask(&target->match.flow,
                                                 &target->match.mask, 0));
@@ -317,11 +339,18 @@ classifier_rule_overlaps(const struct classifier *cls,
         struct minimask mask;
         struct cls_rule *head;
 
+        if (target->priority > table->max_priority) {
+            continue; /* Can skip this table */
+        }
+
         minimask_combine(&mask, &target->match.mask, &table->mask, storage);
         HMAP_FOR_EACH (head, hmap_node, &table->rules) {
             struct cls_rule *rule;
 
             FOR_EACH_RULE_IN_LIST (rule, head) {
+                if (rule->priority < target->priority) {
+                    break; /* Rules in descending priority order */
+                }
                 if (rule->priority == target->priority
                     && miniflow_equal_in_minimask(&target->match.flow,
                                                   &rule->match.flow, &mask)) {
@@ -540,6 +569,7 @@ static struct cls_rule *
 insert_rule(struct cls_table *table, struct cls_rule *new)
 {
     struct cls_rule *head;
+    struct cls_rule *old = NULL;
 
     new->hmap_node.hash = miniflow_hash_in_minimask(&new->match.flow,
                                                     &new->match.mask, 0);
@@ -548,7 +578,7 @@ insert_rule(struct cls_table *table, struct cls_rule *new)
     if (!head) {
         hmap_insert(&table->rules, &new->hmap_node, new->hmap_node.hash);
         list_init(&new->list);
-        return NULL;
+        goto out;
     } else {
         /* Scan the list for the insertion point that will keep the list in
          * order of decreasing priority. */
@@ -563,18 +593,29 @@ insert_rule(struct cls_table *table, struct cls_rule *new)
 
                 if (new->priority == rule->priority) {
                     list_replace(&new->list, &rule->list);
-                    return rule;
+                    old = rule;
+                    goto out;
                 } else {
                     list_insert(&rule->list, &new->list);
-                    return NULL;
+                    goto out;
                 }
             }
         }
 
         /* Insert 'new' at the end of the list. */
         list_push_back(&head->list, &new->list);
-        return NULL;
     }
+
+ out:
+    if (new->priority > table->max_priority) {
+        table->max_priority = new->priority;
+        table->max_count = 1;
+    } else if (!old && new->priority == table->max_priority) {
+        /* Only if we are not replacing an old entry */
+        ++table->max_count;
+    }
+
+    return old;
 }
 
 static struct cls_rule *
diff --git a/lib/classifier.h b/lib/classifier.h
index bc9db33..f6310e5 100644
--- a/lib/classifier.h
+++ b/lib/classifier.h
@@ -49,6 +49,8 @@ struct cls_table {
     struct hmap rules;          /* Contains "struct cls_rule"s. */
     struct minimask mask;       /* Wildcards for fields. */
     int n_table_rules;          /* Number of rules, including duplicates. */
+    unsigned int max_priority;  /* Max priority of any rule in the table */
+    unsigned int max_count;     /* Count of max_priority rules */
 };
 
 /* Returns true if 'table' is a "catch-all" table that will match every
diff --git a/tests/test-classifier.c b/tests/test-classifier.c
index b1461ff..18dee86 100644
--- a/tests/test-classifier.c
+++ b/tests/test-classifier.c
@@ -463,6 +463,8 @@ check_tables(const struct classifier *cls,
 
     HMAP_FOR_EACH (table, hmap_node, &cls->tables) {
         const struct cls_rule *head;
+        unsigned int max_priority = 0;
+        unsigned int max_count = 0;
 
         assert(!hmap_is_empty(&table->rules));
 
@@ -471,15 +473,26 @@ check_tables(const struct classifier *cls,
             unsigned int prev_priority = UINT_MAX;
             const struct cls_rule *rule;
 
+            if (head->priority > max_priority) {
+                max_priority = head->priority;
+                max_count = 1;
+            } else if (head->priority == max_priority) {
+                ++max_count;
+            }
+
             found_rules++;
             LIST_FOR_EACH (rule, list, &head->list) {
                 assert(rule->priority < prev_priority);
+                assert(rule->priority <= table->max_priority);
+
                 prev_priority = rule->priority;
                 found_rules++;
                 found_dups++;
                 assert(classifier_find_rule_exactly(cls, rule) == rule);
             }
         }
+        assert(table->max_priority == max_priority);
+        assert(table->max_count == max_count);
     }
 
     assert(found_tables == hmap_count(&cls->tables));
-- 
1.7.10.4




More information about the dev mailing list