[ovs-dev] [PATCH 2/2] classifier: Maintain tables in descending priority order.

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


Signed-off-by: Jarno Rajahalme <jarno.rajahalme at nsn.com>
---
 lib/classifier.c |  109 ++++++++++++++++++++++++++++++++++++++----------------
 lib/classifier.h |    2 +
 lib/list.h       |    8 ++++
 3 files changed, 88 insertions(+), 31 deletions(-)

diff --git a/lib/classifier.c b/lib/classifier.c
index 2ed0013..f3df676 100644
--- a/lib/classifier.c
+++ b/lib/classifier.c
@@ -134,6 +134,7 @@ classifier_init(struct classifier *cls)
 {
     cls->n_rules = 0;
     hmap_init(&cls->tables);
+    list_init(&cls->tables_priority);
 }
 
 /* Destroys 'cls'.  Rules within 'cls', if any, are not freed; this is the
@@ -165,6 +166,45 @@ classifier_count(const struct classifier *cls)
     return cls->n_rules;
 }
 
+static void
+classifier_update_table_max_priority(struct classifier *cls,
+                                     struct cls_table *table,
+                                     unsigned int priority)
+{
+    struct cls_table *iter = table;
+
+    if (priority > table->max_priority) {
+        /* Possibly move table up in the priority list */
+        LIST_FOR_EACH_REVERSE_CONTINUE(iter, list_node, &cls->tables_priority) {
+            if (iter->max_priority >= priority) {
+                /* Stop on the node after which the table should be moved */
+                break;
+            }
+        }
+        /* Either at the list head or on the node after which to insert */
+        if (iter->list_node.next != &table->list_node) {
+            /* Must move */
+            list_splice(iter->list_node.next,
+                        &table->list_node, table->list_node.next);
+        }
+    } else if (priority < table->max_priority) {
+        /* Possibly move table down in the priority list */
+        LIST_FOR_EACH_CONTINUE (iter, list_node, &cls->tables_priority) {
+            if (iter->max_priority <= priority) {
+                /* Stop on the node on front of which the table should be moved */
+                break;
+            }
+        }
+        /* Either at the list head or on the node before which to insert */
+        if (iter->list_node.prev != &table->list_node) {
+            /* Must move */
+            list_splice(&iter->list_node,
+                        &table->list_node, table->list_node.next);
+        }
+    }
+    table->max_priority = priority;
+}
+
 /* Inserts 'rule' into 'cls'.  Until 'rule' is removed from 'cls', the caller
  * must not modify or free it.
  *
@@ -190,6 +230,15 @@ classifier_replace(struct classifier *cls, struct cls_rule *rule)
     }
 
     old_rule = insert_rule(table, rule);
+
+    if (rule->priority > table->max_priority) {
+        classifier_update_table_max_priority(cls, table, rule->priority);
+        table->max_count = 1;
+    } else if (!old_rule && rule->priority == table->max_priority) {
+        /* Only if we are not replacing an old entry */
+        ++table->max_count;
+    }
+
     if (!old_rule) {
         table->n_table_rules++;
         cls->n_rules++;
@@ -239,16 +288,16 @@ classifier_remove(struct classifier *cls, struct cls_rule *rule)
                && --table->max_count == 0) {
         /* Maintain table's max_priority */
         struct cls_rule *head;
-
-        table->max_priority = 0;
+        unsigned int new_max_priority = 0;
         HMAP_FOR_EACH (head, hmap_node, &table->rules) {
-            if (head->priority > table->max_priority) {
-                table->max_priority = head->priority;
+            if (head->priority > new_max_priority) {
+                new_max_priority = head->priority;
                 table->max_count = 1;
-            } else if (head->priority == table->max_priority) {
+            } else if (head->priority == new_max_priority) {
                 ++table->max_count;
             }
         }
+        classifier_update_table_max_priority(cls, table, new_max_priority);
     }
     cls->n_rules--;
 }
@@ -263,15 +312,22 @@ classifier_lookup(const struct classifier *cls, const struct flow *flow)
     struct cls_rule *best;
 
     best = NULL;
-    HMAP_FOR_EACH (table, hmap_node, &cls->tables) {
-        /* 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;
+    LIST_FOR_EACH (table, list_node, &cls->tables_priority) {
+        struct cls_rule *rule = find_match(table, flow);
+        if (rule) {
+            best = rule;
+            LIST_FOR_EACH_CONTINUE (table, list_node, &cls->tables_priority) {
+                if (table->max_priority <= best->priority) {
+                    /* Tables in descending priority order,
+                     * can not find anything better. */
+                    return best;
+                }
+                rule = find_match(table, flow);
+                if (rule && (rule->priority > best->priority)) {
+                    best = rule;
+                }
             }
+            break;
         }
     }
     return best;
