From patchwork Mon Jun 12 22:28:26 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Pfaff X-Patchwork-Id: 774855 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3wmnfp2Z4rz9s06 for ; Tue, 13 Jun 2017 08:30:58 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 95871BEC; Mon, 12 Jun 2017 22:29:16 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id 4D7E3B92 for ; Mon, 12 Jun 2017 22:29:13 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from relay6-d.mail.gandi.net (relay6-d.mail.gandi.net [217.70.183.198]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id A048FFD for ; Mon, 12 Jun 2017 22:29:09 +0000 (UTC) Received: from mfilter10-d.gandi.net (mfilter10-d.gandi.net [217.70.178.139]) by relay6-d.mail.gandi.net (Postfix) with ESMTP id 91FB4FB8BC; Tue, 13 Jun 2017 00:29:08 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at mfilter10-d.gandi.net Received: from relay6-d.mail.gandi.net ([IPv6:::ffff:217.70.183.198]) by mfilter10-d.gandi.net (mfilter10-d.gandi.net [::ffff:10.0.15.180]) (amavisd-new, port 10024) with ESMTP id CKrsduCjwIvy; Tue, 13 Jun 2017 00:29:04 +0200 (CEST) X-Originating-IP: 208.91.2.3 Received: from sigabrt.benpfaff.org (unknown [208.91.2.3]) (Authenticated sender: blp@ovn.org) by relay6-d.mail.gandi.net (Postfix) with ESMTPSA id 10A29FB8A1; Tue, 13 Jun 2017 00:29:02 +0200 (CEST) From: Ben Pfaff To: dev@openvswitch.org Date: Mon, 12 Jun 2017 15:28:26 -0700 Message-Id: <20170612222856.14108-2-blp@ovn.org> X-Mailer: git-send-email 2.10.2 In-Reply-To: <20170612222856.14108-1-blp@ovn.org> References: <20170612222856.14108-1-blp@ovn.org> X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_LOW autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Cc: Ben Pfaff Subject: [ovs-dev] [PATCH 01/31] userspace: Add OXM field MFF_PACKET_TYPE X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org From: Jan Scheurich 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 Signed-off-by: Ben Pfaff --- 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 | 86 +++++++++++++++++++++++++++++--- 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, 362 insertions(+), 105 deletions(-) diff --git a/build-aux/extract-ofp-fields b/build-aux/extract-ofp-fields index d5b8a820251e..24dd756ad7d5 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 cbfd3ba65b73..3a17d7b0618e 100644 --- a/include/openvswitch/meta-flow.h +++ b/include/openvswitch/meta-flow.h @@ -133,6 +133,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. @@ -248,6 +253,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) @@ -1860,6 +1879,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 1f51b66e7b44..b901a077d790 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -1153,6 +1153,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,%#"PRIx16"),", + pt_ns(value), + pt_ns_type(value)); + } else{ + ds_put_format(s, "packet_type=(%u,%#"PRIx16"/%#"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 68bd4f3c5149..e76adac7e0d4 100644 --- a/lib/flow.h +++ b/lib/flow.h @@ -83,6 +83,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); @@ -964,9 +966,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)); } @@ -975,7 +991,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, @@ -1011,7 +1027,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); } @@ -1023,7 +1039,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); } @@ -1054,7 +1070,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); } @@ -1098,8 +1114,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 ebcdb29d2c6e..2caf10064bd2 100644 --- a/lib/match.c +++ b/lib/match.c @@ -1174,8 +1174,8 @@ match_format(const struct match *match, 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; @@ -1257,24 +1257,16 @@ match_format(const struct match *match, } 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,%#"PRIx16"),", - pt_ns(f->packet_type), - pt_ns_type(f->packet_type)); - } else { - ds_put_format(s, "packet_type=(%u,%#"PRIx16"/%#"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) { @@ -1294,7 +1286,7 @@ match_format(const struct match *match, } 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) { @@ -1312,13 +1304,13 @@ match_format(const struct match *match, } 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; @@ -1390,9 +1382,9 @@ match_format(const struct match *match, 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) { @@ -1406,8 +1398,8 @@ match_format(const struct match *match, 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 { @@ -1415,8 +1407,8 @@ match_format(const struct match *match, 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 { @@ -1424,8 +1416,8 @@ match_format(const struct match *match, 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); } @@ -1478,15 +1470,15 @@ match_format(const struct match *match, 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 a255f1ce9de1..d0980814c36c 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; @@ -1574,6 +1587,7 @@ mf_is_pipeline_field(const struct mf_field *mf) CASE_MFF_REGS: CASE_MFF_XREGS: CASE_MFF_XXREGS: + case MFF_PACKET_TYPE: return true; case MFF_DP_HASH: @@ -1688,6 +1702,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; @@ -2021,6 +2039,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: @@ -2386,6 +2405,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) { @@ -2623,6 +2680,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(); } @@ -2717,6 +2780,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 @@ -2785,6 +2854,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 5efd431004dd..c94288e4c294 100644 --- a/lib/meta-flow.xml +++ b/lib/meta-flow.xml @@ -22,26 +22,37 @@

