From: Ben Pfaff Date: Sat, 9 Jun 2012 22:49:16 +0000 (-0700) Subject: ofp-util: Implement translation to and from OpenFlow 1.1 ofp_match. X-Git-Url: http://git.onelab.eu/?p=sliver-openvswitch.git;a=commitdiff_plain;h=410698cf7d0c9364a2ecb61b692e60da737bec78 ofp-util: Implement translation to and from OpenFlow 1.1 ofp_match. This is another step toward OpenFlow 1.1 support. The change does not affect any outwardly visible OpenFlow behavior yet. Reviewed-by: Simon Horman Signed-off-by: Ben Pfaff --- diff --git a/lib/ofp-util.c b/lib/ofp-util.c index 6fbde7b7c..4af7a1ff2 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -259,6 +259,267 @@ ofputil_cls_rule_to_ofp10_match(const struct cls_rule *rule, memset(match->pad2, '\0', sizeof match->pad2); } +/* Converts the ofp11_match in 'match' into a cls_rule in 'rule', with the + * given 'priority'. Returns 0 if successful, otherwise an OFPERR_* value. */ +enum ofperr +ofputil_cls_rule_from_ofp11_match(const struct ofp11_match *match, + unsigned int priority, + struct cls_rule *rule) +{ + uint16_t wc = ntohl(match->wildcards); + uint8_t dl_src_mask[ETH_ADDR_LEN]; + uint8_t dl_dst_mask[ETH_ADDR_LEN]; + bool ipv4, arp; + int i; + + cls_rule_init_catchall(rule, priority); + + if (!(wc & OFPFW11_IN_PORT)) { + uint16_t ofp_port; + enum ofperr error; + + error = ofputil_port_from_ofp11(match->in_port, &ofp_port); + if (error) { + return OFPERR_OFPBMC_BAD_VALUE; + } + cls_rule_set_in_port(rule, ofp_port); + } + + for (i = 0; i < ETH_ADDR_LEN; i++) { + dl_src_mask[i] = ~match->dl_src_mask[i]; + } + cls_rule_set_dl_src_masked(rule, match->dl_src, dl_src_mask); + + for (i = 0; i < ETH_ADDR_LEN; i++) { + dl_dst_mask[i] = ~match->dl_dst_mask[i]; + } + cls_rule_set_dl_dst_masked(rule, match->dl_dst, dl_dst_mask); + + if (!(wc & OFPFW11_DL_VLAN)) { + if (match->dl_vlan == htons(OFPVID11_NONE)) { + /* Match only packets without a VLAN tag. */ + rule->flow.vlan_tci = htons(0); + rule->wc.vlan_tci_mask = htons(UINT16_MAX); + } else { + if (match->dl_vlan == htons(OFPVID11_ANY)) { + /* Match any packet with a VLAN tag regardless of VID. */ + rule->flow.vlan_tci = htons(VLAN_CFI); + rule->wc.vlan_tci_mask = htons(VLAN_CFI); + } else if (ntohs(match->dl_vlan) < 4096) { + /* Match only packets with the specified VLAN VID. */ + rule->flow.vlan_tci = htons(VLAN_CFI) | match->dl_vlan; + rule->wc.vlan_tci_mask = htons(VLAN_CFI | VLAN_VID_MASK); + } else { + /* Invalid VID. */ + return OFPERR_OFPBMC_BAD_VALUE; + } + + if (!(wc & OFPFW11_DL_VLAN_PCP)) { + if (match->dl_vlan_pcp <= 7) { + rule->flow.vlan_tci |= htons(match->dl_vlan_pcp + << VLAN_PCP_SHIFT); + rule->wc.vlan_tci_mask |= htons(VLAN_PCP_MASK); + } else { + /* Invalid PCP. */ + return OFPERR_OFPBMC_BAD_VALUE; + } + } + } + } + + if (!(wc & OFPFW11_DL_TYPE)) { + cls_rule_set_dl_type(rule, + ofputil_dl_type_from_openflow(match->dl_type)); + } + + ipv4 = rule->flow.dl_type == htons(ETH_TYPE_IP); + arp = rule->flow.dl_type == htons(ETH_TYPE_ARP); + + if (ipv4 && !(wc & OFPFW11_NW_TOS)) { + if (match->nw_tos & ~IP_DSCP_MASK) { + /* Invalid TOS. */ + return OFPERR_OFPBMC_BAD_VALUE; + } + + cls_rule_set_nw_dscp(rule, match->nw_tos); + } + + if (ipv4 || arp) { + if (!(wc & OFPFW11_NW_PROTO)) { + cls_rule_set_nw_proto(rule, match->nw_proto); + } + + if (!ip_is_cidr(~match->nw_src_mask) || + !ip_is_cidr(~match->nw_dst_mask)) { + return OFPERR_OFPBMC_BAD_NW_ADDR_MASK; + } + cls_rule_set_nw_src_masked(rule, match->nw_src, ~match->nw_src_mask); + cls_rule_set_nw_dst_masked(rule, match->nw_dst, ~match->nw_dst_mask); + } + +#define OFPFW11_TP_ALL (OFPFW11_TP_SRC | OFPFW11_TP_DST) + if (ipv4 && (wc & OFPFW11_TP_ALL) != OFPFW11_TP_ALL) { + switch (rule->flow.nw_proto) { + case IPPROTO_ICMP: + /* "A.2.3 Flow Match Structures" in OF1.1 says: + * + * The tp_src and tp_dst fields will be ignored unless the + * network protocol specified is as TCP, UDP or SCTP. + * + * but I'm pretty sure we should support ICMP too, otherwise + * that's a regression from OF1.0. */ + if (!(wc & OFPFW11_TP_SRC)) { + uint16_t icmp_type = ntohs(match->tp_src); + if (icmp_type < 0x100) { + cls_rule_set_icmp_type(rule, icmp_type); + } else { + return OFPERR_OFPBMC_BAD_FIELD; + } + } + if (!(wc & OFPFW11_TP_DST)) { + uint16_t icmp_code = ntohs(match->tp_dst); + if (icmp_code < 0x100) { + cls_rule_set_icmp_code(rule, icmp_code); + } else { + return OFPERR_OFPBMC_BAD_FIELD; + } + } + break; + + case IPPROTO_TCP: + case IPPROTO_UDP: + if (!(wc & (OFPFW11_TP_SRC))) { + cls_rule_set_tp_src(rule, match->tp_src); + } + if (!(wc & (OFPFW11_TP_DST))) { + cls_rule_set_tp_dst(rule, match->tp_dst); + } + break; + + case IPPROTO_SCTP: + /* We don't support SCTP and it seems that we should tell the + * controller, since OF1.1 implementations are supposed to. */ + return OFPERR_OFPBMC_BAD_FIELD; + + default: + /* OF1.1 says explicitly to ignore this. */ + break; + } + } + + if (rule->flow.dl_type == htons(ETH_TYPE_MPLS) || + rule->flow.dl_type == htons(ETH_TYPE_MPLS_MCAST)) { + enum { OFPFW11_MPLS_ALL = OFPFW11_MPLS_LABEL | OFPFW11_MPLS_TC }; + + if ((wc & OFPFW11_MPLS_ALL) != OFPFW11_MPLS_ALL) { + /* MPLS not supported. */ + return OFPERR_OFPBMC_BAD_TAG; + } + } + + if (match->metadata_mask != htonll(UINT64_MAX)) { + /* Metadata field not yet supported because we haven't decided how to + * map it onto our existing fields (or whether to add a new field). */ + return OFPERR_OFPBMC_BAD_FIELD; + } + + return 0; +} + +/* Convert 'rule' into the OpenFlow 1.1 match structure 'match'. */ +void +ofputil_cls_rule_to_ofp11_match(const struct cls_rule *rule, + struct ofp11_match *match) +{ + uint32_t wc = 0; + int i; + + memset(match, 0, sizeof *match); + match->omh.type = htons(OFPMT_STANDARD); + match->omh.length = htons(OFPMT11_STANDARD_LENGTH); + + if (rule->wc.wildcards & FWW_IN_PORT) { + wc |= OFPFW11_IN_PORT; + } else { + match->in_port = ofputil_port_to_ofp11(rule->flow.in_port); + } + + + memcpy(match->dl_src, rule->flow.dl_src, ETH_ADDR_LEN); + for (i = 0; i < ETH_ADDR_LEN; i++) { + match->dl_src_mask[i] = ~rule->wc.dl_src_mask[i]; + } + + memcpy(match->dl_dst, rule->flow.dl_dst, ETH_ADDR_LEN); + for (i = 0; i < ETH_ADDR_LEN; i++) { + match->dl_dst_mask[i] = ~rule->wc.dl_dst_mask[i]; + } + + if (rule->wc.vlan_tci_mask == htons(0)) { + wc |= OFPFW11_DL_VLAN | OFPFW11_DL_VLAN_PCP; + } else if (rule->wc.vlan_tci_mask & htons(VLAN_CFI) + && !(rule->flow.vlan_tci & htons(VLAN_CFI))) { + match->dl_vlan = htons(OFPVID11_NONE); + wc |= OFPFW11_DL_VLAN_PCP; + } else { + if (!(rule->wc.vlan_tci_mask & htons(VLAN_VID_MASK))) { + match->dl_vlan = htons(OFPVID11_ANY); + } else { + match->dl_vlan = htons(vlan_tci_to_vid(rule->flow.vlan_tci)); + } + + if (!(rule->wc.vlan_tci_mask & htons(VLAN_PCP_MASK))) { + wc |= OFPFW11_DL_VLAN_PCP; + } else { + match->dl_vlan_pcp = vlan_tci_to_pcp(rule->flow.vlan_tci); + } + } + + if (rule->wc.wildcards & FWW_DL_TYPE) { + wc |= OFPFW11_DL_TYPE; + } else { + match->dl_type = ofputil_dl_type_to_openflow(rule->flow.dl_type); + } + + if (rule->wc.wildcards & FWW_NW_DSCP) { + wc |= OFPFW11_NW_TOS; + } else { + match->nw_tos = rule->flow.nw_tos & IP_DSCP_MASK; + } + + if (rule->wc.wildcards & FWW_NW_PROTO) { + wc |= OFPFW11_NW_PROTO; + } else { + match->nw_proto = rule->flow.nw_proto; + } + + match->nw_src = rule->flow.nw_src; + match->nw_src_mask = ~rule->wc.nw_src_mask; + match->nw_dst = rule->flow.nw_dst; + match->nw_dst_mask = ~rule->wc.nw_dst_mask; + + if (!rule->wc.tp_src_mask) { + wc |= OFPFW11_TP_SRC; + } else { + match->tp_src = rule->flow.tp_src; + } + + if (!rule->wc.tp_dst_mask) { + wc |= OFPFW11_TP_DST; + } else { + match->tp_dst = rule->flow.tp_dst; + } + + /* MPLS not supported. */ + wc |= OFPFW11_MPLS_LABEL; + wc |= OFPFW11_MPLS_TC; + + /* Metadata field not yet supported */ + match->metadata_mask = htonll(UINT64_MAX); + + match->wildcards = htonl(wc); +} + /* Given a 'dl_type' value in the format used in struct flow, returns the * corresponding 'dl_type' value for use in an ofp10_match or ofp11_match * structure. */ diff --git a/lib/ofp-util.h b/lib/ofp-util.h index 20b624689..9f4520cac 100644 --- a/lib/ofp-util.h +++ b/lib/ofp-util.h @@ -186,6 +186,13 @@ void ofputil_normalize_rule(struct cls_rule *); void ofputil_cls_rule_to_ofp10_match(const struct cls_rule *, struct ofp10_match *); +/* Work with ofp11_match. */ +enum ofperr ofputil_cls_rule_from_ofp11_match(const struct ofp11_match *, + unsigned int priority, + struct cls_rule *); +void ofputil_cls_rule_to_ofp11_match(const struct cls_rule *, + struct ofp11_match *); + /* dl_type translation between OpenFlow and 'struct flow' format. */ ovs_be16 ofputil_dl_type_to_openflow(ovs_be16 flow_dl_type); ovs_be16 ofputil_dl_type_from_openflow(ovs_be16 ofp_dl_type); diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at index 0a02c791f..740892cb8 100644 --- a/tests/ovs-ofctl.at +++ b/tests/ovs-ofctl.at @@ -618,6 +618,314 @@ nx_pull_match() returned error OFPBMC_BAD_FIELD ]) AT_CLEANUP +AT_SETUP([ovs-ofctl parse-ofp11-match]) +AT_KEYWORDS([OF1.1]) +AT_DATA([test-data], [dnl +# in_port=65534 +0000 0058 fffffffe 000003fe dnl +000000000000ffffffffffff 000000000000ffffffffffff dnl +0000 00 00 0000 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl +00000000 00 000000 0000000000000000ffffffffffffffff + +# bad ofp11_match: OFPBMC_BAD_VALUE +& ofp_util|WARN|port 305419896 is outside the supported range 0 through 65279 or 0xffffff00 through 0xffffffff +0000 0058 12345678 000003fe dnl +000000000000ffffffffffff 000000000000ffffffffffff dnl +0000 00 00 0000 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl +00000000 00 000000 0000000000000000ffffffffffffffff + +# dl_src=00:01:02:03:04:05 +0000 0058 00000000 000003ff dnl +000102030405000000000000 000000000000ffffffffffff dnl +0000 00 00 0000 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl +00000000 00 000000 0000000000000000ffffffffffffffff + +# dl_src=55:55:55:55:55:55/55:55:55:55:55:55 +0000 0058 00000000 000003ff dnl +555555555555aaaaaaaaaaaa 000000000000ffffffffffff dnl +0000 00 00 0000 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl +00000000 00 000000 0000000000000000ffffffffffffffff + +# dl_dst=00:01:02:03:04:05 +0000 0058 00000000 000003ff dnl +000000000000ffffffffffff 000102030405000000000000 dnl +0000 00 00 0000 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl +00000000 00 000000 0000000000000000ffffffffffffffff + +# dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 +0000 0058 00000000 000003ff dnl +000000000000ffffffffffff 010000000000feffffffffff dnl +0000 00 00 0000 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl +00000000 00 000000 0000000000000000ffffffffffffffff + +# dl_dst=00:01:02:03:04:05/fe:ff:ff:ff:ff:ff +0000 0058 00000000 000003ff dnl +000000000000ffffffffffff 000102030405010000000000 dnl +0000 00 00 0000 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl +00000000 00 000000 0000000000000000ffffffffffffffff + +# dl_dst=55:55:55:55:55:55/55:55:55:55:55:55 +0000 0058 00000000 000003ff dnl +000000000000ffffffffffff 555555555555aaaaaaaaaaaa dnl +0000 00 00 0000 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl +00000000 00 000000 0000000000000000ffffffffffffffff + +dnl dl_vlan_pcp is ignored if dl_vlan is wildcarded, which causes the +dnl the wildcard bit and the dl_vlan_pcp to be dropped for output: +# in_port=1 +# 11: fa -> fe +# 38: 03 -> 00 +0000 0058 00000001 000003fa dnl +000000000000ffffffffffff 000000000000ffffffffffff dnl +0000 03 00 0000 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl +00000000 00 000000 0000000000000000ffffffffffffffff + +# dl_vlan=291 +0000 0058 00000000 000003fd dnl +000000000000ffffffffffff 000000000000ffffffffffff dnl +0123 00 00 0000 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl +00000000 00 000000 0000000000000000ffffffffffffffff + +dnl OFPVID_NONE: +# vlan_tci=0x0000 +0000 0058 00000000 000003fd dnl +000000000000ffffffffffff 000000000000ffffffffffff dnl +ffff 00 00 0000 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl +00000000 00 000000 0000000000000000ffffffffffffffff + +dnl OFPVID_NONE ignores dl_vlan_pcp even if not wildcarded, which causes +dnl the wildcard bit and the dl_vlan_pcp to be dropped for output: +# vlan_tci=0x0000 +# 11: f9 -> fd +# 38: 05 -> 00 +0000 0058 00000000 000003f9 dnl +000000000000ffffffffffff 000000000000ffffffffffff dnl +ffff 05 00 0000 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl +00000000 00 000000 0000000000000000ffffffffffffffff + +# vlan_tci=0x1000/0x1000 +0000 0058 00000000 000003fd dnl +000000000000ffffffffffff 000000000000ffffffffffff dnl +fffe 00 00 0000 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl +00000000 00 000000 0000000000000000ffffffffffffffff + +dnl Try invalid VID: +# bad ofp11_match: OFPBMC_BAD_VALUE +0000 0058 00000000 000003fd dnl +000000000000ffffffffffff 000000000000ffffffffffff dnl +1234 00 00 0000 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl +00000000 00 000000 0000000000000000ffffffffffffffff + +# dl_vlan_pcp=4 +0000 0058 00000000 000003f9 dnl +000000000000ffffffffffff 000000000000ffffffffffff dnl +fffe 04 00 0000 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl +00000000 00 000000 0000000000000000ffffffffffffffff + +# dl_vlan=10,dl_vlan_pcp=6 +0000 0058 00000000 000003f9 dnl +000000000000ffffffffffff 000000000000ffffffffffff dnl +000a 06 00 0000 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl +00000000 00 000000 0000000000000000ffffffffffffffff + +# dl_type=0x1234 +0000 0058 00000000 000003f7 dnl +000000000000ffffffffffff 000000000000ffffffffffff dnl +0000 00 00 1234 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl +00000000 00 000000 0000000000000000ffffffffffffffff + +# ip,nw_tos=252 +0000 0058 00000000 000003e7 dnl +000000000000ffffffffffff 000000000000ffffffffffff dnl +0000 00 00 0800 fc 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl +00000000 00 000000 0000000000000000ffffffffffffffff + +dnl Try invalid TOS: +# bad ofp11_match: OFPBMC_BAD_VALUE +0000 0058 00000000 000003e7 dnl +000000000000ffffffffffff 000000000000ffffffffffff dnl +0000 00 00 0800 01 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl +00000000 00 000000 0000000000000000ffffffffffffffff + +# ip,nw_proto=5 +0000 0058 00000000 000003d7 dnl +000000000000ffffffffffff 000000000000ffffffffffff dnl +0000 00 00 0800 00 05 00000000ffffffff 00000000ffffffff 0000 0000 dnl +00000000 00 000000 0000000000000000ffffffffffffffff + +# arp,arp_op=2 +0000 0058 00000000 000003d7 dnl +000000000000ffffffffffff 000000000000ffffffffffff dnl +0000 00 00 0806 00 02 00000000ffffffff 00000000ffffffff 0000 0000 dnl +00000000 00 000000 0000000000000000ffffffffffffffff + +# ip,nw_src=192.168.128.0/24 +0000 0058 00000000 000003f7 dnl +000000000000ffffffffffff 000000000000ffffffffffff dnl +0000 00 00 0800 00 00 c0a88000000000ff 00000000ffffffff 0000 0000 dnl +00000000 00 000000 0000000000000000ffffffffffffffff + +dnl Try non-CIDR nw_src_mask: +# bad ofp11_match: OFPBMC_BAD_NW_ADDR_MASK +0000 0058 00000000 000003f7 dnl +000000000000ffffffffffff 000000000000ffffffffffff dnl +0000 00 00 0800 00 00 c0a880005a5a5a5a 00000000ffffffff 0000 0000 dnl +00000000 00 000000 0000000000000000ffffffffffffffff + +# ip,nw_dst=192.168.128.0/24 +0000 0058 00000000 000003f7 dnl +000000000000ffffffffffff 000000000000ffffffffffff dnl +0000 00 00 0800 00 00 00000000ffffffff c0a88000000000ff 0000 0000 dnl +00000000 00 000000 0000000000000000ffffffffffffffff + +dnl Try non-CIDR nw_dst_mask: +# bad ofp11_match: OFPBMC_BAD_NW_ADDR_MASK +0000 0058 00000000 000003f7 dnl +000000000000ffffffffffff 000000000000ffffffffffff dnl +0000 00 00 0800 00 00 00000000ffffffff c0a880005a5a5a5a 0000 0000 dnl +00000000 00 000000 0000000000000000ffffffffffffffff + +# arp,nw_src=192.168.128.0/24 +0000 0058 00000000 000003f7 dnl +000000000000ffffffffffff 000000000000ffffffffffff dnl +0000 00 00 0806 00 00 c0a88000000000ff 00000000ffffffff 0000 0000 dnl +00000000 00 000000 0000000000000000ffffffffffffffff + +# arp,nw_dst=192.168.128.0/24 +0000 0058 00000000 000003f7 dnl +000000000000ffffffffffff 000000000000ffffffffffff dnl +0000 00 00 0806 00 00 00000000ffffffff c0a88000000000ff 0000 0000 dnl +00000000 00 000000 0000000000000000ffffffffffffffff + +# tcp,tp_src=443 +0000 0058 00000000 00000397 dnl +000000000000ffffffffffff 000000000000ffffffffffff dnl +0000 00 00 0800 00 06 00000000ffffffff 00000000ffffffff 01bb 0000 dnl +00000000 00 000000 0000000000000000ffffffffffffffff + +# tcp,tp_dst=443 +0000 0058 00000000 00000357 dnl +000000000000ffffffffffff 000000000000ffffffffffff dnl +0000 00 00 0800 00 06 00000000ffffffff 00000000ffffffff 0000 01bb dnl +00000000 00 000000 0000000000000000ffffffffffffffff + +# udp,tp_src=443 +0000 0058 00000000 00000397 dnl +000000000000ffffffffffff 000000000000ffffffffffff dnl +0000 00 00 0800 00 11 00000000ffffffff 00000000ffffffff 01bb 0000 dnl +00000000 00 000000 0000000000000000ffffffffffffffff + +# icmp,icmp_type=5 +0000 0058 00000000 00000397 dnl +000000000000ffffffffffff 000000000000ffffffffffff dnl +0000 00 00 0800 00 01 00000000ffffffff 00000000ffffffff 0005 0000 dnl +00000000 00 000000 0000000000000000ffffffffffffffff + +# icmp,icmp_code=8 +0000 0058 00000000 00000357 dnl +000000000000ffffffffffff 000000000000ffffffffffff dnl +0000 00 00 0800 00 01 00000000ffffffff 00000000ffffffff 0000 0008 dnl +00000000 00 000000 0000000000000000ffffffffffffffff + +# udp,tp_src=443 +0000 0058 00000000 00000397 dnl +000000000000ffffffffffff 000000000000ffffffffffff dnl +0000 00 00 0800 00 11 00000000ffffffff 00000000ffffffff 01bb 0000 dnl +00000000 00 000000 0000000000000000ffffffffffffffff + +# udp,tp_dst=443 +0000 0058 00000000 00000357 dnl +000000000000ffffffffffff 000000000000ffffffffffff dnl +0000 00 00 0800 00 11 00000000ffffffff 00000000ffffffff 0000 01bb dnl +00000000 00 000000 0000000000000000ffffffffffffffff + +dnl SCTP, no ports. +# ip,nw_proto=132 +0000 0058 00000000 000003d7 dnl +000000000000ffffffffffff 000000000000ffffffffffff dnl +0000 00 00 0800 00 84 00000000ffffffff 00000000ffffffff 0000 0000 dnl +00000000 00 000000 0000000000000000ffffffffffffffff + +dnl SCTP tp_src matching not supported: +# bad ofp11_match: OFPBMC_BAD_FIELD +0000 0058 00000000 00000397 dnl +000000000000ffffffffffff 000000000000ffffffffffff dnl +0000 00 00 0800 00 84 00000000ffffffff 00000000ffffffff 01bb 0000 dnl +00000000 00 000000 0000000000000000ffffffffffffffff + +dnl SCTP tp_dst matching not supported: +# bad ofp11_match: OFPBMC_BAD_FIELD +0000 0058 00000000 00000357 dnl +000000000000ffffffffffff 000000000000ffffffffffff dnl +0000 00 00 0800 00 84 00000000ffffffff 00000000ffffffff 0000 01bb dnl +00000000 00 000000 0000000000000000ffffffffffffffff + +dnl Ignore tp_src if not TCP or UDP or SCTP: +# ip,nw_proto=21 +# 11: 97 -> d7 +# 60: 01 -> 00 +# 61: bb -> 00 +0000 0058 00000000 00000397 dnl +000000000000ffffffffffff 000000000000ffffffffffff dnl +0000 00 00 0800 00 15 00000000ffffffff 00000000ffffffff 01bb 0000 dnl +00000000 00 000000 0000000000000000ffffffffffffffff + +dnl Ignore tp_dst if not TCP or UDP or SCTP: +# ip,nw_proto=22 +# 11: 57 -> d7 +# 62: 01 -> 00 +# 63: bb -> 00 +0000 0058 00000000 00000357 dnl +000000000000ffffffffffff 000000000000ffffffffffff dnl +0000 00 00 0800 00 16 00000000ffffffff 00000000ffffffff 0000 01bb dnl +00000000 00 000000 0000000000000000ffffffffffffffff + +dnl mpls_label not yet supported: +# bad ofp11_match: OFPBMC_BAD_TAG +0000 0058 00000000 000002f7 dnl +000000000000ffffffffffff 000000000000ffffffffffff dnl +0000 00 00 8847 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl +12345678 00 000000 0000000000000000ffffffffffffffff + +dnl mpls_tc not yet supported: +# bad ofp11_match: OFPBMC_BAD_TAG +0000 0058 00000000 000001f7 dnl +000000000000ffffffffffff 000000000000ffffffffffff dnl +0000 00 00 8848 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl +00000000 5a 000000 0000000000000000ffffffffffffffff + +dnl mpls_label and mpls_tc must be ignored if dl_type is not MPLS: +# dl_type=0x1234 +# 10: 00 -> 03 +# 64: 12 -> 00 +# 65: 34 -> 00 +# 66: 56 -> 00 +# 67: 78 -> 00 +# 68: 5a -> 00 +0000 0058 00000000 000000f7 dnl +000000000000ffffffffffff 000000000000ffffffffffff dnl +0000 00 00 1234 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl +12345678 5a 000000 0000000000000000ffffffffffffffff + +dnl metadata match not yet supported: +# bad ofp11_match: OFPBMC_BAD_FIELD +0000 0058 00000000 000003ff dnl +000000000000ffffffffffff 000000000000ffffffffffff dnl +0000 00 00 0000 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl +00000000 00 000000 0000000000000001fffffffffffffffe + +]) +sed '/^[[#&]]/d' < test-data > input.txt +sed -n 's/^# //p; /^$/p' < test-data > expout +sed -n 's/^& //p' < test-data > experr +AT_CAPTURE_FILE([input.txt]) +AT_CAPTURE_FILE([expout]) +AT_CAPTURE_FILE([experr]) +AT_CHECK( + [ovs-ofctl '-vPATTERN:console:%c|%p|%m' parse-ofp11-match < input.txt], + [0], [expout], [experr]) +AT_CLEANUP + AT_SETUP([ovs-ofctl parse-nx-match loose]) AT_KEYWORDS([nx-match]) AT_DATA([nx-match.txt], [dnl @@ -967,3 +1275,4 @@ ofp_util|INFO|post: @&t@ ]) OVS_VSWITCHD_STOP AT_CLEANUP + diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c index 8f021929b..741345554 100644 --- a/utilities/ovs-ofctl.c +++ b/utilities/ovs-ofctl.c @@ -1986,6 +1986,63 @@ do_parse_oxm(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) return do_parse_nxm__(true); } +/* "parse-ofp11-match": reads a series of ofp11_match specifications as hex + * bytes from stdin, converts them to cls_rules, prints them as strings on + * stdout, and then converts them back to hex bytes and prints any differences + * from the input. */ +static void +do_parse_ofp11_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) +{ + struct ds in; + + ds_init(&in); + while (!ds_get_preprocessed_line(&in, stdin)) { + struct ofpbuf match_in; + struct ofp11_match match_out; + struct cls_rule rule; + enum ofperr error; + int i; + + /* Parse hex bytes. */ + ofpbuf_init(&match_in, 0); + if (ofpbuf_put_hex(&match_in, ds_cstr(&in), NULL)[0] != '\0') { + ovs_fatal(0, "Trailing garbage in hex data"); + } + if (match_in.size != sizeof(struct ofp11_match)) { + ovs_fatal(0, "Input is %zu bytes, expected %zu", + match_in.size, sizeof(struct ofp11_match)); + } + + /* Convert to cls_rule. */ + error = ofputil_cls_rule_from_ofp11_match(match_in.data, + OFP_DEFAULT_PRIORITY, &rule); + if (error) { + printf("bad ofp11_match: %s\n\n", ofperr_get_name(error)); + ofpbuf_uninit(&match_in); + continue; + } + + /* Print cls_rule. */ + cls_rule_print(&rule); + + /* Convert back to ofp11_match and print differences from input. */ + ofputil_cls_rule_to_ofp11_match(&rule, &match_out); + + for (i = 0; i < sizeof match_out; i++) { + uint8_t in = ((const uint8_t *) match_in.data)[i]; + uint8_t out = ((const uint8_t *) &match_out)[i]; + + if (in != out) { + printf("%2d: %02"PRIx8" -> %02"PRIx8"\n", i, in, out); + } + } + putchar('\n'); + + ofpbuf_uninit(&match_in); + } + ds_destroy(&in); +} + /* "print-error ENUM": Prints the type and code of ENUM for every OpenFlow * version. */ static void @@ -2062,6 +2119,7 @@ static const struct command all_commands[] = { { "parse-nx-match", 0, 0, do_parse_nxm }, { "parse-nxm", 0, 0, do_parse_nxm }, { "parse-oxm", 0, 0, do_parse_oxm }, + { "parse-ofp11-match", 0, 0, do_parse_ofp11_match }, { "print-error", 1, 1, do_print_error }, { "ofp-print", 1, 2, do_ofp_print },