summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYi-Hung Wei <yihung.wei@gmail.com>2017-05-15 10:04:57 -0700
committerBen Pfaff <blp@ovn.org>2017-05-31 14:54:10 -0700
commitd7892c814a8a9cf5681d34c6470bc9d841f4ad21 (patch)
tree3f0a70672a3781b56f3b6f8ae7e41178d4721c94
parent577bfa9f687936d53970d0ff41928c3a727720e8 (diff)
downloadopenvswitch-d7892c814a8a9cf5681d34c6470bc9d841f4ad21.tar.gz
ofproto: Add pipeline fields support for OF 1.5 packet-out
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@gmail.com> Signed-off-by: Ben Pfaff <blp@ovn.org>
-rw-r--r--include/openvswitch/meta-flow.h1
-rw-r--r--include/openvswitch/ofp-errors.h3
-rw-r--r--lib/meta-flow.c90
-rw-r--r--lib/nx-match.c54
-rw-r--r--lib/nx-match.h14
-rw-r--r--lib/ofp-util.c23
-rw-r--r--ofproto/ofproto.c9
-rw-r--r--tests/ofp-print.at38
-rw-r--r--utilities/ovs-ofctl.c17
9 files changed, 201 insertions, 48 deletions
diff --git a/include/openvswitch/meta-flow.h b/include/openvswitch/meta-flow.h
index 11852d2a0..1a0ba9b38 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 a5bba8619..aeb58e012 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 pipeline 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 b82a27381..b520e11c5 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 68e58d393..5d8aac571 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 6afb310ef..90cb6f8fd 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 6b9d59f7c..62cc3228c 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, NULL, false,
+ 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;
}
@@ -6831,7 +6832,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
@@ -6939,8 +6940,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 1bf4c8213..14985e623 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;
uint16_t in_port = ofp_to_u16(po->flow_metadata.flow.in_port.ofp_port);
if (in_port >= ofproto->max_ports && in_port < ofp_to_u16(OFPP_MAX)) {
@@ -3474,8 +3478,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 6b950a0d9..a00e3f3fe 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 17ee64649..22ac8d126 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));