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,
/* 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,
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.
*
* 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));
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;
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)
}
}
- 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
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,
* 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)
{
}
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
*
* 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
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,
/* 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 *);
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;
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;
}
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;
"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;
}
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;
}
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;
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;
}
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;
}
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
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;
}
{
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)) {
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
"], [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.
/* 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);
}
}
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));
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));