[ovs-dev] [PATCH 3/5] ofproto: Add pipeline fields support for OF 1.5 packet-out

Yi-Hung Wei yihung.wei at gmail.com
Mon May 15 17:04:57 UTC 2017


This patch decodes pipeline fields from a packet-out message, and populates
the pipeline fields into datapath. Error OFPERR_OFPBRC_PIPELINE_FIELDS_ONLY
is returned if the match field of a packet-out messages contains any
non pipeline fields. Currently, the supported pipeline fields
are as following.

* metadata fields:
    - in_port, in_port_oxm

* tunnel fields:
    - tun_id, tun_src, tun_dst, tun_ipv6_src, tun_ipv6_dst
    - tun_gbp_id, tun_gpb_flags, tun_flags
    - tun_metadata0 - tun_metadata63

* register fields:
    - metadata
    - reg0 - reg-15, xreg0 - xreg7, xxreg0 - xxreg3

Signed-off-by: Yi-Hung Wei <yihung.wei at gmail.com>
---
 include/openvswitch/meta-flow.h  |  1 +
 include/openvswitch/ofp-errors.h |  3 ++
 lib/meta-flow.c                  | 90 ++++++++++++++++++++++++++++++++++++++++
 lib/nx-match.c                   | 54 ++++++++++++++----------
 lib/nx-match.h                   | 14 ++++---
 lib/ofp-util.c                   | 23 +++++-----
 ofproto/ofproto.c                |  9 +++-
 tests/ofp-print.at               | 38 +++++++++++++++++
 utilities/ovs-ofctl.c            | 17 ++++----
 9 files changed, 201 insertions(+), 48 deletions(-)

diff --git a/include/openvswitch/meta-flow.h b/include/openvswitch/meta-flow.h
index 11852d2a07d8..1a0ba9b38c3a 100644
--- a/include/openvswitch/meta-flow.h
+++ b/include/openvswitch/meta-flow.h
@@ -2055,6 +2055,7 @@ void mf_set_flow_value_masked(const struct mf_field *,
                               const union mf_value *mask,
                               struct flow *);
 bool mf_is_tun_metadata(const struct mf_field *);
