classifier: Introduce macros for iterating exact-match flows.
[sliver-openvswitch.git] / lib / classifier.c
index 036c372..8e5c1a6 100644 (file)
@@ -19,6 +19,7 @@
 #include <assert.h>
 #include <errno.h>
 #include <netinet/in.h>
+#include "dynamic-string.h"
 #include "flow.h"
 #include "hash.h"
 
@@ -54,8 +55,8 @@ static bool rules_match_2wild(const struct cls_rule *wild1,
 /* Converts the flow in 'flow' into a cls_rule in 'rule', with the given
  * 'wildcards' and 'priority'.*/
 void
-cls_rule_from_flow(struct cls_rule *rule, const flow_t *flow,
-                   uint32_t wildcards, unsigned int priority)
+cls_rule_from_flow(const flow_t *flow, uint32_t wildcards,
+                   unsigned int priority, struct cls_rule *rule)
 {
     assert(!flow->reserved[0] && !flow->reserved[1] && !flow->reserved[2]);
     rule->flow = *flow;
@@ -65,18 +66,32 @@ cls_rule_from_flow(struct cls_rule *rule, const flow_t *flow,
 }
 
 /* Converts the ofp_match in 'match' into a cls_rule in 'rule', with the given
- * 'priority'. */
+ * 'priority'.  If 'tun_id_from_cookie' is set then the upper 32 bits of
+ * 'cookie' are stored in the rule as the tunnel ID. */
 void
-cls_rule_from_match(struct cls_rule *rule, const struct ofp_match *match,
-                    unsigned int priority)
+cls_rule_from_match(const struct ofp_match *match, unsigned int priority,
+                    bool tun_id_from_cookie, uint64_t cookie,
+                    struct cls_rule *rule)
 {
     uint32_t wildcards;
-    flow_from_match(&rule->flow, &wildcards, match);
+    flow_from_match(match, tun_id_from_cookie, cookie, &rule->flow, &wildcards);
     flow_wildcards_init(&rule->wc, wildcards);
     rule->priority = rule->wc.wildcards ? priority : UINT16_MAX;
     rule->table_idx = table_idx_from_wildcards(rule->wc.wildcards);
 }
 
+/* Converts 'rule' to a string and returns the string.  The caller must free
+ * the string (with free()). */
+char *
+cls_rule_to_string(const struct cls_rule *rule)
+{
+    struct ds s = DS_EMPTY_INITIALIZER;
+    ds_put_format(&s, "wildcards=%x priority=%u ",
+                  rule->wc.wildcards, rule->priority);
+    flow_format(&s, &rule->flow);
+    return ds_cstr(&s);
+}
+
 /* Prints cls_rule 'rule', for debugging.
  *
  * (The output could be improved and expanded, but this was good enough to
@@ -292,7 +307,7 @@ classifier_lookup_wild(const struct classifier *cls, const flow_t *flow)
         struct cls_rule target;
         int i;
 
-        cls_rule_from_flow(&target, flow, 0, 0);
+        cls_rule_from_flow(flow, 0, 0, &target);
         for (i = 0; i < CLS_N_FIELDS; i++) {
             struct cls_rule *rule = search_table(&cls->tables[i], i, &target);
             if (rule && (!best || rule->priority > best->priority)) {
@@ -317,7 +332,7 @@ classifier_find_rule_exactly(const struct classifier *cls,
         return search_exact_table(cls, flow_hash(target, 0), target);
     }
 
-    assert(wildcards == (wildcards & OFPFW_ALL));
+    assert(wildcards == (wildcards & OVSFW_ALL));
     table_idx = table_idx_from_wildcards(wildcards);
     hash = hash_fields(target, table_idx);
     HMAP_FOR_EACH_WITH_HASH (bucket, struct cls_bucket, hmap_node, hash,
@@ -338,8 +353,8 @@ classifier_find_rule_exactly(const struct classifier *cls,
     return NULL;
 }
 
-/* Checks if the flow defined by 'target' with 'wildcards' at 'priority' 
- * overlaps with any other rule at the same priority in the classifier.  
+/* Checks if the flow defined by 'target' with 'wildcards' at 'priority'
+ * overlaps with any other rule at the same priority in the classifier.
  * Two rules are considered overlapping if a packet could match both. */
 bool
 classifier_rule_overlaps(const struct classifier *cls,
@@ -354,7 +369,7 @@ classifier_rule_overlaps(const struct classifier *cls,
             true : false;
     }
 
-    cls_rule_from_flow(&target_rule, target, wildcards, priority);
+    cls_rule_from_flow(target, wildcards, priority, &target_rule);
 
     for (tbl = &cls->tables[0]; tbl < &cls->tables[CLS_N_FIELDS]; tbl++) {
         struct cls_bucket *bucket;
@@ -364,7 +379,7 @@ classifier_rule_overlaps(const struct classifier *cls,
 
             LIST_FOR_EACH (rule, struct cls_rule, node.list,
                            &bucket->rules) {
-                if (rule->priority == priority 
+                if (rule->priority == priority
                         && rules_match_2wild(rule, &target_rule, 0)) {
                     return true;
                 }
@@ -450,7 +465,10 @@ classifier_for_each_match(const struct classifier *cls,
  * it must not delete (or move) any other rules in 'cls' that are in the same
  * table as the argument rule.  Two rules are in the same table if their
  * cls_rule structs have the same table_idx; as a special case, a rule with
- * wildcards and an exact-match rule will never be in the same table. */
+ * wildcards and an exact-match rule will never be in the same table.
+ *
+ * If 'include' is CLS_INC_EXACT then CLASSIFIER_FOR_EACH_EXACT_RULE(_SAFE) is
+ * probably easier to use. */
 void
 classifier_for_each(const struct classifier *cls, int include,
                     void (*callback)(struct cls_rule *, void *aux),
@@ -627,14 +645,14 @@ bucket_insert(struct cls_bucket *bucket, struct cls_rule *rule)
 {
     struct cls_rule *pos;
     LIST_FOR_EACH (pos, struct cls_rule, node.list, &bucket->rules) {
-        if (pos->priority <= rule->priority) {
-            if (pos->priority == rule->priority
-                && pos->wc.wildcards == rule->wc.wildcards
+        if (pos->priority == rule->priority) {
+            if (pos->wc.wildcards == rule->wc.wildcards
                 && rules_match_1wild(pos, rule, rule->table_idx))
             {
                 list_replace(&rule->node.list, &pos->node.list);
                 return pos;
             }
+        } else if (pos->priority < rule->priority) {
             break;
         }
     }
@@ -813,10 +831,10 @@ static bool
 rules_match_2wild(const struct cls_rule *wild1, const struct cls_rule *wild2,
                   int field_idx)
 {
-    return rules_match(wild1, wild2, 
-                       wild1->wc.wildcards | wild2->wc.wildcards, 
+    return rules_match(wild1, wild2,
+                       wild1->wc.wildcards | wild2->wc.wildcards,
                        wild1->wc.nw_src_mask & wild2->wc.nw_src_mask,
-                       wild1->wc.nw_dst_mask & wild2->wc.nw_dst_mask, 
+                       wild1->wc.nw_dst_mask & wild2->wc.nw_dst_mask,
                        field_idx);
 }