From: Jan Scheurich <jan.scheur...@ericsson.com> Allow packet type namespace OFPHTN_ETHERTYPE as alternative pre-requisite for matching L3 protocols (MPLS, IP, IPv6, ARP etc).
Change the meta-flow definition of packet_type field to use the new custom format MFS_PACKET_TYPE representing "(NS,NS_TYPE)". Parsing routine for MFS_PACKET_TYPE added to meta-flow.c. Formatting routine for field packet_type extracted from match_format() and moved to flow.c to be used from meta-flow.c for formatting MFS_PACKET_TYPE. Updated the ovs-fields man page source meta-flow.xml with documentation for packet-type-aware bridges and added documentation for field packet_type. Added packet_type to the matching properties in tests/ofproto.at. Should be removed later, when packet_type_aware bridge attribute will be introduced. Signed-off-by: Jan Scheurich <jan.scheur...@ericsson.com> --- build-aux/extract-ofp-fields | 3 +- include/openvswitch/meta-flow.h | 20 ++++++++ lib/flow.c | 18 +++++++ lib/flow.h | 28 ++++++++--- lib/match.c | 52 +++++++++----------- lib/meta-flow.c | 85 +++++++++++++++++++++++++++++--- lib/meta-flow.xml | 106 +++++++++++++++++++++++++++++++--------- lib/nx-match.c | 16 ++++-- lib/odp-util.c | 48 ++++++++++++++++-- lib/ofp-parse.c | 6 +++ lib/ofp-util.c | 42 +++++++++++----- tests/dpif-netdev.at | 14 +++--- tests/odp.at | 1 + tests/ofproto-dpif.at | 20 ++++---- tests/ofproto.at | 1 + tests/pmd.at | 2 +- tests/tunnel-push-pop-ipv6.at | 2 +- tests/tunnel-push-pop.at | 2 +- 18 files changed, 361 insertions(+), 105 deletions(-) diff --git a/build-aux/extract-ofp-fields b/build-aux/extract-ofp-fields index d5b8a82..24dd756 100755 --- a/build-aux/extract-ofp-fields +++ b/build-aux/extract-ofp-fields @@ -36,7 +36,8 @@ FORMATTING = {"decimal": ("MFS_DECIMAL", 1, 8), "OpenFlow 1.1+ port": ("MFS_OFP_PORT_OXM", 4, 4), "frag": ("MFS_FRAG", 1, 1), "tunnel flags": ("MFS_TNL_FLAGS", 2, 2), - "TCP flags": ("MFS_TCP_FLAGS", 2, 2)} + "TCP flags": ("MFS_TCP_FLAGS", 2, 2), + "packet type": ("MFS_PACKET_TYPE", 4, 4)} PREREQS = {"none": "MFP_NONE", "Ethernet": "MFP_ETHERNET", diff --git a/include/openvswitch/meta-flow.h b/include/openvswitch/meta-flow.h index c284ec6..c6b95df 100644 --- a/include/openvswitch/meta-flow.h +++ b/include/openvswitch/meta-flow.h @@ -132,6 +132,11 @@ struct ofputil_tlv_table_mod; * * TCP flags: See the description of tcp_flags in ovs-ofctl(8). * + * packet type: A pair of packet type namespace NS and NS_TYPE within + * that namespace "(NS,NS_TYPE)". NS and NS_TYPE are formatted in + * decimal or hexadecimal as and accept decimal and hexadecimal (with + * 0x prefix) at parsing. + * * Prerequisites: * * The field's prerequisites. The values should be straightfoward. @@ -247,6 +252,20 @@ enum OVS_PACKED_ENUM mf_field_id { */ MFF_RECIRC_ID, + /* "packet_type". + * + * Define the packet type in OpenFlow 1.3+. + * + * Type: be32. + * Maskable: no. + * Formatting: packet type. + * Prerequisites: none. + * Access: read-only. + * NXM: none. + * OXM: OXM_OF_PACKET_TYPE(44) since OF1.3 and v2.8. + */ + MFF_PACKET_TYPE, + /* "conj_id". * * ID for "conjunction" actions. Please refer to ovs-ofctl(8) @@ -1859,6 +1878,7 @@ enum OVS_PACKED_ENUM mf_string { MFS_FRAG, /* no, yes, first, later, not_later */ MFS_TNL_FLAGS, /* FLOW_TNL_F_* flags */ MFS_TCP_FLAGS, /* TCP_* flags */ + MFS_PACKET_TYPE, /* "(NS,NS_TYPE)" */ }; struct mf_field { diff --git a/lib/flow.c b/lib/flow.c index 7f98a46..4f7a041 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -1149,6 +1149,24 @@ format_flags_masked(struct ds *ds, const char *name, } } +void +format_packet_type_masked(struct ds *s, const ovs_be32 value, const ovs_be32 mask) +{ + if (pt_ns_type_be(mask) == 0) { + ds_put_format(s, "packet_type=(%u,*),", + pt_ns(value)); + } else if (pt_ns_type_be(mask) == OVS_BE16_MAX) { + ds_put_format(s, "packet_type=(%u,0x%"PRIx16"),", + pt_ns(value), + pt_ns_type(value)); + } else{ + ds_put_format(s, "packet_type=(%u,0x%"PRIx16"/0x%"PRIx16"),", + pt_ns(value), + pt_ns_type(value), + pt_ns_type(mask)); + } +} + /* Scans a string 's' of flags to determine their numerical value and * returns the number of characters parsed using 'bit_to_string' to * lookup flag names. Scanning continues until the character 'end' is diff --git a/lib/flow.h b/lib/flow.h index 94c8a0c..92a7c63 100644 --- a/lib/flow.h +++ b/lib/flow.h @@ -82,6 +82,8 @@ void format_flags(struct ds *ds, const char *(*bit_to_string)(uint32_t), void format_flags_masked(struct ds *ds, const char *name, const char *(*bit_to_string)(uint32_t), uint32_t flags, uint32_t mask, uint32_t max_mask); +void format_packet_type_masked(struct ds *s, const ovs_be32 value, + const ovs_be32 mask); int parse_flags(const char *s, const char *(*bit_to_string)(uint32_t), char end, const char *field_name, char **res_string, uint32_t *res_flags, uint32_t allowed, uint32_t *res_mask); @@ -962,9 +964,23 @@ static inline bool is_ethernet(const struct flow *flow, return flow->packet_type == htonl(PT_ETH); } +static inline ovs_be16 get_dl_type(const struct flow *flow) +{ + if (flow->packet_type == htonl(PT_ETH)) { + return flow->dl_type; + } else if (pt_ns(flow->packet_type) == OFPHTN_ETHERTYPE) { + return pt_ns_type_be(flow->packet_type); + } else { + return htons(FLOW_DL_TYPE_NONE); + } +} + static inline bool is_vlan(const struct flow *flow, struct flow_wildcards *wc) { + if (!is_ethernet(flow, wc)) { + return false; + } if (wc) { WC_MASK_FIELD_MASK(wc, vlans[0].tci, htons(VLAN_CFI)); } @@ -973,7 +989,7 @@ static inline bool is_vlan(const struct flow *flow, static inline bool is_ip_any(const struct flow *flow) { - return dl_type_is_ip_any(flow->dl_type); + return dl_type_is_ip_any(get_dl_type(flow)); } static inline bool is_ip_proto(const struct flow *flow, uint8_t ip_proto, @@ -1009,7 +1025,7 @@ static inline bool is_sctp(const struct flow *flow, static inline bool is_icmpv4(const struct flow *flow, struct flow_wildcards *wc) { - if (flow->dl_type == htons(ETH_TYPE_IP)) { + if (get_dl_type(flow) == htons(ETH_TYPE_IP)) { if (wc) { memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto); } @@ -1021,7 +1037,7 @@ static inline bool is_icmpv4(const struct flow *flow, static inline bool is_icmpv6(const struct flow *flow, struct flow_wildcards *wc) { - if (flow->dl_type == htons(ETH_TYPE_IPV6)) { + if (get_dl_type(flow) == htons(ETH_TYPE_IPV6)) { if (wc) { memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto); } @@ -1052,7 +1068,7 @@ static inline bool is_nd(const struct flow *flow, static inline bool is_igmp(const struct flow *flow, struct flow_wildcards *wc) { - if (flow->dl_type == htons(ETH_TYPE_IP)) { + if (get_dl_type(flow) == htons(ETH_TYPE_IP)) { if (wc) { memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto); } @@ -1096,8 +1112,8 @@ static inline bool is_mld_report(const struct flow *flow, static inline bool is_stp(const struct flow *flow) { - return (eth_addr_equals(flow->dl_dst, eth_addr_stp) - && flow->dl_type == htons(FLOW_DL_TYPE_NONE)); + return (flow->dl_type == htons(FLOW_DL_TYPE_NONE) + && eth_addr_equals(flow->dl_dst, eth_addr_stp)); } #endif /* flow.h */ diff --git a/lib/match.c b/lib/match.c index 4855c74..ad9927f 100644 --- a/lib/match.c +++ b/lib/match.c @@ -1171,8 +1171,8 @@ match_format(const struct match *match, struct ds *s, int priority) size_t start_len = s->length; const struct flow *f = &match->flow; bool skip_type = false; - bool skip_proto = false; + ovs_be16 dl_type = f->dl_type; int i; @@ -1254,24 +1254,16 @@ match_format(const struct match *match, struct ds *s, int priority) } if (wc->masks.packet_type) { - if (pt_ns_type_be(wc->masks.packet_type) == 0) { - ds_put_format(s, "packet_type=(%u,*),", - pt_ns(f->packet_type)); - } else if (pt_ns_type_be(wc->masks.packet_type) == OVS_BE16_MAX) { - ds_put_format(s, "packet_type=(%u,0x%"PRIx16"),", - pt_ns(f->packet_type), - pt_ns_type(f->packet_type)); - } else{ - ds_put_format(s, "packet_type=(%u,0x%"PRIx16"/0x%"PRIx16"),", - pt_ns(f->packet_type), - pt_ns_type(f->packet_type), - pt_ns_type(wc->masks.packet_type)); + format_packet_type_masked(s, f->packet_type, wc->masks.packet_type); + if (pt_ns(f->packet_type) == OFPHTN_ETHERTYPE) { + dl_type = pt_ns_type_be(f->packet_type); } } if (wc->masks.dl_type) { + dl_type = f->dl_type; skip_type = true; - if (f->dl_type == htons(ETH_TYPE_IP)) { + if (dl_type == htons(ETH_TYPE_IP)) { if (wc->masks.nw_proto) { skip_proto = true; if (f->nw_proto == IPPROTO_ICMP) { @@ -1291,7 +1283,7 @@ match_format(const struct match *match, struct ds *s, int priority) } else { ds_put_format(s, "%sip%s,", colors.value, colors.end); } - } else if (f->dl_type == htons(ETH_TYPE_IPV6)) { + } else if (dl_type == htons(ETH_TYPE_IPV6)) { if (wc->masks.nw_proto) { skip_proto = true; if (f->nw_proto == IPPROTO_ICMPV6) { @@ -1309,13 +1301,13 @@ match_format(const struct match *match, struct ds *s, int priority) } else { ds_put_format(s, "%sipv6%s,", colors.value, colors.end); } - } else if (f->dl_type == htons(ETH_TYPE_ARP)) { + } else if (dl_type == htons(ETH_TYPE_ARP)) { ds_put_format(s, "%sarp%s,", colors.value, colors.end); - } else if (f->dl_type == htons(ETH_TYPE_RARP)) { + } else if (dl_type == htons(ETH_TYPE_RARP)) { ds_put_format(s, "%srarp%s,", colors.value, colors.end); - } else if (f->dl_type == htons(ETH_TYPE_MPLS)) { + } else if (dl_type == htons(ETH_TYPE_MPLS)) { ds_put_format(s, "%smpls%s,", colors.value, colors.end); - } else if (f->dl_type == htons(ETH_TYPE_MPLS_MCAST)) { + } else if (dl_type == htons(ETH_TYPE_MPLS_MCAST)) { ds_put_format(s, "%smplsm%s,", colors.value, colors.end); } else { skip_type = false; @@ -1387,9 +1379,9 @@ match_format(const struct match *match, struct ds *s, int priority) if (!skip_type && wc->masks.dl_type) { ds_put_format(s, "%sdl_type=%s0x%04"PRIx16",", - colors.param, colors.end, ntohs(f->dl_type)); + colors.param, colors.end, ntohs(dl_type)); } - if (f->dl_type == htons(ETH_TYPE_IPV6)) { + if (dl_type == htons(ETH_TYPE_IPV6)) { format_ipv6_netmask(s, "ipv6_src", &f->ipv6_src, &wc->masks.ipv6_src); format_ipv6_netmask(s, "ipv6_dst", &f->ipv6_dst, &wc->masks.ipv6_dst); if (wc->masks.ipv6_label) { @@ -1403,8 +1395,8 @@ match_format(const struct match *match, struct ds *s, int priority) ntohl(wc->masks.ipv6_label)); } } - } else if (f->dl_type == htons(ETH_TYPE_ARP) || - f->dl_type == htons(ETH_TYPE_RARP)) { + } else if (dl_type == htons(ETH_TYPE_ARP) || + dl_type == htons(ETH_TYPE_RARP)) { format_ip_netmask(s, "arp_spa", f->nw_src, wc->masks.nw_src); format_ip_netmask(s, "arp_tpa", f->nw_dst, wc->masks.nw_dst); } else { @@ -1412,8 +1404,8 @@ match_format(const struct match *match, struct ds *s, int priority) format_ip_netmask(s, "nw_dst", f->nw_dst, wc->masks.nw_dst); } if (!skip_proto && wc->masks.nw_proto) { - if (f->dl_type == htons(ETH_TYPE_ARP) || - f->dl_type == htons(ETH_TYPE_RARP)) { + if (dl_type == htons(ETH_TYPE_ARP) || + dl_type == htons(ETH_TYPE_RARP)) { ds_put_format(s, "%sarp_op=%s%"PRIu8",", colors.param, colors.end, f->nw_proto); } else { @@ -1421,8 +1413,8 @@ match_format(const struct match *match, struct ds *s, int priority) colors.param, colors.end, f->nw_proto); } } - if (f->dl_type == htons(ETH_TYPE_ARP) || - f->dl_type == htons(ETH_TYPE_RARP)) { + if (dl_type == htons(ETH_TYPE_ARP) || + dl_type == htons(ETH_TYPE_RARP)) { format_eth_masked(s, "arp_sha", f->arp_sha, wc->masks.arp_sha); format_eth_masked(s, "arp_tha", f->arp_tha, wc->masks.arp_tha); } @@ -1475,15 +1467,15 @@ match_format(const struct match *match, struct ds *s, int priority) f->nw_frag & FLOW_NW_FRAG_LATER ? "later" : "not_later"); break; } - if (f->dl_type == htons(ETH_TYPE_IP) && + if (dl_type == htons(ETH_TYPE_IP) && f->nw_proto == IPPROTO_ICMP) { format_be16_masked(s, "icmp_type", f->tp_src, wc->masks.tp_src); format_be16_masked(s, "icmp_code", f->tp_dst, wc->masks.tp_dst); - } else if (f->dl_type == htons(ETH_TYPE_IP) && + } else if (dl_type == htons(ETH_TYPE_IP) && f->nw_proto == IPPROTO_IGMP) { format_be16_masked(s, "igmp_type", f->tp_src, wc->masks.tp_src); format_be16_masked(s, "igmp_code", f->tp_dst, wc->masks.tp_dst); - } else if (f->dl_type == htons(ETH_TYPE_IPV6) && + } else if (dl_type == htons(ETH_TYPE_IPV6) && f->nw_proto == IPPROTO_ICMPV6) { format_be16_masked(s, "icmp_type", f->tp_src, wc->masks.tp_src); format_be16_masked(s, "icmp_code", f->tp_dst, wc->masks.tp_dst); diff --git a/lib/meta-flow.c b/lib/meta-flow.c index a963cce..0096917 100644 --- a/lib/meta-flow.c +++ b/lib/meta-flow.c @@ -205,6 +205,8 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc) return !wc->masks.dp_hash; case MFF_RECIRC_ID: return !wc->masks.recirc_id; + case MFF_PACKET_TYPE: + return !wc->masks.packet_type; case MFF_CONJ_ID: return !wc->masks.conj_id; case MFF_TUN_SRC: @@ -401,22 +403,24 @@ mf_are_prereqs_ok__(const struct mf_field *mf, const struct flow *flow, const struct flow_wildcards *mask, struct flow_wildcards *wc) { + ovs_be16 dl_type = get_dl_type(flow); + switch (mf->prereqs) { case MFP_NONE: return true; case MFP_ETHERNET: return is_ethernet(flow, wc); case MFP_ARP: - return (flow->dl_type == htons(ETH_TYPE_ARP) || - flow->dl_type == htons(ETH_TYPE_RARP)); + return (dl_type == htons(ETH_TYPE_ARP) || + dl_type == htons(ETH_TYPE_RARP)); case MFP_IPV4: - return flow->dl_type == htons(ETH_TYPE_IP); + return dl_type == htons(ETH_TYPE_IP); case MFP_IPV6: - return flow->dl_type == htons(ETH_TYPE_IPV6); + return dl_type == htons(ETH_TYPE_IPV6); case MFP_VLAN_VID: return is_vlan(flow, wc); case MFP_MPLS: - return eth_type_mpls(flow->dl_type); + return eth_type_mpls(dl_type); case MFP_IP_ANY: return is_ip_any(flow); case MFP_CT_VALID: @@ -476,6 +480,7 @@ mf_is_value_valid(const struct mf_field *mf, const union mf_value *value) switch (mf->id) { case MFF_DP_HASH: case MFF_RECIRC_ID: + case MFF_PACKET_TYPE: case MFF_CONJ_ID: case MFF_TUN_ID: case MFF_TUN_SRC: @@ -600,6 +605,9 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow, case MFF_RECIRC_ID: value->be32 = htonl(flow->recirc_id); break; + case MFF_PACKET_TYPE: + value->be32 = flow->packet_type; + break; case MFF_CONJ_ID: value->be32 = htonl(flow->conj_id); break; @@ -883,6 +891,9 @@ mf_set_value(const struct mf_field *mf, case MFF_RECIRC_ID: match_set_recirc_id(match, ntohl(value->be32)); break; + case MFF_PACKET_TYPE: + match_set_packet_type(match, value->be32); + break; case MFF_CONJ_ID: match_set_conj_id(match, ntohl(value->be32)); break; @@ -1248,6 +1259,9 @@ mf_set_flow_value(const struct mf_field *mf, case MFF_RECIRC_ID: flow->recirc_id = ntohl(value->be32); break; + case MFF_PACKET_TYPE: + flow->packet_type = value->be32; + break; case MFF_CONJ_ID: flow->conj_id = ntohl(value->be32); break; @@ -1292,7 +1306,6 @@ mf_set_flow_value(const struct mf_field *mf, case MFF_IN_PORT: flow->in_port.ofp_port = u16_to_ofp(ntohs(value->be16)); break; - case MFF_IN_PORT_OXM: ofputil_port_from_ofp11(value->be32, &flow->in_port.ofp_port); break; @@ -1598,6 +1611,10 @@ mf_set_wild(const struct mf_field *mf, struct match *match, char **err_str) match->flow.recirc_id = 0; match->wc.masks.recirc_id = 0; break; + case MFF_PACKET_TYPE: + match->flow.packet_type = 0; + match->wc.masks.packet_type = 0; + break; case MFF_CONJ_ID: match->flow.conj_id = 0; match->wc.masks.conj_id = 0; @@ -1931,6 +1948,7 @@ mf_set(const struct mf_field *mf, case MFF_CT_TP_SRC: case MFF_CT_TP_DST: case MFF_RECIRC_ID: + case MFF_PACKET_TYPE: case MFF_CONJ_ID: case MFF_IN_PORT: case MFF_IN_PORT_OXM: @@ -2296,6 +2314,44 @@ syntax_error: } static char * +mf_from_packet_type_string(const char *s, ovs_be32 *packet_type) +{ + char *tail; + const char *err_str = ""; + int err; + + if (*s != '(') { + err_str = "missing '('"; + goto syntax_error; + } + s++; + err = parse_int_string(s, (uint8_t *)packet_type, 2, &tail); + if (err) { + err_str = "ns"; + goto syntax_error; + } + if (*tail != ',') { + err_str = "missing ','"; + goto syntax_error; + } + s = tail + 1; + err = parse_int_string(s, ((uint8_t *)packet_type) + 2, 2, &tail); + if (err) { + err_str = "ns_type"; + goto syntax_error; + } + if (*tail != ')') { + err_str = "missing ')'"; + goto syntax_error; + } + + return NULL; + +syntax_error: + return xasprintf("%s: bad syntax for packet type %s", s, err_str); +} + +static char * mf_from_ethernet_string(const struct mf_field *mf, const char *s, struct eth_addr *mac, struct eth_addr *mask) { @@ -2528,6 +2584,12 @@ mf_parse(const struct mf_field *mf, const char *s, error = mf_from_tcp_flags_string(s, &value->be16, &mask->be16); break; + case MFS_PACKET_TYPE: + ovs_assert(mf->n_bytes == sizeof(ovs_be32)); + error = mf_from_packet_type_string(s, &value->be32); + mask->be32 = OVS_BE32_MAX; + break; + default: OVS_NOT_REACHED(); } @@ -2621,6 +2683,12 @@ mf_format_ct_state_string(ovs_be32 value, ovs_be32 mask, struct ds *s) ntohl(mask), UINT16_MAX); } +static void +mf_format_packet_type_string(ovs_be32 value, ovs_be32 mask, struct ds *s) +{ + format_packet_type_masked(s, value, mask); +} + /* Appends to 's' a string representation of field 'mf' whose value is in * 'value' and 'mask'. 'mask' may be NULL to indicate an exact match. */ void @@ -2688,6 +2756,11 @@ mf_format(const struct mf_field *mf, mask ? mask->be16 : OVS_BE16_MAX, s); break; + case MFS_PACKET_TYPE: + mf_format_packet_type_string(value->be32, + mask ? mask->be32 : OVS_BE32_MAX, s); + break; + default: OVS_NOT_REACHED(); } diff --git a/lib/meta-flow.xml b/lib/meta-flow.xml index 5efd431..c94288e 100644 --- a/lib/meta-flow.xml +++ b/lib/meta-flow.xml @@ -22,26 +22,37 @@ </p> <p> - Some data fields, called <dfn>root fields</dfn>, are always present as a - consequence of the basic networking technology in use. The Ethernet header - fields are root fields in current versions of Open vSwitch, though future - versions might support other roots. (Currently, to support LISP tunnels, - which do not encapsulate an Ethernet header, Open vSwitch synthesizes one.) + Data fields that are always present as a consequence of the basic + networking technology in use are called called <dfn>root fields</dfn>. + In earlier versions of Open vSwitch, the Ethernet header was always + present and, as a consequence, the Ethernet header fields were root fields. + This remains the default mode of operation of Open vSwitch. When packets + are received from a "layer3" Tunnel which does not encapsulate an Ethernet + header (such as LISP or GRE), Open vSwitch synthesizes one. </p> - <!-- future directions: EXT-112 --> <p> - Other data fields are not always present. A packet contains ARP fields, - for example, only when its Ethernet header indicates the Ethertype for ARP, + The present version of Open vSwitch supports the concept of packet type- + aware pipeline introduced in OpenFlow 1.5. A bridge configured as packet + type-aware can handle packets of multiple networking technologies, such as + Ethernet, IP, ARP, MPLS, or NSH in parallel. + The new packet type data metadata field <cite>packet_type</cite> becomes + the single root field and determines the applicability of all data fields. + </p> + + <p> + Non-root data fields are not always present. A packet contains ARP + fields, for example, only when its packet type is ARP or when it is an + Ethernet packet whose Ethernet header indicates the Ethertype for ARP, 0x0806. In this documentation, we say that a field is <dfn>applicable</dfn> when it is present in a packet, and <dfn>inapplicable</dfn> when it is not. (These are not standard terms.) We refer to the conditions that determine whether a field is applicable as <dfn>prerequisites</dfn>. Some VLAN-related fields are a special case: - these fields are always applicable, but have a designated value or bit that - indicates whether a VLAN header is present, with the remaining values or - bits indicating the VLAN header's content (if it is present). <!-- XXX - also ethertype --> + these fields are always applicable for Ethernet packets, but have a + designated value or bit that indicates whether a VLAN header is present, + with the remaining values or bits indicating the VLAN header's content + (if it is present). <!-- XXX also ethertype --> </p> <p> @@ -51,7 +62,8 @@ example, one may match (see <cite>Matching</cite>, below) a given field only if the match includes the field's prerequisite, e.g. matching an ARP field is only allowed if one also matches on - Ethertype 0x0806. + Ethertype 0x0806 or the packet_type for ARP in a packet type-aware + bridge. </p> <p> @@ -317,6 +329,15 @@ tcp,tp_src=0x07c0/0xfff0 <dt><code>mplsm</code></dt> <dd><code>eth_type=0x8848</code></dd> </dl> + <p> + These shorthand notations continue to work in packet type-aware bridges. + The absence of a packet_type match implies packet_type=ethernet, so that + shorthands match on Ethernet packets with the implied eth_type. Please + note that the shorthand <code>ip</code> does not match packets of packet_type + (1,0x800) for IPv4. + </p> + + <h2>Evolution of OpenFlow Fields</h2> <p> @@ -802,20 +823,12 @@ tcp,tp_src=0x07c0/0xfff0 </p> <ul> + <li>Packet type.</li> <li>TCP flags.</li> <li>Packet registers.</li> <li>The output port in the OpenFlow action set.</li> </ul> - <p> - OpenFlow 1.5 also added OXMs for the following fields not documented here - and not yet implemented by Open vSwitch: - </p> - - <ul> - <li>Packet type.</li> - </ul> - <h1>Fields Reference</h1> <p> @@ -2273,6 +2286,55 @@ actions=clone(load:0->NXM_OF_IN_PORT[],output:123) <field id="MFF_DP_HASH" title="Datapath Hash" internal="yes"/> <field id="MFF_RECIRC_ID" title="Datapath Recirculation ID" internal="yes"/> + + <field id="MFF_PACKET_TYPE" title="Packet Type"> + <p> + Holds the current type of the packet in the format specified in + OpenFlow 1.5. The 32-bit value consists of the name space <code>NS</code> + in the upper 16 bits and a type <code>NS_TYPE</code> (within that name + space) in the lower 16 bits. For ease of use the packet type field is + specified and displayed in the <code>(NS,NS_TYPE)</code> syntax. + </p> + + <p> + Open vSwitch currently supports the following classes of packet types + for matching: + <dl> + <dt><code>(0,0)</code></dt> + <dd>(NS=ONF and NS_TYPE=Ethernet)</dd> + <dt><code>(1,xxxx)</code></dt> + <dd>(NS=Ethertype and xxxx=Ethertype value)</dd> + </dl> + </p> + + <p> + Even though Open vSwitch can forward packets with any NS_TYPE value + for NS=Ethertype, it can only match on and process data fields for + the following list of supported packet types: + <dl> + <dt><code>(1,0x800)</code></dt> <dd>IPv4</dd> + <dt><code>(1,0x806)</code></dt> <dd>ARP</dd> + <dt><code>(1,0x86dd)</code></dt> <dd>IPv6</dd> + <dt><code>(1,0x8847)</code></dt> <dd>MPLS</dd> + <dt><code>(1,0x8848)</code></dt> <dd>MPLS multicast</dd> + <dt><code>(1,0x8035)</code></dt> <dd>RARP</dd> + <dt><code>(1,0x894f)</code></dt> <dd>NSH</dd> + </dl> + </p> + + <p> + The packet type field is mandatory if the OVS bridge is configured + to be packet type-aware. In that case the packet type becomes a + pre-requisite for all matches. If it is omitted from the match, + it defaults to <code>(0,0)</code> (Ethernet) for backward + compatibility. + </p> + + <p> + Open vSwitch allows any table to match this field. + </p> + </field> + </group> <group title="Connection Tracking"> diff --git a/lib/nx-match.c b/lib/nx-match.c index 68e58d3..af19fb2 100644 --- a/lib/nx-match.c +++ b/lib/nx-match.c @@ -873,8 +873,9 @@ static void nxm_put_ip(struct ofpbuf *b, const struct match *match, enum ofp_version oxm) { const struct flow *flow = &match->flow; + ovs_be16 dl_type = get_dl_type(flow); - if (flow->dl_type == htons(ETH_TYPE_IP)) { + if (dl_type == htons(ETH_TYPE_IP)) { nxm_put_32m(b, MFF_IPV4_SRC, oxm, flow->nw_src, match->wc.masks.nw_src); nxm_put_32m(b, MFF_IPV4_DST, oxm, @@ -983,11 +984,18 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const struct match *match, { const struct flow *flow = &match->flow; const size_t start_len = b->size; + ovs_be16 dl_type = get_dl_type(flow); int match_len; int i; BUILD_ASSERT_DECL(FLOW_WC_SEQ == 39); + /* OpenFlow Packet Type. Must be first. */ + if (match->wc.masks.packet_type) { + nxm_put_32m(b, MFF_PACKET_TYPE, oxm, flow->packet_type, + match->wc.masks.packet_type); + } + /* Metadata. */ if (match->wc.masks.dp_hash) { nxm_put_32m(b, MFF_DP_HASH, oxm, @@ -1049,7 +1057,7 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const struct match *match, } /* MPLS. */ - if (eth_type_mpls(flow->dl_type)) { + if (eth_type_mpls(dl_type)) { if (match->wc.masks.mpls_lse[0] & htonl(MPLS_TC_MASK)) { nxm_put_8(b, MFF_MPLS_TC, oxm, mpls_lse_to_tc(flow->mpls_lse[0])); @@ -1069,8 +1077,8 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const struct match *match, /* L3. */ if (is_ip_any(flow)) { nxm_put_ip(b, match, oxm); - } else if (flow->dl_type == htons(ETH_TYPE_ARP) || - flow->dl_type == htons(ETH_TYPE_RARP)) { + } else if (dl_type == htons(ETH_TYPE_ARP) || + dl_type == htons(ETH_TYPE_RARP)) { /* ARP. */ if (match->wc.masks.nw_proto) { nxm_put_16(b, MFF_ARP_OP, oxm, diff --git a/lib/odp-util.c b/lib/odp-util.c index 4d07d1c..5ddb08f 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -4350,6 +4350,50 @@ parse_odp_key_mask_attr(const char *s, const struct simap *port_names, return s - start; } + /* Packet_type open-coded. */ + if (strncmp(s, "packet_type(", strlen("packet_type(")) == 0) { + const char *start = s; + ovs_be32 skey = 0; + ovs_be32 smask = 0; + int len; + uint16_t ns = 0; + uint16_t ns_type = 0; + + s += strlen("packet_type("); + if (ovs_scan(s, "ns=%"SCNu16",id=%n", &ns, &len)){ + if (len == 0) { + return -EINVAL; + } + s += len; + if (strncmp(s, "*", 1) == 0) { + s++; + } else if (ovs_scan(s, "0x%"SCNx16"%n", &ns_type, &len)) { + s += len; + skey = PACKET_TYPE_BE(ns, ns_type); + if ( *s == '/' ) { + uint16_t ns_type_mask = 0; + if (ovs_scan(s, "/0x%"SCNx16"%n", &ns_type_mask, &len)) { + s += len; + smask = PACKET_TYPE_BE(ns, ns_type_mask); + } + } + } + + if (*s++ != ')') { + return -EINVAL; + } + + nl_msg_put_unspec(key, OVS_KEY_ATTR_PACKET_TYPE, &skey, + sizeof(skey)); + if (mask) { + nl_msg_put_unspec(mask, OVS_KEY_ATTR_PACKET_TYPE, &smask, + sizeof(smask)); + } + } + + return s - start; + } + return -EINVAL; } @@ -4500,9 +4544,7 @@ odp_flow_key_from_flow__(const struct odp_flow_key_parms *parms, nl_msg_put_odp_port(buf, OVS_KEY_ATTR_IN_PORT, data->in_port.odp_port); } - if (export_mask || flow->packet_type != htonl(PT_ETH)) { - nl_msg_put_be32(buf, OVS_KEY_ATTR_PACKET_TYPE, data->packet_type); - } + nl_msg_put_be32(buf, OVS_KEY_ATTR_PACKET_TYPE, data->packet_type); if (OVS_UNLIKELY(parms->probe)) { max_vlans = FLOW_MAX_VLAN_HEADERS; diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c index c8cac5b..c443784 100644 --- a/lib/ofp-parse.c +++ b/lib/ofp-parse.c @@ -513,6 +513,12 @@ parse_ofp_str__(struct ofputil_flow_mod *fm, int command, char *string, return error; } } + /* Copy ethertype to flow->dl_type for matches on packet_type + * (OFPHTN_ETHERTYPE, ethertype). */ + if (fm->match.wc.masks.packet_type == OVS_BE32_MAX && + pt_ns(fm->match.flow.packet_type) == OFPHTN_ETHERTYPE) { + fm->match.flow.dl_type = pt_ns_type_be(fm->match.flow.packet_type); + } /* Check for usable protocol interdependencies between match fields. */ if (fm->match.flow.dl_type == htons(ETH_TYPE_IPV6)) { const struct flow_wildcards *wc = &fm->match.wc; diff --git a/lib/ofp-util.c b/lib/ofp-util.c index bdf89b6..758f905 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -7431,21 +7431,37 @@ ofputil_normalize_match__(struct match *match, bool may_log) MAY_IPV6 = 1 << 6, /* ipv6_src, ipv6_dst, ipv6_label */ MAY_ND_TARGET = 1 << 7, /* nd_target */ MAY_MPLS = 1 << 8, /* mpls label and tc */ + MAY_ETHER = 1 << 9, /* dl_src, dl_dst */ } may_match; - struct flow_wildcards wc; + struct flow_wildcards wc = match->wc; + ovs_be16 dl_type; /* Figure out what fields may be matched. */ - if (match->flow.dl_type == htons(ETH_TYPE_IP)) { - may_match = MAY_NW_PROTO | MAY_IPVx | MAY_NW_ADDR; + /* Check the packet_type first and extract dl_type. */ + if (wc.masks.packet_type == 0 || + (wc.masks.packet_type == OVS_BE32_MAX && + match->flow.packet_type == htonl(PT_ETH))) { + may_match = MAY_ETHER; + dl_type = match->flow.dl_type; + } else if (wc.masks.packet_type == OVS_BE32_MAX && + pt_ns(match->flow.packet_type) == OFPHTN_ETHERTYPE) { + may_match = 0; + dl_type = pt_ns_type_be(match->flow.packet_type); + } else { + may_match = 0; + dl_type = 0; + } + if (dl_type == htons(ETH_TYPE_IP)) { + may_match |= MAY_NW_PROTO | MAY_IPVx | MAY_NW_ADDR; if (match->flow.nw_proto == IPPROTO_TCP || match->flow.nw_proto == IPPROTO_UDP || match->flow.nw_proto == IPPROTO_SCTP || match->flow.nw_proto == IPPROTO_ICMP) { may_match |= MAY_TP_ADDR; } - } else if (match->flow.dl_type == htons(ETH_TYPE_IPV6)) { - may_match = MAY_NW_PROTO | MAY_IPVx | MAY_IPV6; + } else if (dl_type == htons(ETH_TYPE_IPV6)) { + may_match |= MAY_NW_PROTO | MAY_IPVx | MAY_IPV6; if (match->flow.nw_proto == IPPROTO_TCP || match->flow.nw_proto == IPPROTO_UDP || match->flow.nw_proto == IPPROTO_SCTP) { @@ -7458,17 +7474,17 @@ ofputil_normalize_match__(struct match *match, bool may_log) may_match |= MAY_ND_TARGET | MAY_ARP_THA; } } - } else if (match->flow.dl_type == htons(ETH_TYPE_ARP) || - match->flow.dl_type == htons(ETH_TYPE_RARP)) { - may_match = MAY_NW_PROTO | MAY_NW_ADDR | MAY_ARP_SHA | MAY_ARP_THA; - } else if (eth_type_mpls(match->flow.dl_type)) { - may_match = MAY_MPLS; - } else { - may_match = 0; + } else if (dl_type == htons(ETH_TYPE_ARP) || + dl_type == htons(ETH_TYPE_RARP)) { + may_match |= MAY_NW_PROTO | MAY_NW_ADDR | MAY_ARP_SHA | MAY_ARP_THA; + } else if (eth_type_mpls(dl_type)) { + may_match |= MAY_MPLS; } /* Clear the fields that may not be matched. */ - wc = match->wc; + if (!(may_match & MAY_ETHER)) { + wc.masks.dl_src = wc.masks.dl_dst = eth_addr_zero; + } if (!(may_match & MAY_NW_ADDR)) { wc.masks.nw_src = wc.masks.nw_dst = htonl(0); } diff --git a/tests/dpif-netdev.at b/tests/dpif-netdev.at index 586a5b1..774619d 100644 --- a/tests/dpif-netdev.at +++ b/tests/dpif-netdev.at @@ -99,7 +99,7 @@ m4_define([DPIF_NETDEV_MISS_FLOW_INSTALL], sleep 1 AT_CHECK([grep -A 1 'miss upcall' ovs-vswitchd.log | tail -n 1], [0], [dnl -skb_priority(0),skb_mark(0),ct_state(0),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0) +skb_priority(0),skb_mark(0),ct_state(0),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet_type(ns=0,id=0x0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0) ]) AT_CHECK([filter_flow_install < ovs-vswitchd.log | strip_xout], [0], [dnl recirc_id(0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(frag=no), actions: <del> @@ -112,7 +112,7 @@ recirc_id(0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_typ sleep 1 AT_CHECK([grep -A 1 'miss upcall' ovs-vswitchd.log | tail -n 1], [0], [dnl -skb_priority(0),skb_mark(0),ct_state(0),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0) +skb_priority(0),skb_mark(0),ct_state(0),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet_type(ns=0,id=0x0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0) ]) AT_CHECK([filter_flow_install < ovs-vswitchd.log | strip_xout], [0], [dnl recirc_id(0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(frag=no), actions: <del> @@ -140,10 +140,10 @@ m4_define([DPIF_NETDEV_MISS_FLOW_DUMP], sleep 1 AT_CHECK([grep -A 1 'miss upcall' ovs-vswitchd.log | tail -n 1], [0], [dnl -skb_priority(0),skb_mark(0),ct_state(0),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0) +skb_priority(0),skb_mark(0),ct_state(0),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet_type(ns=0,id=0x0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0) ]) AT_CHECK([filter_flow_dump < ovs-vswitchd.log | strip_xout], [0], [dnl -skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0), packets:0, bytes:0, used:never, actions: <del> +skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(1),packet_type(ns=0,id=*),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0), packets:0, bytes:0, used:never, actions: <del> ]) # Now, the same again without megaflows. @@ -155,11 +155,11 @@ skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label sleep 1 AT_CHECK([grep -A 1 'miss upcall' ovs-vswitchd.log | tail -n 1], [0], [dnl -skb_priority(0),skb_mark(0),ct_state(0),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0) +skb_priority(0),skb_mark(0),ct_state(0),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet_type(ns=0,id=0x0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0) ]) AT_CHECK([filter_flow_dump < ovs-vswitchd.log | strip_xout], [0], [dnl -skb_priority(0),skb_mark(0),ct_state(0/0xff),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:0, bytes:0, used:never, actions: <del> -skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0), packets:0, bytes:0, used:never, actions: <del> +skb_priority(0),skb_mark(0),ct_state(0/0xff),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet_type(ns=0,id=*),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:0, bytes:0, used:never, actions: <del> +skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(1),packet_type(ns=0,id=*),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0), packets:0, bytes:0, used:never, actions: <del> ]) OVS_VSWITCHD_STOP diff --git a/tests/odp.at b/tests/odp.at index e408c9f..72167ee 100644 --- a/tests/odp.at +++ b/tests/odp.at @@ -94,6 +94,7 @@ dnl Some fields are always printed for this test, because wildcards aren't dnl specified. We can skip these. sed -i 's/\(skb_mark(0)\),\(ct\)/\1,ct_state(0),ct_zone(0),\2/' odp-out.txt sed -i 's/\(skb_mark([[^)]]*)\),\(recirc\)/\1,ct_state(0),ct_zone(0),ct_mark(0),ct_label(0),\2/' odp-out.txt +sed -i 's/\(in_port(1)\),\(eth\)/\1,packet_type(ns=0,id=0x0),\2/' odp-out.txt AT_CHECK_UNQUOTED([ovstest test-odp parse-keys < odp-in.txt], [0], [`cat odp-out.txt` ]) diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at index 1f6cd84..d4cee2f 100644 --- a/tests/ofproto-dpif.at +++ b/tests/ofproto-dpif.at @@ -7211,12 +7211,12 @@ recirc_id(0),in_port(3),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used ]) AT_CHECK([ovs-appctl dpif/dump-flows -m br0 | strip_ufid | strip_used | sort], [0], [dnl -skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(p1),eth(src=50:54:00:00:00:05/00:00:00:00:00:00,dst=50:54:00:00:00:07/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.0.1/0.0.0.0,dst=192.168.0.2/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0), packets:0, bytes:0, used:never, actions:drop -skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(p2),eth(src=50:54:00:00:00:07/00:00:00:00:00:00,dst=50:54:00:00:00:05/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.0.2/0.0.0.0,dst=192.168.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=0/0,code=0/0), packets:0, bytes:0, used:never, actions:drop +skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(p1),packet_type(ns=0,id=*),eth(src=50:54:00:00:00:05/00:00:00:00:00:00,dst=50:54:00:00:00:07/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.0.1/0.0.0.0,dst=192.168.0.2/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0), packets:0, bytes:0, used:never, actions:drop +skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(p2),packet_type(ns=0,id=*),eth(src=50:54:00:00:00:07/00:00:00:00:00:00,dst=50:54:00:00:00:05/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.0.2/0.0.0.0,dst=192.168.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=0/0,code=0/0), packets:0, bytes:0, used:never, actions:drop ]) AT_CHECK([ovs-appctl dpif/dump-flows -m br1 | strip_ufid | strip_used | sort], [0], [dnl -skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(p3),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0), packets:0, bytes:0, used:never, actions:drop +skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(p3),packet_type(ns=0,id=*),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0), packets:0, bytes:0, used:never, actions:drop ]) OVS_VSWITCHD_STOP @@ -7376,10 +7376,10 @@ recirc_id(0),in_port(101),eth_type(0x0800),ipv4(frag=no), actions:100,2,3 ]) AT_CHECK([grep -e 'in_port(100).*packets:9' ovs-vswitchd.log | strip_ufid | filter_flow_dump], [0], [dnl -skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(100),eth(src=50:54:00:00:00:05/00:00:00:00:00:00,dst=50:54:00:00:00:07/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.0.1/0.0.0.0,dst=192.168.0.2/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0), packets:9, bytes:378, used:0.0s, actions:101,3,2 +skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(100),packet_type(ns=0,id=*),eth(src=50:54:00:00:00:05/00:00:00:00:00:00,dst=50:54:00:00:00:07/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.0.1/0.0.0.0,dst=192.168.0.2/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0), packets:9, bytes:378, used:0.0s, actions:101,3,2 ]) AT_CHECK([grep -e 'in_port(101).*packets:4' ovs-vswitchd.log | strip_ufid | filter_flow_dump], [0], [dnl -skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(101),eth(src=50:54:00:00:00:07/00:00:00:00:00:00,dst=50:54:00:00:00:05/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.0.2/0.0.0.0,dst=192.168.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0), packets:4, bytes:168, used:0.0s, actions:100,2,3 +skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(101),packet_type(ns=0,id=*),eth(src=50:54:00:00:00:07/00:00:00:00:00:00,dst=50:54:00:00:00:05/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.0.2/0.0.0.0,dst=192.168.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0), packets:4, bytes:168, used:0.0s, actions:100,2,3 ]) AT_CHECK([ovs-ofctl dump-ports br0 pbr0], [0], [dnl @@ -7990,8 +7990,8 @@ skb_priority(0),skb_mark(0),ct_state(-new-est-rel-rpl-inv-trk-snat-dnat),ct_zone skb_priority(0),skb_mark(0),ct_state(-new-est-rel-rpl-inv-trk-snat-dnat),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), actions:drop ]) AT_CHECK([strip_ufid < ovs-vswitchd.log | filter_flow_dump | grep 'packets:3'], [0], [dnl -skb_priority(0),skb_mark(0),ct_state(0/0xff),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:3, bytes:126, used:0.0s, actions:2 -skb_priority(0),skb_mark(0),ct_state(0/0xff),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:3, bytes:126, used:0.0s, actions:drop +skb_priority(0),skb_mark(0),ct_state(0/0xff),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet_type(ns=0,id=*),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:3, bytes:126, used:0.0s, actions:2 +skb_priority(0),skb_mark(0),ct_state(0/0xff),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet_type(ns=0,id=*),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:3, bytes:126, used:0.0s, actions:drop ]) OVS_VSWITCHD_STOP AT_CLEANUP]) @@ -8603,7 +8603,7 @@ recirc_id(0),in_port(1),eth_type(0x1234), packets:5, bytes:70, used:0.0s, action ]) AT_CHECK([grep 'modify' ovs-vswitchd.log | strip_ufid ], [0], [dnl -dpif|DBG|dummy@ovs-dummy: put[[modify]] skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(1),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x1234), actions:push_vlan(vid=4,pcp=0),100 +dpif|DBG|dummy@ovs-dummy: put[[modify]] skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(1),packet_type(ns=0,id=*),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x1234), actions:push_vlan(vid=4,pcp=0),100 ]) OVS_VSWITCHD_STOP AT_CLEANUP @@ -8683,8 +8683,8 @@ recirc_id(0),in_port(1),eth_type(0x8100),vlan(vid=99,pcp=7/0x0),encap(eth_type(0 # are wildcarded. AT_CHECK([grep '\(modify\)\|\(flow_add\)' ovs-vswitchd.log | strip_ufid ], [0], [dnl dpif_netdev|DBG|flow_add: recirc_id(0),in_port(1),eth_type(0x1234), actions:100 -dpif|DBG|dummy@ovs-dummy: put[[modify]] skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(1),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x1234) -dpif|DBG|dummy@ovs-dummy: put[[modify]] skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(1),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x1234), actions:100 +dpif|DBG|dummy@ovs-dummy: put[[modify]] skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(1),packet_type(ns=0,id=*),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x1234) +dpif|DBG|dummy@ovs-dummy: put[[modify]] skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(1),packet_type(ns=0,id=*),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x1234), actions:100 dpif_netdev|DBG|flow_add: recirc_id(0),in_port(1),eth_type(0x8100),vlan(vid=99,pcp=7/0x0),encap(eth_type(0x1234)), actions:drop ]) OVS_VSWITCHD_STOP diff --git a/tests/ofproto.at b/tests/ofproto.at index 5431f4e..246eb12 100644 --- a/tests/ofproto.at +++ b/tests/ofproto.at @@ -2390,6 +2390,7 @@ metadata in_port in_port_oxm pkt_mark ct_mark ct_label reg0 reg1 reg2 reg3 reg4 matching: dp_hash: arbitrary mask recirc_id: exact match or wildcard + packet_type: exact match or wildcard conj_id: exact match or wildcard tun_id: arbitrary mask tun_src: arbitrary mask diff --git a/tests/pmd.at b/tests/pmd.at index 2816d45..9ba2576 100644 --- a/tests/pmd.at +++ b/tests/pmd.at @@ -190,7 +190,7 @@ for i in `seq 0 19`; ovs-appctl time/warp 100 AT_CHECK([grep -A 1 'miss upcall' ovs-vswitchd.log | tail -n 1], [0], [dnl -skb_priority(0),skb_mark(0),ct_state(0),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),eth(src=50:54:00:00:00:77,dst=50:54:00:00:01:78),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0) +skb_priority(0),skb_mark(0),ct_state(0),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet_type(ns=0,id=0x0),eth(src=50:54:00:00:00:77,dst=50:54:00:00:01:78),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0) ]) AT_CHECK([cat ovs-vswitchd.log | filter_flow_install | strip_xout], [0], [dnl recirc_id(0),in_port(1),eth(src=50:54:00:00:00:77,dst=50:54:00:00:01:78),eth_type(0x0800),ipv4(frag=no), actions: <del> diff --git a/tests/tunnel-push-pop-ipv6.at b/tests/tunnel-push-pop-ipv6.at index cbeb578..9e37845 100644 --- a/tests/tunnel-push-pop-ipv6.at +++ b/tests/tunnel-push-pop-ipv6.at @@ -164,7 +164,7 @@ AT_CHECK([ovs-ofctl dump-ports int-br | grep 'port 5'], [0], [dnl port 5: rx pkts=1, bytes=98, drop=?, errs=?, frame=?, over=?, crc=? ]) AT_CHECK([ovs-appctl dpif/dump-flows int-br | grep 'in_port(6081)'], [0], [dnl -tunnel(tun_id=0x7b,ipv6_src=2001:cafe::92,ipv6_dst=2001:cafe::88,geneve({class=0xffff,type=0x80,len=4,0xa/0xf}{class=0xffff,type=0,len=4}),flags(-df-csum+key)),recirc_id(0),in_port(6081),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:userspace(pid=0,slow_path(controller)) +tunnel(tun_id=0x7b,ipv6_src=2001:cafe::92,ipv6_dst=2001:cafe::88,geneve({class=0xffff,type=0x80,len=4,0xa/0xf}{class=0xffff,type=0,len=4}),flags(-df-csum+key)),recirc_id(0),in_port(6081),packet_type(ns=0,id=0x0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:userspace(pid=0,slow_path(controller)) ]) OVS_VSWITCHD_STOP diff --git a/tests/tunnel-push-pop.at b/tests/tunnel-push-pop.at index 961ac34..bc48d31 100644 --- a/tests/tunnel-push-pop.at +++ b/tests/tunnel-push-pop.at @@ -215,7 +215,7 @@ AT_CHECK([ovs-ofctl dump-ports int-br | grep 'port 5'], [0], [dnl port 5: rx pkts=1, bytes=98, drop=?, errs=?, frame=?, over=?, crc=? ]) AT_CHECK([ovs-appctl dpif/dump-flows int-br | grep 'in_port(6081)'], [0], [dnl -tunnel(tun_id=0x7b,src=1.1.2.92,dst=1.1.2.88,geneve({class=0xffff,type=0x80,len=4,0xa/0xf}{class=0xffff,type=0,len=4}),flags(-df-csum+key)),recirc_id(0),in_port(6081),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:userspace(pid=0,slow_path(controller)) +tunnel(tun_id=0x7b,src=1.1.2.92,dst=1.1.2.88,geneve({class=0xffff,type=0x80,len=4,0xa/0xf}{class=0xffff,type=0,len=4}),flags(-df-csum+key)),recirc_id(0),in_port(6081),packet_type(ns=0,id=0x0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:userspace(pid=0,slow_path(controller)) ]) OVS_VSWITCHD_STOP -- 1.9.1 _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev