Implement arbitrary bitwise masks for tun_id field.
authorBen Pfaff <blp@nicira.com>
Thu, 20 Jan 2011 23:29:00 +0000 (15:29 -0800)
committerBen Pfaff <blp@nicira.com>
Thu, 20 Jan 2011 23:29:00 +0000 (15:29 -0800)
This was documented to work, but not implemented.

Requested-by: Pankaj Thakkar <thakkar@nicira.com>
lib/classifier.c
lib/classifier.h
lib/flow.c
lib/flow.h
lib/nx-match.c
lib/nx-match.def
lib/ofp-parse.c
lib/ofp-util.c
tests/ovs-ofctl.at
tests/test-classifier.c
utilities/ovs-ofctl.8.in

index ba10272f77a0b632a8031efd2a1e91b0d7fcc99b..b05b491e89adb043b9876ff3b35df2f3b348b6b9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010 Nicira Networks.
+ * Copyright (c) 2009, 2010, 2011 Nicira Networks.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -130,8 +130,15 @@ cls_rule_set_reg_masked(struct cls_rule *rule, unsigned int reg_idx,
 void
 cls_rule_set_tun_id(struct cls_rule *rule, ovs_be64 tun_id)
 {
-    rule->wc.wildcards &= ~FWW_TUN_ID;
-    rule->flow.tun_id = tun_id;
+    cls_rule_set_tun_id_masked(rule, tun_id, htonll(UINT64_MAX));
+}
+
+void
+cls_rule_set_tun_id_masked(struct cls_rule *rule,
+                           ovs_be64 tun_id, ovs_be64 mask)
+{
+    rule->wc.tun_id_mask = mask;
+    rule->flow.tun_id = tun_id & mask;
 }
 
 void
@@ -393,8 +400,16 @@ cls_rule_format(const struct cls_rule *rule, struct ds *s)
             break;
         }
     }
