This code, which leverages the existing NXM implementation, adds parsing and serialisation of OXM matches. Test cases have also been provided.
This patch only implements parsing and serialisation of OXM fields that are already handled by NXM. It should be noted that in OXM ports are 32bit whereas in NXM they are 16 bit. This has been handled as a special case as all other field widths are the same in both OXM and NXM. This patch does not address differences in wildcarding between OXM and NXM. It is planned that liberal wildcarding policy dictated by either OXM or NXM will be implemented. This patch also does not address any (subtle?) differences between OXM and NXM treatment of specific fields. It is envisages that his can be handled by subsequent patches. Signed-off-by: Simon Horman <[email protected]> --- lib/learn.c | 2 +- lib/meta-flow.c | 57 ++++++---- lib/meta-flow.h | 6 +- lib/nx-match.c | 168 +++++++++++++++++------------ lib/nx-match.h | 10 +- lib/ofp-print.c | 3 +- lib/ofp-util.c | 32 +++--- lib/ofp-util.h | 6 ++ tests/ovs-ofctl.at | 279 +++++++++++++++++++++++++++++++++++++++++++++++++ utilities/ovs-ofctl.c | 38 +++++-- 10 files changed, 476 insertions(+), 125 deletions(-) diff --git a/lib/learn.c b/lib/learn.c index 7f30f6e..516000a 100644 --- a/lib/learn.c +++ b/lib/learn.c @@ -62,7 +62,7 @@ get_bits(int n_bits, const void **p) static void get_subfield(int n_bits, const void **p, struct mf_subfield *sf) { - sf->field = mf_from_nxm_header(ntohl(get_be32(p))); + sf->field = mf_from_nxm_header(ntohl(get_be32(p)), false); sf->ofs = ntohs(get_be16(p)); sf->n_bits = n_bits; } diff --git a/lib/meta-flow.c b/lib/meta-flow.c index 51db7b1..926cfb9 100644 --- a/lib/meta-flow.c +++ b/lib/meta-flow.c @@ -441,6 +441,7 @@ struct nxm_field { }; 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. */ @@ -476,26 +477,29 @@ mf_from_name(const char *name) } 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 void -nxm_init(void) +nxm_init(bool oxm) { const struct mf_field *mf; + struct hmap *all_fields = oxm ? &all_oxm_fields : &all_nxm_fields; for (mf = mf_fields; mf < &mf_fields[MFF_N_IDS]; mf++) { - if (mf->nxm_header) { - add_nxm_field(mf->nxm_header, mf); + uint32_t header = oxm ? mf->oxm_header : mf->nxm_header; + if (header) { + add_nxm_field(all_fields, header, mf); if (mf->maskable != MFM_NONE) { - add_nxm_field(NXM_MAKE_WILD_HEADER(mf->nxm_header), mf); + add_nxm_field(all_fields, NXM_MAKE_WILD_HEADER(header), mf); } } } @@ -503,11 +507,14 @@ nxm_init(void) #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); + uint32_t header = oxm ? mf->oxm_header : mf->nxm_header; + if (header) { + assert(mf_from_nxm_header(header, oxm) == mf); + /* Some OXM fields are not maskable while their NXM + * counterparts are, just skip this check for now */ + if (!oxm && mf->maskable != MFM_NONE) { + assert(mf_from_nxm_header(NXM_MAKE_WILD_HEADER(mf->nxm_header), + oxm) == mf); } } } @@ -515,16 +522,16 @@ nxm_init(void) } const struct mf_field * -mf_from_nxm_header(uint32_t header) +mf_from_nxm_header(uint32_t header, bool oxm) { const struct nxm_field *f; + struct hmap *all_fields = oxm ? &all_oxm_fields : &all_nxm_fields; - if (hmap_is_empty(&all_nxm_fields)) { - nxm_init(); + if (hmap_is_empty(all_fields)) { + nxm_init(oxm); } - 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; } @@ -1124,9 +1131,9 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow, /* Makes 'rule' match field 'mf' exactly, with the value matched taken from * 'value'. The caller is responsible for ensuring that 'rule' meets 'mf''s * prerequisites. */ -void +int mf_set_value(const struct mf_field *mf, - const union mf_value *value, struct cls_rule *rule) + const union mf_value *value, struct cls_rule *rule, bool oxm) { switch (mf->id) { case MFF_TUN_ID: @@ -1134,8 +1141,15 @@ mf_set_value(const struct mf_field *mf, break; case MFF_IN_PORT: + if (!oxm) { cls_rule_set_in_port(rule, ntohs(value->be16)); - break; + } else { + uint16_t port; + if (ofputil_port_from_ofp11(value->be32, &port)) + return OFPERR_OFPBRC_BAD_PORT; + cls_rule_set_in_port(rule, port); + } + break; #if FLOW_N_REGS > 0 case MFF_REG0: @@ -1289,6 +1303,7 @@ mf_set_value(const struct mf_field *mf, default: NOT_REACHED(); } + return 0; } /* Makes 'rule' match field 'mf' exactly, with the value matched taken from @@ -1656,7 +1671,7 @@ mf_set(const struct mf_field *mf, struct cls_rule *rule) { if (!mask || is_all_ones((const uint8_t *) mask, mf->n_bytes)) { - mf_set_value(mf, value, rule); + mf_set_value(mf, value, rule, false); return; } else if (is_all_zeros((const uint8_t *) mask, mf->n_bytes)) { mf_set_wild(mf, rule); @@ -2342,7 +2357,7 @@ mf_set_subfield(const struct mf_subfield *sf, uint64_t x, ((uint8_t *) &value)[i] = x; x >>= 8; } - mf_set_value(field, &value, rule); + mf_set_value(field, &value, rule, false); } else { union mf_value value, mask; uint8_t *vp = (uint8_t *) &value; diff --git a/lib/meta-flow.h b/lib/meta-flow.h index 6340b3e..5e1eed1 100644 --- a/lib/meta-flow.h +++ b/lib/meta-flow.h @@ -241,7 +241,7 @@ BUILD_ASSERT_DECL(sizeof(union mf_value) == sizeof (union mf_subvalue)); /* Finding mf_fields. */ const struct mf_field *mf_from_id(enum mf_field_id); const struct mf_field *mf_from_name(const char *name); -const struct mf_field *mf_from_nxm_header(uint32_t nxm_header); +const struct mf_field *mf_from_nxm_header(uint32_t nxm_header, bool oxm); const struct mf_field *mf_from_nxm_name(const char *nxm_name); /* Inspecting wildcarded bits. */ @@ -260,8 +260,8 @@ bool mf_is_value_valid(const struct mf_field *, const union mf_value *value); void mf_get_value(const struct mf_field *, const struct flow *, union mf_value *value); -void mf_set_value(const struct mf_field *, const union mf_value *value, - struct cls_rule *); +int mf_set_value(const struct mf_field *, const union mf_value *value, + struct cls_rule *, bool oxm); void mf_set_flow_value(const struct mf_field *, const union mf_value *value, struct flow *); diff --git a/lib/nx-match.c b/lib/nx-match.c index 91dd7fc..6907731 100644 --- a/lib/nx-match.c +++ b/lib/nx-match.c @@ -90,7 +90,7 @@ nx_entry_ok(const void *p, unsigned int match_len) static enum ofperr nx_pull_match__(struct ofpbuf *b, unsigned int match_len, bool strict, - uint16_t priority, struct cls_rule *rule, + bool oxm, uint16_t priority, struct cls_rule *rule, ovs_be64 *cookie, ovs_be64 *cookie_mask) { uint32_t header; @@ -116,7 +116,7 @@ nx_pull_match__(struct ofpbuf *b, unsigned int match_len, bool strict, const struct mf_field *mf; enum ofperr error; - mf = mf_from_nxm_header(header); + mf = mf_from_nxm_header(header, oxm); if (!mf) { if (strict) { error = OFPERR_OFPBMC_BAD_FIELD; @@ -131,12 +131,15 @@ nx_pull_match__(struct ofpbuf *b, unsigned int match_len, bool strict, unsigned int width = mf->n_bytes; union mf_value value; + /* Special case for 32bit ports when using OXM, + * ports are 16 bits wide otherwise */ + if (oxm && mf->id == MFF_IN_PORT) + width = sizeof(__be32); memcpy(&value, p + 4, width); if (!mf_is_value_valid(mf, &value)) { error = OFPERR_OFPBMC_BAD_VALUE; } else if (!NXM_HASMASK(header)) { - error = 0; - mf_set_value(mf, &value, rule); + error = mf_set_value(mf, &value, rule, oxm); } else { union mf_value mask; @@ -191,22 +194,22 @@ nx_pull_match__(struct ofpbuf *b, unsigned int match_len, bool strict, * * Returns 0 if successful, otherwise an OpenFlow error code. */ enum ofperr -nx_pull_match(struct ofpbuf *b, unsigned int match_len, +nx_pull_match(struct ofpbuf *b, unsigned int match_len, bool oxm, uint16_t priority, struct cls_rule *rule, ovs_be64 *cookie, ovs_be64 *cookie_mask) { - return nx_pull_match__(b, match_len, true, priority, rule, cookie, + return nx_pull_match__(b, match_len, true, oxm, priority, rule, cookie, cookie_mask); } /* Behaves the same as nx_pull_match() with one exception. Skips over unknown * NXM headers instead of failing with an error when they are encountered. */ enum ofperr -nx_pull_match_loose(struct ofpbuf *b, unsigned int match_len, +nx_pull_match_loose(struct ofpbuf *b, unsigned int match_len, bool oxm, uint16_t priority, struct cls_rule *rule, ovs_be64 *cookie, ovs_be64 *cookie_mask) { - return nx_pull_match__(b, match_len, false, priority, rule, cookie, + return nx_pull_match__(b, match_len, false, oxm, priority, rule, cookie, cookie_mask); } @@ -355,18 +358,19 @@ nxm_put_eth(struct ofpbuf *b, uint32_t header, static void nxm_put_eth_dst(struct ofpbuf *b, - flow_wildcards_t wc, const uint8_t value[ETH_ADDR_LEN]) + flow_wildcards_t wc, const uint8_t value[ETH_ADDR_LEN], + bool oxm) { switch (wc & (FWW_DL_DST | FWW_ETH_MCAST)) { case FWW_DL_DST | FWW_ETH_MCAST: break; default: - nxm_put_header(b, NXM_OF_ETH_DST_W); + nxm_put_header(b, oxm ? OXM_OF_ETH_DST_W : NXM_OF_ETH_DST_W); ofpbuf_put(b, value, ETH_ADDR_LEN); ofpbuf_put(b, flow_wildcards_to_dl_dst_mask(wc), ETH_ADDR_LEN); break; case 0: - nxm_put_eth(b, NXM_OF_ETH_DST, value); + nxm_put_eth(b, oxm ? OXM_OF_ETH_DST : NXM_OF_ETH_DST, value); break; } } @@ -410,7 +414,7 @@ nxm_put_frag(struct ofpbuf *b, const struct cls_rule *cr) 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; @@ -418,26 +422,32 @@ nxm_put_ip(struct ofpbuf *b, const struct cls_rule *cr, 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)); @@ -462,7 +472,7 @@ nxm_put_ip(struct ofpbuf *b, const struct cls_rule *cr, * 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; @@ -476,16 +486,19 @@ nx_put_match(struct ofpbuf *b, const struct cls_rule *cr, /* 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_dst(b, wc, flow->dl_dst); + nxm_put_eth_dst(b, wc, flow->dl_dst, oxm); if (!(wc & FWW_DL_SRC)) { - nxm_put_eth(b, NXM_OF_ETH_SRC, flow->dl_src); + nxm_put_eth(b, oxm ? OXM_OF_ETH_SRC : NXM_OF_ETH_SRC, flow->dl_src); } 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)); } @@ -495,62 +508,77 @@ nx_put_match(struct ofpbuf *b, const struct cls_rule *cr, /* 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); } } /* Tunnel ID. */ - nxm_put_64m(b, NXM_NX_TUN_ID, flow->tun_id, cr->wc.tun_id_mask); + if (!oxm) { + nxm_put_64m(b, NXM_NX_TUN_ID, flow->tun_id, cr->wc.tun_id_mask); - /* Registers. */ - for (i = 0; i < FLOW_N_REGS; i++) { - nxm_put_32m(b, NXM_NX_REG(i), - htonl(flow->regs[i]), htonl(cr->wc.reg_masks[i])); - } + /* Registers. */ + for (i = 0; i < FLOW_N_REGS; i++) { + nxm_put_32m(b, NXM_NX_REG(i), + htonl(flow->regs[i]), htonl(cr->wc.reg_masks[i])); + } - /* Cookie. */ - nxm_put_64m(b, NXM_NX_COOKIE, cookie, cookie_mask); + /* Cookie. */ + nxm_put_64m(b, NXM_NX_COOKIE, cookie, cookie_mask); + } match_len = b->size - start_len; ofpbuf_put_zeros(b, ROUND_UP(match_len, 8) - match_len); @@ -559,10 +587,10 @@ nx_put_match(struct ofpbuf *b, const struct cls_rule *cr, /* nx_match_to_string() and helpers. */ -static void format_nxm_field_name(struct ds *, uint32_t header); +static void format_nxm_field_name(struct ds *, uint32_t header, bool oxm); char * -nx_match_to_string(const uint8_t *p, unsigned int match_len) +nx_match_to_string(const uint8_t *p, unsigned int match_len, bool oxm) { uint32_t header; struct ds s; @@ -583,7 +611,7 @@ nx_match_to_string(const uint8_t *p, unsigned int match_len) ds_put_cstr(&s, ", "); } - format_nxm_field_name(&s, header); + format_nxm_field_name(&s, header, oxm); ds_put_char(&s, '('); for (i = 0; i < value_len; i++) { @@ -613,11 +641,11 @@ nx_match_to_string(const uint8_t *p, unsigned int match_len) } static void -format_nxm_field_name(struct ds *s, uint32_t header) +format_nxm_field_name(struct ds *s, uint32_t header, bool oxm) { - const struct mf_field *mf = mf_from_nxm_header(header); + const struct mf_field *mf = mf_from_nxm_header(header, oxm); if (mf) { - ds_put_cstr(s, mf->nxm_name); + ds_put_cstr(s, oxm ? mf->oxm_name : mf->nxm_name); if (NXM_HASMASK(header)) { ds_put_cstr(s, "_W"); } @@ -631,7 +659,7 @@ format_nxm_field_name(struct ds *s, uint32_t header) } static uint32_t -parse_nxm_field_name(const char *name, int name_len) +parse_nxm_field_name(const char *name, int name_len, bool oxm) { bool wild; int i; @@ -644,19 +672,21 @@ parse_nxm_field_name(const char *name, int name_len) for (i = 0; i < MFF_N_IDS; i++) { const struct mf_field *mf = mf_from_id(i); + const char *m_name = oxm ? mf->oxm_name : mf->nxm_name; - if (mf->nxm_name - && !strncmp(mf->nxm_name, name, name_len) - && mf->nxm_name[name_len] == '\0') { + if (m_name + && !strncmp(m_name, name, name_len) + && m_name[name_len] == '\0') { + uint32_t header = oxm ? mf->oxm_header : mf->nxm_header; if (!wild) { - return mf->nxm_header; + return header; } else if (mf->maskable != MFM_NONE) { - return NXM_MAKE_WILD_HEADER(mf->nxm_header); + return NXM_MAKE_WILD_HEADER(header); } } } - if (!strncmp("NXM_NX_COOKIE", name, name_len) + if (!oxm && !strncmp("NXM_NX_COOKIE", name, name_len) && (name_len == strlen("NXM_NX_COOKIE"))) { if (!wild) { return NXM_NX_COOKIE; @@ -680,7 +710,7 @@ parse_nxm_field_name(const char *name, int name_len) /* nx_match_from_string(). */ int -nx_match_from_string(const char *s, struct ofpbuf *b) +nx_match_from_string(const char *s, struct ofpbuf *b, bool oxm) { const char *full_s = s; const size_t start_len = b->size; @@ -704,7 +734,7 @@ nx_match_from_string(const char *s, struct ofpbuf *b) ovs_fatal(0, "%s: missing ( at end of nx_match", full_s); } - header = parse_nxm_field_name(name, name_len); + header = parse_nxm_field_name(name, name_len, oxm); if (!header) { ovs_fatal(0, "%s: unknown field `%.*s'", full_s, name_len, s); } @@ -913,7 +943,7 @@ nxm_execute_reg_load(const struct nx_action_reg_load *action, void nxm_decode(struct mf_subfield *sf, ovs_be32 header, ovs_be16 ofs_nbits) { - sf->field = mf_from_nxm_header(ntohl(header)); + sf->field = mf_from_nxm_header(ntohl(header), false); sf->ofs = nxm_decode_ofs(ofs_nbits); sf->n_bits = nxm_decode_n_bits(ofs_nbits); } @@ -934,7 +964,7 @@ void nxm_decode_discrete(struct mf_subfield *sf, ovs_be32 header, ovs_be16 ofs, ovs_be16 n_bits) { - sf->field = mf_from_nxm_header(ntohl(header)); + sf->field = mf_from_nxm_header(ntohl(header), false); sf->ofs = ntohs(ofs); sf->n_bits = ntohs(n_bits); } diff --git a/lib/nx-match.h b/lib/nx-match.h index 296a63a..3a76738 100644 --- a/lib/nx-match.h +++ b/lib/nx-match.h @@ -38,16 +38,16 @@ struct nx_action_reg_move; */ enum ofperr nx_pull_match(struct ofpbuf *, unsigned int match_len, - uint16_t priority, struct cls_rule *, + bool oxm, uint16_t priority, struct cls_rule *, ovs_be64 *cookie, ovs_be64 *cookie_mask); enum ofperr nx_pull_match_loose(struct ofpbuf *, unsigned int match_len, - uint16_t priority, struct cls_rule *, + bool oxm, 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); -int nx_match_from_string(const char *, struct ofpbuf *); +char *nx_match_to_string(const uint8_t *, unsigned int match_len, bool oxm); +int nx_match_from_string(const char *, struct ofpbuf *, bool oxm); void nxm_parse_reg_move(struct nx_action_reg_move *, const char *); void nxm_parse_reg_load(struct nx_action_reg_load *, const char *); diff --git a/lib/ofp-print.c b/lib/ofp-print.c index 23dadd9..2d90c9b 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -947,7 +947,8 @@ ofp_print_flow_mod(struct ds *s, const struct ofp_header *oh, const void *nxm = nfm + 1; char *nxm_s; - nxm_s = nx_match_to_string(nxm, ntohs(nfm->match_len)); + nxm_s = nx_match_to_string(nxm, ntohs(nfm->match_len), + ofputil_native_match_format_is_oxm(oh)); ds_put_cstr(s, nxm_s); free(nxm_s); diff --git a/lib/ofp-util.c b/lib/ofp-util.c index ae9b30d..778dc94 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -1409,8 +1409,10 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm, /* Dissect the message. */ nfm = ofpbuf_pull(&b, sizeof *nfm); - error = nx_pull_match(&b, ntohs(nfm->match_len), ntohs(nfm->priority), - &fm->cr, &fm->cookie, &fm->cookie_mask); + error = nx_pull_match(&b, ntohs(nfm->match_len), + ofputil_native_match_format_is_oxm(oh), + ntohs(nfm->priority), &fm->cr, &fm->cookie, + &fm->cookie_mask); if (error) { return error; } @@ -1496,10 +1498,10 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm, nfm->command = htons(command); if (command == OFPFC_ADD) { nfm->cookie = fm->cookie; - match_len = nx_put_match(msg, &fm->cr, 0, 0); + match_len = nx_put_match(msg, false, &fm->cr, 0, 0); } else { nfm->cookie = 0; - match_len = nx_put_match(msg, &fm->cr, + match_len = nx_put_match(msg, false, &fm->cr, fm->cookie, fm->cookie_mask); } nfm->idle_timeout = htons(fm->idle_timeout); @@ -1578,7 +1580,7 @@ ofputil_decode_nxst_flow_request(struct ofputil_flow_stats_request *fsr, ofpbuf_use_const(&b, oh, ntohs(oh->length)); nfsr = ofpbuf_pull(&b, sizeof *nfsr); - error = nx_pull_match(&b, ntohs(nfsr->match_len), 0, &fsr->match, + error = nx_pull_match(&b, ntohs(nfsr->match_len), false, 0, &fsr->match, &fsr->cookie, &fsr->cookie_mask); if (error) { return error; @@ -1659,7 +1661,7 @@ ofputil_encode_flow_stats_request(const struct ofputil_flow_stats_request *fsr, 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; @@ -1785,8 +1787,8 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs, "claims invalid length %zu", match_len, length); return EINVAL; } - if (nx_pull_match(msg, match_len, ntohs(nfs->priority), &fs->rule, - NULL, NULL)) { + if (nx_pull_match(msg, match_len, false, ntohs(nfs->priority), + &fs->rule, NULL, NULL)) { return EINVAL; } @@ -1886,7 +1888,7 @@ ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs, 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); @@ -1963,8 +1965,8 @@ ofputil_decode_flow_removed(struct ofputil_flow_removed *fr, ofpbuf_use_const(&b, oh, ntohs(oh->length)); nfr = ofpbuf_pull(&b, sizeof *nfr); - error = nx_pull_match(&b, ntohs(nfr->match_len), ntohs(nfr->priority), - &fr->rule, NULL, NULL); + error = nx_pull_match(&b, ntohs(nfr->match_len), false, + ntohs(nfr->priority), &fr->rule, NULL, NULL); if (error) { return error; } @@ -2020,7 +2022,7 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr, 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; @@ -2073,8 +2075,8 @@ ofputil_decode_packet_in(struct ofputil_packet_in *pin, ofpbuf_use_const(&b, oh, ntohs(oh->length)); npi = ofpbuf_pull(&b, sizeof *npi); - error = nx_pull_match_loose(&b, ntohs(npi->match_len), 0, &rule, NULL, - NULL); + error = nx_pull_match_loose(&b, ntohs(npi->match_len), false, + 0, &rule, NULL, NULL); if (error) { return error; } @@ -2155,7 +2157,7 @@ ofputil_encode_packet_in(const struct ofputil_packet_in *pin, 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); diff --git a/lib/ofp-util.h b/lib/ofp-util.h index fd76eac..71925f7 100644 --- a/lib/ofp-util.h +++ b/lib/ofp-util.h @@ -653,4 +653,10 @@ union ofp_action *ofputil_actions_clone(const union ofp_action *, size_t n); /* Handy utility for parsing flows and actions. */ bool ofputil_parse_key_value(char **stringp, char **keyp, char **valuep); +static inline bool +ofputil_native_match_format_is_oxm(const struct ofp_header *oh) +{ + return oh->version == OFP12_VERSION; +} + #endif /* ofp-util.h */ diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at index 37498a7..70d5fc3 100644 --- a/tests/ovs-ofctl.at +++ b/tests/ovs-ofctl.at @@ -627,6 +627,285 @@ NXM_OF_IN_PORT(0001), NXM_OF_ETH_TYPE(0800) ]) 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]) diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c index 2b91a28..3ee58b4 100644 --- a/utilities/ovs-ofctl.c +++ b/utilities/ovs-ofctl.c @@ -1769,11 +1769,8 @@ do_parse_flows(int argc OVS_UNUSED, char *argv[]) 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; @@ -1802,14 +1799,14 @@ do_parse_nx_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) /* Convert string to nx_match. */ ofpbuf_init(&nx_match, 0); - match_len = nx_match_from_string(ds_cstr(&in), &nx_match); + match_len = nx_match_from_string(ds_cstr(&in), &nx_match, oxm); /* Convert nx_match to cls_rule. */ if (strict) { - error = nx_pull_match(&nx_match, match_len, 0, &rule, + error = nx_pull_match(&nx_match, match_len, oxm, 0, &rule, &cookie, &cookie_mask); } else { - error = nx_pull_match_loose(&nx_match, match_len, 0, &rule, + error = nx_pull_match_loose(&nx_match, match_len, oxm, 0, &rule, &cookie, &cookie_mask); } @@ -1819,10 +1816,11 @@ do_parse_nx_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) /* 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); + out = nx_match_to_string(nx_match.data, match_len, oxm); puts(out); free(out); } else { @@ -1835,6 +1833,24 @@ do_parse_nx_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) 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 @@ -1907,7 +1923,9 @@ static const struct command all_commands[] = { /* 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 }, -- 1.7.9.5 _______________________________________________ dev mailing list [email protected] http://openvswitch.org/mailman/listinfo/dev
