ofp-util: Implement translation to and from OpenFlow 1.1 ofp_match.
authorBen Pfaff <blp@nicira.com>
Sat, 9 Jun 2012 22:49:16 +0000 (15:49 -0700)
committerBen Pfaff <blp@nicira.com>
Wed, 13 Jun 2012 04:19:19 +0000 (21:19 -0700)
This is another step toward OpenFlow 1.1 support.  The change does not
affect any outwardly visible OpenFlow behavior yet.

Reviewed-by: Simon Horman <horms@verge.net.au>
Signed-off-by: Ben Pfaff <blp@nicira.com>
lib/ofp-util.c
lib/ofp-util.h
tests/ovs-ofctl.at
utilities/ovs-ofctl.c

index 6fbde7b7c07cf0a4b36034279e163a3acbbd17ae..4af7a1ff2b15e43789852f4d2d1504af371d8225 100644 (file)
@@ -259,6 +259,267 @@ ofputil_cls_rule_to_ofp10_match(const struct cls_rule *rule,
     memset(match->pad2, '\0', sizeof match->pad2);
 }
 
+/* Converts the ofp11_match in 'match' into a cls_rule in 'rule', with the
+ * given 'priority'.  Returns 0 if successful, otherwise an OFPERR_* value. */
+enum ofperr
+ofputil_cls_rule_from_ofp11_match(const struct ofp11_match *match,
+                                  unsigned int priority,
+                                  struct cls_rule *rule)
+{
+    uint16_t wc = ntohl(match->wildcards);
+    uint8_t dl_src_mask[ETH_ADDR_LEN];
+    uint8_t dl_dst_mask[ETH_ADDR_LEN];
+    bool ipv4, arp;
+    int i;
+
+    cls_rule_init_catchall(rule, priority);
+
+    if (!(wc & OFPFW11_IN_PORT)) {
+        uint16_t ofp_port;
+        enum ofperr error;
+
+        error = ofputil_port_from_ofp11(match->in_port, &ofp_port);
+        if (error) {
+            return OFPERR_OFPBMC_BAD_VALUE;
+        }
+        cls_rule_set_in_port(rule, ofp_port);
+    }
+
+    for (i = 0; i < ETH_ADDR_LEN; i++) {
+        dl_src_mask[i] = ~match->dl_src_mask[i];
+    }
+    cls_rule_set_dl_src_masked(rule, match->dl_src, dl_src_mask);
+
+    for (i = 0; i < ETH_ADDR_LEN; i++) {
+        dl_dst_mask[i] = ~match->dl_dst_mask[i];
+    }
+    cls_rule_set_dl_dst_masked(rule, match->dl_dst, dl_dst_mask);
+
+    if (!(wc & OFPFW11_DL_VLAN)) {
+        if (match->dl_vlan == htons(OFPVID11_NONE)) {
+            /* Match only packets without a VLAN tag. */
+            rule->flow.vlan_tci = htons(0);
+            rule->wc.vlan_tci_mask = htons(UINT16_MAX);
+        } else {
+            if (match->dl_vlan == htons(OFPVID11_ANY)) {
+                /* Match any packet with a VLAN tag regardless of VID. */
+                rule->flow.vlan_tci = htons(VLAN_CFI);
+                rule->wc.vlan_tci_mask = htons(VLAN_CFI);
+            } else if (ntohs(match->dl_vlan) < 4096) {
+                /* Match only packets with the specified VLAN VID. */
+                rule->flow.vlan_tci = htons(VLAN_CFI) | match->dl_vlan;
+                rule->wc.vlan_tci_mask = htons(VLAN_CFI | VLAN_VID_MASK);
+            } else {
+                /* Invalid VID. */
+                return OFPERR_OFPBMC_BAD_VALUE;
+            }
+
+            if (!(wc & OFPFW11_DL_VLAN_PCP)) {
+                if (match->dl_vlan_pcp <= 7) {
+                    rule->flow.vlan_tci |= htons(match->dl_vlan_pcp
+                                                 << VLAN_PCP_SHIFT);
+                    rule->wc.vlan_tci_mask |= htons(VLAN_PCP_MASK);
+                } else {
+                    /* Invalid PCP. */
+                    return OFPERR_OFPBMC_BAD_VALUE;
+                }
+            }
+        }
+    }
+
+    if (!(wc & OFPFW11_DL_TYPE)) {
+        cls_rule_set_dl_type(rule,
+                             ofputil_dl_type_from_openflow(match->dl_type));
+    }
+
+    ipv4 = rule->flow.dl_type == htons(ETH_TYPE_IP);
+    arp = rule->flow.dl_type == htons(ETH_TYPE_ARP);
+
+    if (ipv4 && !(wc & OFPFW11_NW_TOS)) {
+        if (match->nw_tos & ~IP_DSCP_MASK) {
+            /* Invalid TOS. */
+            return OFPERR_OFPBMC_BAD_VALUE;
+        }
+
+        cls_rule_set_nw_dscp(rule, match->nw_tos);
+    }
+
+    if (ipv4 || arp) {
+        if (!(wc & OFPFW11_NW_PROTO)) {
+            cls_rule_set_nw_proto(rule, match->nw_proto);
+        }
+
+        if (!ip_is_cidr(~match->nw_src_mask) ||
+            !ip_is_cidr(~match->nw_dst_mask)) {
+            return OFPERR_OFPBMC_BAD_NW_ADDR_MASK;
+        }
+        cls_rule_set_nw_src_masked(rule, match->nw_src, ~match->nw_src_mask);
+        cls_rule_set_nw_dst_masked(rule, match->nw_dst, ~match->nw_dst_mask);
+    }
+
+#define OFPFW11_TP_ALL (OFPFW11_TP_SRC | OFPFW11_TP_DST)
+    if (ipv4 && (wc & OFPFW11_TP_ALL) != OFPFW11_TP_ALL) {
+        switch (rule->flow.nw_proto) {
+        case IPPROTO_ICMP:
+            /* "A.2.3 Flow Match Structures" in OF1.1 says:
+             *
+             *    The tp_src and tp_dst fields will be ignored unless the
+             *    network protocol specified is as TCP, UDP or SCTP.
+             *
+             * but I'm pretty sure we should support ICMP too, otherwise
+             * that's a regression from OF1.0. */
+            if (!(wc & OFPFW11_TP_SRC)) {
+                uint16_t icmp_type = ntohs(match->tp_src);
+                if (icmp_type < 0x100) {
+                    cls_rule_set_icmp_type(rule, icmp_type);
+                } else {
+                    return OFPERR_OFPBMC_BAD_FIELD;
+                }
+            }
+            if (!(wc & OFPFW11_TP_DST)) {
+                uint16_t icmp_code = ntohs(match->tp_dst);
+                if (icmp_code < 0x100) {
+                    cls_rule_set_icmp_code(rule, icmp_code);
+                } else {
+                    return OFPERR_OFPBMC_BAD_FIELD;
+                }
+            }
+            break;
+
+        case IPPROTO_TCP:
+        case IPPROTO_UDP:
+            if (!(wc & (OFPFW11_TP_SRC))) {
+                cls_rule_set_tp_src(rule, match->tp_src);
+            }
+            if (!(wc & (OFPFW11_TP_DST))) {
+                cls_rule_set_tp_dst(rule, match->tp_dst);
+            }
+            break;
+
+        case IPPROTO_SCTP:
+            /* We don't support SCTP and it seems that we should tell the
+             * controller, since OF1.1 implementations are supposed to. */
+            return OFPERR_OFPBMC_BAD_FIELD;
+
+        default:
+            /* OF1.1 says explicitly to ignore this. */
+            break;
+        }
+    }
+
+    if (rule->flow.dl_type == htons(ETH_TYPE_MPLS) ||
+        rule->flow.dl_type == htons(ETH_TYPE_MPLS_MCAST)) {
+        enum { OFPFW11_MPLS_ALL = OFPFW11_MPLS_LABEL | OFPFW11_MPLS_TC };
+
+        if ((wc & OFPFW11_MPLS_ALL) != OFPFW11_MPLS_ALL) {
+            /* MPLS not supported. */
+            return OFPERR_OFPBMC_BAD_TAG;
+        }
+    }
+
+    if (match->metadata_mask != htonll(UINT64_MAX)) {
+        /* Metadata field not yet supported because we haven't decided how to
+         * map it onto our existing fields (or whether to add a new field). */
+        return OFPERR_OFPBMC_BAD_FIELD;
+    }
+
+    return 0;
+}
+
+/* Convert 'rule' into the OpenFlow 1.1 match structure 'match'. */
+void
+ofputil_cls_rule_to_ofp11_match(const struct cls_rule *rule,
+                                struct ofp11_match *match)
+{
+    uint32_t wc = 0;
+    int i;
+
+    memset(match, 0, sizeof *match);
+    match->omh.type = htons(OFPMT_STANDARD);
+    match->omh.length = htons(OFPMT11_STANDARD_LENGTH);
+
+    if (rule->wc.wildcards & FWW_IN_PORT) {
+        wc |= OFPFW11_IN_PORT;
+    } else {
+        match->in_port = ofputil_port_to_ofp11(rule->flow.in_port);
+    }
+
+
+    memcpy(match->dl_src, rule->flow.dl_src, ETH_ADDR_LEN);
+    for (i = 0; i < ETH_ADDR_LEN; i++) {
+        match->dl_src_mask[i] = ~rule->wc.dl_src_mask[i];
+    }
+
+    memcpy(match->dl_dst, rule->flow.dl_dst, ETH_ADDR_LEN);
+    for (i = 0; i < ETH_ADDR_LEN; i++) {
+        match->dl_dst_mask[i] = ~rule->wc.dl_dst_mask[i];
+    }
+
+    if (rule->wc.vlan_tci_mask == htons(0)) {
+        wc |= OFPFW11_DL_VLAN | OFPFW11_DL_VLAN_PCP;
+    } else if (rule->wc.vlan_tci_mask & htons(VLAN_CFI)
+               && !(rule->flow.vlan_tci & htons(VLAN_CFI))) {
+        match->dl_vlan = htons(OFPVID11_NONE);
+        wc |= OFPFW11_DL_VLAN_PCP;
+    } else {
+        if (!(rule->wc.vlan_tci_mask & htons(VLAN_VID_MASK))) {
+            match->dl_vlan = htons(OFPVID11_ANY);
+        } else {
+            match->dl_vlan = htons(vlan_tci_to_vid(rule->flow.vlan_tci));
+        }
+
+        if (!(rule->wc.vlan_tci_mask & htons(VLAN_PCP_MASK))) {
+            wc |= OFPFW11_DL_VLAN_PCP;
+        } else {
+            match->dl_vlan_pcp = vlan_tci_to_pcp(rule->flow.vlan_tci);
+        }
+    }
+
+    if (rule->wc.wildcards & FWW_DL_TYPE) {
+        wc |= OFPFW11_DL_TYPE;
+    } else {
+        match->dl_type = ofputil_dl_type_to_openflow(rule->flow.dl_type);
+    }
+
+    if (rule->wc.wildcards & FWW_NW_DSCP) {
+        wc |= OFPFW11_NW_TOS;
+    } else {
+        match->nw_tos = rule->flow.nw_tos & IP_DSCP_MASK;
+    }
+
+    if (rule->wc.wildcards & FWW_NW_PROTO) {
+        wc |= OFPFW11_NW_PROTO;
+    } else {
+        match->nw_proto = rule->flow.nw_proto;
+    }
+
+    match->nw_src = rule->flow.nw_src;
+    match->nw_src_mask = ~rule->wc.nw_src_mask;
+    match->nw_dst = rule->flow.nw_dst;
+    match->nw_dst_mask = ~rule->wc.nw_dst_mask;
+
+    if (!rule->wc.tp_src_mask) {
+        wc |= OFPFW11_TP_SRC;
+    } else {
+        match->tp_src = rule->flow.tp_src;
+    }
+
+    if (!rule->wc.tp_dst_mask) {
+        wc |= OFPFW11_TP_DST;
+    } else {
+        match->tp_dst = rule->flow.tp_dst;
+    }
+
+    /* MPLS not supported. */
+    wc |= OFPFW11_MPLS_LABEL;
+    wc |= OFPFW11_MPLS_TC;
+
+    /* Metadata field not yet supported */
+    match->metadata_mask = htonll(UINT64_MAX);
+
+    match->wildcards = htonl(wc);
+}
+
 /* Given a 'dl_type' value in the format used in struct flow, returns the
  * corresponding 'dl_type' value for use in an ofp10_match or ofp11_match
  * structure. */