- Some data fields, called root fields, 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 root fields. + 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.

-

- 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 packet_type becomes + the single root field and determines the applicability of all data fields. +

+ +

+ 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 applicable when it is present in a packet, and inapplicable when it is not. (These are not standard terms.) We refer to the conditions that determine whether a field is applicable as prerequisites. 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). + 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).

@@ -51,7 +62,8 @@ example, one may match (see Matching, 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.

@@ -317,6 +329,15 @@ tcp,tp_src=0x07c0/0xfff0

mplsm
eth_type=0x8848
+

+ 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 ip does not match packets of packet_type + (1,0x800) for IPv4. +

+ +

Evolution of OpenFlow Fields

@@ -802,20 +823,12 @@ tcp,tp_src=0x07c0/0xfff0

    +
  • Packet type.
  • TCP flags.
  • Packet registers.
  • The output port in the OpenFlow action set.
-

- OpenFlow 1.5 also added OXMs for the following fields not documented here - and not yet implemented by Open vSwitch: -

- -
    -
  • Packet type.
  • -
-

Fields Reference

@@ -2273,6 +2286,55 @@ actions=clone(load:0->NXM_OF_IN_PORT[],output:123) + + +

+ Holds the current type of the packet in the format specified in + OpenFlow 1.5. The 32-bit value consists of the name space NS + in the upper 16 bits and a type NS_TYPE (within that name + space) in the lower 16 bits. For ease of use the packet type field is + specified and displayed in the (NS,NS_TYPE) syntax. +

+ +

+ Open vSwitch currently supports the following classes of packet types + for matching: +

+
(0,0)
+
(NS=ONF and NS_TYPE=Ethernet)
+
(1,xxxx)
+
(NS=Ethertype and xxxx=Ethertype value)
+
+

+ +

+ 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: +

+
(1,0x800)
IPv4
+
(1,0x806)
ARP
+
(1,0x86dd)
IPv6
+
(1,0x8847)
MPLS
+
(1,0x8848)
MPLS multicast
+
(1,0x8035)
RARP
+
(1,0x894f)
NSH
+
+

+ +

+ 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 (0,0) (Ethernet) for backward + compatibility. +

+ +

+ Open vSwitch allows any table to match this field. +

+ + diff --git a/lib/nx-match.c b/lib/nx-match.c index 334ecd4a3f1a..7284f2213817 100644 --- a/lib/nx-match.c +++ b/lib/nx-match.c @@ -885,8 +885,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, @@ -995,11 +996,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, @@ -1061,7 +1069,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])); @@ -1081,8 +1089,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 dea5ab2ea545..b57934ba1cd4 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 2e4942262ea0..146fa4b2b82c 100644 --- a/lib/ofp-parse.c +++ b/lib/ofp-parse.c @@ -517,6 +517,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 da171cdf6fe5..941000c24745 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -7680,21 +7680,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) { @@ -7707,17 +7723,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 586a5b1c2240..d6f92eb19bb2 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=0),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: @@ -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=0),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: @@ -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=0),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: +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: ]) # 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=0),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: -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: +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: +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: ]) OVS_VSWITCHD_STOP diff --git a/tests/odp.at b/tests/odp.at index e408c9f9b778..0e8cbedc130d 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=0),\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 e2228661fd09..5a1b6e7e7b12 100644 --- a/tests/ofproto-dpif.at +++ b/tests/ofproto-dpif.at @@ -7212,12 +7212,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 @@ -7377,10 +7377,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 @@ -7991,8 +7991,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]) @@ -8653,7 +8653,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 @@ -8733,8 +8733,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 76a33b6902aa..25aa00aff4a2 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 05755b3f7202..40138332a679 100644 --- a/tests/pmd.at +++ b/tests/pmd.at @@ -191,7 +191,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=0),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: diff --git a/tests/tunnel-push-pop-ipv6.at b/tests/tunnel-push-pop-ipv6.at index cbeb5788550f..228a9af43573 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=0),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 e3aecb45e9a5..5a2c423839db 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=0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:userspace(pid=0,slow_path(controller)) ]) OVS_VSWITCHD_STOP