OXM, NXM: Add tests for all zero and all one masks
[openvswitch] / lib / classifier.c
index 327a8b2ccdc3aa8a601e6ce8d2b1a51b91bae4e2..2d9fd0a97e15680302d2b9410accdd2620b49956 100644 (file)
@@ -118,6 +118,20 @@ cls_rule_set_reg_masked(struct cls_rule *rule, unsigned int reg_idx,
     rule->flow.regs[reg_idx] = value & mask;
 }
 
+void
+cls_rule_set_metadata(struct cls_rule *rule, ovs_be64 metadata)
+{
+    cls_rule_set_metadata_masked(rule, metadata, htonll(UINT64_MAX));
+}
+
+void
+cls_rule_set_metadata_masked(struct cls_rule *rule, ovs_be64 metadata,
+                             ovs_be64 mask)
+{
+    rule->wc.metadata_mask = mask;
+    rule->flow.metadata = metadata & mask;
+}
+
 void
 cls_rule_set_tun_id(struct cls_rule *rule, ovs_be64 tun_id)
 {
@@ -233,7 +247,7 @@ void
 cls_rule_set_dl_vlan(struct cls_rule *rule, ovs_be16 dl_vlan)
 {
     flow_set_vlan_vid(&rule->flow, dl_vlan);
-    if (dl_vlan == htons(OFP_VLAN_NONE)) {
+    if (dl_vlan == htons(OFP10_VLAN_NONE)) {
         rule->wc.vlan_tci_mask = htons(UINT16_MAX);
     } else {
         rule->wc.vlan_tci_mask |= htons(VLAN_VID_MASK | VLAN_CFI);
@@ -525,7 +539,7 @@ cls_rule_format(const struct cls_rule *rule, struct ds *s)
 
     int i;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 12);
 
     if (rule->priority != OFP_DEFAULT_PRIORITY) {
         ds_put_format(s, "priority=%d,", rule->priority);
@@ -595,6 +609,17 @@ cls_rule_format(const struct cls_rule *rule, struct ds *s)
                       ntohll(f->tun_id), ntohll(wc->tun_id_mask));
         break;
     }
+    switch (wc->metadata_mask) {
+    case 0:
+        break;
+    case CONSTANT_HTONLL(UINT64_MAX):
+        ds_put_format(s, "metadata=%#"PRIx64",", ntohll(f->metadata));
+        break;
+    default:
+        ds_put_format(s, "metadata=%#"PRIx64"/%#"PRIx64",",
+                      ntohll(f->metadata), ntohll(wc->metadata_mask));
+        break;
+    }
     if (!(w & FWW_IN_PORT)) {
         ds_put_format(s, "in_port=%"PRIu16",", f->in_port);
     }
@@ -909,6 +934,47 @@ classifier_rule_overlaps(const struct classifier *cls,
 
     return false;
 }
+
+/* Returns true if 'rule' exactly matches 'criteria' or if 'rule' is more
+ * specific than 'criteria'.  That is, 'rule' matches 'criteria' and this
+ * function returns true if, for every field:
+ *
+ *   - 'criteria' and 'rule' specify the same (non-wildcarded) value for the
+ *     field, or
+ *
+ *   - 'criteria' wildcards the field,
+ *
+ * Conversely, 'rule' does not match 'criteria' and this function returns false
+ * if, for at least one field:
+ *
+ *   - 'criteria' and 'rule' specify different values for the field, or
+ *
+ *   - 'criteria' specifies a value for the field but 'rule' wildcards it.
+ *
+ * Equivalently, the truth table for whether a field matches is:
+ *
+ *                                     rule
+ *
+ *                   c         wildcard    exact
+ *                   r        +---------+---------+
+ *                   i   wild |   yes   |   yes   |
+ *                   t   card |         |         |
+ *                   e        +---------+---------+
+ *                   r  exact |    no   |if values|
+ *                   i        |         |are equal|
+ *                   a        +---------+---------+
+ *
+ * This is the matching rule used by OpenFlow 1.0 non-strict OFPT_FLOW_MOD
+ * commands and by OpenFlow 1.0 aggregate and flow stats.
+ *
+ * Ignores rule->priority and criteria->priority. */
+bool
+cls_rule_is_loose_match(const struct cls_rule *rule,
+                        const struct cls_rule *criteria)
+{
+    return (!flow_wildcards_has_extra(&rule->wc, &criteria->wc)
+            && flow_equal_except(&rule->flow, &criteria->flow, &criteria->wc));
+}
 \f
 /* Iteration. */
 
@@ -934,40 +1000,14 @@ search_table(const struct cls_table *table, const struct cls_rule *target)
     return NULL;
 }
 
-/* Initializes 'cursor' for iterating through 'cls' rules that exactly match
- * 'target' or are more specific than 'target'.  That is, a given 'rule'
- * matches 'target' if, for every field:
- *
- *   - 'target' and 'rule' specify the same (non-wildcarded) value for the
- *     field, or
+/* Initializes 'cursor' for iterating through rules in 'cls':
  *
- *   - 'target' wildcards the field,
- *
- * but not if:
- *
- *   - 'target' and 'rule' specify different values for the field, or
- *
- *   - 'target' specifies a value for the field but 'rule' wildcards it.
- *
- * Equivalently, the truth table for whether a field matches is:
- *
- *                                     rule
- *
- *                             wildcard    exact
- *                            +---------+---------+
- *                   t   wild |   yes   |   yes   |
- *                   a   card |         |         |
- *                   r        +---------+---------+
- *                   g  exact |    no   |if values|
- *                   e        |         |are equal|
- *                   t        +---------+---------+
- *
- * This is the matching rule used by OpenFlow 1.0 non-strict OFPT_FLOW_MOD
- * commands and by OpenFlow 1.0 aggregate and flow stats.
+ *     - If 'target' is null, the cursor will visit every rule in 'cls'.
  *
- * Ignores target->priority.
+ *     - If 'target' is nonnull, the cursor will visit each 'rule' in 'cls'
+ *       such that cls_rule_is_loose_match(rule, target) returns true.
  *
- * 'target' may be NULL to iterate over every rule in 'cls'. */
+ * Ignores target->priority. */
 void
 cls_cursor_init(struct cls_cursor *cursor, const struct classifier *cls,
                 const struct cls_rule *target)
@@ -1188,7 +1228,7 @@ flow_equal_except(const struct flow *a, const struct flow *b,
     const flow_wildcards_t wc = wildcards->wildcards;
     int i;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 12);
 
     for (i = 0; i < FLOW_N_REGS; i++) {
         if ((a->regs[i] ^ b->regs[i]) & wildcards->reg_masks[i]) {
@@ -1197,6 +1237,7 @@ flow_equal_except(const struct flow *a, const struct flow *b,
     }
 
     return (!((a->tun_id ^ b->tun_id) & wildcards->tun_id_mask)
+            && !((a->metadata ^ b->metadata) & wildcards->metadata_mask)
             && !((a->nw_src ^ b->nw_src) & wildcards->nw_src_mask)
             && !((a->nw_dst ^ b->nw_dst) & wildcards->nw_dst_mask)
             && (wc & FWW_IN_PORT || a->in_port == b->in_port)
@@ -1204,10 +1245,10 @@ flow_equal_except(const struct flow *a, const struct flow *b,
             && (wc & FWW_DL_TYPE || a->dl_type == b->dl_type)
             && !((a->tp_src ^ b->tp_src) & wildcards->tp_src_mask)
             && !((a->tp_dst ^ b->tp_dst) & wildcards->tp_dst_mask)
-            && !eth_addr_equal_except(a->dl_src, b->dl_src,
-                    wildcards->dl_src_mask)
-            && !eth_addr_equal_except(a->dl_dst, b->dl_dst,
-                    wildcards->dl_dst_mask)
+            && eth_addr_equal_except(a->dl_src, b->dl_src,
+                                     wildcards->dl_src_mask)
+            && eth_addr_equal_except(a->dl_dst, b->dl_dst,
+                                     wildcards->dl_dst_mask)
             && (wc & FWW_NW_PROTO || a->nw_proto == b->nw_proto)
             && (wc & FWW_NW_TTL || a->nw_ttl == b->nw_ttl)
             && (wc & FWW_NW_DSCP || !((a->nw_tos ^ b->nw_tos) & IP_DSCP_MASK))