+bool mf_is_pipeline_field(const struct mf_field *);
 bool mf_is_set(const struct mf_field *, const struct flow *);
 void mf_mask_field(const struct mf_field *, struct flow_wildcards *);
 void mf_mask_field_masked(const struct mf_field *, const union mf_value *mask,
diff --git a/include/openvswitch/ofp-errors.h b/include/openvswitch/ofp-errors.h
index a5bba8619bcb..e228ff0b010a 100644
--- a/include/openvswitch/ofp-errors.h
+++ b/include/openvswitch/ofp-errors.h
@@ -175,6 +175,9 @@ enum ofperr {
     /* OF1.3+(1,13).  Multipart request overflowed the assigned buffer. */
     OFPERR_OFPBRC_MULTIPART_BUFFER_OVERFLOW,
 
+    /* OF1.5+(1,17).  Match fields must include only pipleline fields. */
+    OFPERR_OFPBRC_PIPELINE_FIELDS_ONLY,
+
     /* NX1.0-1.1(1,256), NX1.2+(2).  Invalid NXM flow match. */
     OFPERR_NXBRC_NXM_INVALID,
 
diff --git a/lib/meta-flow.c b/lib/meta-flow.c
index 6b97794f1753..d9c3b28b5cdb 100644
--- a/lib/meta-flow.c
+++ b/lib/meta-flow.c
@@ -1553,6 +1553,96 @@ mf_is_tun_metadata(const struct mf_field *mf)
            mf->id < MFF_TUN_METADATA0 + TUN_METADATA_NUM_OPTS;
 }
 
+bool
+mf_is_pipeline_field(const struct mf_field *mf)
+{
+    switch (mf->id) {
+    case MFF_TUN_ID:
+    case MFF_TUN_SRC:
+    case MFF_TUN_DST:
+    case MFF_TUN_IPV6_SRC:
+    case MFF_TUN_IPV6_DST:
+    case MFF_TUN_FLAGS:
+    case MFF_TUN_GBP_ID:
+    case MFF_TUN_GBP_FLAGS:
+    CASE_MFF_TUN_METADATA:
+    case MFF_METADATA:
+    case MFF_IN_PORT:
+    case MFF_IN_PORT_OXM:
+    CASE_MFF_REGS:
+    CASE_MFF_XREGS:
+    CASE_MFF_XXREGS:
+        return true;
+
+    case MFF_DP_HASH:
+    case MFF_RECIRC_ID:
+    case MFF_CONJ_ID:
+    case MFF_TUN_TTL:
+    case MFF_TUN_TOS:
+    case MFF_ACTSET_OUTPUT:
+    case MFF_SKB_PRIORITY:
+    case MFF_PKT_MARK:
+    case MFF_CT_STATE:
+    case MFF_CT_ZONE:
+    case MFF_CT_MARK:
+    case MFF_CT_LABEL:
+    case MFF_CT_NW_PROTO:
+    case MFF_CT_NW_SRC:
+    case MFF_CT_NW_DST:
+    case MFF_CT_IPV6_SRC:
+    case MFF_CT_IPV6_DST:
+    case MFF_CT_TP_SRC:
+    case MFF_CT_TP_DST:
+    case MFF_ETH_SRC:
+    case MFF_ETH_DST:
+    case MFF_ETH_TYPE:
+    case MFF_VLAN_TCI:
+    case MFF_DL_VLAN:
+    case MFF_VLAN_VID:
+    case MFF_DL_VLAN_PCP:
+    case MFF_VLAN_PCP:
+    case MFF_MPLS_LABEL:
+    case MFF_MPLS_TC:
+    case MFF_MPLS_BOS:
+    case MFF_MPLS_TTL:
+    case MFF_IPV4_SRC:
+    case MFF_IPV4_DST:
+    case MFF_IPV6_SRC:
+    case MFF_IPV6_DST:
+    case MFF_IPV6_LABEL:
+    case MFF_IP_PROTO:
+    case MFF_IP_DSCP:
+    case MFF_IP_DSCP_SHIFTED:
+    case MFF_IP_ECN:
+    case MFF_IP_TTL:
+    case MFF_IP_FRAG:
+    case MFF_ARP_OP:
+    case MFF_ARP_SPA:
+    case MFF_ARP_TPA:
+    case MFF_ARP_SHA:
+    case MFF_ARP_THA:
+    case MFF_TCP_SRC:
+    case MFF_TCP_DST:
+    case MFF_TCP_FLAGS:
+    case MFF_UDP_SRC:
+    case MFF_UDP_DST:
+    case MFF_SCTP_SRC:
+    case MFF_SCTP_DST:
+    case MFF_ICMPV4_TYPE:
+    case MFF_ICMPV4_CODE:
+    case MFF_ICMPV6_TYPE:
+    case MFF_ICMPV6_CODE:
+    case MFF_ND_TARGET:
+    case MFF_ND_SLL:
+    case MFF_ND_TLL:
+        return false;
+
+    case MFF_N_IDS:
+    default:
+        OVS_NOT_REACHED();
+    }
+}
+
 /* Returns true if 'mf' has previously been set in 'flow', false if
  * it contains a non-default value.
  *
diff --git a/lib/nx-match.c b/lib/nx-match.c
index 68e58d393198..5d8aac571ac3 100644
--- a/lib/nx-match.c
+++ b/lib/nx-match.c
@@ -510,8 +510,8 @@ nx_pull_match_entry(struct ofpbuf *b, bool allow_cookie,
  * ethertype being present, when decoding metadata only. */
 static enum ofperr
 nx_pull_raw(const uint8_t *p, unsigned int match_len, bool strict,
-            struct match *match, ovs_be64 *cookie, ovs_be64 *cookie_mask,
-            const struct tun_table *tun_table,
+            bool pipeline_fields_only, struct match *match, ovs_be64 *cookie,
+            ovs_be64 *cookie_mask, const struct tun_table *tun_table,
             const struct vl_mff_map *vl_mff_map)
 {
     ovs_assert((cookie != NULL) == (cookie_mask != NULL));
@@ -549,6 +549,8 @@ nx_pull_raw(const uint8_t *p, unsigned int match_len, bool strict,
             error = OFPERR_OFPBMC_BAD_PREREQ;
         } else if (!mf_is_all_wild(field, &match->wc)) {
             error = OFPERR_OFPBMC_DUP_FIELD;
+        } else if (pipeline_fields_only && !mf_is_pipeline_field(field)) {
+            error = OFPERR_OFPBRC_PIPELINE_FIELDS_ONLY;
         } else {
             char *err_str;
 
@@ -575,7 +577,7 @@ nx_pull_raw(const uint8_t *p, unsigned int match_len, bool strict,
 
 static enum ofperr
 nx_pull_match__(struct ofpbuf *b, unsigned int match_len, bool strict,
-                struct match *match,
+                bool pipeline_fields_only, struct match *match,
                 ovs_be64 *cookie, ovs_be64 *cookie_mask,
                 const struct tun_table *tun_table,
                 const struct vl_mff_map *vl_mff_map)
@@ -592,14 +594,17 @@ nx_pull_match__(struct ofpbuf *b, unsigned int match_len, bool strict,
         }
     }
 
-    return nx_pull_raw(p, match_len, strict, match, cookie, cookie_mask,
-                       tun_table, vl_mff_map);
+    return nx_pull_raw(p, match_len, strict, pipeline_fields_only, match,
+                       cookie, cookie_mask, tun_table, vl_mff_map);
 }
 
 /* Parses the nx_match formatted match description in 'b' with length
  * 'match_len'.  Stores the results in 'match'.  If 'cookie' and 'cookie_mask'
  * are valid pointers, then stores the cookie and mask in them if 'b' contains
  * a "NXM_NX_COOKIE*" match.  Otherwise, stores 0 in both.
+ * If 'pipeline_fields_only' is true, this function returns
+ * OFPERR_OFPBRC_PIPELINE_FIELDS_ONLY if there is any non pipeline fields
+ * in 'b'.
  *
  * 'vl_mff_map" is an optional parameter that is used to validate the length
  * of variable length mf_fields in 'match'. If it is not provided, the
@@ -611,11 +616,11 @@ nx_pull_match__(struct ofpbuf *b, unsigned int match_len, bool strict,
 enum ofperr
 nx_pull_match(struct ofpbuf *b, unsigned int match_len, struct match *match,
               ovs_be64 *cookie, ovs_be64 *cookie_mask,
-              const struct tun_table *tun_table,
+              bool pipeline_fields_only, const struct tun_table *tun_table,
               const struct vl_mff_map *vl_mff_map)
 {
-    return nx_pull_match__(b, match_len, true, match, cookie, cookie_mask,
-                           tun_table, vl_mff_map);
+    return nx_pull_match__(b, match_len, true, pipeline_fields_only, match,
+                           cookie, cookie_mask, tun_table, vl_mff_map);
 }
 
 /* Behaves the same as nx_pull_match(), but skips over unknown NXM headers,
@@ -623,16 +628,16 @@ nx_pull_match(struct ofpbuf *b, unsigned int match_len, struct match *match,
  * prerequisities. */
 enum ofperr
 nx_pull_match_loose(struct ofpbuf *b, unsigned int match_len,
-                    struct match *match,
-                    ovs_be64 *cookie, ovs_be64 *cookie_mask,
+                    struct match *match, ovs_be64 *cookie,
+                    ovs_be64 *cookie_mask, bool pipeline_fields_only,
                     const struct tun_table *tun_table)
 {
-    return nx_pull_match__(b, match_len, false, match, cookie, cookie_mask,
-                           tun_table, NULL);
+    return nx_pull_match__(b, match_len, false, pipeline_fields_only, match,
+                           cookie, cookie_mask, tun_table, NULL);
 }
 
 static enum ofperr
-oxm_pull_match__(struct ofpbuf *b, bool strict,
+oxm_pull_match__(struct ofpbuf *b, bool strict, bool pipeline_fields_only,
                  const struct tun_table *tun_table,
                  const struct vl_mff_map *vl_mff_map, struct match *match)
 {
@@ -662,11 +667,15 @@ oxm_pull_match__(struct ofpbuf *b, bool strict,
     }
 
     return nx_pull_raw(p + sizeof *omh, match_len - sizeof *omh,
-                       strict, match, NULL, NULL, tun_table, vl_mff_map);
+                       strict, pipeline_fields_only, match, NULL, NULL,
+                       tun_table, vl_mff_map);
 }
 
 /* Parses the oxm formatted match description preceded by a struct
  * ofp11_match_header in 'b'.  Stores the result in 'match'.
+ * If 'pipeline_fields_only' is true, this function returns
+ * OFPERR_OFPBRC_PIPELINE_FIELDS_ONLY if there is any non pipeline fields
+ * in 'b'.
  *
  * 'vl_mff_map' is an optional parameter that is used to validate the length
  * of variable length mf_fields in 'match'. If it is not provided, the
@@ -676,20 +685,23 @@ oxm_pull_match__(struct ofpbuf *b, bool strict,
  *
  * Returns 0 if successful, otherwise an OpenFlow error code. */
 enum ofperr
-oxm_pull_match(struct ofpbuf *b, const struct tun_table *tun_table,
+oxm_pull_match(struct ofpbuf *b, bool pipeline_fields_only,
+               const struct tun_table *tun_table,
                const struct vl_mff_map *vl_mff_map, struct match *match)
 {
-    return oxm_pull_match__(b, true, tun_table, vl_mff_map, match);
+    return oxm_pull_match__(b, true, pipeline_fields_only, tun_table,
+                            vl_mff_map, match);
 }
 
 /* Behaves the same as oxm_pull_match() with two exceptions.  Skips over
  * unknown OXM headers instead of failing with an error when they are
  * encountered, and does not check for field prerequisities. */
 enum ofperr
-oxm_pull_match_loose(struct ofpbuf *b, const struct tun_table *tun_table,
-                     struct match *match)
+oxm_pull_match_loose(struct ofpbuf *b, bool pipeline_fields_only,
+                     const struct tun_table *tun_table, struct match *match)
 {
-    return oxm_pull_match__(b, false, tun_table, NULL, match);
+    return oxm_pull_match__(b, false, pipeline_fields_only, tun_table, NULL,
+                            match);
 }
 
 /* Parses the OXM match description in the 'oxm_len' bytes in 'oxm'.  Stores
@@ -705,8 +717,8 @@ oxm_decode_match(const void *oxm, size_t oxm_len, bool loose,
                  const struct tun_table *tun_table,
                  const struct vl_mff_map *vl_mff_map, struct match *match)
 {
-    return nx_pull_raw(oxm, oxm_len, !loose, match, NULL, NULL, tun_table,
-                       vl_mff_map);
+    return nx_pull_raw(oxm, oxm_len, !loose, false, match, NULL, NULL,
+                       tun_table, vl_mff_map);
 }
 
 /* Verify an array of OXM TLVs treating value of each TLV as a mask,
diff --git a/lib/nx-match.h b/lib/nx-match.h
index 6afb310efa4b..90cb6f8fd329 100644
--- a/lib/nx-match.h
+++ b/lib/nx-match.h
@@ -50,17 +50,19 @@ char *mf_parse_subfield(struct mf_subfield *, const char *s)
 
 /* Decoding matches. */
 enum ofperr nx_pull_match(struct ofpbuf *, unsigned int match_len,
-                          struct match *,
-                          ovs_be64 *cookie, ovs_be64 *cookie_mask,
+                          struct match *, ovs_be64 *cookie,
+                          ovs_be64 *cookie_mask, bool pipeline_fields_only,
                           const struct tun_table *, const struct vl_mff_map *);
 enum ofperr nx_pull_match_loose(struct ofpbuf *, unsigned int match_len,
                                 struct match *, ovs_be64 *cookie,
                                 ovs_be64 *cookie_mask,
+                                bool pipeline_fields_only,
                                 const struct tun_table *);
-enum ofperr oxm_pull_match(struct ofpbuf *, const struct tun_table *,
-                           const struct vl_mff_map *, struct match *);
-enum ofperr oxm_pull_match_loose(struct ofpbuf *, const struct tun_table *,
-                                 struct match *);
+enum ofperr oxm_pull_match(struct ofpbuf *, bool pipeline_fields_only,
+                           const struct tun_table *, const struct vl_mff_map *,
+                           struct match *);
+enum ofperr oxm_pull_match_loose(struct ofpbuf *, bool pipeline_fields_only,
+                                 const struct tun_table *, struct match *);
 enum ofperr oxm_decode_match(const void *, size_t, bool,
                              const struct tun_table *,
                              const struct vl_mff_map *, struct match *);
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index b4d63931ecdb..5ba11239883e 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -309,7 +309,7 @@ ofputil_pull_ofp11_match(struct ofpbuf *buf, const struct tun_table *tun_table,
         if (padded_match_len) {
             *padded_match_len = ROUND_UP(match_len, 8);
         }
-        return oxm_pull_match(buf, tun_table, vl_mff_map, match);
+        return oxm_pull_match(buf, false, tun_table, vl_mff_map, match);
 
     default:
         return OFPERR_OFPBMC_BAD_TYPE;
@@ -1685,7 +1685,7 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
             nfm = ofpbuf_pull(&b, sizeof *nfm);
             error = nx_pull_match(&b, ntohs(nfm->match_len),
                                   &fm->match, &fm->cookie, &fm->cookie_mask,
-                                  tun_table, vl_mff_map);
+                                  false, tun_table, vl_mff_map);
             if (error) {
                 return error;
             }
@@ -2324,7 +2324,7 @@ ofputil_decode_nxst_flow_request(struct ofputil_flow_stats_request *fsr,
 
     nfsr = ofpbuf_pull(b, sizeof *nfsr);
     error = nx_pull_match(b, ntohs(nfsr->match_len), &fsr->match,
-                          &fsr->cookie, &fsr->cookie_mask, tun_table,
+                          &fsr->cookie, &fsr->cookie_mask, false, tun_table,
                           vl_mff_map);
     if (error) {
         return error;
@@ -2996,7 +2996,7 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs,
                          "claims invalid length %"PRIuSIZE, match_len, length);
             return EINVAL;
         }
-        if (nx_pull_match(msg, match_len, &fs->match, NULL, NULL, NULL,
+        if (nx_pull_match(msg, match_len, &fs->match, NULL, NULL, false, NULL,
                           NULL)) {
             return EINVAL;
         }
@@ -3253,7 +3253,7 @@ ofputil_decode_flow_removed(struct ofputil_flow_removed *fr,
 
         nfr = ofpbuf_pull(&b, sizeof *nfr);
         error = nx_pull_match(&b, ntohs(nfr->match_len), &fr->match, NULL,
-                              NULL, NULL, NULL);
+                              NULL, false, NULL, NULL);
         if (error) {
             return error;
         }
@@ -3514,7 +3514,7 @@ ofputil_decode_packet_in(const struct ofp_header *oh, bool loose,
         const ovs_be64 *cookie = (raw == OFPRAW_OFPT13_PACKET_IN
                                   ? ofpbuf_pull(&b, sizeof *cookie)
                                   : NULL);
-        enum ofperr error = oxm_pull_match_loose(&b, tun_table,
+        enum ofperr error = oxm_pull_match_loose(&b, false, tun_table,
                                                  &pin->flow_metadata);
         if (error) {
             return error;
@@ -3574,7 +3574,8 @@ ofputil_decode_packet_in(const struct ofp_header *oh, bool loose,
 
         npi = ofpbuf_pull(&b, sizeof *npi);
         error = nx_pull_match_loose(&b, ntohs(npi->match_len),
-                                    &pin->flow_metadata, NULL, NULL, NULL);
+                                    &pin->flow_metadata, NULL, false, NULL,
+                                    NULL);
         if (error) {
             return error;
         }
@@ -4210,7 +4211,7 @@ ofputil_decode_packet_out(struct ofputil_packet_out *po,
         const struct ofp15_packet_out *opo = ofpbuf_pull(&b, sizeof *opo);
 
         po->buffer_id = ntohl(opo->buffer_id);
-        error = oxm_pull_match_loose(&b, NULL, &po->flow_metadata);
+        error = oxm_pull_match_loose(&b, true, NULL, &po->flow_metadata);
         if (error) {
             return error;
         }
@@ -6829,7 +6830,7 @@ ofputil_decode_flow_monitor_request(struct ofputil_flow_monitor_request *rq,
     rq->table_id = nfmr->table_id;
 
     return nx_pull_match(msg, ntohs(nfmr->match_len), &rq->match, NULL,
-                         NULL, NULL, NULL);
+                         NULL, false, NULL, NULL);
 }
 
 void
@@ -6937,8 +6938,8 @@ ofputil_decode_flow_update(struct ofputil_flow_update *update,
         update->cookie = nfuf->cookie;
         update->priority = ntohs(nfuf->priority);
 
-        error = nx_pull_match(msg, match_len, &update->match, NULL, NULL, NULL,
-                              NULL);
+        error = nx_pull_match(msg, match_len, &update->match, NULL, NULL,
+                              false, NULL, NULL);
         if (error) {
             return error;
         }
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index 2020fe85df7a..23ba3a191034 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -3458,6 +3458,10 @@ ofproto_packet_out_init(struct ofproto *ofproto,
 {
     enum ofperr error;
     struct match match;
+    struct {
+        struct miniflow mf;
+        uint64_t buf[FLOW_U64S];
+    } m;
 
     if (ofp_to_u16(po->flow_metadata.flow.in_port.ofp_port) >=
             ofproto->max_ports
@@ -3476,8 +3480,9 @@ ofproto_packet_out_init(struct ofproto *ofproto,
                                                      po->packet_len, 2);
     /* Store struct flow. */
     opo->flow = xmalloc(sizeof *opo->flow);
-    flow_extract(opo->packet, opo->flow);
-    opo->flow->in_port.ofp_port = po->flow_metadata.flow.in_port.ofp_port;
+    *opo->flow = po->flow_metadata.flow;
+    miniflow_extract(opo->packet, &m.mf);
+    flow_union_with_miniflow(opo->flow, &m.mf);
 
     /* Check actions like for flow mods.  We pass a 'table_id' of 0 to
      * ofproto_check_consistency(), which isn't strictly correct because these
diff --git a/tests/ofp-print.at b/tests/ofp-print.at
index 6b950a0d90e9..a00e3f3fe74b 100644
--- a/tests/ofp-print.at
+++ b/tests/ofp-print.at
@@ -815,6 +815,44 @@ AT_CHECK([ovs-ofctl ofp-print "\
 "], [0], [dnl
 OFPT_PACKET_OUT (OF1.5) (xid=0x11223344): ***decode error: OFPBRC_BAD_PORT***
 ])
+
+AT_CHECK([ovs-ofctl ofp-print "\
+06 0d 00 48 11 22 33 44 ff ff ff 00 00 10 00 00 \
+00 01 00 28 80 00 00 04 00 00 00 01 80 00 04 08 \
+00 00 00 00 00 00 00 03 80 00 4C 08 00 00 00 00 \
+00 00 00 05 00 00 00 00 00 00 00 10 ff ff ff fb \
+05 dc 00 00 00 00 00 00 \
+"], [0], [dnl
+OFPT_PACKET_OUT (OF1.5) (xid=0x11223344): tun_id=0x5,metadata=0x3,in_port=1 actions=FLOOD buffer=0xffffff00
+])
+
+dnl include non pipeline field
+AT_CHECK([ovs-ofctl ofp-print "\
+06 0d 00 38 11 22 33 44 ff ff ff 00 00 10 00 00 \
+00 01 00 18 80 00 00 04 00 00 00 01 80 00 16 04 \
+11 22 33 44 00 00 00 00 00 00 00 10 ff ff ff fb \
+05 dc 00 00 00 00 00 00 \
+"], [0], [dnl
+OFPT_PACKET_OUT (OF1.5) (xid=0x11223344): ***decode error: OFPBRC_PIPELINE_FIELDS_ONLY***
+])
+
+AT_CLEANUP
+
+AT_SETUP([OFPT_PACKET_OUT - OF1.5, with packet])
+AT_KEYWORDS([ofp-print packet-out])
+AT_CHECK([ovs-ofctl ofp-print "\
+06 0d 00 74 11 22 33 44 ff ff ff ff 00 10 00 00 \
+00 01 00 18 80 00 00 04 00 00 00 01 80 00 04 08 \
+00 00 00 00 00 00 00 03 00 00 00 10 ff ff ff fb \
+05 dc 00 00 00 00 00 00 50 54 00 00 00 05 50 54 \
+00 00 00 06 08 00 45 00 00 28 00 00 40 00 40 06 \
+b9 7c c0 a8 00 02 c0 a8 00 01 00 00 2b 60 00 00 \
+00 00 6a 4f 2b 58 50 14 00 00 6d 75 00 00 00 00 \
+00 00 00 00
+"], [0], [dnl
+OFPT_PACKET_OUT (OF1.5) (xid=0x11223344): metadata=0x3,in_port=1 actions=FLOOD data_len=60
+tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,nw_src=192.168.0.2,nw_dst=192.168.0.1,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=11104,tcp_flags=rst|ack tcp_csum:6d75
+])
 AT_CLEANUP
 
 # The flow is formatted with cls_rule_format() for the low-verbosity case.
diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
index 17ee64649f7f..22ac8d126000 100644
--- a/utilities/ovs-ofctl.c
+++ b/utilities/ovs-ofctl.c
@@ -3744,17 +3744,18 @@ ofctl_parse_nxm__(bool oxm, enum ofp_version version)
         /* Convert nx_match to match. */
         if (strict) {
             if (oxm) {
-                error = oxm_pull_match(&nx_match, NULL, NULL, &match);
+                error = oxm_pull_match(&nx_match, false, NULL, NULL, &match);
             } else {
-                error = nx_pull_match(&nx_match, match_len, &match,
-                                      &cookie, &cookie_mask, NULL, NULL);
+                error = nx_pull_match(&nx_match, match_len, &match, &cookie,
+                                      &cookie_mask, false, NULL, NULL);
             }
         } else {
             if (oxm) {
-                error = oxm_pull_match_loose(&nx_match, NULL, &match);
+                error = oxm_pull_match_loose(&nx_match, false, NULL, &match);
             } else {
                 error = nx_pull_match_loose(&nx_match, match_len, &match,
-                                            &cookie, &cookie_mask, NULL);
+                                            &cookie, &cookie_mask, false,
+                                            NULL);
             }
         }
 
@@ -4164,8 +4165,8 @@ ofctl_check_vlan(struct ovs_cmdl_context *ctx)
     ofpbuf_init(&nxm, 0);
     nxm_match_len = nx_put_match(&nxm, &match, htonll(0), htonll(0));
     nxm_s = nx_match_to_string(nxm.data, nxm_match_len);
-    error = nx_pull_match(&nxm, nxm_match_len, &nxm_match, NULL, NULL, NULL,
-                          NULL);
+    error = nx_pull_match(&nxm, nxm_match_len, &nxm_match, NULL, NULL, false,
+                          NULL, NULL);
     printf("NXM: %s -> ", nxm_s);
     if (error) {
         printf("%s\n", ofperr_to_string(error));
@@ -4181,7 +4182,7 @@ ofctl_check_vlan(struct ovs_cmdl_context *ctx)
     ofpbuf_init(&nxm, 0);
     nxm_match_len = oxm_put_match(&nxm, &match, OFP12_VERSION);
     nxm_s = oxm_match_to_string(&nxm, nxm_match_len);
-    error = oxm_pull_match(&nxm, NULL, NULL, &nxm_match);
+    error = oxm_pull_match(&nxm, false, NULL, NULL, &nxm_match);
     printf("OXM: %s -> ", nxm_s);
     if (error) {
         printf("%s\n", ofperr_to_string(error));
-- 
2.7.4



More information about the dev mailing list