index 20b6246899358bc4ac4abc848bf45774259fb843..9f4520cac5ac81c5e0e2e8714fc3327573a3cf95 100644 (file)
@@ -186,6 +186,13 @@ void ofputil_normalize_rule(struct cls_rule *);
 void ofputil_cls_rule_to_ofp10_match(const struct cls_rule *,
                                      struct ofp10_match *);
 
+/* Work with ofp11_match. */
+enum ofperr ofputil_cls_rule_from_ofp11_match(const struct ofp11_match *,
+                                              unsigned int priority,
+                                              struct cls_rule *);
+void ofputil_cls_rule_to_ofp11_match(const struct cls_rule *,
+                                     struct ofp11_match *);
+
 /* dl_type translation between OpenFlow and 'struct flow' format. */
 ovs_be16 ofputil_dl_type_to_openflow(ovs_be16 flow_dl_type);
 ovs_be16 ofputil_dl_type_from_openflow(ovs_be16 ofp_dl_type);
index 0a02c791f3cc6c9c038893d1a9a723283911c923..740892cb8c229f4ec61a51810437b5446e717985 100644 (file)
@@ -618,6 +618,314 @@ nx_pull_match() returned error OFPBMC_BAD_FIELD
 ])
 AT_CLEANUP
 
+AT_SETUP([ovs-ofctl parse-ofp11-match])
+AT_KEYWORDS([OF1.1])
+AT_DATA([test-data], [dnl
+# in_port=65534
+0000 0058 fffffffe 000003fe dnl
+000000000000ffffffffffff 000000000000ffffffffffff dnl
+0000 00 00 0000 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl
+00000000 00 000000 0000000000000000ffffffffffffffff
+
+# bad ofp11_match: OFPBMC_BAD_VALUE
+& ofp_util|WARN|port 305419896 is outside the supported range 0 through 65279 or 0xffffff00 through 0xffffffff
+0000 0058 12345678 000003fe dnl
+000000000000ffffffffffff 000000000000ffffffffffff dnl
+0000 00 00 0000 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl
+00000000 00 000000 0000000000000000ffffffffffffffff
+
+# dl_src=00:01:02:03:04:05
+0000 0058 00000000 000003ff dnl
+000102030405000000000000 000000000000ffffffffffff dnl
+0000 00 00 0000 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl
+00000000 00 000000 0000000000000000ffffffffffffffff
+
+# dl_src=55:55:55:55:55:55/55:55:55:55:55:55
+0000 0058 00000000 000003ff dnl
+555555555555aaaaaaaaaaaa 000000000000ffffffffffff dnl
+0000 00 00 0000 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl
+00000000 00 000000 0000000000000000ffffffffffffffff
+
+# dl_dst=00:01:02:03:04:05
+0000 0058 00000000 000003ff dnl
+000000000000ffffffffffff 000102030405000000000000 dnl
+0000 00 00 0000 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl
+00000000 00 000000 0000000000000000ffffffffffffffff
+
+# dl_dst=01:00:00:00:00:00/01:00:00:00:00:00
+0000 0058 00000000 000003ff dnl
+000000000000ffffffffffff 010000000000feffffffffff dnl
+0000 00 00 0000 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl
+00000000 00 000000 0000000000000000ffffffffffffffff
+
+# dl_dst=00:01:02:03:04:05/fe:ff:ff:ff:ff:ff
+0000 0058 00000000 000003ff dnl
+000000000000ffffffffffff 000102030405010000000000 dnl
+0000 00 00 0000 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl
+00000000 00 000000 0000000000000000ffffffffffffffff
+
+# dl_dst=55:55:55:55:55:55/55:55:55:55:55:55
+0000 0058 00000000 000003ff dnl
+000000000000ffffffffffff 555555555555aaaaaaaaaaaa dnl
+0000 00 00 0000 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl
+00000000 00 000000 0000000000000000ffffffffffffffff
+
+dnl dl_vlan_pcp is ignored if dl_vlan is wildcarded, which causes the
+dnl the wildcard bit and the dl_vlan_pcp to be dropped for output:
+# in_port=1
+# 11: fa -> fe
+# 38: 03 -> 00
+0000 0058 00000001 000003fa dnl
+000000000000ffffffffffff 000000000000ffffffffffff dnl
+0000 03 00 0000 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl
+00000000 00 000000 0000000000000000ffffffffffffffff
+
+# dl_vlan=291
+0000 0058 00000000 000003fd dnl
+000000000000ffffffffffff 000000000000ffffffffffff dnl
+0123 00 00 0000 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl
+00000000 00 000000 0000000000000000ffffffffffffffff
+
+dnl OFPVID_NONE:
+# vlan_tci=0x0000
+0000 0058 00000000 000003fd dnl
+000000000000ffffffffffff 000000000000ffffffffffff dnl
+ffff 00 00 0000 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl
+00000000 00 000000 0000000000000000ffffffffffffffff
+
+dnl OFPVID_NONE ignores dl_vlan_pcp even if not wildcarded, which causes
+dnl the wildcard bit and the dl_vlan_pcp to be dropped for output:
+# vlan_tci=0x0000
+# 11: f9 -> fd
+# 38: 05 -> 00
+0000 0058 00000000 000003f9 dnl
+000000000000ffffffffffff 000000000000ffffffffffff dnl
+ffff 05 00 0000 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl
+00000000 00 000000 0000000000000000ffffffffffffffff
+
+# vlan_tci=0x1000/0x1000
+0000 0058 00000000 000003fd dnl
+000000000000ffffffffffff 000000000000ffffffffffff dnl
+fffe 00 00 0000 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl
+00000000 00 000000 0000000000000000ffffffffffffffff
+
+dnl Try invalid VID:
+# bad ofp11_match: OFPBMC_BAD_VALUE
+0000 0058 00000000 000003fd dnl
+000000000000ffffffffffff 000000000000ffffffffffff dnl
+1234 00 00 0000 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl
+00000000 00 000000 0000000000000000ffffffffffffffff
+
+# dl_vlan_pcp=4
+0000 0058 00000000 000003f9 dnl
+000000000000ffffffffffff 000000000000ffffffffffff dnl
+fffe 04 00 0000 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl
+00000000 00 000000 0000000000000000ffffffffffffffff
+
+# dl_vlan=10,dl_vlan_pcp=6
+0000 0058 00000000 000003f9 dnl
+000000000000ffffffffffff 000000000000ffffffffffff dnl
+000a 06 00 0000 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl
+00000000 00 000000 0000000000000000ffffffffffffffff
+
+# dl_type=0x1234
+0000 0058 00000000 000003f7 dnl
+000000000000ffffffffffff 000000000000ffffffffffff dnl
+0000 00 00 1234 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl
+00000000 00 000000 0000000000000000ffffffffffffffff
+
+# ip,nw_tos=252
+0000 0058 00000000 000003e7 dnl
+000000000000ffffffffffff 000000000000ffffffffffff dnl
+0000 00 00 0800 fc 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl
+00000000 00 000000 0000000000000000ffffffffffffffff
+
+dnl Try invalid TOS:
+# bad ofp11_match: OFPBMC_BAD_VALUE
+0000 0058 00000000 000003e7 dnl
+000000000000ffffffffffff 000000000000ffffffffffff dnl
+0000 00 00 0800 01 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl
+00000000 00 000000 0000000000000000ffffffffffffffff
+
+# ip,nw_proto=5
+0000 0058 00000000 000003d7 dnl
+000000000000ffffffffffff 000000000000ffffffffffff dnl
+0000 00 00 0800 00 05 00000000ffffffff 00000000ffffffff 0000 0000 dnl
+00000000 00 000000 0000000000000000ffffffffffffffff
+
+# arp,arp_op=2
+0000 0058 00000000 000003d7 dnl
+000000000000ffffffffffff 000000000000ffffffffffff dnl
+0000 00 00 0806 00 02 00000000ffffffff 00000000ffffffff 0000 0000 dnl
+00000000 00 000000 0000000000000000ffffffffffffffff
+
+# ip,nw_src=192.168.128.0/24
+0000 0058 00000000 000003f7 dnl
+000000000000ffffffffffff 000000000000ffffffffffff dnl
+0000 00 00 0800 00 00 c0a88000000000ff 00000000ffffffff 0000 0000 dnl
+00000000 00 000000 0000000000000000ffffffffffffffff
+
+dnl Try non-CIDR nw_src_mask:
+# bad ofp11_match: OFPBMC_BAD_NW_ADDR_MASK
+0000 0058 00000000 000003f7 dnl
+000000000000ffffffffffff 000000000000ffffffffffff dnl
+0000 00 00 0800 00 00 c0a880005a5a5a5a 00000000ffffffff 0000 0000 dnl
+00000000 00 000000 0000000000000000ffffffffffffffff
+
+# ip,nw_dst=192.168.128.0/24
+0000 0058 00000000 000003f7 dnl
+000000000000ffffffffffff 000000000000ffffffffffff dnl
+0000 00 00 0800 00 00 00000000ffffffff c0a88000000000ff 0000 0000 dnl
+00000000 00 000000 0000000000000000ffffffffffffffff
+
+dnl Try non-CIDR nw_dst_mask:
+# bad ofp11_match: OFPBMC_BAD_NW_ADDR_MASK
+0000 0058 00000000 000003f7 dnl
+000000000000ffffffffffff 000000000000ffffffffffff dnl
+0000 00 00 0800 00 00 00000000ffffffff c0a880005a5a5a5a 0000 0000 dnl
+00000000 00 000000 0000000000000000ffffffffffffffff
+
+# arp,nw_src=192.168.128.0/24
+0000 0058 00000000 000003f7 dnl
+000000000000ffffffffffff 000000000000ffffffffffff dnl
+0000 00 00 0806 00 00 c0a88000000000ff 00000000ffffffff 0000 0000 dnl
+00000000 00 000000 0000000000000000ffffffffffffffff
+
+# arp,nw_dst=192.168.128.0/24
+0000 0058 00000000 000003f7 dnl
+000000000000ffffffffffff 000000000000ffffffffffff dnl
+0000 00 00 0806 00 00 00000000ffffffff c0a88000000000ff 0000 0000 dnl
+00000000 00 000000 0000000000000000ffffffffffffffff
+
+# tcp,tp_src=443
+0000 0058 00000000 00000397 dnl
+000000000000ffffffffffff 000000000000ffffffffffff dnl
+0000 00 00 0800 00 06 00000000ffffffff 00000000ffffffff 01bb 0000 dnl
+00000000 00 000000 0000000000000000ffffffffffffffff
+
+# tcp,tp_dst=443
+0000 0058 00000000 00000357 dnl
+000000000000ffffffffffff 000000000000ffffffffffff dnl
+0000 00 00 0800 00 06 00000000ffffffff 00000000ffffffff 0000 01bb dnl
+00000000 00 000000 0000000000000000ffffffffffffffff
+
+# udp,tp_src=443
+0000 0058 00000000 00000397 dnl
+000000000000ffffffffffff 000000000000ffffffffffff dnl
+0000 00 00 0800 00 11 00000000ffffffff 00000000ffffffff 01bb 0000 dnl
+00000000 00 000000 0000000000000000ffffffffffffffff
+
+# icmp,icmp_type=5
+0000 0058 00000000 00000397 dnl
+000000000000ffffffffffff 000000000000ffffffffffff dnl
+0000 00 00 0800 00 01 00000000ffffffff 00000000ffffffff 0005 0000 dnl
+00000000 00 000000 0000000000000000ffffffffffffffff
+
+# icmp,icmp_code=8
+0000 0058 00000000 00000357 dnl
+000000000000ffffffffffff 000000000000ffffffffffff dnl
+0000 00 00 0800 00 01 00000000ffffffff 00000000ffffffff 0000 0008 dnl
+00000000 00 000000 0000000000000000ffffffffffffffff
+
+# udp,tp_src=443
+0000 0058 00000000 00000397 dnl
+000000000000ffffffffffff 000000000000ffffffffffff dnl
+0000 00 00 0800 00 11 00000000ffffffff 00000000ffffffff 01bb 0000 dnl
+00000000 00 000000 0000000000000000ffffffffffffffff
+
+# udp,tp_dst=443
+0000 0058 00000000 00000357 dnl
+000000000000ffffffffffff 000000000000ffffffffffff dnl
+0000 00 00 0800 00 11 00000000ffffffff 00000000ffffffff 0000 01bb dnl
+00000000 00 000000 0000000000000000ffffffffffffffff
+
+dnl SCTP, no ports.
+# ip,nw_proto=132
+0000 0058 00000000 000003d7 dnl
+000000000000ffffffffffff 000000000000ffffffffffff dnl
+0000 00 00 0800 00 84 00000000ffffffff 00000000ffffffff 0000 0000 dnl
+00000000 00 000000 0000000000000000ffffffffffffffff
+
+dnl SCTP tp_src matching not supported:
+# bad ofp11_match: OFPBMC_BAD_FIELD
+0000 0058 00000000 00000397 dnl
+000000000000ffffffffffff 000000000000ffffffffffff dnl
+0000 00 00 0800 00 84 00000000ffffffff 00000000ffffffff 01bb 0000 dnl
+00000000 00 000000 0000000000000000ffffffffffffffff
+
+dnl SCTP tp_dst matching not supported:
+# bad ofp11_match: OFPBMC_BAD_FIELD
+0000 0058 00000000 00000357 dnl
+000000000000ffffffffffff 000000000000ffffffffffff dnl
+0000 00 00 0800 00 84 00000000ffffffff 00000000ffffffff 0000 01bb dnl
+00000000 00 000000 0000000000000000ffffffffffffffff
+
+dnl Ignore tp_src if not TCP or UDP or SCTP:
+# ip,nw_proto=21
+# 11: 97 -> d7
+# 60: 01 -> 00
+# 61: bb -> 00
+0000 0058 00000000 00000397 dnl
+000000000000ffffffffffff 000000000000ffffffffffff dnl
+0000 00 00 0800 00 15 00000000ffffffff 00000000ffffffff 01bb 0000 dnl
+00000000 00 000000 0000000000000000ffffffffffffffff
+
+dnl Ignore tp_dst if not TCP or UDP or SCTP:
+# ip,nw_proto=22
+# 11: 57 -> d7
+# 62: 01 -> 00
+# 63: bb -> 00
+0000 0058 00000000 00000357 dnl
+000000000000ffffffffffff 000000000000ffffffffffff dnl
+0000 00 00 0800 00 16 00000000ffffffff 00000000ffffffff 0000 01bb dnl
+00000000 00 000000 0000000000000000ffffffffffffffff
+
+dnl mpls_label not yet supported:
+# bad ofp11_match: OFPBMC_BAD_TAG
+0000 0058 00000000 000002f7 dnl
+000000000000ffffffffffff 000000000000ffffffffffff dnl
+0000 00 00 8847 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl
+12345678 00 000000 0000000000000000ffffffffffffffff
+
+dnl mpls_tc not yet supported:
+# bad ofp11_match: OFPBMC_BAD_TAG
+0000 0058 00000000 000001f7 dnl
+000000000000ffffffffffff 000000000000ffffffffffff dnl
+0000 00 00 8848 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl
+00000000 5a 000000 0000000000000000ffffffffffffffff
+
+dnl mpls_label and mpls_tc must be ignored if dl_type is not MPLS:
+# dl_type=0x1234
+# 10: 00 -> 03
+# 64: 12 -> 00
+# 65: 34 -> 00
+# 66: 56 -> 00
+# 67: 78 -> 00
+# 68: 5a -> 00
+0000 0058 00000000 000000f7 dnl
+000000000000ffffffffffff 000000000000ffffffffffff dnl
+0000 00 00 1234 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl
+12345678 5a 000000 0000000000000000ffffffffffffffff
+
+dnl metadata match not yet supported:
+# bad ofp11_match: OFPBMC_BAD_FIELD
+0000 0058 00000000 000003ff dnl
+000000000000ffffffffffff 000000000000ffffffffffff dnl
+0000 00 00 0000 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl
+00000000 00 000000 0000000000000001fffffffffffffffe
+
+])
+sed '/^[[#&]]/d' < test-data > input.txt
+sed -n 's/^# //p; /^$/p' < test-data > expout
+sed -n 's/^& //p' < test-data > experr
+AT_CAPTURE_FILE([input.txt])
+AT_CAPTURE_FILE([expout])
+AT_CAPTURE_FILE([experr])
+AT_CHECK(
+  [ovs-ofctl '-vPATTERN:console:%c|%p|%m' parse-ofp11-match < input.txt],
+  [0], [expout], [experr])
+AT_CLEANUP
+
 AT_SETUP([ovs-ofctl parse-nx-match loose])
 AT_KEYWORDS([nx-match])
 AT_DATA([nx-match.txt], [dnl
@@ -967,3 +1275,4 @@ ofp_util|INFO|post: @&t@
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
+
index 8f021929beb79d6be0c3617c401e1c38803b8373..74134555430892644181984519b68cd6302f184b 100644 (file)
@@ -1986,6 +1986,63 @@ do_parse_oxm(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
     return do_parse_nxm__(true);
 }
 
+/* "parse-ofp11-match": reads a series of ofp11_match specifications as hex
+ * bytes from stdin, converts them to cls_rules, prints them as strings on
+ * stdout, and then converts them back to hex bytes and prints any differences
+ * from the input. */
+static void
+do_parse_ofp11_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
+{
+    struct ds in;
+
+    ds_init(&in);
+    while (!ds_get_preprocessed_line(&in, stdin)) {
+        struct ofpbuf match_in;
+        struct ofp11_match match_out;
+        struct cls_rule rule;
+        enum ofperr error;
+        int i;
+
+        /* Parse hex bytes. */
+        ofpbuf_init(&match_in, 0);
+        if (ofpbuf_put_hex(&match_in, ds_cstr(&in), NULL)[0] != '\0') {
+            ovs_fatal(0, "Trailing garbage in hex data");
+        }
+        if (match_in.size != sizeof(struct ofp11_match)) {
+            ovs_fatal(0, "Input is %zu bytes, expected %zu",
+                      match_in.size, sizeof(struct ofp11_match));
+        }
+
+        /* Convert to cls_rule. */
+        error = ofputil_cls_rule_from_ofp11_match(match_in.data,
+                                                  OFP_DEFAULT_PRIORITY, &rule);
+        if (error) {
+            printf("bad ofp11_match: %s\n\n", ofperr_get_name(error));
+            ofpbuf_uninit(&match_in);
+            continue;
+        }
+
+        /* Print cls_rule. */
+        cls_rule_print(&rule);
+
+        /* Convert back to ofp11_match and print differences from input. */
+        ofputil_cls_rule_to_ofp11_match(&rule, &match_out);
+
+        for (i = 0; i < sizeof match_out; i++) {
+            uint8_t in = ((const uint8_t *) match_in.data)[i];
+            uint8_t out = ((const uint8_t *) &match_out)[i];
+
+            if (in != out) {
+                printf("%2d: %02"PRIx8" -> %02"PRIx8"\n", i, in, out);
+            }
+        }
+        putchar('\n');
+
+        ofpbuf_uninit(&match_in);
+    }
+    ds_destroy(&in);
+}
+
 /* "print-error ENUM": Prints the type and code of ENUM for every OpenFlow
  * version. */
 static void
@@ -2062,6 +2119,7 @@ static const struct command all_commands[] = {
     { "parse-nx-match", 0, 0, do_parse_nxm },
     { "parse-nxm", 0, 0, do_parse_nxm },
     { "parse-oxm", 0, 0, do_parse_oxm },
+    { "parse-ofp11-match", 0, 0, do_parse_ofp11_match },
     { "print-error", 1, 1, do_print_error },
     { "ofp-print", 1, 2, do_ofp_print },