@@ -334,13 +390,14 @@ classifier_rule_overlaps(const struct classifier *cls,
 {
     struct cls_table *table;
 
-    HMAP_FOR_EACH (table, hmap_node, &cls->tables) {
+    /* Iterate tables in the descending max priority order */
+    LIST_FOR_EACH (table, list_node, &cls->tables_priority) {
         uint32_t storage[FLOW_U32S];
         struct minimask mask;
         struct cls_rule *head;
 
         if (target->priority > table->max_priority) {
-            continue; /* Can skip this table */
+            break; /* Can skip this and the rest of the tables */
         }
 
         minimask_combine(&mask, &target->match.mask, &table->mask, storage);
@@ -523,6 +580,7 @@ insert_table(struct classifier *cls, const struct minimask *mask)
     hmap_init(&table->rules);
     minimask_clone(&table->mask, mask);
     hmap_insert(&cls->tables, &table->hmap_node, minimask_hash(mask, 0));
+    list_push_back(&cls->tables_priority, &table->list_node);
 
     return table;
 }
@@ -533,6 +591,7 @@ destroy_table(struct classifier *cls, struct cls_table *table)
     minimask_destroy(&table->mask);
     hmap_remove(&cls->tables, &table->hmap_node);
     hmap_destroy(&table->rules);
+    list_remove(&table->list_node);
     free(table);
 }
 
@@ -569,7 +628,6 @@ 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);
@@ -578,7 +636,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);
-        goto out;
+        return NULL;
     } else {
         /* Scan the list for the insertion point that will keep the list in
          * order of decreasing priority. */
@@ -593,29 +651,18 @@ insert_rule(struct cls_table *table, struct cls_rule *new)
 
                 if (new->priority == rule->priority) {
                     list_replace(&new->list, &rule->list);
-                    old = rule;
-                    goto out;
+                    return rule;
                 } else {
                     list_insert(&rule->list, &new->list);
-                    goto out;
+                    return NULL;
                 }
             }
         }
 
         /* 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 f6310e5..c3e5ffa 100644
--- a/lib/classifier.h
+++ b/lib/classifier.h
@@ -41,11 +41,13 @@ extern "C" {
 struct classifier {
     int n_rules;                /* Total number of rules. */
     struct hmap tables;         /* Contains "struct cls_table"s.  */
+    struct list tables_priority; /* Tables in descending priority order */
 };
 
 /* A set of rules that all have the same fields wildcarded. */
 struct cls_table {
     struct hmap_node hmap_node; /* Within struct classifier 'tables' hmap. */
+    struct list list_node;      /* Within classifier 'tables_priority_list' */
     struct hmap rules;          /* Contains "struct cls_rule"s. */
     struct minimask mask;       /* Wildcards for fields. */
     int n_table_rules;          /* Number of rules, including duplicates. */
diff --git a/lib/list.h b/lib/list.h
index 8ffa797..55e0d0a 100644
--- a/lib/list.h
+++ b/lib/list.h
@@ -60,10 +60,18 @@ bool list_is_short(const struct list *);
     for (ASSIGN_CONTAINER(ITER, (LIST)->next, MEMBER);                  \
          &(ITER)->MEMBER != (LIST);                                     \
          ASSIGN_CONTAINER(ITER, (ITER)->MEMBER.next, MEMBER))
+#define LIST_FOR_EACH_CONTINUE(ITER, MEMBER, LIST)                      \
+    for (ASSIGN_CONTAINER(ITER, (ITER)->MEMBER.next, MEMBER);           \
+         &(ITER)->MEMBER != (LIST);                                     \
+         ASSIGN_CONTAINER(ITER, (ITER)->MEMBER.next, MEMBER))
 #define LIST_FOR_EACH_REVERSE(ITER, MEMBER, LIST)                       \
     for (ASSIGN_CONTAINER(ITER, (LIST)->prev, MEMBER);                  \
          &(ITER)->MEMBER != (LIST);                                     \
          ASSIGN_CONTAINER(ITER, (ITER)->MEMBER.prev, MEMBER))
+#define LIST_FOR_EACH_REVERSE_CONTINUE(ITER, MEMBER, LIST)              \
+    for (ASSIGN_CONTAINER(ITER, (ITER)->MEMBER.prev, MEMBER);           \
+         &(ITER)->MEMBER != (LIST);                                     \
+         ASSIGN_CONTAINER(ITER, (ITER)->MEMBER.prev, MEMBER))
 #define LIST_FOR_EACH_SAFE(ITER, NEXT, MEMBER, LIST)            \
     for (ASSIGN_CONTAINER(ITER, (LIST)->next, MEMBER);          \
          (&(ITER)->MEMBER != (LIST)                             \
-- 
1.7.10.4




More information about the dev mailing list