#define OXM_HEADER_W(FIELD, LENGTH) \
NXM_HEADER_W(OFPXMC12_OPENFLOW_BASIC, FIELD, LENGTH)
+#define IS_OXM_HEADER(header) (NXM_VENDOR(header) == OFPXMC12_OPENFLOW_BASIC)
+
#define OXM_OF_IN_PORT OXM_HEADER (OFPXMT12_OFB_IN_PORT, 4)
#define OXM_OF_IN_PHY_PORT OXM_HEADER (OFPXMT12_OFB_IN_PHY_PORT, 4)
#define OXM_OF_METADATA OXM_HEADER (OFPXMT12_OFB_METADATA, 8)
};
static struct hmap all_nxm_fields = HMAP_INITIALIZER(&all_nxm_fields);
+static struct hmap all_oxm_fields = HMAP_INITIALIZER(&all_oxm_fields);
/* Rate limit for parse errors. These always indicate a bug in an OpenFlow
* controller and so there's not much point in showing a lot of them. */
}
static void
-add_nxm_field(uint32_t nxm_header, const struct mf_field *mf)
+add_nxm_field(struct hmap *all_fields, uint32_t nxm_header,
+ const struct mf_field *mf)
{
struct nxm_field *f;
f = xmalloc(sizeof *f);
- hmap_insert(&all_nxm_fields, &f->hmap_node, hash_int(nxm_header, 0));
+ hmap_insert(all_fields, &f->hmap_node, hash_int(nxm_header, 0));
f->nxm_header = nxm_header;
f->mf = mf;
}
+static struct hmap *
+get_all_fields(uint32_t header)
+{
+ return IS_OXM_HEADER(header) ? &all_oxm_fields : &all_nxm_fields;
+}
+
+static void
+nxm_init_add_field(const struct mf_field *mf, uint32_t header)
+{
+ struct hmap *all_fields = get_all_fields(header);
+
+ if (!header) {
+ return;
+ }
+ add_nxm_field(all_fields, header, mf);
+ if (mf->maskable == MFM_NONE) {
+ return;
+ }
+ add_nxm_field(all_fields, NXM_MAKE_WILD_HEADER(header), mf);
+}
+
+#ifndef NDEBUG
+static void
+nxm_init_verify_field(const struct mf_field *mf, uint32_t header)
+{
+ if (!header) {
+ return;
+ }
+ assert(mf_from_nxm_header(header) == mf);
+ /* Some OXM fields are not maskable while their NXM
+ * counterparts are, just skip this check for now */
+ if (mf->maskable == MFM_NONE || IS_OXM_HEADER(header)) {
+ return;
+ }
+ assert(mf_from_nxm_header(NXM_MAKE_WILD_HEADER(mf->nxm_header)) == mf);
+}
+#endif
+
static void
nxm_init(void)
{
const struct mf_field *mf;
for (mf = mf_fields; mf < &mf_fields[MFF_N_IDS]; mf++) {
- if (mf->nxm_header) {
- add_nxm_field(mf->nxm_header, mf);
- if (mf->maskable != MFM_NONE) {
- add_nxm_field(NXM_MAKE_WILD_HEADER(mf->nxm_header), mf);
- }
- }
+ nxm_init_add_field(mf, mf->nxm_header);
+ nxm_init_add_field(mf, mf->oxm_header);
}
#ifndef NDEBUG
/* Verify that the header values are unique. */
for (mf = mf_fields; mf < &mf_fields[MFF_N_IDS]; mf++) {
- if (mf->nxm_header) {
- assert(mf_from_nxm_header(mf->nxm_header) == mf);
- if (mf->maskable != MFM_NONE) {
- assert(mf_from_nxm_header(NXM_MAKE_WILD_HEADER(mf->nxm_header))
- == mf);
- }
- }
+ nxm_init_verify_field(mf, mf->nxm_header);
+ nxm_init_verify_field(mf, mf->oxm_header);
}
#endif
}
mf_from_nxm_header(uint32_t header)
{
const struct nxm_field *f;
+ struct hmap *all_fields = get_all_fields(header);
- if (hmap_is_empty(&all_nxm_fields)) {
+ if (hmap_is_empty(all_fields)) {
nxm_init();
}
- HMAP_FOR_EACH_IN_BUCKET (f, hmap_node, hash_int(header, 0),
- &all_nxm_fields) {
+ HMAP_FOR_EACH_IN_BUCKET (f, hmap_node, hash_int(header, 0), all_fields) {
if (f->nxm_header == header) {
return f->mf;
}
error = OFPERR_OFPBMC_BAD_PREREQ;
} else if (!mf_is_all_wild(mf, &rule->wc)) {
error = OFPERR_OFPBMC_DUP_FIELD;
- } else {
+ } else if (header != OXM_OF_IN_PORT) {
unsigned int width = mf->n_bytes;
union mf_value value;
mf_set(mf, &value, &mask, rule);
}
}
+ } else {
+ /* Special case for 32bit ports when using OXM,
+ * ports are 16 bits wide otherwise. */
+ ovs_be32 port_of11;
+ uint16_t port;
+
+ memcpy(&port_of11, p + 4, sizeof port_of11);
+ error = ofputil_port_from_ofp11(port_of11, &port);
+ if (!error) {
+ cls_rule_set_in_port(rule, port);
+ }
}
/* Check if the match is for a cookie rather than a classifier rule. */
static void
nxm_put_ip(struct ofpbuf *b, const struct cls_rule *cr,
- uint8_t icmp_proto, uint32_t icmp_type, uint32_t icmp_code)
+ uint8_t icmp_proto, uint32_t icmp_type, uint32_t icmp_code,
+ bool oxm)
{
const flow_wildcards_t wc = cr->wc.wildcards;
const struct flow *flow = &cr->flow;
nxm_put_frag(b, cr);
if (!(wc & FWW_NW_DSCP)) {
- nxm_put_8(b, NXM_OF_IP_TOS, flow->nw_tos & IP_DSCP_MASK);
+ nxm_put_8(b, oxm ? OXM_OF_IP_DSCP : NXM_OF_IP_TOS,
+ flow->nw_tos & IP_DSCP_MASK);
}
if (!(wc & FWW_NW_ECN)) {
- nxm_put_8(b, NXM_NX_IP_ECN, flow->nw_tos & IP_ECN_MASK);
+ nxm_put_8(b, oxm ? OXM_OF_IP_ECN : NXM_NX_IP_ECN,
+ flow->nw_tos & IP_ECN_MASK);
}
- if (!(wc & FWW_NW_TTL)) {
+ if (!oxm && !(wc & FWW_NW_TTL)) {
nxm_put_8(b, NXM_NX_IP_TTL, flow->nw_ttl);
}
if (!(wc & FWW_NW_PROTO)) {
- nxm_put_8(b, NXM_OF_IP_PROTO, flow->nw_proto);
+ nxm_put_8(b, oxm ? OXM_OF_IP_PROTO : NXM_OF_IP_PROTO, flow->nw_proto);
if (flow->nw_proto == IPPROTO_TCP) {
- nxm_put_16m(b, NXM_OF_TCP_SRC, flow->tp_src, cr->wc.tp_src_mask);
- nxm_put_16m(b, NXM_OF_TCP_DST, flow->tp_dst, cr->wc.tp_dst_mask);
+ nxm_put_16m(b, oxm ? OXM_OF_TCP_SRC : NXM_OF_TCP_SRC,
+ flow->tp_src, cr->wc.tp_src_mask);
+ nxm_put_16m(b, oxm ? OXM_OF_TCP_DST : NXM_OF_TCP_DST,
+ flow->tp_dst, cr->wc.tp_dst_mask);
} else if (flow->nw_proto == IPPROTO_UDP) {
- nxm_put_16m(b, NXM_OF_UDP_SRC, flow->tp_src, cr->wc.tp_src_mask);
- nxm_put_16m(b, NXM_OF_UDP_DST, flow->tp_dst, cr->wc.tp_dst_mask);
+ nxm_put_16m(b, oxm ? OXM_OF_UDP_SRC : NXM_OF_UDP_SRC,
+ flow->tp_src, cr->wc.tp_src_mask);
+ nxm_put_16m(b, oxm ? OXM_OF_UDP_DST : NXM_OF_UDP_DST,
+ flow->tp_dst, cr->wc.tp_dst_mask);
} else if (flow->nw_proto == icmp_proto) {
if (cr->wc.tp_src_mask) {
nxm_put_8(b, icmp_type, ntohs(flow->tp_src));
* If 'cr' is a catch-all rule that matches every packet, then this function
* appends nothing to 'b' and returns 0. */
int
-nx_put_match(struct ofpbuf *b, const struct cls_rule *cr,
+nx_put_match(struct ofpbuf *b, bool oxm, const struct cls_rule *cr,
ovs_be64 cookie, ovs_be64 cookie_mask)
{
const flow_wildcards_t wc = cr->wc.wildcards;
/* Metadata. */
if (!(wc & FWW_IN_PORT)) {
uint16_t in_port = flow->in_port;
- nxm_put_16(b, NXM_OF_IN_PORT, htons(in_port));
+ if (oxm) {
+ nxm_put_32(b, OXM_OF_IN_PORT, ofputil_port_to_ofp11(in_port));
+ } else {
+ nxm_put_16(b, NXM_OF_IN_PORT, htons(in_port));
+ }
}
/* Ethernet. */
- nxm_put_eth_masked(b, NXM_OF_ETH_SRC, flow->dl_src, cr->wc.dl_src_mask);
- nxm_put_eth_masked(b, NXM_OF_ETH_DST, flow->dl_dst, cr->wc.dl_dst_mask);
+ nxm_put_eth_masked(b, oxm ? OXM_OF_ETH_SRC : NXM_OF_ETH_SRC,
+ flow->dl_src, cr->wc.dl_src_mask);
+ nxm_put_eth_masked(b, oxm ? OXM_OF_ETH_DST : NXM_OF_ETH_DST,
+ flow->dl_dst, cr->wc.dl_dst_mask);
if (!(wc & FWW_DL_TYPE)) {
- nxm_put_16(b, NXM_OF_ETH_TYPE,
+ nxm_put_16(b, oxm ? OXM_OF_ETH_TYPE : NXM_OF_ETH_TYPE,
ofputil_dl_type_to_openflow(flow->dl_type));
}
- /* 802.1Q. */
+ /* 802.1Q.
+ *
+ * XXX missing OXM support */
nxm_put_16m(b, NXM_OF_VLAN_TCI, flow->vlan_tci, cr->wc.vlan_tci_mask);
/* L3. */
if (!(wc & FWW_DL_TYPE) && flow->dl_type == htons(ETH_TYPE_IP)) {
/* IP. */
- nxm_put_32m(b, NXM_OF_IP_SRC, flow->nw_src, cr->wc.nw_src_mask);
- nxm_put_32m(b, NXM_OF_IP_DST, flow->nw_dst, cr->wc.nw_dst_mask);
- nxm_put_ip(b, cr, IPPROTO_ICMP, NXM_OF_ICMP_TYPE, NXM_OF_ICMP_CODE);
+ nxm_put_32m(b, oxm ? OXM_OF_IPV4_SRC : NXM_OF_IP_SRC,
+ flow->nw_src, cr->wc.nw_src_mask);
+ nxm_put_32m(b, oxm ? OXM_OF_IPV4_DST : NXM_OF_IP_DST,
+ flow->nw_dst, cr->wc.nw_dst_mask);
+ nxm_put_ip(b, cr, IPPROTO_ICMP,
+ oxm ? OXM_OF_ICMPV4_TYPE : NXM_OF_ICMP_TYPE,
+ oxm ? OXM_OF_ICMPV4_CODE : NXM_OF_ICMP_CODE, oxm);
} else if (!(wc & FWW_DL_TYPE) && flow->dl_type == htons(ETH_TYPE_IPV6)) {
/* IPv6. */
- nxm_put_ipv6(b, NXM_NX_IPV6_SRC, &flow->ipv6_src,
- &cr->wc.ipv6_src_mask);
- nxm_put_ipv6(b, NXM_NX_IPV6_DST, &flow->ipv6_dst,
- &cr->wc.ipv6_dst_mask);
- nxm_put_ip(b, cr,
- IPPROTO_ICMPV6, NXM_NX_ICMPV6_TYPE, NXM_NX_ICMPV6_CODE);
+ nxm_put_ipv6(b, oxm ? OXM_OF_IPV6_SRC : NXM_NX_IPV6_SRC,
+ &flow->ipv6_src, &cr->wc.ipv6_src_mask);
+ nxm_put_ipv6(b, oxm ? OXM_OF_IPV6_DST : NXM_NX_IPV6_DST,
+ &flow->ipv6_dst, &cr->wc.ipv6_dst_mask);
+ nxm_put_ip(b, cr, IPPROTO_ICMPV6,
+ oxm ? OXM_OF_ICMPV6_TYPE : NXM_NX_ICMPV6_TYPE,
+ oxm ? OXM_OF_ICMPV6_CODE : NXM_NX_ICMPV6_CODE, oxm);
if (!(wc & FWW_IPV6_LABEL)) {
- nxm_put_32(b, NXM_NX_IPV6_LABEL, flow->ipv6_label);
+ nxm_put_32(b, oxm ? OXM_OF_IPV6_FLABEL : NXM_NX_IPV6_LABEL,
+ flow->ipv6_label);
}
if (flow->nw_proto == IPPROTO_ICMPV6
&& (flow->tp_src == htons(ND_NEIGHBOR_SOLICIT) ||
flow->tp_src == htons(ND_NEIGHBOR_ADVERT))) {
- nxm_put_ipv6(b, NXM_NX_ND_TARGET, &flow->nd_target,
- &cr->wc.nd_target_mask);
+ nxm_put_ipv6(b, oxm ? OXM_OF_IPV6_ND_TARGET : NXM_NX_ND_TARGET,
+ &flow->nd_target, &cr->wc.nd_target_mask);
if (!(wc & FWW_ARP_SHA)
&& flow->tp_src == htons(ND_NEIGHBOR_SOLICIT)) {
- nxm_put_eth(b, NXM_NX_ND_SLL, flow->arp_sha);
+ nxm_put_eth(b, oxm ? OXM_OF_IPV6_ND_SLL : NXM_NX_ND_SLL,
+ flow->arp_sha);
}
if (!(wc & FWW_ARP_THA)
&& flow->tp_src == htons(ND_NEIGHBOR_ADVERT)) {
- nxm_put_eth(b, NXM_NX_ND_TLL, flow->arp_tha);
+ nxm_put_eth(b, oxm ? OXM_OF_IPV6_ND_TLL : NXM_NX_ND_TLL,
+ flow->arp_tha);
}
}
} else if (!(wc & FWW_DL_TYPE) && flow->dl_type == htons(ETH_TYPE_ARP)) {
/* ARP. */
if (!(wc & FWW_NW_PROTO)) {
- nxm_put_16(b, NXM_OF_ARP_OP, htons(flow->nw_proto));
+ nxm_put_16(b, oxm ? OXM_OF_ARP_OP : NXM_OF_ARP_OP,
+ htons(flow->nw_proto));
}
- nxm_put_32m(b, NXM_OF_ARP_SPA, flow->nw_src, cr->wc.nw_src_mask);
- nxm_put_32m(b, NXM_OF_ARP_TPA, flow->nw_dst, cr->wc.nw_dst_mask);
+ nxm_put_32m(b, oxm ? OXM_OF_ARP_SPA : NXM_OF_ARP_SPA,
+ flow->nw_src, cr->wc.nw_src_mask);
+ nxm_put_32m(b, oxm ? OXM_OF_ARP_TPA : NXM_OF_ARP_TPA,
+ flow->nw_dst, cr->wc.nw_dst_mask);
if (!(wc & FWW_ARP_SHA)) {
- nxm_put_eth(b, NXM_NX_ARP_SHA, flow->arp_sha);
+ nxm_put_eth(b, oxm ? OXM_OF_ARP_SHA : NXM_NX_ARP_SHA,
+ flow->arp_sha);
}
if (!(wc & FWW_ARP_THA)) {
- nxm_put_eth(b, NXM_NX_ARP_THA, flow->arp_tha);
+ nxm_put_eth(b, oxm ? OXM_OF_ARP_THA : NXM_NX_ARP_THA,
+ flow->arp_tha);
}
}
{
const struct mf_field *mf = mf_from_nxm_header(header);
if (mf) {
- ds_put_cstr(s, mf->nxm_name);
+ ds_put_cstr(s, IS_OXM_HEADER(header) ? mf->oxm_name : mf->nxm_name);
if (NXM_HASMASK(header)) {
ds_put_cstr(s, "_W");
}
for (i = 0; i < MFF_N_IDS; i++) {
const struct mf_field *mf = mf_from_id(i);
+ uint32_t header;
- if (mf->nxm_name
- && !strncmp(mf->nxm_name, name, name_len)
- && mf->nxm_name[name_len] == '\0') {
- if (!wild) {
- return mf->nxm_header;
- } else if (mf->maskable != MFM_NONE) {
- return NXM_MAKE_WILD_HEADER(mf->nxm_header);
- }
+ if (mf->nxm_name &&
+ !strncmp(mf->nxm_name, name, name_len) &&
+ mf->nxm_name[name_len] == '\0') {
+ header = mf->nxm_header;
+ } else if (mf->oxm_name &&
+ !strncmp(mf->oxm_name, name, name_len) &&
+ mf->oxm_name[name_len] == '\0') {
+ header = mf->oxm_header;
+ } else {
+ continue;
+ }
+
+ if (!wild) {
+ return header;
+ } else if (mf->maskable != MFM_NONE) {
+ return NXM_MAKE_WILD_HEADER(header);
}
}
- if (!strncmp("NXM_NX_COOKIE", name, name_len)
- && (name_len == strlen("NXM_NX_COOKIE"))) {
+ if (!strncmp("NXM_NX_COOKIE", name, name_len) &&
+ (name_len == strlen("NXM_NX_COOKIE"))) {
if (!wild) {
return NXM_NX_COOKIE;
} else {
enum ofperr nx_pull_match_loose(struct ofpbuf *, unsigned int match_len,
uint16_t priority, struct cls_rule *,
ovs_be64 *cookie, ovs_be64 *cookie_mask);
-int nx_put_match(struct ofpbuf *, const struct cls_rule *,
+int nx_put_match(struct ofpbuf *, bool oxm, const struct cls_rule *,
ovs_be64 cookie, ovs_be64 cookie_mask);
char *nx_match_to_string(const uint8_t *, unsigned int match_len);
nfm = msg->data;
nfm->command = htons(command);
nfm->cookie = fm->new_cookie;
- match_len = nx_put_match(msg, &fm->cr, fm->cookie, fm->cookie_mask);
+ match_len = nx_put_match(msg, false, &fm->cr,
+ fm->cookie, fm->cookie_mask);
nfm->idle_timeout = htons(fm->idle_timeout);
nfm->hard_timeout = htons(fm->hard_timeout);
nfm->priority = htons(fm->cr.priority);
subtype = fsr->aggregate ? NXST_AGGREGATE : NXST_FLOW;
ofputil_make_stats_request(sizeof *nfsr, OFPST_VENDOR, subtype, &msg);
- match_len = nx_put_match(msg, &fsr->match,
+ match_len = nx_put_match(msg, false, &fsr->match,
fsr->cookie, fsr->cookie_mask);
nfsr = msg->data;
nfs->hard_age = htons(fs->hard_age < 0 ? 0
: fs->hard_age < UINT16_MAX ? fs->hard_age + 1
: UINT16_MAX);
- nfs->match_len = htons(nx_put_match(msg, &fs->rule, 0, 0));
+ nfs->match_len = htons(nx_put_match(msg, false, &fs->rule, 0, 0));
nfs->cookie = fs->cookie;
nfs->packet_count = htonll(fs->packet_count);
nfs->byte_count = htonll(fs->byte_count);
int match_len;
make_nxmsg_xid(sizeof *nfr, NXT_FLOW_REMOVED, htonl(0), &msg);
- match_len = nx_put_match(msg, &fr->rule, 0, 0);
+ match_len = nx_put_match(msg, false, &fr->rule, 0, 0);
nfr = msg->data;
nfr->cookie = fr->cookie;
npi = ofpbuf_pull(&b, sizeof *npi);
error = nx_pull_match_loose(&b, ntohs(npi->match_len), 0, &rule, NULL,
- NULL);
+ NULL);
if (error) {
return error;
}
cls_rule_set_in_port(&rule, pin->fmd.in_port);
ofpbuf_put_zeros(packet, sizeof *npi);
- match_len = nx_put_match(packet, &rule, 0, 0);
+ match_len = nx_put_match(packet, false, &rule, 0, 0);
ofpbuf_put_zeros(packet, 2);
ofpbuf_put(packet, pin->packet, send_len);
])
AT_CLEANUP
+AT_SETUP([ovs-ofctl parse-oxm])
+AT_KEYWORDS([oxm])
+AT_DATA([oxm.txt], [dnl
+<any>
+
+# in port
+OXM_OF_IN_PORT(00000000)
+OXM_OF_IN_PORT(fffffffe)
+
+# eth dst
+OXM_OF_ETH_DST(0002e30f80a4)
+OXM_OF_ETH_DST_W(010000000000/010000000000)
+OXM_OF_ETH_DST_W(000000000000/010000000000)
+OXM_OF_ETH_DST_W(ffffffffffff/010000000000)
+OXM_OF_ETH_DST_W(0002e30f80a4/ffffffffffff)
+OXM_OF_ETH_DST_W(0002e30f80a4/feffffffffff)
+
+# eth src
+OXM_OF_ETH_SRC(020898456ddb)
+
+# eth type
+OXM_OF_ETH_TYPE(0800)
+OXM_OF_ETH_TYPE(0800) OXM_OF_IN_PORT(00000012)
+
+# IP ECN
+OXM_OF_ETH_TYPE(0800) OXM_OF_IP_ECN(03)
+OXM_OF_ETH_TYPE(0800) OXM_OF_IP_ECN(06)
+OXM_OF_IP_ECN(03)
+
+# IP protocol
+OXM_OF_ETH_TYPE(0800) OXM_OF_IP_PROTO(01)
+OXM_OF_ETH_TYPE(0800) OXM_OF_IP_PROTO(05)
+OXM_OF_IP_PROTO(05)
+
+# IP source
+OXM_OF_ETH_TYPE(0800) OXM_OF_IPV4_SRC(ac100014)
+OXM_OF_ETH_TYPE(0800) OXM_OF_IPV4_SRC_W(C0a80000/FFFF0000)
+OXM_OF_ETH_TYPE(0806) OXM_OF_IPV4_SRC(ac100014)
+OXM_OF_IPV4_SRC_W(C0D80000/FFFF0000)
+
+# IP destination
+OXM_OF_ETH_TYPE(0800) OXM_OF_IPV4_DST(ac100014)
+OXM_OF_ETH_TYPE(0800) OXM_OF_IPV4_DST_W(C0a88012/FFFF0000)
+OXM_OF_IPV4_DST(ac100014)
+OXM_OF_ETH_TYPE(0806) OXM_OF_IPV4_DST_W(C0D80000/FFFF0000)
+
+# TCP source port
+OXM_OF_ETH_TYPE(0800) OXM_OF_IP_PROTO(06) OXM_OF_TCP_SRC(4231)
+OXM_OF_ETH_TYPE(0800) OXM_OF_IP_PROTO(06) OXM_OF_TCP_SRC_W(5050/F0F0)
+OXM_OF_ETH_TYPE(0800) OXM_OF_IP_PROTO(07) OXM_OF_TCP_SRC(4231)
+
+# TCP destination port
+OXM_OF_ETH_TYPE(0800) OXM_OF_IP_PROTO(06) OXM_OF_TCP_DST(4231)
+OXM_OF_ETH_TYPE(0800) OXM_OF_IP_PROTO(06) OXM_OF_TCP_DST_W(FDE0/FFF0)
+OXM_OF_ETH_TYPE(0800) OXM_OF_IP_PROTO(07) OXM_OF_TCP_DST(4231)
+
+# UDP source port
+OXM_OF_ETH_TYPE(0800) OXM_OF_IP_PROTO(11) OXM_OF_UDP_SRC(8732)
+OXM_OF_ETH_TYPE(0800) OXM_OF_IP_PROTO(11) OXM_OF_UDP_SRC_W(0132/01FF)
+OXM_OF_ETH_TYPE(0800) OXM_OF_IP_PROTO(06) OXM_OF_UDP_SRC(7823)
+
+# UDP destination port
+OXM_OF_ETH_TYPE(0800) OXM_OF_IP_PROTO(11) OXM_OF_UDP_DST(1782)
+OXM_OF_ETH_TYPE(0800) OXM_OF_IP_PROTO(11) OXM_OF_UDP_DST_W(5005/F00F)
+OXM_OF_ETH_TYPE(0800) OXM_OF_IP_PROTO(02) OXM_OF_UDP_DST(1293)
+
+# ICMP type
+OXM_OF_ETH_TYPE(0800) OXM_OF_IP_PROTO(01) OXM_OF_ICMPV4_TYPE(12)
+OXM_OF_ETH_TYPE(0800) OXM_OF_IP_PROTO(00) OXM_OF_ICMPV4_TYPE(10)
+
+# ICMP code
+OXM_OF_ETH_TYPE(0800) OXM_OF_IP_PROTO(01) OXM_OF_ICMPV4_CODE(12)
+OXM_OF_ETH_TYPE(0800) OXM_OF_IP_PROTO(00) OXM_OF_ICMPV4_CODE(10)
+OXM_OF_ETH_TYPE(0800) OXM_OF_ICMPV4_CODE(10)
+OXM_OF_ICMPV4_CODE(00)
+
+# ARP opcode
+OXM_OF_ETH_TYPE(0806) OXM_OF_ARP_OP(0001)
+OXM_OF_ETH_TYPE(0806) OXM_OF_ARP_OP(1111)
+OXM_OF_ETH_TYPE(0000) OXM_OF_ARP_OP(0001)
+OXM_OF_ARP_OP(0001)
+OXM_OF_ETH_TYPE(0806) OXM_OF_ARP_OP(0001) OXM_OF_ARP_OP(0001)
+
+# ARP source protocol address
+OXM_OF_ETH_TYPE(0806) OXM_OF_ARP_SPA(ac100014)
+OXM_OF_ETH_TYPE(0806) OXM_OF_ARP_SPA_W(C0a81234/FFFFFF00)
+OXM_OF_ETH_TYPE(0800) OXM_OF_ARP_SPA(ac100014)
+OXM_OF_ARP_SPA_W(C0D8fedc/FFFF0000)
+
+# ARP destination protocol address
+OXM_OF_ETH_TYPE(0806) OXM_OF_ARP_TPA(ac100014)
+OXM_OF_ETH_TYPE(0806) OXM_OF_ARP_TPA_W(C0a812fe/FFFFFF00)
+OXM_OF_ETH_TYPE(0800) OXM_OF_ARP_TPA(ac100014)
+OXM_OF_ARP_TPA_W(C0D80000/FFFF0000)
+
+# ARP source hardware address
+OXM_OF_ETH_TYPE(0806) OXM_OF_ARP_SHA(0002e30f80a4)
+OXM_OF_ETH_TYPE(0800) OXM_OF_ARP_SHA(0002e30f80a4)
+OXM_OF_ARP_SHA(0002e30f80a4)
+
+# ARP destination hardware address
+OXM_OF_ETH_TYPE(0806) OXM_OF_ARP_THA(0002e30f80a4)
+OXM_OF_ETH_TYPE(0800) OXM_OF_ARP_THA(0002e30f80a4)
+OXM_OF_ARP_THA(0002e30f80a4)
+
+# IPv6 source
+OXM_OF_ETH_TYPE(86dd) OXM_OF_IPV6_SRC(20010db83c4d00010002000300040005)
+OXM_OF_ETH_TYPE(0800) OXM_OF_IPV6_SRC(20010db83c4d00010002000300040005)
+OXM_OF_ETH_TYPE(86dd) OXM_OF_IPV6_SRC_W(20010db83c4d00010000000000000000/ffffffffffffffff0000000000000000)
+OXM_OF_ETH_TYPE(0800) OXM_OF_IPV6_SRC_W(20010db83c4d00010000000000000000/ffffffffffffffff0000000000000000)
+
+# IPv6 destination
+OXM_OF_ETH_TYPE(86dd) OXM_OF_IPV6_DST(20010db83c4d00010002000300040005)
+OXM_OF_ETH_TYPE(0800) OXM_OF_IPV6_DST(20010db83c4d00010002000300040005)
+OXM_OF_ETH_TYPE(86dd) OXM_OF_IPV6_DST_W(20010db83c4d00010000000000000000/ffffffffffffffff0000000000000000)
+OXM_OF_ETH_TYPE(0800) OXM_OF_IPV6_DST_W(20010db83c4d00010000000000000000/ffffffffffffffff0000000000000000)
+
+# ND source hardware address
+OXM_OF_ETH_TYPE(86dd) OXM_OF_IP_PROTO(3a) OXM_OF_ICMPV6_TYPE(87) OXM_OF_IPV6_ND_TARGET(20010db83c4d00010002000300040005) OXM_OF_IPV6_ND_SLL(0002e30f80a4)
+OXM_OF_ETH_TYPE(86dd) OXM_OF_IP_PROTO(3a) OXM_OF_ICMPV6_TYPE(88) OXM_OF_IPV6_ND_TARGET(20010db83c4d00010002000300040005) OXM_OF_IPV6_ND_SLL(0002e30f80a4)
+OXM_OF_ETH_TYPE(86dd) OXM_OF_IP_PROTO(3b) OXM_OF_ICMPV6_TYPE(87) OXM_OF_IPV6_ND_TARGET(20010db83c4d00010002000300040005) OXM_OF_IPV6_ND_SLL(0002e30f80a4)
+OXM_OF_ETH_TYPE(0800) OXM_OF_IP_PROTO(3a) OXM_OF_ICMPV6_TYPE(87) OXM_OF_IPV6_ND_TARGET(20010db83c4d00010002000300040005) OXM_OF_IPV6_ND_SLL(0002e30f80a4)
+
+# ND destination hardware address
+OXM_OF_ETH_TYPE(86dd) OXM_OF_IP_PROTO(3a) OXM_OF_ICMPV6_TYPE(88) OXM_OF_IPV6_ND_TARGET(20010db83c4d00010002000300040005) OXM_OF_IPV6_ND_TLL(0002e30f80a4)
+OXM_OF_ETH_TYPE(86dd) OXM_OF_IP_PROTO(3a) OXM_OF_ICMPV6_TYPE(87) OXM_OF_IPV6_ND_TARGET(20010db83c4d00010002000300040005) OXM_OF_IPV6_ND_TLL(0002e30f80a4)
+OXM_OF_ETH_TYPE(86dd) OXM_OF_IP_PROTO(3b) OXM_OF_ICMPV6_TYPE(87) OXM_OF_IPV6_ND_TARGET(20010db83c4d00010002000300040005) OXM_OF_IPV6_ND_TLL(0002e30f80a4)
+OXM_OF_ETH_TYPE(0800) OXM_OF_IP_PROTO(3a) OXM_OF_ICMPV6_TYPE(88) OXM_OF_IPV6_ND_TARGET(20010db83c4d00010002000300040005) OXM_OF_IPV6_ND_TLL(0002e30f80a4)
+
+# Invalid field number.
+01020304(1111/2222)
+])
+AT_CHECK([ovs-ofctl --strict parse-oxm < oxm.txt], [0], [dnl
+<any>
+
+# in port
+OXM_OF_IN_PORT(00000000)
+OXM_OF_IN_PORT(fffffffe)
+
+# eth dst
+OXM_OF_ETH_DST(0002e30f80a4)
+OXM_OF_ETH_DST_W(010000000000/010000000000)
+OXM_OF_ETH_DST_W(000000000000/010000000000)
+OXM_OF_ETH_DST_W(010000000000/010000000000)
+OXM_OF_ETH_DST(0002e30f80a4)
+OXM_OF_ETH_DST_W(0002e30f80a4/feffffffffff)
+
+# eth src
+OXM_OF_ETH_SRC(020898456ddb)
+
+# eth type
+OXM_OF_ETH_TYPE(0800)
+OXM_OF_IN_PORT(00000012), OXM_OF_ETH_TYPE(0800)
+
+# IP ECN
+OXM_OF_ETH_TYPE(0800), OXM_OF_IP_ECN(03)
+nx_pull_match() returned error OFPBMC_BAD_VALUE
+nx_pull_match() returned error OFPBMC_BAD_PREREQ
+
+# IP protocol
+OXM_OF_ETH_TYPE(0800), OXM_OF_IP_PROTO(01)
+OXM_OF_ETH_TYPE(0800), OXM_OF_IP_PROTO(05)
+nx_pull_match() returned error OFPBMC_BAD_PREREQ
+
+# IP source
+OXM_OF_ETH_TYPE(0800), OXM_OF_IPV4_SRC(ac100014)
+OXM_OF_ETH_TYPE(0800), OXM_OF_IPV4_SRC_W(c0a80000/ffff0000)
+nx_pull_match() returned error OFPBMC_BAD_PREREQ
+nx_pull_match() returned error OFPBMC_BAD_PREREQ
+
+# IP destination
+OXM_OF_ETH_TYPE(0800), OXM_OF_IPV4_DST(ac100014)
+OXM_OF_ETH_TYPE(0800), OXM_OF_IPV4_DST_W(c0a80000/ffff0000)
+nx_pull_match() returned error OFPBMC_BAD_PREREQ
+nx_pull_match() returned error OFPBMC_BAD_PREREQ
+
+# TCP source port
+OXM_OF_ETH_TYPE(0800), OXM_OF_IP_PROTO(06), OXM_OF_TCP_SRC(4231)
+OXM_OF_ETH_TYPE(0800), OXM_OF_IP_PROTO(06), OXM_OF_TCP_SRC_W(5050/f0f0)
+nx_pull_match() returned error OFPBMC_BAD_PREREQ
+
+# TCP destination port
+OXM_OF_ETH_TYPE(0800), OXM_OF_IP_PROTO(06), OXM_OF_TCP_DST(4231)
+OXM_OF_ETH_TYPE(0800), OXM_OF_IP_PROTO(06), OXM_OF_TCP_DST_W(fde0/fff0)
+nx_pull_match() returned error OFPBMC_BAD_PREREQ
+
+# UDP source port
+OXM_OF_ETH_TYPE(0800), OXM_OF_IP_PROTO(11), OXM_OF_UDP_SRC(8732)
+OXM_OF_ETH_TYPE(0800), OXM_OF_IP_PROTO(11), OXM_OF_UDP_SRC_W(0132/01ff)
+nx_pull_match() returned error OFPBMC_BAD_PREREQ
+
+# UDP destination port
+OXM_OF_ETH_TYPE(0800), OXM_OF_IP_PROTO(11), OXM_OF_UDP_DST(1782)
+OXM_OF_ETH_TYPE(0800), OXM_OF_IP_PROTO(11), OXM_OF_UDP_DST_W(5005/f00f)
+nx_pull_match() returned error OFPBMC_BAD_PREREQ
+
+# ICMP type
+OXM_OF_ETH_TYPE(0800), OXM_OF_IP_PROTO(01), OXM_OF_ICMPV4_TYPE(12)
+nx_pull_match() returned error OFPBMC_BAD_PREREQ
+
+# ICMP code
+OXM_OF_ETH_TYPE(0800), OXM_OF_IP_PROTO(01), OXM_OF_ICMPV4_CODE(12)
+nx_pull_match() returned error OFPBMC_BAD_PREREQ
+nx_pull_match() returned error OFPBMC_BAD_PREREQ
+nx_pull_match() returned error OFPBMC_BAD_PREREQ
+
+# ARP opcode
+OXM_OF_ETH_TYPE(0806), OXM_OF_ARP_OP(0001)
+nx_pull_match() returned error OFPBMC_BAD_VALUE
+nx_pull_match() returned error OFPBMC_BAD_PREREQ
+nx_pull_match() returned error OFPBMC_BAD_PREREQ
+nx_pull_match() returned error OFPBMC_DUP_FIELD
+
+# ARP source protocol address
+OXM_OF_ETH_TYPE(0806), OXM_OF_ARP_SPA(ac100014)
+OXM_OF_ETH_TYPE(0806), OXM_OF_ARP_SPA_W(c0a81200/ffffff00)
+nx_pull_match() returned error OFPBMC_BAD_PREREQ
+nx_pull_match() returned error OFPBMC_BAD_PREREQ
+
+# ARP destination protocol address
+OXM_OF_ETH_TYPE(0806), OXM_OF_ARP_TPA(ac100014)
+OXM_OF_ETH_TYPE(0806), OXM_OF_ARP_TPA_W(c0a81200/ffffff00)
+nx_pull_match() returned error OFPBMC_BAD_PREREQ
+nx_pull_match() returned error OFPBMC_BAD_PREREQ
+
+# ARP source hardware address
+OXM_OF_ETH_TYPE(0806), OXM_OF_ARP_SHA(0002e30f80a4)
+nx_pull_match() returned error OFPBMC_BAD_PREREQ
+nx_pull_match() returned error OFPBMC_BAD_PREREQ
+
+# ARP destination hardware address
+OXM_OF_ETH_TYPE(0806), OXM_OF_ARP_THA(0002e30f80a4)
+nx_pull_match() returned error OFPBMC_BAD_PREREQ
+nx_pull_match() returned error OFPBMC_BAD_PREREQ
+
+# IPv6 source
+OXM_OF_ETH_TYPE(86dd), OXM_OF_IPV6_SRC(20010db83c4d00010002000300040005)
+nx_pull_match() returned error OFPBMC_BAD_PREREQ
+OXM_OF_ETH_TYPE(86dd), OXM_OF_IPV6_SRC_W(20010db83c4d00010000000000000000/ffffffffffffffff0000000000000000)
+nx_pull_match() returned error OFPBMC_BAD_PREREQ
+
+# IPv6 destination
+OXM_OF_ETH_TYPE(86dd), OXM_OF_IPV6_DST(20010db83c4d00010002000300040005)
+nx_pull_match() returned error OFPBMC_BAD_PREREQ
+OXM_OF_ETH_TYPE(86dd), OXM_OF_IPV6_DST_W(20010db83c4d00010000000000000000/ffffffffffffffff0000000000000000)
+nx_pull_match() returned error OFPBMC_BAD_PREREQ
+
+# ND source hardware address
+OXM_OF_ETH_TYPE(86dd), OXM_OF_IP_PROTO(3a), OXM_OF_ICMPV6_TYPE(87), OXM_OF_IPV6_ND_TARGET(20010db83c4d00010002000300040005), OXM_OF_IPV6_ND_SLL(0002e30f80a4)
+nx_pull_match() returned error OFPBMC_BAD_PREREQ
+nx_pull_match() returned error OFPBMC_BAD_PREREQ
+nx_pull_match() returned error OFPBMC_BAD_PREREQ
+
+# ND destination hardware address
+OXM_OF_ETH_TYPE(86dd), OXM_OF_IP_PROTO(3a), OXM_OF_ICMPV6_TYPE(88), OXM_OF_IPV6_ND_TARGET(20010db83c4d00010002000300040005), OXM_OF_IPV6_ND_TLL(0002e30f80a4)
+nx_pull_match() returned error OFPBMC_BAD_PREREQ
+nx_pull_match() returned error OFPBMC_BAD_PREREQ
+nx_pull_match() returned error OFPBMC_BAD_PREREQ
+
+# Invalid field number.
+nx_pull_match() returned error OFPBMC_BAD_FIELD
+])
+AT_CLEANUP
+
+AT_SETUP([ovs-ofctl parse-oxm loose])
+AT_KEYWORDS([oxm])
+AT_DATA([oxm.txt], [dnl
+OXM_OF_IN_PORT(00000001), 01020304(1111/2222), OXM_OF_ETH_TYPE(0800)
+])
+
+AT_CHECK([ovs-ofctl --strict parse-oxm < oxm.txt], [0], [dnl
+nx_pull_match() returned error OFPBMC_BAD_FIELD
+])
+
+AT_CHECK([ovs-ofctl parse-oxm < oxm.txt], [0], [dnl
+OXM_OF_IN_PORT(00000001), OXM_OF_ETH_TYPE(0800)
+])
+AT_CLEANUP
+
dnl Check that "-F openflow10" rejects a flow_mod with a tun_id, since
dnl OpenFlow 1.0 doesn't support tunnels.
AT_SETUP([ovs-ofctl -F option and tun_id])
free(fms);
}
-/* "parse-nx-match": reads a series of nx_match specifications as strings from
- * stdin, does some internal fussing with them, and then prints them back as
- * strings on stdout. */
static void
-do_parse_nx_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
+do_parse_nxm__(bool oxm)
{
struct ds in;
/* Convert cls_rule back to nx_match. */
ofpbuf_uninit(&nx_match);
ofpbuf_init(&nx_match, 0);
- match_len = nx_put_match(&nx_match, &rule, cookie, cookie_mask);
+ match_len = nx_put_match(&nx_match, oxm, &rule,
+ cookie, cookie_mask);
/* Convert nx_match to string. */
out = nx_match_to_string(nx_match.data, match_len);
ds_destroy(&in);
}
+/* "parse-nxm": reads a series of NXM nx_match specifications as strings from
+ * stdin, does some internal fussing with them, and then prints them back as
+ * strings on stdout. */
+static void
+do_parse_nxm(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
+{
+ return do_parse_nxm__(false);
+}
+
+/* "parse-oxm": reads a series of OXM nx_match specifications as strings from
+ * stdin, does some internal fussing with them, and then prints them back as
+ * strings on stdout. */
+static void
+do_parse_oxm(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
+{
+ return do_parse_nxm__(true);
+}
+
/* "print-error ENUM": Prints the type and code of ENUM for every OpenFlow
* version. */
static void
/* Undocumented commands for testing. */
{ "parse-flow", 1, 1, do_parse_flow },
{ "parse-flows", 1, 1, do_parse_flows },
- { "parse-nx-match", 0, 0, do_parse_nx_match },
+ { "parse-nx-match", 0, 0, do_parse_nxm },
+ { "parse-nxm", 0, 0, do_parse_nxm },
+ { "parse-oxm", 0, 0, do_parse_oxm },
{ "print-error", 1, 1, do_print_error },
{ "ofp-print", 1, 2, do_ofp_print },