-    if (!(w & FWW_TUN_ID)) {
-        ds_put_format(s, "tun_id=0x%"PRIx64",", ntohll(f->tun_id));
+    switch (wc->tun_id_mask) {
+    case 0:
+        break;
+    case CONSTANT_HTONLL(UINT64_MAX):
+        ds_put_format(s, "tun_id=%#"PRIx64",", ntohll(f->tun_id));
+        break;
+    default:
+        ds_put_format(s, "tun_id=%#"PRIx64"/%#"PRIx64",",
+                      ntohll(f->tun_id), ntohll(wc->tun_id_mask));
+        break;
     }
     if (!(w & FWW_IN_PORT)) {
         ds_put_format(s, "in_port=%"PRIu16",",
@@ -940,7 +955,7 @@ flow_equal_except(const struct flow *a, const struct flow *b,
         }
     }
 
-    return ((wc & FWW_TUN_ID || a->tun_id == b->tun_id)
+    return (!((a->tun_id ^ b->tun_id) & wildcards->tun_id_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)
@@ -973,9 +988,7 @@ zero_wildcards(struct flow *flow, const struct flow_wildcards *wildcards)
     for (i = 0; i < FLOW_N_REGS; i++) {
         flow->regs[i] &= wildcards->reg_masks[i];
     }
-    if (wc & FWW_TUN_ID) {
-        flow->tun_id = 0;
-    }
+    flow->tun_id &= wildcards->tun_id_mask;
     flow->nw_src &= wildcards->nw_src_mask;
     flow->nw_dst &= wildcards->nw_dst_mask;
     if (wc & FWW_IN_PORT) {
index 453417da6a4859f7a925d7dff109526fab046930..7b347e7b992ef122b4c51a43b97b789c9b8c222d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010 Nicira Networks.
+ * Copyright (c) 2009, 2010, 2011 Nicira Networks.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -78,6 +78,8 @@ void cls_rule_set_reg(struct cls_rule *, unsigned int reg_idx, uint32_t value);
 void cls_rule_set_reg_masked(struct cls_rule *, unsigned int reg_idx,
                              uint32_t value, uint32_t mask);
 void cls_rule_set_tun_id(struct cls_rule *, ovs_be64 tun_id);
+void cls_rule_set_tun_id_masked(struct cls_rule *,
+                                ovs_be64 tun_id, ovs_be64 mask);
 void cls_rule_set_in_port(struct cls_rule *, uint16_t odp_port);
 void cls_rule_set_dl_type(struct cls_rule *, ovs_be16);
 void cls_rule_set_dl_src(struct cls_rule *, const uint8_t[6]);
index e7ed2a97efe1b33e58d72765653289cea61573c6..42f850fbde53b14da8ef4a96409113b3dcd677cd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -302,6 +302,7 @@ void
 flow_wildcards_init_catchall(struct flow_wildcards *wc)
 {
     wc->wildcards = FWW_ALL;
+    wc->tun_id_mask = htonll(0);
     wc->nw_src_mask = htonl(0);
     wc->nw_dst_mask = htonl(0);
     memset(wc->reg_masks, 0, sizeof wc->reg_masks);
@@ -315,6 +316,7 @@ void
 flow_wildcards_init_exact(struct flow_wildcards *wc)
 {
     wc->wildcards = 0;
+    wc->tun_id_mask = htonll(UINT64_MAX);
     wc->nw_src_mask = htonl(UINT32_MAX);
     wc->nw_dst_mask = htonl(UINT32_MAX);
     memset(wc->reg_masks, 0xff, sizeof wc->reg_masks);
@@ -330,6 +332,7 @@ flow_wildcards_is_exact(const struct flow_wildcards *wc)
     int i;
 
     if (wc->wildcards
+        || wc->tun_id_mask != htonll(UINT64_MAX)
         || wc->nw_src_mask != htonl(UINT32_MAX)
         || wc->nw_dst_mask != htonl(UINT32_MAX)
         || wc->vlan_tci_mask != htons(UINT16_MAX)) {
@@ -356,6 +359,7 @@ flow_wildcards_combine(struct flow_wildcards *dst,
     int i;
 
     dst->wildcards = src1->wildcards | src2->wildcards;
+    dst->tun_id_mask = src1->tun_id_mask & src2->tun_id_mask;
     dst->nw_src_mask = src1->nw_src_mask & src2->nw_src_mask;
     dst->nw_dst_mask = src1->nw_dst_mask & src2->nw_dst_mask;
     for (i = 0; i < FLOW_N_REGS; i++) {
@@ -371,7 +375,7 @@ flow_wildcards_hash(const struct flow_wildcards *wc)
     /* If you change struct flow_wildcards and thereby trigger this
      * assertion, please check that the new struct flow_wildcards has no holes
      * in it before you update the assertion. */
-    BUILD_ASSERT_DECL(sizeof *wc == 16 + FLOW_N_REGS * 4);
+    BUILD_ASSERT_DECL(sizeof *wc == 24 + FLOW_N_REGS * 4);
     return hash_bytes(wc, sizeof *wc, 0);
 }
 
@@ -384,6 +388,7 @@ flow_wildcards_equal(const struct flow_wildcards *a,
     int i;
 
     if (a->wildcards != b->wildcards
+        || a->tun_id_mask != b->tun_id_mask
         || a->nw_src_mask != b->nw_src_mask
         || a->nw_dst_mask != b->nw_dst_mask
         || a->vlan_tci_mask != b->vlan_tci_mask) {
@@ -414,6 +419,7 @@ flow_wildcards_has_extra(const struct flow_wildcards *a,
     }
 
     return (a->wildcards & ~b->wildcards
+            || (a->tun_id_mask & b->tun_id_mask) != b->tun_id_mask
             || (a->nw_src_mask & b->nw_src_mask) != b->nw_src_mask
             || (a->nw_dst_mask & b->nw_dst_mask) != b->nw_dst_mask
             || (a->vlan_tci_mask & b->vlan_tci_mask) != b->vlan_tci_mask);
index ee460e386589e4fc44ac333992aa3f466a052402..966f1d684bdf3213fc2d656391d7ea08579b9da0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -107,18 +107,17 @@ typedef unsigned int OVS_BITWISE flow_wildcards_t;
 #define FWW_TP_DST      ((OVS_FORCE flow_wildcards_t) (1 << 7))
 /* Same meanings as corresponding OFPFW_* bits, but differ in value. */
 #define FWW_NW_TOS      ((OVS_FORCE flow_wildcards_t) (1 << 1))
-/* No OFPFW_* bits, but they do have corresponding OVSFW_* bits. */
-#define FWW_TUN_ID      ((OVS_FORCE flow_wildcards_t) (1 << 8))
 /* No corresponding OFPFW_* or OVSFW_* bits. */
-#define FWW_ETH_MCAST   ((OVS_FORCE flow_wildcards_t) (1 << 9))
+#define FWW_ETH_MCAST   ((OVS_FORCE flow_wildcards_t) (1 << 8))
                                                        /* multicast bit only */
-#define FWW_ALL         ((OVS_FORCE flow_wildcards_t) (((1 << 10)) - 1))
+#define FWW_ALL         ((OVS_FORCE flow_wildcards_t) (((1 << 9)) - 1))
 
 /* Information on wildcards for a flow, as a supplement to "struct flow".
  *
  * Note that the meaning of 1-bits in 'wildcards' is opposite that of 1-bits in
  * the rest of the members. */
 struct flow_wildcards {
+    ovs_be64 tun_id_mask;       /* 1-bit in each significant tun_id bit. */
     flow_wildcards_t wildcards; /* 1-bit in each FWW_* wildcarded field. */
     uint32_t reg_masks[FLOW_N_REGS]; /* 1-bit in each significant regs bit. */
     ovs_be32 nw_src_mask;       /* 1-bit in each significant nw_src bit. */
index fc3af68df33f2ad759455b118c266d5f287ba429..392ea869f5df6b72e651cec2b378937927819595 100644 (file)
@@ -320,8 +320,21 @@ parse_nxm_entry(struct cls_rule *rule, const struct nxm_field *f,
 
         /* Tunnel ID. */
     case NFI_NXM_NX_TUN_ID:
-        flow->tun_id = get_unaligned_be64(value);
-        return 0;
+        if (wc->tun_id_mask) {
+            return NXM_DUP_TYPE;
+        } else {
+            cls_rule_set_tun_id(rule, get_unaligned_be64(value));
+            return 0;
+        }
+    case NFI_NXM_NX_TUN_ID_W:
+        if (wc->tun_id_mask) {
+            return NXM_DUP_TYPE;
+        } else {
+            ovs_be64 tun_id = get_unaligned_be64(value);
+            ovs_be64 tun_mask = get_unaligned_be64(mask);
+            cls_rule_set_tun_id_masked(rule, tun_id, tun_mask);
+            return 0;
+        }
 
         /* Registers. */
     case NFI_NXM_NX_REG0:
@@ -533,6 +546,31 @@ nxm_put_64(struct ofpbuf *b, uint32_t header, ovs_be64 value)
     ofpbuf_put(b, &value, sizeof value);
 }
 
+static void
+nxm_put_64w(struct ofpbuf *b, uint32_t header, ovs_be64 value, ovs_be64 mask)
+{
+    nxm_put_header(b, header);
+    ofpbuf_put(b, &value, sizeof value);
+    ofpbuf_put(b, &mask, sizeof mask);
+}
+
+static void
+nxm_put_64m(struct ofpbuf *b, uint32_t header, ovs_be64 value, ovs_be64 mask)
+{
+    switch (mask) {
+    case 0:
+        break;
+
+    case CONSTANT_HTONLL(UINT64_MAX):
+        nxm_put_64(b, header, value);
+        break;
+
+    default:
+        nxm_put_64w(b, NXM_MAKE_WILD_HEADER(header), value, mask);
+        break;
+    }
+}
+
 static void
 nxm_put_eth(struct ofpbuf *b, uint32_t header,
             const uint8_t value[ETH_ADDR_LEN])
@@ -657,9 +695,7 @@ nx_put_match(struct ofpbuf *b, const struct cls_rule *cr)
     }
 
     /* Tunnel ID. */
-    if (!(wc & FWW_TUN_ID)) {
-        nxm_put_64(b, NXM_NX_TUN_ID, flow->tun_id);
-    }
+    nxm_put_64m(b, NXM_NX_TUN_ID, flow->tun_id, cr->wc.tun_id_mask);
 
     /* Registers. */
     for (i = 0; i < FLOW_N_REGS; i++) {
@@ -1125,6 +1161,7 @@ nxm_read_field(const struct nxm_field *src, const struct flow *flow)
 #error
 #endif
 
+    case NFI_NXM_NX_TUN_ID_W:
     case NFI_NXM_OF_ETH_DST_W:
     case NFI_NXM_OF_VLAN_TCI_W:
     case NFI_NXM_OF_IP_SRC_W:
@@ -1189,6 +1226,7 @@ nxm_write_field(const struct nxm_field *dst, struct flow *flow,
     case NFI_NXM_OF_UDP_DST:
     case NFI_NXM_OF_ICMP_TYPE:
     case NFI_NXM_OF_ICMP_CODE:
+    case NFI_NXM_NX_TUN_ID_W:
     case NFI_NXM_OF_ETH_DST_W:
     case NFI_NXM_OF_VLAN_TCI_W:
     case NFI_NXM_OF_IP_SRC_W:
index 9c113eb286a99599e1782e66436dd9cbd4f0c326..09f375bdfec55b50e6885b5885027ca116e7e6de 100644 (file)
@@ -38,7 +38,7 @@ DEFINE_FIELD  (OF_ICMP_CODE, FWW_TP_DST,   ETH_TYPE_IP,  IP_TYPE_ICMP, false)
 DEFINE_FIELD  (OF_ARP_OP,    FWW_NW_PROTO, ETH_TYPE_ARP, 0,            false)
 DEFINE_FIELD_M(OF_ARP_SPA,   0,            ETH_TYPE_ARP, 0,            false)
 DEFINE_FIELD_M(OF_ARP_TPA,   0,            ETH_TYPE_ARP, 0,            false)
-DEFINE_FIELD  (NX_TUN_ID,    FWW_TUN_ID,   0,            0,            true)
+DEFINE_FIELD_M(NX_TUN_ID,    0,            0,            0,            true)
 
 DEFINE_FIELD_M(NX_REG0,      0,            0,            0,            true)
 #if FLOW_N_REGS >= 2
index f8464b99d7fbde5f96cecb86e1776b8d6679810a..7fed553eadc0aa8fde0e434a11c8c21f8a7918b6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Nicira Networks.
+ * Copyright (c) 2010, 2011 Nicira Networks.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -128,6 +128,35 @@ str_to_ip(const char *str_, ovs_be32 *ip, ovs_be32 *maskp)
     free(str);
 }
 
+static void
+str_to_tun_id(const char *str, ovs_be64 *tun_idp, ovs_be64 *maskp)
+{
+    uint64_t tun_id, mask;
+    char *tail;
+
+    errno = 0;
+    tun_id = strtoull(str, &tail, 0);
+    if (errno || (*tail != '\0' && *tail != '/')) {
+        goto error;
+    }
+
+    if (*tail == '/') {
+        mask = strtoull(tail + 1, &tail, 0);
+        if (errno || *tail != '\0') {
+            goto error;
+        }
+    } else {
+        mask = UINT64_MAX;
+    }
+
+    *tun_idp = htonll(tun_id);
+    *maskp = htonll(mask);
+    return;
+
+error:
+    ovs_fatal(0, "%s: bad syntax for tunnel id", str);
+}
+
 static void *
 put_action(struct ofpbuf *b, size_t size, uint16_t type)
 {
@@ -448,7 +477,7 @@ parse_protocol(const char *name, const struct protocol **p_out)
 }
 
 #define FIELDS                                              \
-    FIELD(F_TUN_ID,      "tun_id",      FWW_TUN_ID)         \
+    FIELD(F_TUN_ID,      "tun_id",      0)                  \
     FIELD(F_IN_PORT,     "in_port",     FWW_IN_PORT)        \
     FIELD(F_DL_VLAN,     "dl_vlan",     0)                  \
     FIELD(F_DL_VLAN_PCP, "dl_vlan_pcp", 0)                  \
@@ -502,12 +531,14 @@ parse_field_value(struct cls_rule *rule, enum field_index index,
                   const char *value)
 {
     uint8_t mac[ETH_ADDR_LEN];
+    ovs_be64 tun_id, tun_mask;
     ovs_be32 ip, mask;
     uint16_t port_no;
 
     switch (index) {
     case F_TUN_ID:
-        cls_rule_set_tun_id(rule, htonll(str_to_u64(value)));
+        str_to_tun_id(value, &tun_id, &tun_mask);
+        cls_rule_set_tun_id_masked(rule, tun_id, tun_mask);
         break;
 
     case F_IN_PORT:
index 7aea3319e727b0074ac2d77aa713e08f61e51baf..ed2325c3cda6e8b757333255552f0ff8669be0e9 100644 (file)
@@ -132,9 +132,6 @@ ofputil_cls_rule_from_match(const struct ofp_match *match,
 
     if (flow_format == NXFF_TUN_ID_FROM_COOKIE && !(ofpfw & NXFW_TUN_ID)) {
         rule->flow.tun_id = htonll(ntohll(cookie) >> 32);
-    } else {
-        wc->wildcards |= FWW_TUN_ID;
-        rule->flow.tun_id = htonll(0);
     }
 
     if (ofpfw & OFPFW_DL_DST) {
@@ -233,7 +230,7 @@ ofputil_cls_rule_to_match(const struct cls_rule *rule,
 
     /* Tunnel ID. */
     if (flow_format == NXFF_TUN_ID_FROM_COOKIE) {
-        if (wc->wildcards & FWW_TUN_ID) {
+        if (wc->tun_id_mask == htonll(0)) {
             ofpfw |= NXFW_TUN_ID;
         } else {
             uint32_t cookie_lo = ntohll(cookie_in);
@@ -829,6 +826,47 @@ regs_fully_wildcarded(const struct flow_wildcards *wc)
     return true;
 }
 
+static inline bool
+is_nxm_required(const struct cls_rule *rule, bool cookie_support,
+                ovs_be64 cookie)
+{
+    const struct flow_wildcards *wc = &rule->wc;
+    ovs_be32 cookie_hi;
+
+    /* Only NXM supports separately wildcards the Ethernet multicast bit. */
+    if (!(wc->wildcards & FWW_DL_DST) != !(wc->wildcards & FWW_ETH_MCAST)) {
+        return true;
+    }
+
+    /* Only NXM supports matching registers. */
+    if (!regs_fully_wildcarded(wc)) {
+        return true;
+    }
+
+    switch (wc->tun_id_mask) {
+    case CONSTANT_HTONLL(0):
+        /* Other formats can fully wildcard tun_id. */
+        break;
+
+    case CONSTANT_HTONLL(UINT64_MAX):
+        /* Only NXM supports matching tunnel ID, unless there is a cookie and
+         * the top 32 bits of the cookie are the desired tunnel ID value. */
+        cookie_hi = htonl(ntohll(cookie) >> 32);
+        if (!cookie_support
+            || (cookie_hi && cookie_hi != ntohll(rule->flow.tun_id))) {
+            return true;
+        }
+        break;
+
+    default:
+        /* Only NXM supports partial matches on tunnel ID. */
+        return true;
+    }
+
+    /* Other formats can express this rule. */
+    return false;
+}
+
 /* Returns the minimum nx_flow_format to use for sending 'rule' to a switch
  * (e.g. to add or remove a flow).  'cookie_support' should be true if the
  * command to be sent includes a flow cookie (as OFPT_FLOW_MOD does, for
@@ -853,16 +891,9 @@ enum nx_flow_format
 ofputil_min_flow_format(const struct cls_rule *rule, bool cookie_support,
                         ovs_be64 cookie)
 {
-    const struct flow_wildcards *wc = &rule->wc;
-    ovs_be32 cookie_hi = htonl(ntohll(cookie) >> 32);
-
-    if (!(wc->wildcards & FWW_DL_DST) != !(wc->wildcards & FWW_ETH_MCAST)
-        || !regs_fully_wildcarded(wc)
-        || (!(wc->wildcards & FWW_TUN_ID)
-            && (!cookie_support
-                || (cookie_hi && cookie_hi != ntohll(rule->flow.tun_id))))) {
+    if (is_nxm_required(rule, cookie_support, cookie)) {
         return NXFF_NXM;
-    } else if (!(wc->wildcards & FWW_TUN_ID)) {
+    } else if (rule->wc.tun_id_mask != htonll(0)) {
         return NXFF_TUN_ID_FROM_COOKIE;
     } else {
         return NXFF_OPENFLOW10;
index 143c59bd1b83b5c7078f4b37191d49b42e1bf8d4..0648f067d901ceab632cf0a6e5e8fd2a5de790f1 100644 (file)
@@ -15,6 +15,7 @@ tun_id=0x1234,cookie=0x5678,actions=flood
 actions=set_tunnel:0x1234,set_tunnel64:0x9876,set_tunnel:0x123456789
 actions=multipath(eth_src, 50, hrw, 12, 0, NXM_NX_REG0[0..3]),multipath(symmetric_l4, 1024, iter_hash, 5000, 5050, NXM_NX_REG0[0..12])
 actions=drop
+tun_id=0x1234000056780000/0xffff0000ffff0000,actions=drop
 ]])
 AT_CHECK([ovs-ofctl parse-flows flows.txt
 ], [0], [stdout], [stderr])
@@ -32,6 +33,8 @@ OFPT_FLOW_MOD: ADD cookie:0x123400005678 actions=FLOOD
 OFPT_FLOW_MOD: ADD actions=set_tunnel:0x1234,set_tunnel64:0x9876,set_tunnel64:0x123456789
 OFPT_FLOW_MOD: ADD actions=multipath(eth_src,50,hrw,12,0,NXM_NX_REG0[0..3]),multipath(symmetric_l4,1024,iter_hash,5000,5050,NXM_NX_REG0[0..12])
 OFPT_FLOW_MOD: ADD actions=drop
+NXT_SET_FLOW_FORMAT: format=nxm
+NXT_FLOW_MOD: ADD tun_id=0x1234000056780000/0xffff0000ffff0000 actions=drop
 ]])
 AT_CHECK([sed 's/.*|//' stderr], [0], [dnl
 normalization changed ofp_match, details:
@@ -65,6 +68,7 @@ cookie=0x123456789abcdef hard_timeout=10 priority=60000 actions=controller
 actions=note:41.42.43,note:00.01.02.03.04.05.06.07,note
 tun_id=0x1234,cookie=0x5678,actions=flood
 actions=drop
+tun_id=0x1234000056780000/0xffff0000ffff0000,actions=drop
 ])
 AT_CHECK([ovs-ofctl -F nxm parse-flows flows.txt], [0], [stdout])
 AT_CHECK([[sed 's/ (xid=0x[0-9a-fA-F]*)//' stdout]], [0], [dnl
@@ -78,6 +82,7 @@ NXT_FLOW_MOD: ADD priority=60000 cookie:0x123456789abcdef hard:10 actions=CONTRO
 NXT_FLOW_MOD: ADD actions=note:41.42.43.00.00.00,note:00.01.02.03.04.05.06.07.00.00.00.00.00.00,note:00.00.00.00.00.00
 NXT_FLOW_MOD: ADD tun_id=0x1234 cookie:0x5678 actions=FLOOD
 NXT_FLOW_MOD: ADD actions=drop
+NXT_FLOW_MOD: ADD tun_id=0x1234000056780000/0xffff0000ffff0000 actions=drop
 ])
 AT_CLEANUP
 
@@ -214,6 +219,7 @@ NXM_OF_ARP_TPA_W(C0D80000/FFFF0000)
 
 # Tunnel ID.
 NXM_NX_TUN_ID(00000000abcdef01)
+NXM_NX_TUN_ID_W(84200000abcdef01/84200000FFFFFFFF)
 
 # Register 0.
 NXM_NX_REG0(acebdf56)
@@ -331,6 +337,7 @@ nx_pull_match() returned error 44010104
 
 # Tunnel ID.
 NXM_NX_TUN_ID(00000000abcdef01)
+NXM_NX_TUN_ID_W(84200000abcdef01/84200000ffffffff)
 
 # Register 0.
 NXM_NX_REG0(acebdf56)
index 63a7adacc7db4c8be8818e08282393e145e5f12e..e1f93a09d95afb21d056f15bcfb6cce5cbf2f689 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010 Nicira Networks.
+ * Copyright (c) 2009, 2010, 2011 Nicira Networks.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -44,7 +44,7 @@
     /*                                    struct flow  all-caps */  \
     /*        FWW_* bit(s)                member name  name     */  \
     /*        --------------------------  -----------  -------- */  \
-    CLS_FIELD(FWW_TUN_ID,                 tun_id,      TUN_ID)      \
+    CLS_FIELD(0,                          tun_id,      TUN_ID)      \
     CLS_FIELD(0,                          nw_src,      NW_SRC)      \
     CLS_FIELD(0,                          nw_dst,      NW_DST)      \
     CLS_FIELD(FWW_IN_PORT,                in_port,     IN_PORT)     \
@@ -201,6 +201,8 @@ match(const struct cls_rule *wild, const struct flow *fixed)
         } else if (f_idx == CLS_F_IDX_VLAN_TCI) {
             eq = !((fixed->vlan_tci ^ wild->flow.vlan_tci)
                    & wild->wc.vlan_tci_mask);
+        } else if (f_idx == CLS_F_IDX_TUN_ID) {
+            eq = !((fixed->tun_id ^ wild->flow.tun_id) & wild->wc.tun_id_mask);
         } else {
             NOT_REACHED();
         }
@@ -463,6 +465,8 @@ make_rule(int wc_fields, unsigned int priority, int value_pat)
             rule->cls_rule.wc.nw_dst_mask = htonl(UINT32_MAX);
         } else if (f_idx == CLS_F_IDX_VLAN_TCI) {
             rule->cls_rule.wc.vlan_tci_mask = htons(UINT16_MAX);
+        } else if (f_idx == CLS_F_IDX_TUN_ID) {
+            rule->cls_rule.wc.tun_id_mask = htonll(UINT64_MAX);
         } else {
             NOT_REACHED();
         }
index 0a2a5e9884b83be78625ad57ff7d0c3215385d58..75047748371decec4ce30d96c573002aaee6ea27 100644 (file)
@@ -337,20 +337,25 @@ as a decimal number between 0 and 255, inclusive.
 .IP
 When \fBdl_type\fR and \fBnw_proto\fR take other values, the values of
 these settings are ignored (see \fBFlow Syntax\fR above).
-.IP \fBtun_id=\fItunnel\-id\fR
-Matches tunnel identifier \fItunnel\-id\fR.  Only packets that arrive
+.IP \fBtun_id=\fItunnel-id\fR[\fB/\fImask\fR]
+Matches tunnel identifier \fItunnel-id\fR.  Only packets that arrive
 over a tunnel that carries a key (e.g. GRE with the RFC 2890 key
-extension) will have a nonzero tunnel ID.
+extension) will have a nonzero tunnel ID.  If \fImask\fR is omitted,
+\fItunnel-id\fR is the exact tunnel ID to match; \fImask\fR is
+specified, then a 1-bit in \fImask\fR indicates that the corresponding
+bit in \fItunnel-id\fR must match exactly, and a 0-bit wildcards that
+bit.
 .IP
 \fBtun_id\fR requires use of one of two Nicira extensions to OpenFlow:
 .RS
 .IP "NXM (Nicira Extended Match)"
 This extension fully supports \fBtun_id\fR. 
 .IP "Tunnel ID from Cookie"
-This extension supports \fBtun_id\fR with two caveats: the top 32 bits
-of the \fBcookie\fR (see below) are used for \fItunnel\-id\fR and thus
-unavailable for other use, and specifying \fBtun_id\fR on
-\fBdump\-flows\fR or \fBdump\-aggregate\fR has no effect.
+This extension supports \fBtun_id\fR with three caveats: the top 32 bits
+of the \fBcookie\fR (see below) are used for \fItunnel-id\fR and thus
+unavailable for other use, specifying \fBtun_id\fR on
+\fBdump\-flows\fR or \fBdump\-aggregate\fR has no effect, and
+\fImask\fR is not supported.
 .RE
 .IP
 When \fBtun_id\fR is specified, \fBovs\-ofctl\fR will automatically