From patchwork Tue Aug 29 18:21:01 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Yang, Yi" X-Patchwork-Id: 807219 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) 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 3xhcXV6Jshz9sMN for ; Wed, 30 Aug 2017 04:26:18 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id C5718B68; Tue, 29 Aug 2017 18:25:09 +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 09A81B56 for ; Tue, 29 Aug 2017 18:25:06 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mga07.intel.com (mga07.intel.com [134.134.136.100]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 45EC0E3 for ; Tue, 29 Aug 2017 18:25:02 +0000 (UTC) Received: from orsmga003.jf.intel.com ([10.7.209.27]) by orsmga105.jf.intel.com with ESMTP; 29 Aug 2017 11:25:02 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos; i="5.41,445,1498546800"; d="scan'208"; a="1008955788" Received: from unknown (HELO localhost.localdomain.bj.intel.com) ([10.240.224.185]) by orsmga003.jf.intel.com with ESMTP; 29 Aug 2017 11:24:58 -0700 From: Yi Yang To: dev@openvswitch.org Date: Wed, 30 Aug 2017 02:21:01 +0800 Message-Id: <1504030862-14591-2-git-send-email-yi.y.yang@intel.com> X-Mailer: git-send-email 2.1.0 In-Reply-To: <1504030862-14591-1-git-send-email-yi.y.yang@intel.com> References: <1504030862-14591-1-git-send-email-yi.y.yang@intel.com> X-Spam-Status: No, score=-2.3 required=5.0 tests=RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD autolearn=disabled version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Cc: e@erig.me, jbenc@redhat.com Subject: [ovs-dev] [PATCH v5 1/2] nsh: add new flow key 'ttl' 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 IETF NSH draft will be approved by end of August, NSH header format has been finalized and won't be change anymore, so we need to follow this final spec to implement nsh. kernel data path also needs finalized uAPIs, they can't be changed once they are merged. This patch adds new nsh key 'ttl', bits of flags and mdtype fields are also changed to follow the final spec. A new action dec_nsh_ttl will be added in the following patch. Signed-off-by: Yi Yang --- datapath/linux/compat/include/linux/openvswitch.h | 17 +- include/openvswitch/flow.h | 6 +- include/openvswitch/match.h | 6 + include/openvswitch/meta-flow.h | 31 +- include/openvswitch/nsh.h | 326 ++++++++++++++++++++-- include/openvswitch/packets.h | 18 +- lib/flow.c | 64 ++--- lib/flow.h | 2 +- lib/match.c | 56 +++- lib/meta-flow.c | 49 +++- lib/meta-flow.xml | 9 +- lib/nx-match.c | 33 ++- lib/odp-execute.c | 16 +- lib/odp-util.c | 173 ++++++------ lib/packets.c | 5 +- ofproto/ofproto-dpif-xlate.c | 10 +- tests/nsh.at | 46 +-- 17 files changed, 608 insertions(+), 259 deletions(-) diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h index bc6c94b..04308aa 100644 --- a/datapath/linux/compat/include/linux/openvswitch.h +++ b/datapath/linux/compat/include/linux/openvswitch.h @@ -492,15 +492,6 @@ struct ovs_key_ct_labels { }; }; -struct ovs_key_nsh { - __u8 flags; - __u8 mdtype; - __u8 np; - __u8 pad; - __be32 path_hdr; - __be32 c[4]; -}; - /* OVS_KEY_ATTR_CT_STATE flags */ #define OVS_CS_F_NEW 0x01 /* Beginning of a new connection. */ #define OVS_CS_F_ESTABLISHED 0x02 /* Part of an existing connection. */ @@ -793,10 +784,10 @@ struct ovs_action_push_eth { struct ovs_key_ethernet addresses; }; -#define OVS_ENCAP_NSH_MAX_MD_LEN 16 /* * struct ovs_action_encap_nsh - %OVS_ACTION_ATTR_ENCAP_NSH * @flags: NSH header flags. + * @ttl: NSH header TTL. * @mdtype: NSH metadata type. * @mdlen: Length of NSH metadata in bytes. * @np: NSH next_protocol: Inner packet type. @@ -805,11 +796,13 @@ struct ovs_action_push_eth { */ struct ovs_action_encap_nsh { uint8_t flags; + uint8_t ttl; uint8_t mdtype; - uint8_t mdlen; uint8_t np; __be32 path_hdr; - uint8_t metadata[OVS_ENCAP_NSH_MAX_MD_LEN]; + uint8_t mdlen; + uint8_t pad[3]; /* Aligned to 32 bit boundary for metadata */ + uint8_t metadata[]; }; /** diff --git a/include/openvswitch/flow.h b/include/openvswitch/flow.h index a658a58..cd61fff 100644 --- a/include/openvswitch/flow.h +++ b/include/openvswitch/flow.h @@ -146,7 +146,7 @@ struct flow { struct eth_addr arp_tha; /* ARP/ND target hardware address. */ ovs_be16 tcp_flags; /* TCP flags. With L3 to avoid matching L4. */ ovs_be16 pad2; /* Pad to 64 bits. */ - struct flow_nsh nsh; /* Network Service Header keys */ + struct ovs_key_nsh nsh; /* Network Service Header keys */ /* L4 (64-bit aligned) */ ovs_be16 tp_src; /* TCP/UDP/SCTP source port/ICMP type. */ @@ -159,13 +159,13 @@ struct flow { }; BUILD_ASSERT_DECL(sizeof(struct flow) % sizeof(uint64_t) == 0); BUILD_ASSERT_DECL(sizeof(struct flow_tnl) % sizeof(uint64_t) == 0); -BUILD_ASSERT_DECL(sizeof(struct flow_nsh) % sizeof(uint64_t) == 0); +BUILD_ASSERT_DECL(sizeof(struct ovs_key_nsh) % sizeof(uint64_t) == 0); #define FLOW_U64S (sizeof(struct flow) / sizeof(uint64_t)) /* Remember to update FLOW_WC_SEQ when changing 'struct flow'. */ BUILD_ASSERT_DECL(offsetof(struct flow, igmp_group_ip4) + sizeof(uint32_t) - == sizeof(struct flow_tnl) + sizeof(struct flow_nsh) + 300 + == sizeof(struct flow_tnl) + sizeof(struct ovs_key_nsh) + 300 && FLOW_WC_SEQ == 40); /* Incremental points at which flow classification may be performed in diff --git a/include/openvswitch/match.h b/include/openvswitch/match.h index 61a67de..c22b0b1 100644 --- a/include/openvswitch/match.h +++ b/include/openvswitch/match.h @@ -205,6 +205,12 @@ void match_set_ipv6_label_masked(struct match *, ovs_be32, ovs_be32); void match_set_nd_target(struct match *, const struct in6_addr *); void match_set_nd_target_masked(struct match *, const struct in6_addr *, const struct in6_addr *); +void match_set_any_nsh_spi(struct match *); +void match_set_any_nsh_si(struct match *); +void match_set_nsh_spi(struct match *, ovs_be32); +void match_set_nsh_si(struct match *, uint8_t); +void match_set_nsh_spi_masked(struct match *, ovs_be32, ovs_be32); +void match_set_nsh_si_masked(struct match *, uint8_t, uint8_t); bool match_equal(const struct match *, const struct match *); uint32_t match_hash(const struct match *, uint32_t basis); diff --git a/include/openvswitch/meta-flow.h b/include/openvswitch/meta-flow.h index 436501f..14e6b59 100644 --- a/include/openvswitch/meta-flow.h +++ b/include/openvswitch/meta-flow.h @@ -1757,6 +1757,21 @@ enum OVS_PACKED_ENUM mf_field_id { */ MFF_NSH_FLAGS, + /* "nsh_ttl". + * + * TTL field in NSH base header. + * + * Type: u8. + * Maskable: no. + * Formatting: decimal. + * Prerequisites: NSH. + * Access: read/write. + * NXM: none. + * OXM: NXOXM_NSH_TTL(2) since OF1.3 and v2.8. + */ + MFF_NSH_TTL, + + /* "nsh_mdtype". * * mdtype field in NSH base header. @@ -1767,7 +1782,7 @@ enum OVS_PACKED_ENUM mf_field_id { * Prerequisites: NSH. * Access: read-only. * NXM: none. - * OXM: NXOXM_NSH_MDTYPE(2) since OF1.3 and v2.8. + * OXM: NXOXM_NSH_MDTYPE(3) since OF1.3 and v2.8. */ MFF_NSH_MDTYPE, @@ -1781,7 +1796,7 @@ enum OVS_PACKED_ENUM mf_field_id { * Prerequisites: NSH. * Access: read-only. * NXM: none. - * OXM: NXOXM_NSH_NP(3) since OF1.3 and v2.8. + * OXM: NXOXM_NSH_NP(4) since OF1.3 and v2.8. */ MFF_NSH_NP, @@ -1795,7 +1810,7 @@ enum OVS_PACKED_ENUM mf_field_id { * Prerequisites: NSH. * Access: read/write. * NXM: none. - * OXM: NXOXM_NSH_SPI(4) since OF1.3 and v2.8. + * OXM: NXOXM_NSH_SPI(5) since OF1.3 and v2.8. */ MFF_NSH_SPI, @@ -1809,7 +1824,7 @@ enum OVS_PACKED_ENUM mf_field_id { * Prerequisites: NSH. * Access: read/write. * NXM: none. - * OXM: NXOXM_NSH_SI(5) since OF1.3 and v2.8. + * OXM: NXOXM_NSH_SI(6) since OF1.3 and v2.8. */ MFF_NSH_SI, @@ -1823,10 +1838,10 @@ enum OVS_PACKED_ENUM mf_field_id { * Prerequisites: NSH. * Access: read/write. * NXM: none. - * OXM: NXOXM_NSH_C1(6) since OF1.3 and v2.8. <1> - * OXM: NXOXM_NSH_C2(7) since OF1.3 and v2.8. <2> - * OXM: NXOXM_NSH_C3(8) since OF1.3 and v2.8. <3> - * OXM: NXOXM_NSH_C4(9) since OF1.3 and v2.8. <4> + * OXM: NXOXM_NSH_C1(7) since OF1.3 and v2.8. <1> + * OXM: NXOXM_NSH_C2(8) since OF1.3 and v2.8. <2> + * OXM: NXOXM_NSH_C3(9) since OF1.3 and v2.8. <3> + * OXM: NXOXM_NSH_C4(10) since OF1.3 and v2.8. <4> */ MFF_NSH_C1, MFF_NSH_C2, diff --git a/include/openvswitch/nsh.h b/include/openvswitch/nsh.h index a3611d0..4b8dbaa 100644 --- a/include/openvswitch/nsh.h +++ b/include/openvswitch/nsh.h @@ -5,41 +5,189 @@ /* * Network Service Header: + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * |Ver|O|C|R|R|R|R|R|R| Length | MD Type | Next Proto | + * |Ver|O|U| TTL | Length |U|U|U|U|MD Type| Next Protocol | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Service Path ID | Service Index | + * | Service Path Identifier (SPI) | Service Index | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | | - * ~ Mandatory/Optional Context Header ~ + * ~ Mandatory/Optional Context Headers ~ * | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * Ver = The version field is used to ensure backward compatibility - * going forward with future NSH updates. It MUST be set to 0x0 - * by the sender, in this first revision of NSH. * - * O = OAM. when set to 0x1 indicates that this packet is an operations - * and management (OAM) packet. The receiving SFF and SFs nodes - * MUST examine the payload and take appropriate action. + * Version: The version field is used to ensure backward compatibility + * going forward with future NSH specification updates. It MUST be set + * to 0x0 by the sender, in this first revision of NSH. Given the + * widespread implementation of existing hardware that uses the first + * nibble after an MPLS label stack for ECMP decision processing, this + * document reserves version 01b and this value MUST NOT be used in + * future versions of the protocol. Please see [RFC7325] for further + * discussion of MPLS-related forwarding requirements. * - * C = context. Indicates that a critical metadata TLV is present. + * O bit: Setting this bit indicates an Operations, Administration, and + * Maintenance (OAM) packet. The actual format and processing of SFC + * OAM packets is outside the scope of this specification (see for + * example [I-D.ietf-sfc-oam-framework] for one approach). * - * Length : total length, in 4-byte words, of NSH including the Base - * Header, the Service Path Header and the optional variable - * TLVs. - * MD Type: indicates the format of NSH beyond the mandatory Base Header - * and the Service Path Header. + * The O bit MUST be set for OAM packets and MUST NOT be set for non-OAM + * packets. The O bit MUST NOT be modified along the SFP. * - * Next Protocol: indicates the protocol type of the original packet. A - * new IANA registry will be created for protocol type. + * SF/SFF/SFC Proxy/Classifier implementations that do not support SFC + * OAM procedures SHOULD discard packets with O bit set, but MAY support + * a configurable parameter to enable forwarding received SFC OAM + * packets unmodified to the next element in the chain. Forwarding OAM + * packets unmodified by SFC elements that do not support SFC OAM + * procedures may be acceptable for a subset of OAM functions, but can + * result in unexpected outcomes for others, thus it is recommended to + * analyze the impact of forwarding an OAM packet for all OAM functions + * prior to enabling this behavior. The configurable parameter MUST be + * disabled by default. * - * Service Path Identifier (SPI): identifies a service path. - * Participating nodes MUST use this identifier for Service - * Function Path selection. + * TTL: Indicates the maximum SFF hops for an SFP. This field is used + * for service plane loop detection. The initial TTL value SHOULD be + * configurable via the control plane; the configured initial value can + * be specific to one or more SFPs. If no initial value is explicitly + * provided, the default initial TTL value of 63 MUST be used. Each SFF + * involved in forwarding an NSH packet MUST decrement the TTL value by + * 1 prior to NSH forwarding lookup. Decrementing by 1 from an incoming + * value of 0 shall result in a TTL value of 63. The packet MUST NOT be + * forwarded if TTL is, after decrement, 0. * - * Service Index (SI): provides location within the SFP. + * All other flag fields, marked U, are unassigned and available for + * future use, see Section 11.2.1. Unassigned bits MUST be set to zero + * upon origination, and MUST be ignored and preserved unmodified by + * other NSH supporting elements. Elements which do not understand the + * meaning of any of these bits MUST NOT modify their actions based on + * those unknown bits. * - * [0] https://tools.ietf.org/html/draft-ietf-sfc-nsh-13 + * Length: The total length, in 4-byte words, of NSH including the Base + * Header, the Service Path Header, the Fixed Length Context Header or + * Variable Length Context Header(s). The length MUST be 0x6 for MD + * Type equal to 0x1, and MUST be 0x2 or greater for MD Type equal to + * 0x2. The length of the NSH header MUST be an integer multiple of 4 + * bytes, thus variable length metadata is always padded out to a + * multiple of 4 bytes. + * + * MD Type: Indicates the format of NSH beyond the mandatory Base Header + * and the Service Path Header. MD Type defines the format of the + * metadata being carried. + * + * 0x0 - This is a reserved value. Implementations SHOULD silently + * discard packets with MD Type 0x0. + * + * 0x1 - This indicates that the format of the header includes a fixed + * length Context Header (see Figure 4 below). + * + * 0x2 - This does not mandate any headers beyond the Base Header and + * Service Path Header, but may contain optional variable length Context + * Header(s). The semantics of the variable length Context Header(s) + * are not defined in this document. The format of the optional + * variable length Context Headers is provided in Section 2.5.1. + * + * 0xF - This value is reserved for experimentation and testing, as per + * [RFC3692]. Implementations not explicitly configured to be part of + * an experiment SHOULD silently discard packets with MD Type 0xF. + * + * Next Protocol: indicates the protocol type of the encapsulated data. + * NSH does not alter the inner payload, and the semantics on the inner + * protocol remain unchanged due to NSH service function chaining. + * Please see the IANA Considerations section below, Section 11.2.5. + * + * This document defines the following Next Protocol values: + * + * 0x1: IPv4 + * 0x2: IPv6 + * 0x3: Ethernet + * 0x4: NSH + * 0x5: MPLS + * 0xFE: Experiment 1 + * 0xFF: Experiment 2 + * + * Packets with Next Protocol values not supported SHOULD be silently + * dropped by default, although an implementation MAY provide a + * configuration parameter to forward them. Additionally, an + * implementation not explicitly configured for a specific experiment + * [RFC3692] SHOULD silently drop packets with Next Protocol values 0xFE + * and 0xFF. + * + * Service Path Identifier (SPI): Identifies a service path. + * Participating nodes MUST use this identifier for Service Function + * Path selection. The initial classifier MUST set the appropriate SPI + * for a given classification result. + * + * Service Index (SI): Provides location within the SFP. The initial + * classifier for a given SFP SHOULD set the SI to 255, however the + * control plane MAY configure the initial value of SI as appropriate + * (i.e., taking into account the length of the service function path). + * The Service Index MUST be decremented by a value of 1 by Service + * Functions or by SFC Proxy nodes after performing required services + * and the new decremented SI value MUST be used in the egress packet's + * NSH. The initial Classifier MUST send the packet to the first SFF in + * the identified SFP for forwarding along an SFP. If re-classification + * occurs, and that re-classification results in a new SPI, the + * (re)classifier is, in effect, the initial classifier for the + * resultant SPI. + * + * The SI is used in conjunction the with Service Path Identifier for + * Service Function Path Selection and for determining the next SFF/SF + * in the path. The SI is also valuable when troubleshooting or + * reporting service paths. Additionally, while the TTL field is the + * main mechanism for service plane loop detection, the SI can also be + * used for detecting service plane loops. + * + * When the Base Header specifies MD Type = 0x1, a Fixed Length Context + * Header (16-bytes) MUST be present immediately following the Service + * Path Header. The value of a Fixed Length Context + * Header that carries no metadata MUST be set to zero. + * + * When the base header specifies MD Type = 0x2, zero or more Variable + * Length Context Headers MAY be added, immediately following the + * Service Path Header (see Figure 5). Therefore, Length = 0x2, + * indicates that only the Base Header followed by the Service Path + * Header are present. The optional Variable Length Context Headers + * MUST be of an integer number of 4-bytes. The base header Length + * field MUST be used to determine the offset to locate the original + * packet or frame for SFC nodes that require access to that + * information. + * + * The format of the optional variable length Context Headers + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Metadata Class | Type |U| Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Variable Metadata | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * Metadata Class (MD Class): Defines the scope of the 'Type' field to + * provide a hierarchical namespace. The IANA Considerations + * Section 11.2.4 defines how the MD Class values can be allocated to + * standards bodies, vendors, and others. + * + * Type: Indicates the explicit type of metadata being carried. The + * definition of the Type is the responsibility of the MD Class owner. + * + * Unassigned bit: One unassigned bit is available for future use. This + * bit MUST NOT be set, and MUST be ignored on receipt. + * + * Length: Indicates the length of the variable metadata, in bytes. In + * case the metadata length is not an integer number of 4-byte words, + * the sender MUST add pad bytes immediately following the last metadata + * byte to extend the metadata to an integer number of 4-byte words. + * The receiver MUST round up the length field to the nearest 4-byte + * word boundary, to locate and process the next field in the packet. + * The receiver MUST access only those bytes in the metadata indicated + * by the length field (i.e., actual number of bytes) and MUST ignore + * the remaining bytes up to the nearest 4-byte word boundary. The + * Length may be 0 or greater. + * + * A value of 0 denotes a Context Header without a Variable Metadata + * field. + * + * [0] https://datatracker.ietf.org/doc/draft-ietf-sfc-nsh/ */ #ifdef __cplusplus @@ -62,7 +210,7 @@ struct nsh_md2_tlv { }; struct nsh_hdr { - ovs_be16 ver_flags_len; + ovs_be16 ver_flags_ttl_len; uint8_t md_type; uint8_t next_proto; ovs_16aligned_be32 path_hdr; @@ -75,11 +223,16 @@ struct nsh_hdr { /* Masking NSH header fields. */ #define NSH_VER_MASK 0xc000 #define NSH_VER_SHIFT 14 -#define NSH_FLAGS_MASK 0x3fc0 -#define NSH_FLAGS_SHIFT 6 +#define NSH_FLAGS_MASK 0x3000 +#define NSH_FLAGS_SHIFT 12 +#define NSH_TTL_MASK 0x0fc0 +#define NSH_TTL_SHIFT 6 #define NSH_LEN_MASK 0x003f #define NSH_LEN_SHIFT 0 +#define NSH_MDTYPE_MASK 0x0f +#define NSH_MDTYPE_SHIFT 0 + #define NSH_SPI_MASK 0xffffff00 #define NSH_SPI_SHIFT 8 #define NSH_SI_MASK 0x000000ff @@ -110,10 +263,14 @@ struct nsh_hdr { /* NSH MD Type 1 header Length. */ #define NSH_M_TYPE1_LEN 24 +/* NSH Context headers Max Length. */ +#define NSH_CTX_HDRS_MAX_LEN 248 + static inline uint16_t nsh_hdr_len(const struct nsh_hdr *nsh) { - return ((ntohs(nsh->ver_flags_len) & NSH_LEN_MASK) >> NSH_LEN_SHIFT) << 2; + return ((ntohs(nsh->ver_flags_ttl_len) & NSH_LEN_MASK) + >> NSH_LEN_SHIFT) << 2; } static inline struct nsh_md1_ctx * @@ -128,6 +285,123 @@ nsh_md2_ctx(struct nsh_hdr *nsh) return &nsh->md2; } +static inline uint8_t +nsh_get_ver(const struct nsh_hdr *nsh) +{ + return (ntohs(nsh->ver_flags_ttl_len) & NSH_VER_MASK) >> NSH_VER_SHIFT; +} + +static inline uint8_t +nsh_get_len(const struct nsh_hdr *nsh) +{ + return (ntohs(nsh->ver_flags_ttl_len) & NSH_LEN_MASK) >> NSH_LEN_SHIFT; +} + +static inline uint8_t +nsh_get_flags(const struct nsh_hdr *nsh) +{ + return (ntohs(nsh->ver_flags_ttl_len) & NSH_FLAGS_MASK) >> NSH_FLAGS_SHIFT; +} + +static inline uint8_t +nsh_get_ttl(const struct nsh_hdr *nsh) +{ + return (ntohs(nsh->ver_flags_ttl_len) & NSH_TTL_MASK) >> NSH_TTL_SHIFT; +} + +static inline ovs_be32 +nsh_16aligned_be32(const ovs_16aligned_be32 *x) +{ +#ifdef WORDS_BIGENDIAN + return ((ovs_be32) x->hi << 16) | x->lo; +#else + return ((ovs_be32) x->lo << 16) | x->hi; +#endif +} + +static inline ovs_be32 +nsh_get_path_hdr(const struct nsh_hdr *nsh) +{ + return nsh_16aligned_be32(&nsh->path_hdr); +} + +static inline ovs_be32 +nsh_get_spi(const struct nsh_hdr *nsh) +{ + ovs_be32 path_hdr = ntohl(nsh_16aligned_be32(&nsh->path_hdr)); + return htonl((path_hdr & NSH_SPI_MASK) >> NSH_SPI_SHIFT); +} + +static inline uint8_t +nsh_get_si(const struct nsh_hdr *nsh) +{ + ovs_be32 path_hdr = ntohl(nsh_16aligned_be32(&nsh->path_hdr)); + return (path_hdr & NSH_SI_MASK) >> NSH_SI_SHIFT; +} + +static inline ovs_be32 +nsh_path_hdr_to_spi(ovs_be32 path_hdr) +{ + return htonl((ntohl(path_hdr) & NSH_SPI_MASK) >> NSH_SPI_SHIFT); +} + +static inline uint32_t +nsh_path_hdr_to_spi_uint32(ovs_be32 path_hdr) +{ + return (ntohl(path_hdr) & NSH_SPI_MASK) >> NSH_SPI_SHIFT; +} + +static inline uint8_t +nsh_path_hdr_to_si(ovs_be32 path_hdr) +{ + return (ntohl(path_hdr) & NSH_SI_MASK) >> NSH_SI_SHIFT; +} + +static inline ovs_be32 +nsh_spi_si_to_path_hdr(uint32_t spi, uint8_t si) +{ + return htonl((spi << NSH_SPI_SHIFT) | si); +} + +static inline void +nsh_set_xflag__(struct nsh_hdr *nsh, uint16_t xflag, uint16_t xmask) +{ + nsh->ver_flags_ttl_len + = (nsh->ver_flags_ttl_len & ~htons(xmask)) | htons(xflag); +} + +static inline void nsh_set_flags_and_ttl(struct nsh_hdr *nsh, uint8_t flags, + uint8_t ttl) +{ + nsh_set_xflag__(nsh, ((flags << NSH_FLAGS_SHIFT) & NSH_FLAGS_MASK) | + ((ttl << NSH_TTL_SHIFT) & NSH_TTL_MASK), + NSH_FLAGS_MASK | NSH_TTL_MASK); +} + +static inline void nsh_set_flags_ttl_len(struct nsh_hdr *nsh, uint8_t flags, + uint8_t ttl, uint8_t len) +{ + len = len >> 2; + nsh_set_xflag__(nsh, ((flags << NSH_FLAGS_SHIFT) & NSH_FLAGS_MASK) | + ((ttl << NSH_TTL_SHIFT) & NSH_TTL_MASK) | + ((len << NSH_LEN_SHIFT) & NSH_LEN_MASK), + NSH_FLAGS_MASK | NSH_TTL_MASK | NSH_LEN_MASK); +} + +static inline void +nsh_path_hdr_set_spi(ovs_be32 *path_hdr, ovs_be32 spi) +{ + *path_hdr = htonl((ntohl(*path_hdr) & ~NSH_SPI_MASK) | + ((ntohl(spi) << NSH_SPI_SHIFT) & NSH_SPI_MASK)); +} + +static inline void +nsh_path_hdr_set_si(ovs_be32 *path_hdr, uint8_t si) +{ + *path_hdr = htonl((ntohl(*path_hdr) & ~NSH_SI_MASK) | + ((si << NSH_SI_SHIFT) & NSH_SI_MASK)); +} + #ifdef __cplusplus } #endif diff --git a/include/openvswitch/packets.h b/include/openvswitch/packets.h index be91e02..603ec44 100644 --- a/include/openvswitch/packets.h +++ b/include/openvswitch/packets.h @@ -73,24 +73,18 @@ union flow_vlan_hdr { }; }; -#ifdef __cplusplus -} -#endif - /* Network Service Header keys */ -struct flow_nsh { +struct ovs_key_nsh { uint8_t flags; + uint8_t ttl; uint8_t mdtype; uint8_t np; - uint8_t si; - ovs_be32 spi; + ovs_be32 path_hdr; ovs_be32 c[4]; }; -/* NSH flags */ -#define FLOW_NSH_F_OAM (1 << 0) -#define FLOW_NSH_F_CTX (1 << 1) - -#define FLOW_NSH_F_MASK ((1 << 2) - 1) +#ifdef __cplusplus +} +#endif #endif /* packets.h */ diff --git a/lib/flow.c b/lib/flow.c index b2b10aa..708aaa5 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -530,53 +530,48 @@ parse_ipv6_ext_hdrs(const void **datap, size_t *sizep, uint8_t *nw_proto, } bool -parse_nsh(const void **datap, size_t *sizep, struct flow_nsh *key) +parse_nsh(const void **datap, size_t *sizep, struct ovs_key_nsh *key) { const struct nsh_hdr *nsh = (const struct nsh_hdr *) *datap; - uint16_t ver_flags_len; - uint8_t version, length, flags; - uint32_t path_hdr; - - /* Check if it is long enough for NSH header, doesn't support - * MD type 2 yet - */ - if (OVS_UNLIKELY(*sizep < NSH_M_TYPE1_LEN)) { + uint8_t version, length, flags, ttl; + + if (OVS_UNLIKELY(*sizep < NSH_BASE_HDR_LEN)) { return false; } - memset(key, 0, sizeof(struct flow_nsh)); - - ver_flags_len = ntohs(nsh->ver_flags_len); - version = (ver_flags_len & NSH_VER_MASK) >> NSH_VER_SHIFT; - flags = (ver_flags_len & NSH_FLAGS_MASK) >> NSH_FLAGS_SHIFT; + version = nsh_get_ver(nsh); + flags = nsh_get_flags(nsh); + ttl = nsh_get_ttl(nsh); - /* NSH header length is in 4 byte words. */ - length = ((ver_flags_len & NSH_LEN_MASK) >> NSH_LEN_SHIFT) << 2; + length = nsh_hdr_len(nsh); if (version != 0) { return false; } - if (length != NSH_M_TYPE1_LEN) { - return false; + if (OVS_UNLIKELY(*sizep < length)) { + return false; } key->flags = flags; + key->ttl = ttl; key->mdtype = nsh->md_type; key->np = nsh->next_proto; - - path_hdr = ntohl(get_16aligned_be32(&nsh->path_hdr)); - key->si = (path_hdr & NSH_SI_MASK) >> NSH_SI_SHIFT; - key->spi = htonl((path_hdr & NSH_SPI_MASK) >> NSH_SPI_SHIFT); + key->path_hdr = get_16aligned_be32(&nsh->path_hdr); switch (key->mdtype) { case NSH_M_TYPE1: + if (length != NSH_M_TYPE1_LEN) { + return false; + } for (size_t i = 0; i < 4; i++) { key->c[i] = get_16aligned_be32(&nsh->md1.c[i]); } break; case NSH_M_TYPE2: - /* Don't support MD type 2 yet, so return false */ + /* Don't support MD type 2 metedata parsing yet */ + memset(key->c, 0, sizeof(key->c)); + break; default: return false; } @@ -876,19 +871,12 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst) miniflow_pad_to_64(mf, arp_tha); } } else if (dl_type == htons(ETH_TYPE_NSH)) { - struct flow_nsh nsh; + struct ovs_key_nsh nsh; if (OVS_LIKELY(parse_nsh(&data, &size, &nsh))) { - if (nsh.mdtype == NSH_M_TYPE1) { - miniflow_push_words(mf, nsh, &nsh, - sizeof(struct flow_nsh) / - sizeof(uint64_t)); - } - else if (nsh.mdtype == NSH_M_TYPE2) { - /* parse_nsh has stopped it from arriving here for - * MD type 2, will add MD type 2 support code here later - */ - } + miniflow_push_words(mf, nsh, &nsh, + sizeof(struct ovs_key_nsh) / + sizeof(uint64_t)); } } goto out; @@ -1688,10 +1676,10 @@ flow_wildcards_init_for_packet(struct flow_wildcards *wc, return; } else if (flow->dl_type == htons(ETH_TYPE_NSH)) { WC_MASK_FIELD(wc, nsh.flags); + WC_MASK_FIELD(wc, nsh.ttl); WC_MASK_FIELD(wc, nsh.mdtype); WC_MASK_FIELD(wc, nsh.np); - WC_MASK_FIELD(wc, nsh.spi); - WC_MASK_FIELD(wc, nsh.si); + WC_MASK_FIELD(wc, nsh.path_hdr); WC_MASK_FIELD(wc, nsh.c); } else { return; /* Unknown ethertype. */ @@ -1822,10 +1810,10 @@ flow_wc_map(const struct flow *flow, struct flowmap *map) FLOWMAP_SET(map, arp_tha); } else if (flow->dl_type == htons(ETH_TYPE_NSH)) { FLOWMAP_SET(map, nsh.flags); + FLOWMAP_SET(map, nsh.ttl); FLOWMAP_SET(map, nsh.mdtype); FLOWMAP_SET(map, nsh.np); - FLOWMAP_SET(map, nsh.spi); - FLOWMAP_SET(map, nsh.si); + FLOWMAP_SET(map, nsh.path_hdr); FLOWMAP_SET(map, nsh.c); } } diff --git a/lib/flow.h b/lib/flow.h index 6ae5a67..42a8426 100644 --- a/lib/flow.h +++ b/lib/flow.h @@ -129,7 +129,7 @@ bool flow_compose(struct dp_packet *, const struct flow *, size_t); bool parse_ipv6_ext_hdrs(const void **datap, size_t *sizep, uint8_t *nw_proto, uint8_t *nw_frag); ovs_be16 parse_dl_type(const struct eth_header *data_, size_t size); -bool parse_nsh(const void **datap, size_t *sizep, struct flow_nsh *key); +bool parse_nsh(const void **datap, size_t *sizep, struct ovs_key_nsh *key); static inline uint64_t flow_get_xreg(const struct flow *flow, int idx) diff --git a/lib/match.c b/lib/match.c index 36c78eb..27540e6 100644 --- a/lib/match.c +++ b/lib/match.c @@ -1017,6 +1017,50 @@ match_set_nd_target_masked(struct match *match, match->wc.masks.nd_target = *mask; } +void +match_set_any_nsh_spi(struct match *match) +{ + match->wc.masks.nsh.path_hdr &= ~htonl(NSH_SPI_MASK); + nsh_path_hdr_set_spi(&match->flow.nsh.path_hdr, htonl(0)); +} + +void +match_set_any_nsh_si(struct match *match) +{ + match->wc.masks.nsh.path_hdr &= ~htonl(NSH_SI_MASK); + nsh_path_hdr_set_si(&match->flow.nsh.path_hdr, 0); +} + +void +match_set_nsh_spi(struct match *match, ovs_be32 value) +{ + match->wc.masks.nsh.path_hdr |= htonl(NSH_SPI_MASK); + nsh_path_hdr_set_spi(&match->flow.nsh.path_hdr, value); +} + +void +match_set_nsh_si(struct match *match, uint8_t value) +{ + match->wc.masks.nsh.path_hdr |= htonl(NSH_SI_MASK); + nsh_path_hdr_set_si(&match->flow.nsh.path_hdr, value); +} + +void +match_set_nsh_spi_masked(struct match *match, ovs_be32 value, ovs_be32 mask) +{ + nsh_path_hdr_set_spi(&match->wc.masks.nsh.path_hdr, + mask); + nsh_path_hdr_set_spi(&match->flow.nsh.path_hdr, value & mask); +} + +void +match_set_nsh_si_masked(struct match *match, uint8_t value, uint8_t mask) +{ + nsh_path_hdr_set_si(&match->wc.masks.nsh.path_hdr, + mask); + nsh_path_hdr_set_si(&match->flow.nsh.path_hdr, value & mask); +} + /* Returns true if 'a' and 'b' wildcard the same fields and have the same * values for fixed fields, otherwise false. */ bool @@ -1260,11 +1304,19 @@ format_ct_label_masked(struct ds *s, const ovs_u128 *key, const ovs_u128 *mask) static void format_nsh_masked(struct ds *s, const struct flow *f, const struct flow *m) { + ovs_be32 spi_mask = nsh_path_hdr_to_spi(m->nsh.path_hdr); + if (spi_mask == htonl(NSH_SPI_MASK >> NSH_SPI_SHIFT)) { + spi_mask = OVS_BE32_MAX; + } format_uint8_masked(s, "nsh_flags", f->nsh.flags, m->nsh.flags); + format_uint8_masked(s, "nsh_ttl", f->nsh.ttl, m->nsh.ttl); format_uint8_masked(s, "nsh_mdtype", f->nsh.mdtype, m->nsh.mdtype); format_uint8_masked(s, "nsh_np", f->nsh.np, m->nsh.np); - format_be32_masked_hex(s, "nsh_spi", f->nsh.spi, m->nsh.spi); - format_uint8_masked(s, "nsh_si", f->nsh.si, m->nsh.si); + + format_be32_masked_hex(s, "nsh_spi", nsh_path_hdr_to_spi(f->nsh.path_hdr), + spi_mask); + format_uint8_masked(s, "nsh_si", nsh_path_hdr_to_si(f->nsh.path_hdr), + nsh_path_hdr_to_si(m->nsh.path_hdr)); if (m->nsh.mdtype == UINT8_MAX && f->nsh.mdtype == NSH_M_TYPE1) { format_be32_masked_hex(s, "nsh_c1", f->nsh.c[0], m->nsh.c[0]); format_be32_masked_hex(s, "nsh_c2", f->nsh.c[1], m->nsh.c[1]); diff --git a/lib/meta-flow.c b/lib/meta-flow.c index 64a8cf1..f309b33 100644 --- a/lib/meta-flow.c +++ b/lib/meta-flow.c @@ -40,6 +40,7 @@ #include "openvswitch/ofp-errors.h" #include "openvswitch/vlog.h" #include "vl-mff-map.h" +#include "openvswitch/nsh.h" VLOG_DEFINE_THIS_MODULE(meta_flow); @@ -361,14 +362,16 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc) case MFF_NSH_FLAGS: return !wc->masks.nsh.flags; + case MFF_NSH_TTL: + return !wc->masks.nsh.ttl; case MFF_NSH_MDTYPE: return !wc->masks.nsh.mdtype; case MFF_NSH_NP: return !wc->masks.nsh.np; case MFF_NSH_SPI: - return !wc->masks.nsh.spi; + return !(wc->masks.nsh.path_hdr & htonl(NSH_SPI_MASK)); case MFF_NSH_SI: - return !wc->masks.nsh.si; + return !(wc->masks.nsh.path_hdr & htonl(NSH_SI_MASK)); case MFF_NSH_C1: case MFF_NSH_C2: case MFF_NSH_C3: @@ -605,13 +608,15 @@ mf_is_value_valid(const struct mf_field *mf, const union mf_value *value) return !(value->be32 & ~htonl(CS_SUPPORTED_MASK)); case MFF_NSH_FLAGS: - return true; + return (value->u8 <= 3); + case MFF_NSH_TTL: + return (value->u8 <= 63); case MFF_NSH_MDTYPE: return (value->u8 == 1 || value->u8 == 2); case MFF_NSH_NP: return true; case MFF_NSH_SPI: - return !(value->be32 & htonl(0xFF000000)); + return !(value->be32 & ~htonl(NSH_SPI_MASK >> NSH_SPI_SHIFT)); case MFF_NSH_SI: case MFF_NSH_C1: case MFF_NSH_C2: @@ -899,6 +904,9 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow, case MFF_NSH_FLAGS: value->u8 = flow->nsh.flags; break; + case MFF_NSH_TTL: + value->u8 = flow->nsh.ttl; + break; case MFF_NSH_MDTYPE: value->u8 = flow->nsh.mdtype; break; @@ -906,10 +914,10 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow, value->u8 = flow->nsh.np; break; case MFF_NSH_SPI: - value->be32 = flow->nsh.spi; + value->be32 = nsh_path_hdr_to_spi(flow->nsh.path_hdr); break; case MFF_NSH_SI: - value->u8 = flow->nsh.si; + value->u8 = nsh_path_hdr_to_si(flow->nsh.path_hdr); break; case MFF_NSH_C1: case MFF_NSH_C2: @@ -1214,6 +1222,9 @@ mf_set_value(const struct mf_field *mf, case MFF_NSH_FLAGS: MATCH_SET_FIELD_UINT8(match, nsh.flags, value->u8); break; + case MFF_NSH_TTL: + MATCH_SET_FIELD_UINT8(match, nsh.ttl, value->u8); + break; case MFF_NSH_MDTYPE: MATCH_SET_FIELD_UINT8(match, nsh.mdtype, value->u8); break; @@ -1221,10 +1232,10 @@ mf_set_value(const struct mf_field *mf, MATCH_SET_FIELD_UINT8(match, nsh.np, value->u8); break; case MFF_NSH_SPI: - MATCH_SET_FIELD_BE32(match, nsh.spi, value->be32); + match_set_nsh_spi(match, value->be32); break; case MFF_NSH_SI: - MATCH_SET_FIELD_UINT8(match, nsh.si, value->u8); + match_set_nsh_si(match, value->u8); break; case MFF_NSH_C1: case MFF_NSH_C2: @@ -1605,6 +1616,9 @@ mf_set_flow_value(const struct mf_field *mf, case MFF_NSH_FLAGS: flow->nsh.flags = value->u8; break; + case MFF_NSH_TTL: + flow->nsh.ttl = value->u8; + break; case MFF_NSH_MDTYPE: flow->nsh.mdtype = value->u8; break; @@ -1612,10 +1626,10 @@ mf_set_flow_value(const struct mf_field *mf, flow->nsh.np = value->u8; break; case MFF_NSH_SPI: - flow->nsh.spi = value->be32; + nsh_path_hdr_set_spi(&flow->nsh.path_hdr, value->be32); break; case MFF_NSH_SI: - flow->nsh.si = value->u8; + nsh_path_hdr_set_si(&flow->nsh.path_hdr, value->u8); break; case MFF_NSH_C1: case MFF_NSH_C2: @@ -1751,6 +1765,7 @@ mf_is_pipeline_field(const struct mf_field *mf) case MFF_ND_SLL: case MFF_ND_TLL: case MFF_NSH_FLAGS: + case MFF_NSH_TTL: case MFF_NSH_MDTYPE: case MFF_NSH_NP: case MFF_NSH_SPI: @@ -2096,6 +2111,9 @@ mf_set_wild(const struct mf_field *mf, struct match *match, char **err_str) case MFF_NSH_FLAGS: MATCH_SET_FIELD_MASKED(match, nsh.flags, 0, 0); break; + case MFF_NSH_TTL: + MATCH_SET_FIELD_MASKED(match, nsh.ttl, 0, 0); + break; case MFF_NSH_MDTYPE: MATCH_SET_FIELD_MASKED(match, nsh.mdtype, 0, 0); break; @@ -2103,10 +2121,10 @@ mf_set_wild(const struct mf_field *mf, struct match *match, char **err_str) MATCH_SET_FIELD_MASKED(match, nsh.np, 0, 0); break; case MFF_NSH_SPI: - MATCH_SET_FIELD_MASKED(match, nsh.spi, htonl(0), htonl(0)); + match_set_any_nsh_spi(match); break; case MFF_NSH_SI: - MATCH_SET_FIELD_MASKED(match, nsh.si, 0, 0); + match_set_any_nsh_si(match); break; case MFF_NSH_C1: case MFF_NSH_C2: @@ -2356,6 +2374,9 @@ mf_set(const struct mf_field *mf, case MFF_NSH_FLAGS: MATCH_SET_FIELD_MASKED(match, nsh.flags, value->u8, mask->u8); break; + case MFF_NSH_TTL: + MATCH_SET_FIELD_MASKED(match, nsh.ttl, value->u8, mask->u8); + break; case MFF_NSH_MDTYPE: MATCH_SET_FIELD_MASKED(match, nsh.mdtype, value->u8, mask->u8); break; @@ -2363,10 +2384,10 @@ mf_set(const struct mf_field *mf, MATCH_SET_FIELD_MASKED(match, nsh.np, value->u8, mask->u8); break; case MFF_NSH_SPI: - MATCH_SET_FIELD_MASKED(match, nsh.spi, value->be32, mask->be32); + match_set_nsh_spi_masked(match, value->be32, mask->be32); break; case MFF_NSH_SI: - MATCH_SET_FIELD_MASKED(match, nsh.si, value->u8, mask->u8); + match_set_nsh_si_masked(match, value->u8, mask->u8); break; case MFF_NSH_C1: case MFF_NSH_C2: diff --git a/lib/meta-flow.xml b/lib/meta-flow.xml index 065fb03..4171b40 100644 --- a/lib/meta-flow.xml +++ b/lib/meta-flow.xml @@ -1311,7 +1311,12 @@ tcp,tp_src=0x07c0/0xfff0 + title="flags field (2 bits)"> + nsh_flags only allows a 2-bit value, i.e. 0-3, high bit is version, + low bit is reserved, currently, version bit must be 0 per NSH spec. + + OFPR_INVALID_TTL ``packet-in'' messages via OpenFlow. - +

Specifies what kinds of IP fragments or non-fragments to match. The diff --git a/lib/nx-match.c b/lib/nx-match.c index b782e8c..7a918d0 100644 --- a/lib/nx-match.c +++ b/lib/nx-match.c @@ -1155,18 +1155,27 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const struct match *match, tun_metadata_to_nx_match(b, oxm, match); /* Network Service Header */ - nxm_put_8m(&ctx, MFF_NSH_FLAGS, oxm, flow->nsh.flags, - match->wc.masks.nsh.flags); - nxm_put_8m(&ctx, MFF_NSH_MDTYPE, oxm, flow->nsh.mdtype, - match->wc.masks.nsh.mdtype); - nxm_put_8m(&ctx, MFF_NSH_NP, oxm, flow->nsh.np, - match->wc.masks.nsh.np); - nxm_put_32m(&ctx, MFF_NSH_SPI, oxm, flow->nsh.spi, - match->wc.masks.nsh.spi); - nxm_put_8m(&ctx, MFF_NSH_SI, oxm, flow->nsh.si, match->wc.masks.nsh.si); - for (int i = 0; i < 4; i++) { - nxm_put_32m(&ctx, MFF_NSH_C1 + i, oxm, flow->nsh.c[i], - match->wc.masks.nsh.c[i]); + if (dl_type == htons(ETH_P_NSH)) { + nxm_put_8m(&ctx, MFF_NSH_FLAGS, oxm, flow->nsh.flags, + match->wc.masks.nsh.flags); + nxm_put_8m(&ctx, MFF_NSH_TTL, oxm, flow->nsh.ttl, + match->wc.masks.nsh.ttl); + nxm_put_8m(&ctx, MFF_NSH_MDTYPE, oxm, flow->nsh.mdtype, + match->wc.masks.nsh.mdtype); + nxm_put_8m(&ctx, MFF_NSH_NP, oxm, flow->nsh.np, + match->wc.masks.nsh.np); + if (match->wc.masks.nsh.path_hdr & htonl(NSH_SPI_MASK)) { + nxm_put_32m(&ctx, MFF_NSH_SPI, oxm, + nsh_path_hdr_to_spi(flow->nsh.path_hdr), + OVS_BE32_MAX); + } + nxm_put_8m(&ctx, MFF_NSH_SI, oxm, + nsh_path_hdr_to_si(flow->nsh.path_hdr), + nsh_path_hdr_to_si(match->wc.masks.nsh.path_hdr)); + for (int i = 0; i < 4; i++) { + nxm_put_32m(&ctx, MFF_NSH_C1 + i, oxm, flow->nsh.c[i], + match->wc.masks.nsh.c[i]); + } } /* Registers. */ diff --git a/lib/odp-execute.c b/lib/odp-execute.c index 5f4d23a..6561a39 100644 --- a/lib/odp-execute.c +++ b/lib/odp-execute.c @@ -277,10 +277,10 @@ odp_set_nsh(struct dp_packet *packet, const struct ovs_key_nsh *key, const struct ovs_key_nsh *mask) { struct nsh_hdr *nsh = dp_packet_l3(packet); + ovs_be32 path_hdr; if (!mask) { - nsh->ver_flags_len = htons(key->flags << NSH_FLAGS_SHIFT) | - (nsh->ver_flags_len & ~htons(NSH_FLAGS_MASK)); + nsh_set_flags_and_ttl(nsh, key->flags, key->ttl); put_16aligned_be32(&nsh->path_hdr, key->path_hdr); switch (nsh->md_type) { case NSH_M_TYPE1: @@ -294,15 +294,17 @@ odp_set_nsh(struct dp_packet *packet, const struct ovs_key_nsh *key, break; } } else { - uint8_t flags = (ntohs(nsh->ver_flags_len) & NSH_FLAGS_MASK) >> - NSH_FLAGS_SHIFT; + uint8_t flags = nsh_get_flags(nsh); + uint8_t ttl = nsh_get_ttl(nsh); + flags = key->flags | (flags & ~mask->flags); - nsh->ver_flags_len = htons(flags << NSH_FLAGS_SHIFT) | - (nsh->ver_flags_len & ~htons(NSH_FLAGS_MASK)); + ttl = key->ttl | (ttl & ~mask->ttl); + nsh_set_flags_and_ttl (nsh, flags, ttl); - ovs_be32 path_hdr = get_16aligned_be32(&nsh->path_hdr); + path_hdr = nsh_get_path_hdr(nsh); path_hdr = key->path_hdr | (path_hdr & ~mask->path_hdr); put_16aligned_be32(&nsh->path_hdr, path_hdr); + switch (nsh->md_type) { case NSH_M_TYPE1: for (int i = 0; i < 4; i++) { diff --git a/lib/odp-util.c b/lib/odp-util.c index 4f1499e..244a8dc 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -254,12 +254,13 @@ static void format_nsh_key(struct ds *ds, const struct ovs_key_nsh *key) { ds_put_format(ds, "flags=%d", key->flags); + ds_put_format(ds, ",ttl=%d", key->ttl); ds_put_format(ds, ",mdtype=%d", key->mdtype); ds_put_format(ds, ",np=%d", key->np); ds_put_format(ds, ",spi=0x%x", - (ntohl(key->path_hdr) & NSH_SPI_MASK) >> NSH_SPI_SHIFT); + nsh_path_hdr_to_spi_uint32(key->path_hdr)); ds_put_format(ds, ",si=%d", - (ntohl(key->path_hdr) & NSH_SI_MASK) >> NSH_SI_SHIFT); + nsh_path_hdr_to_si(key->path_hdr)); switch (key->mdtype) { case NSH_M_TYPE1: @@ -319,17 +320,16 @@ format_nsh_key_mask(struct ds *ds, const struct ovs_key_nsh *key, format_nsh_key(ds, key); } else { bool first = true; - uint32_t spi = (ntohl(key->path_hdr) & NSH_SPI_MASK) >> NSH_SPI_SHIFT; - uint32_t spi_mask = (ntohl(mask->path_hdr) & NSH_SPI_MASK) >> - NSH_SPI_SHIFT; - if (spi_mask == 0x00ffffff) { + uint32_t spi = nsh_path_hdr_to_spi_uint32(key->path_hdr); + uint32_t spi_mask = nsh_path_hdr_to_spi_uint32(mask->path_hdr); + if (spi_mask == (NSH_SPI_MASK >> NSH_SPI_SHIFT)) { spi_mask = UINT32_MAX; } - uint8_t si = (ntohl(key->path_hdr) & NSH_SI_MASK) >> NSH_SI_SHIFT; - uint8_t si_mask = (ntohl(mask->path_hdr) & NSH_SI_MASK) >> - NSH_SI_SHIFT; + uint8_t si = nsh_path_hdr_to_si(key->path_hdr); + uint8_t si_mask = nsh_path_hdr_to_si(mask->path_hdr); format_uint8_masked(ds, &first, "flags", key->flags, mask->flags); + format_uint8_masked(ds, &first, "ttl", key->ttl, mask->ttl); format_uint8_masked(ds, &first, "mdtype", key->mdtype, mask->mdtype); format_uint8_masked(ds, &first, "np", key->np, mask->np); format_be32_masked(ds, &first, "spi", htonl(spi), htonl(spi_mask)); @@ -345,12 +345,12 @@ static void format_odp_encap_nsh_action(struct ds *ds, const struct ovs_action_encap_nsh *encap_nsh) { - uint32_t path_hdr = ntohl(encap_nsh->path_hdr); - uint32_t spi = (path_hdr & NSH_SPI_MASK) >> NSH_SPI_SHIFT; - uint8_t si = (path_hdr & NSH_SI_MASK) >> NSH_SI_SHIFT; + uint32_t spi = nsh_path_hdr_to_spi_uint32(encap_nsh->path_hdr); + uint8_t si = nsh_path_hdr_to_si(encap_nsh->path_hdr); ds_put_cstr(ds, "encap_nsh("); ds_put_format(ds, "flags=%d", encap_nsh->flags); + ds_put_format(ds, ",ttl=%d", encap_nsh->ttl); ds_put_format(ds, ",mdtype=%d", encap_nsh->mdtype); ds_put_format(ds, ",np=%d", encap_nsh->np); ds_put_format(ds, ",spi=0x%x", spi); @@ -1785,7 +1785,8 @@ parse_odp_encap_nsh_action(const char *s, struct ofpbuf *actions) { int n = 0; int ret = 0; - struct ovs_action_encap_nsh encap_nsh; + struct ovs_action_encap_nsh *encap_nsh + = xmalloc(sizeof *encap_nsh + NSH_CTX_HDRS_MAX_LEN); uint32_t spi; uint8_t si; uint32_t cd; @@ -1796,11 +1797,12 @@ parse_odp_encap_nsh_action(const char *s, struct ofpbuf *actions) } /* The default is NSH_M_TYPE1 */ - encap_nsh.flags = 0; - encap_nsh.mdtype = NSH_M_TYPE1; - encap_nsh.mdlen = NSH_M_TYPE1_MDLEN; - encap_nsh.path_hdr = htonl(255); - memset(encap_nsh.metadata, 0, NSH_M_TYPE1_MDLEN); + encap_nsh->flags = 0; + encap_nsh->ttl = 63; + encap_nsh->mdtype = NSH_M_TYPE1; + encap_nsh->path_hdr = htonl(255); + encap_nsh->mdlen = NSH_M_TYPE1_MDLEN; + memset(encap_nsh->metadata, 0, NSH_M_TYPE1_MDLEN); for (;;) { n += strspn(s + n, delimiters); @@ -1808,17 +1810,28 @@ parse_odp_encap_nsh_action(const char *s, struct ofpbuf *actions) break; } - if (ovs_scan_len(s, &n, "flags=%"SCNi8, &encap_nsh.flags)) { + if (ovs_scan_len(s, &n, "flags=%"SCNi8, &encap_nsh->flags)) { + if (encap_nsh->flags > 3) { + ret = -EINVAL; + goto out; + } continue; } - if (ovs_scan_len(s, &n, "mdtype=%"SCNi8, &encap_nsh.mdtype)) { - switch (encap_nsh.mdtype) { + if (ovs_scan_len(s, &n, "ttl=%"SCNi8, &encap_nsh->ttl)) { + if (encap_nsh->ttl > 63) { + ret = -EINVAL; + goto out; + } + continue; + } + if (ovs_scan_len(s, &n, "mdtype=%"SCNi8, &encap_nsh->mdtype)) { + switch (encap_nsh->mdtype) { case NSH_M_TYPE1: /* This is the default format. */; break; case NSH_M_TYPE2: /* Length will be updated later. */ - encap_nsh.mdlen = 0; + encap_nsh->mdlen = 0; break; default: ret = -EINVAL; @@ -1826,24 +1839,24 @@ parse_odp_encap_nsh_action(const char *s, struct ofpbuf *actions) } continue; } - if (ovs_scan_len(s, &n, "np=%"SCNi8, &encap_nsh.np)) { + if (ovs_scan_len(s, &n, "np=%"SCNi8, &encap_nsh->np)) { continue; } if (ovs_scan_len(s, &n, "spi=0x%"SCNx32, &spi)) { - encap_nsh.path_hdr = - htonl(((spi << NSH_SPI_SHIFT) & NSH_SPI_MASK) | - (ntohl(encap_nsh.path_hdr) & ~NSH_SPI_MASK)); + if ((spi & (NSH_SPI_MASK >> NSH_SPI_SHIFT)) != spi) { + ret = -EINVAL; + goto out; + } + nsh_path_hdr_set_spi(&encap_nsh->path_hdr, htonl(spi)); continue; } if (ovs_scan_len(s, &n, "si=%"SCNi8, &si)) { - encap_nsh.path_hdr = - htonl((si << NSH_SI_SHIFT) | - (ntohl(encap_nsh.path_hdr) & ~NSH_SI_MASK)); + nsh_path_hdr_set_si(&encap_nsh->path_hdr, si); continue; } - if (encap_nsh.mdtype == NSH_M_TYPE1) { + if (encap_nsh->mdtype == NSH_M_TYPE1) { struct nsh_md1_ctx *md1 = - ALIGNED_CAST(struct nsh_md1_ctx *, encap_nsh.metadata); + ALIGNED_CAST(struct nsh_md1_ctx *, encap_nsh->metadata); if (ovs_scan_len(s, &n, "c1=0x%"SCNx32, &cd)) { put_16aligned_be32(&md1->c[0], htonl(cd)); continue; @@ -1861,28 +1874,34 @@ parse_odp_encap_nsh_action(const char *s, struct ofpbuf *actions) continue; } } - else if (encap_nsh.mdtype == NSH_M_TYPE2) { + else if (encap_nsh->mdtype == NSH_M_TYPE2) { struct ofpbuf b; char buf[512]; size_t mdlen; if (ovs_scan_len(s, &n, "md2=0x%511[0-9a-fA-F]", buf)) { - ofpbuf_use_stub(&b, encap_nsh.metadata, - OVS_ENCAP_NSH_MAX_MD_LEN); + ofpbuf_use_stub(&b, encap_nsh->metadata, + NSH_CTX_HDRS_MAX_LEN); ofpbuf_put_hex(&b, buf, &mdlen); - encap_nsh.mdlen = mdlen; + encap_nsh->mdlen = mdlen; ofpbuf_uninit(&b); } continue; } } out: + free(encap_nsh); if (ret < 0) { return ret; } else { size_t size = offsetof(struct ovs_action_encap_nsh, metadata) - + ROUND_UP(encap_nsh.mdlen, 4); + + ROUND_UP(encap_nsh->mdlen, 4); + if (encap_nsh->mdlen % 4 != 0) { + size_t padding = ROUND_UP(encap_nsh->mdlen, 4) - + encap_nsh->mdlen; + memset(encap_nsh->metadata + encap_nsh->mdlen, 0, padding); + } nl_msg_put_unspec(actions, OVS_ACTION_ATTR_ENCAP_NSH, - &encap_nsh, size); + encap_nsh, size); return n; } } @@ -6613,26 +6632,10 @@ commit_set_nw_action(const struct flow *flow, struct flow *base, static void get_nsh_key(const struct flow *flow, struct ovs_key_nsh *nsh, bool is_mask) { - nsh->flags = flow->nsh.flags; - nsh->mdtype = flow->nsh.mdtype; - nsh->np = flow->nsh.np; - nsh->path_hdr = htonl((ntohl(flow->nsh.spi) << NSH_SPI_SHIFT) | - flow->nsh.si); - if (is_mask) { - for (int i = 0; i < 4; i++) { - nsh->c[i] = flow->nsh.c[i]; - } - } else { - switch (nsh->mdtype) { - case NSH_M_TYPE1: - for (int i = 0; i < 4; i++) { - nsh->c[i] = flow->nsh.c[i]; - } - break; - case NSH_M_TYPE2: - default: - /* No match support for other MD formats yet. */ - break; + memcpy(nsh, &flow->nsh, sizeof(*nsh)); + if (!is_mask) { + if (nsh->mdtype != NSH_M_TYPE1) { + memset(nsh, 0, sizeof(nsh->c)); } } } @@ -6641,23 +6644,9 @@ static void put_nsh_key(const struct ovs_key_nsh *nsh, struct flow *flow, bool is_mask OVS_UNUSED) { - flow->nsh.flags = nsh->flags; - flow->nsh.mdtype = nsh->mdtype; - flow->nsh.np = nsh->np; - flow->nsh.spi = htonl((ntohl(nsh->path_hdr) & NSH_SPI_MASK) >> - NSH_SPI_SHIFT); - flow->nsh.si = (ntohl(nsh->path_hdr) & NSH_SI_MASK) >> NSH_SI_SHIFT; - switch (nsh->mdtype) { - case NSH_M_TYPE1: - for (int i = 0; i < 4; i++) { - flow->nsh.c[i] = nsh->c[i]; - } - break; - case NSH_M_TYPE2: - default: - /* No match support for other MD formats yet. */ - memset(flow->nsh.c, 0, sizeof flow->nsh.c); - break; + memcpy(&flow->nsh, nsh, sizeof(*nsh)); + if (flow->nsh.mdtype != NSH_M_TYPE1) { + memset(flow->nsh.c, 0, sizeof(flow->nsh.c)); } } @@ -6798,39 +6787,39 @@ odp_put_encap_nsh_action(struct ofpbuf *odp_actions, const struct flow *flow, struct ofpbuf *encap_data) { - struct ovs_action_encap_nsh encap_nsh; + struct ovs_action_encap_nsh *encap_nsh + = xmalloc(sizeof *encap_nsh + NSH_CTX_HDRS_MAX_LEN); - encap_nsh.flags = flow->nsh.flags; - encap_nsh.mdtype = flow->nsh.mdtype; - encap_nsh.np = flow->nsh.np; - encap_nsh.path_hdr = htonl((ntohl(flow->nsh.spi) << NSH_SPI_SHIFT) | - flow->nsh.si); + encap_nsh->flags = flow->nsh.flags; + encap_nsh->ttl = flow->nsh.ttl; + encap_nsh->mdtype = flow->nsh.mdtype; + encap_nsh->np = flow->nsh.np; + encap_nsh->path_hdr = flow->nsh.path_hdr; - switch (encap_nsh.mdtype) { + switch (encap_nsh->mdtype) { case NSH_M_TYPE1: { struct nsh_md1_ctx *md1 = - ALIGNED_CAST(struct nsh_md1_ctx *, encap_nsh.metadata); - encap_nsh.mdlen = NSH_M_TYPE1_MDLEN; - for (int i = 0; i < 4; i++) { - put_16aligned_be32(&md1->c[i], flow->nsh.c[i]); - } + ALIGNED_CAST(struct nsh_md1_ctx *, encap_nsh->metadata); + encap_nsh->mdlen = NSH_M_TYPE1_MDLEN; + memcpy(md1, flow->nsh.c, sizeof(*md1)); break; } case NSH_M_TYPE2: if (encap_data) { - ovs_assert(encap_data->size < OVS_ENCAP_NSH_MAX_MD_LEN); - encap_nsh.mdlen = encap_data->size; - memcpy(encap_nsh.metadata, encap_data->data, encap_data->size); + ovs_assert(encap_data->size <= NSH_CTX_HDRS_MAX_LEN); + encap_nsh->mdlen = encap_data->size; + memcpy(encap_nsh->metadata, encap_data->data, encap_data->size); } else { - encap_nsh.mdlen = 0; + encap_nsh->mdlen = 0; } break; default: - encap_nsh.mdlen = 0; + encap_nsh->mdlen = 0; break; } nl_msg_put_unspec(odp_actions, OVS_ACTION_ATTR_ENCAP_NSH, - &encap_nsh, sizeof(encap_nsh)); + encap_nsh, sizeof(*encap_nsh) + encap_nsh->mdlen); + free(encap_nsh); } static void diff --git a/lib/packets.c b/lib/packets.c index 74d87ed..80dadf9 100644 --- a/lib/packets.c +++ b/lib/packets.c @@ -427,10 +427,11 @@ encap_nsh(struct dp_packet *packet, const struct ovs_action_encap_nsh *encap) } nsh = (struct nsh_hdr *) dp_packet_push_uninit(packet, length); - nsh->ver_flags_len = htons(encap->flags << NSH_FLAGS_SHIFT | length >> 2); + nsh->ver_flags_ttl_len = 0; + nsh_set_flags_ttl_len(nsh, encap->flags, encap->ttl, length); + nsh->md_type = encap->mdtype & NSH_MDTYPE_MASK; nsh->next_proto = next_proto; put_16aligned_be32(&nsh->path_hdr, encap->path_hdr); - nsh->md_type = encap->mdtype; switch (nsh->md_type) { case NSH_M_TYPE1: nsh->md1 = *ALIGNED_CAST(struct nsh_md1_ctx *, encap->metadata); diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index 9e1f837..933256e 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -5807,7 +5807,7 @@ rewrite_flow_encap_nsh(struct xlate_ctx *ctx, { ovs_be32 packet_type = flow->packet_type; const char *ptr = (char *) encap->props; - struct ofpbuf *buf = ofpbuf_new(OVS_ENCAP_NSH_MAX_MD_LEN); + struct ofpbuf *buf = ofpbuf_new(NSH_CTX_HDRS_MAX_LEN); uint8_t md_type = NSH_M_TYPE1; uint8_t np = 0; int i; @@ -5847,7 +5847,7 @@ rewrite_flow_encap_nsh(struct xlate_ctx *ctx, } ptr += ROUND_UP(prop_ptr->len, 8); } - if (buf->size == 0 || buf->size > OVS_ENCAP_NSH_MAX_MD_LEN) { + if (buf->size == 0 || buf->size > NSH_CTX_HDRS_MAX_LEN) { ofpbuf_delete(buf); buf = NULL; } @@ -5885,10 +5885,10 @@ rewrite_flow_encap_nsh(struct xlate_ctx *ctx, /* Populate the flow with the new NSH header. */ flow->packet_type = htonl(PT_NSH); flow->dl_type = htons(ETH_TYPE_NSH); - flow->nsh.flags = 0; /* */ + flow->nsh.flags = 0; + flow->nsh.ttl = 63; flow->nsh.np = np; - flow->nsh.spi = 0; - flow->nsh.si = 255; + nsh_path_hdr_set_si(&flow->nsh.path_hdr, 255); if (md_type == NSH_M_TYPE1) { flow->nsh.mdtype = NSH_M_TYPE1; diff --git a/tests/nsh.at b/tests/nsh.at index aa80a2a..93d8b42 100644 --- a/tests/nsh.at +++ b/tests/nsh.at @@ -13,7 +13,7 @@ OVS_VSWITCHD_START([dnl add-port br0 p2 -- set Interface p2 type=dummy ofport_request=2]) AT_DATA([flows.txt], [dnl - table=0,in_port=1,dl_type=0x894f,nsh_mdtype=1,nsh_np=3,nsh_spi=0x123456,nsh_si=255,nsh_c1=0x11223344,actions=set_field:0x80->nsh_flags,set_field:254->nsh_si,set_field:0x44332211->nsh_c1,2 + table=0,in_port=1,dl_type=0x894f,nsh_ttl=63,nsh_mdtype=1,nsh_np=3,nsh_spi=0x123456,nsh_si=255,nsh_c1=0x11223344,actions=set_field:0x2->nsh_flags,set_field:254->nsh_si,set_field:0x44332211->nsh_c1,2 ]) AT_CHECK([ @@ -21,25 +21,25 @@ AT_CHECK([ ovs-ofctl -Oopenflow13 add-flows br0 flows.txt ovs-ofctl -Oopenflow13 dump-flows br0 | ofctl_strip | sort | grep actions ], [0], [dnl - in_port=1,dl_type=0x894f,nsh_mdtype=1,nsh_np=3,nsh_spi=0x123456,nsh_si=255,nsh_c1=0x11223344 actions=set_field:128->nsh_flags,set_field:254->nsh_si,set_field:0x44332211->nsh_c1,output:2 + in_port=1,dl_type=0x894f,nsh_ttl=63,nsh_mdtype=1,nsh_np=3,nsh_spi=0x123456,nsh_si=255,nsh_c1=0x11223344 actions=set_field:2->nsh_flags,set_field:254->nsh_si,set_field:0x44332211->nsh_c1,output:2 ]) AT_CHECK([ - ovs-appctl ofproto/trace br0 'in_port=1,dl_type=0x894f,nsh_mdtype=1,nsh_np=3,nsh_spi=0x123456,nsh_si=255,nsh_c1=0x11223344,nsh_c2=0x55667788,nsh_c3=0x99aabbcc,nsh_c4=0xddeeff00' + ovs-appctl ofproto/trace br0 'in_port=1,dl_type=0x894f,nsh_ttl=63,nsh_mdtype=1,nsh_np=3,nsh_spi=0x123456,nsh_si=255,nsh_c1=0x11223344,nsh_c2=0x55667788,nsh_c3=0x99aabbcc,nsh_c4=0xddeeff00' ], [0], [dnl -Flow: in_port=1,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x894f,nsh_flags=0,nsh_mdtype=1,nsh_np=3,nsh_spi=0x123456,nsh_si=255,nsh_c1=0x11223344,nsh_c2=0x55667788,nsh_c3=0x99aabbcc,nsh_c4=0xddeeff00,nw_proto=0,nw_tos=0,nw_ecn=0,nw_ttl=0 +Flow: in_port=1,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x894f,nsh_flags=0,nsh_ttl=63,nsh_mdtype=1,nsh_np=3,nsh_spi=0x123456,nsh_si=255,nsh_c1=0x11223344,nsh_c2=0x55667788,nsh_c3=0x99aabbcc,nsh_c4=0xddeeff00,nw_proto=0,nw_tos=0,nw_ecn=0,nw_ttl=0 bridge("br0") ------------- - 0. in_port=1,dl_type=0x894f,nsh_mdtype=1,nsh_np=3,nsh_spi=0x123456,nsh_si=255,nsh_c1=0x11223344, priority 32768 - set_field:128->nsh_flags + 0. in_port=1,dl_type=0x894f,nsh_ttl=63,nsh_mdtype=1,nsh_np=3,nsh_spi=0x123456,nsh_si=255,nsh_c1=0x11223344, priority 32768 + set_field:2->nsh_flags set_field:254->nsh_si set_field:0x44332211->nsh_c1 output:2 -Final flow: in_port=1,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x894f,nsh_flags=128,nsh_mdtype=1,nsh_np=3,nsh_spi=0x123456,nsh_si=254,nsh_c1=0x44332211,nsh_c2=0x55667788,nsh_c3=0x99aabbcc,nsh_c4=0xddeeff00,nw_proto=0,nw_tos=0,nw_ecn=0,nw_ttl=0 -Megaflow: recirc_id=0,eth,in_port=1,dl_type=0x894f,nsh_flags=0,nsh_mdtype=1,nsh_np=3,nsh_spi=0x123456,nsh_si=255,nsh_c1=0x11223344 -Datapath actions: set(nsh(flags=128,spi=0x123456,si=254,c1=0x44332211)),2 +Final flow: in_port=1,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x894f,nsh_flags=2,nsh_ttl=63,nsh_mdtype=1,nsh_np=3,nsh_spi=0x123456,nsh_si=254,nsh_c1=0x44332211,nsh_c2=0x55667788,nsh_c3=0x99aabbcc,nsh_c4=0xddeeff00,nw_proto=0,nw_tos=0,nw_ecn=0,nw_ttl=0 +Megaflow: recirc_id=0,eth,in_port=1,dl_type=0x894f,nsh_flags=0,nsh_ttl=63,nsh_mdtype=1,nsh_np=3,nsh_spi=0x123456,nsh_si=255,nsh_c1=0x11223344 +Datapath actions: set(nsh(flags=2,ttl=63,spi=0x123456,si=254,c1=0x44332211)),2 ]) OVS_VSWITCHD_STOP @@ -103,15 +103,15 @@ bridge("br0") decap() decap() -Final flow: in_port=1,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=11:22:33:44:55:66,dl_type=0x894f,nsh_flags=0,nsh_mdtype=1,nsh_np=3,nsh_spi=0x1234,nsh_si=255,nsh_c1=0x11223344,nsh_c2=0x0,nsh_c3=0x0,nsh_c4=0x0,nw_proto=0,nw_tos=0,nw_ecn=0,nw_ttl=0 +Final flow: in_port=1,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=11:22:33:44:55:66,dl_type=0x894f,nsh_flags=0,nsh_ttl=63,nsh_mdtype=1,nsh_np=3,nsh_spi=0x1234,nsh_si=255,nsh_c1=0x11223344,nsh_c2=0x0,nsh_c3=0x0,nsh_c4=0x0,nw_proto=0,nw_tos=0,nw_ecn=0,nw_ttl=0 Megaflow: recirc_id=0,eth,ip,in_port=1,dl_dst=66:77:88:99:aa:bb,nw_frag=no -Datapath actions: encap_nsh(flags=0,mdtype=1,np=3,spi=0x1234,si=255,c1=0x11223344,c2=0x0,c3=0x0,c4=0x0),push_eth(src=00:00:00:00:00:00,dst=11:22:33:44:55:66),pop_eth,decap_nsh(),set(eth(dst=11:22:33:44:55:66)),recirc(0x1) +Datapath actions: encap_nsh(flags=0,ttl=63,mdtype=1,np=3,spi=0x1234,si=255,c1=0x11223344,c2=0x0,c3=0x0,c4=0x0),push_eth(src=00:00:00:00:00:00,dst=11:22:33:44:55:66),pop_eth,decap_nsh(),set(eth(dst=11:22:33:44:55:66)),recirc(0x1) ]) AT_CHECK([ ovs-appctl ofproto/trace br0 'in_port=4,dl_type=0x894f,nsh_mdtype=1,nsh_np=3,nsh_spi=0x1234,nsh_c1=0x11223344' ], [0], [dnl -Flow: in_port=4,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x894f,nsh_flags=0,nsh_mdtype=1,nsh_np=3,nsh_spi=0x1234,nsh_si=0,nsh_c1=0x11223344,nsh_c2=0x0,nsh_c3=0x0,nsh_c4=0x0,nw_proto=0,nw_tos=0,nw_ecn=0,nw_ttl=0 +Flow: in_port=4,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x894f,nsh_flags=0,nsh_ttl=0,nsh_mdtype=1,nsh_np=3,nsh_spi=0x1234,nsh_si=0,nsh_c1=0x11223344,nsh_c2=0x0,nsh_c3=0x0,nsh_c4=0x0,nw_proto=0,nw_tos=0,nw_ecn=0,nw_ttl=0 bridge("br0") ------------- @@ -139,7 +139,7 @@ ovs-appctl time/warp 1000 AT_CHECK([ ovs-appctl dpctl/dump-flows dummy@ovs-dummy | strip_used | grep -v ipv6 | sort ], [0], [flow-dump from non-dpdk interfaces: -recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(dst=1e:2c:e9:2a:66:9e),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:encap_nsh(flags=0,mdtype=1,np=3,spi=0x1234,si=255,c1=0x11223344,c2=0x0,c3=0x0,c4=0x0),push_eth(src=00:00:00:00:00:00,dst=11:22:33:44:55:66),pop_eth,decap_nsh(),set(eth(dst=11:22:33:44:55:66)),recirc(0x3) +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(dst=1e:2c:e9:2a:66:9e),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:encap_nsh(flags=0,ttl=63,mdtype=1,np=3,spi=0x1234,si=255,c1=0x11223344,c2=0x0,c3=0x0,c4=0x0),push_eth(src=00:00:00:00:00:00,dst=11:22:33:44:55:66),pop_eth,decap_nsh(),set(eth(dst=11:22:33:44:55:66)),recirc(0x3) recirc_id(0x3),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:2 ]) @@ -170,7 +170,7 @@ ovs-appctl time/warp 1000 AT_CHECK([ ovs-appctl dpctl/dump-flows dummy@ovs-dummy | strip_used | grep -v ipv6 | sort ], [0], [flow-dump from non-dpdk interfaces: -recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:push_vlan(vid=100,pcp=0),encap_nsh(flags=0,mdtype=1,np=3,spi=0x0,si=255,c1=0x0,c2=0x0,c3=0x0,c4=0x0),decap_nsh(),recirc(0x4) +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:push_vlan(vid=100,pcp=0),encap_nsh(flags=0,ttl=63,mdtype=1,np=3,spi=0x0,si=255,c1=0x0,c2=0x0,c3=0x0,c4=0x0),decap_nsh(),recirc(0x4) recirc_id(0x4),in_port(1),packet_type(ns=0,id=0),eth_type(0x8100),vlan(vid=100,pcp=0),encap(eth_type(0x0800),ipv4(frag=no)), packets:1, bytes:102, used:0.0s, actions:2 ]) @@ -195,7 +195,7 @@ ovs-vsctl set bridge br0 datapath_type=dummy \ add-port br0 v4 -- set Interface v4 type=patch options:peer=v3 ofport_request=4]) AT_DATA([flows.txt], [dnl - table=0,in_port=1,ip,actions=encap(nsh(md_type=2,tlv(0x1000,10,0x12345678))),set_field:0x1234->nsh_spi,encap(ethernet),set_field:11:22:33:44:55:66->dl_dst,3 + table=0,in_port=1,ip,actions=encap(nsh(md_type=2,tlv(0x1000,10,0x12345678),tlv(0x2000,20,0xfedcba9876543210))),set_field:0x1234->nsh_spi,encap(ethernet),set_field:11:22:33:44:55:66->dl_dst,3 table=0,in_port=4,dl_type=0x894f,nsh_mdtype=2,nsh_spi=0x1234,actions=decap(),decap(),2 ]) @@ -205,7 +205,7 @@ AT_CHECK([ ovs-ofctl -Oopenflow13 dump-flows br0 | ofctl_strip | sort | grep actions ], [0], [dnl in_port=4,dl_type=0x894f,nsh_mdtype=2,nsh_spi=0x1234 actions=decap(),decap(),output:2 - ip,in_port=1 actions=encap(nsh(md_type=2,tlv(0x1000,10,0x12345678))),set_field:0x1234->nsh_spi,encap(ethernet),set_field:11:22:33:44:55:66->eth_dst,output:3 + ip,in_port=1 actions=encap(nsh(md_type=2,tlv(0x1000,10,0x12345678),tlv(0x2000,20,0xfedcba9876543210))),set_field:0x1234->nsh_spi,encap(ethernet),set_field:11:22:33:44:55:66->eth_dst,output:3 ]) AT_CHECK([ @@ -216,7 +216,7 @@ Flow: icmp,in_port=1,vlan_tci=0x0000,dl_src=00:11:22:33:44:55,dl_dst=66:77:88:99 bridge("br0") ------------- 0. ip,in_port=1, priority 32768 - encap(nsh(md_type=2,tlv(0x1000,10,0x12345678))) + encap(nsh(md_type=2,tlv(0x1000,10,0x12345678),tlv(0x2000,20,0xfedcba9876543210))) set_field:0x1234->nsh_spi encap(ethernet) set_field:11:22:33:44:55:66->eth_dst @@ -228,15 +228,15 @@ bridge("br0") decap() decap() -Final flow: in_port=1,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=11:22:33:44:55:66,dl_type=0x894f,nsh_flags=0,nsh_mdtype=2,nsh_np=3,nsh_spi=0x1234,nsh_si=255,nw_proto=0,nw_tos=0,nw_ecn=0,nw_ttl=0 +Final flow: in_port=1,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=11:22:33:44:55:66,dl_type=0x894f,nsh_flags=0,nsh_ttl=63,nsh_mdtype=2,nsh_np=3,nsh_spi=0x1234,nsh_si=255,nw_proto=0,nw_tos=0,nw_ecn=0,nw_ttl=0 Megaflow: recirc_id=0,eth,ip,in_port=1,dl_dst=66:77:88:99:aa:bb,nw_frag=no -Datapath actions: encap_nsh(flags=0,mdtype=2,np=3,spi=0x1234,si=255,md2=0x10000a0412345678),push_eth(src=00:00:00:00:00:00,dst=11:22:33:44:55:66),pop_eth,decap_nsh(),set(eth(dst=11:22:33:44:55:66)),recirc(0x1) +Datapath actions: encap_nsh(flags=0,ttl=63,mdtype=2,np=3,spi=0x1234,si=255,md2=0x10000a041234567820001408fedcba9876543210),push_eth(src=00:00:00:00:00:00,dst=11:22:33:44:55:66),pop_eth,decap_nsh(),set(eth(dst=11:22:33:44:55:66)),recirc(0x1) ]) AT_CHECK([ ovs-appctl ofproto/trace br0 'in_port=4,dl_type=0x894f,nsh_mdtype=2,nsh_np=3,nsh_spi=0x1234' ], [0], [dnl -Flow: in_port=4,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x894f,nsh_flags=0,nsh_mdtype=2,nsh_np=3,nsh_spi=0x1234,nsh_si=0,nw_proto=0,nw_tos=0,nw_ecn=0,nw_ttl=0 +Flow: in_port=4,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x894f,nsh_flags=0,nsh_ttl=0,nsh_mdtype=2,nsh_np=3,nsh_spi=0x1234,nsh_si=0,nw_proto=0,nw_tos=0,nw_ecn=0,nw_ttl=0 bridge("br0") ------------- @@ -264,7 +264,7 @@ ovs-appctl time/warp 1000 AT_CHECK([ ovs-appctl dpctl/dump-flows dummy@ovs-dummy | strip_used | grep -v ipv6 | sort ], [0], [flow-dump from non-dpdk interfaces: -recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(dst=1e:2c:e9:2a:66:9e),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:encap_nsh(flags=0,mdtype=2,np=3,spi=0x1234,si=255,md2=0x10000a0412345678),push_eth(src=00:00:00:00:00:00,dst=11:22:33:44:55:66),pop_eth,decap_nsh(),set(eth(dst=11:22:33:44:55:66)),recirc(0x3) +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(dst=1e:2c:e9:2a:66:9e),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:encap_nsh(flags=0,ttl=63,mdtype=2,np=3,spi=0x1234,si=255,md2=0x10000a041234567820001408fedcba9876543210),push_eth(src=00:00:00:00:00:00,dst=11:22:33:44:55:66),pop_eth,decap_nsh(),set(eth(dst=11:22:33:44:55:66)),recirc(0x3) recirc_id(0x3),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:2 ]) @@ -577,7 +577,7 @@ ovs-appctl time/warp 1000 AT_CHECK([ ovs-appctl dpctl/dump-flows dummy@ovs-dummy | strip_used | grep -v ipv6 | sort ], [0], [flow-dump from non-dpdk interfaces: -recirc_id(0),in_port(4),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.30,frag=no), packets:1, bytes:98, used:0.0s, actions:pop_eth,encap_nsh(flags=0,mdtype=1,np=1,spi=0x3000,si=255,c1=0x0,c2=0x0,c3=0x0,c4=0x0),clone(tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=aa:55:00:00:00:03,src=aa:55:00:00:00:01,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.3,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0xc000004,vni=0x0)),out_port(1)),set(ipv4(src=30.0.0.1,dst=30.0.0.3)),tnl_pop(4789)) +recirc_id(0),in_port(4),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.30,frag=no), packets:1, bytes:98, used:0.0s, actions:pop_eth,encap_nsh(flags=0,ttl=63,mdtype=1,np=1,spi=0x3000,si=255,c1=0x0,c2=0x0,c3=0x0,c4=0x0),clone(tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=aa:55:00:00:00:03,src=aa:55:00:00:00:01,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.3,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0xc000004,vni=0x0)),out_port(1)),set(ipv4(src=30.0.0.1,dst=30.0.0.3)),tnl_pop(4789)) tunnel(tun_id=0x0,src=30.0.0.1,dst=30.0.0.3,flags(-df-csum+key)),recirc_id(0),in_port(4789),packet_type(ns=1,id=0x894f),nsh(np=1,spi=0x3000,si=255), packets:1, bytes:108, used:0.0s, actions:decap_nsh(),recirc(0x1) tunnel(tun_id=0x0,src=30.0.0.1,dst=30.0.0.3,flags(-df-csum+key)),recirc_id(0x1),in_port(4789),packet_type(ns=1,id=0x800),ipv4(frag=no), packets:1, bytes:84, used:0.0s, actions:push_eth(src=00:00:00:00:00:00,dst=aa:55:aa:55:00:03),6 ]) @@ -631,7 +631,7 @@ ovs-appctl time/warp 1000 AT_CHECK([ ovs-appctl dpctl/dump-flows dummy@ovs-dummy | strip_used | grep -v ipv6 | sort ], [0], [flow-dump from non-dpdk interfaces: -recirc_id(0),in_port(4),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.20/255.255.255.248,frag=no), packets:1, bytes:98, used:0.0s, actions:pop_eth,encap_nsh(flags=0,mdtype=1,np=1,spi=0x3020,si=255,c1=0x0,c2=0x0,c3=0x0,c4=0x0),clone(tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=aa:55:00:00:00:02,src=aa:55:00:00:00:01,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.2,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0xc000004,vni=0x0)),out_port(1)),set(ipv4(src=20.0.0.1,dst=20.0.0.2)),tnl_pop(4789)) +recirc_id(0),in_port(4),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.20/255.255.255.248,frag=no), packets:1, bytes:98, used:0.0s, actions:pop_eth,encap_nsh(flags=0,ttl=63,mdtype=1,np=1,spi=0x3020,si=255,c1=0x0,c2=0x0,c3=0x0,c4=0x0),clone(tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=aa:55:00:00:00:02,src=aa:55:00:00:00:01,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.2,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0xc000004,vni=0x0)),out_port(1)),set(ipv4(src=20.0.0.1,dst=20.0.0.2)),tnl_pop(4789)) tunnel(tun_id=0x0,src=20.0.0.1,dst=20.0.0.2,flags(-df-csum+key)),recirc_id(0),in_port(4789),packet_type(ns=1,id=0x894f),nsh(spi=0x3020,si=255), packets:1, bytes:108, used:0.0s, actions:push_eth(src=00:00:00:00:00:00,dst=11:22:33:44:55:66),set(nsh(spi=0x3020,si=254)),pop_eth,clone(tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=aa:55:00:00:00:03,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=20.0.0.2,dst=20.0.0.3,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0xc000004,vni=0x0)),out_port(2)),set(ipv4(src=30.0.0.2,dst=30.0.0.3)),tnl_pop(4789)) tunnel(tun_id=0x0,src=30.0.0.2,dst=30.0.0.3,flags(-df-csum+key)),recirc_id(0),in_port(4789),packet_type(ns=1,id=0x894f),nsh(np=1,spi=0x3020,si=254), packets:1, bytes:108, used:0.0s, actions:decap_nsh(),recirc(0x2) tunnel(tun_id=0x0,src=30.0.0.2,dst=30.0.0.3,flags(-df-csum+key)),recirc_id(0x2),in_port(4789),packet_type(ns=1,id=0x800),ipv4(frag=no), packets:1, bytes:84, used:0.0s, actions:push_eth(src=00:00:00:00:00:00,dst=aa:55:aa:55:00:03),6 From patchwork Tue Aug 29 18:21:02 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Yang, Yi" X-Patchwork-Id: 807218 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) 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 3xhcWs6lRXz9sMN for ; Wed, 30 Aug 2017 04:25:45 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id C9B13B1F; Tue, 29 Aug 2017 18:25:05 +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 23787B1F for ; Tue, 29 Aug 2017 18:25:05 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mga07.intel.com (mga07.intel.com [134.134.136.100]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id DDEF2196 for ; Tue, 29 Aug 2017 18:25:03 +0000 (UTC) Received: from orsmga003.jf.intel.com ([10.7.209.27]) by orsmga105.jf.intel.com with ESMTP; 29 Aug 2017 11:25:03 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos; i="5.41,445,1498546800"; d="scan'208"; a="1008955831" Received: from unknown (HELO localhost.localdomain.bj.intel.com) ([10.240.224.185]) by orsmga003.jf.intel.com with ESMTP; 29 Aug 2017 11:25:01 -0700 From: Yi Yang To: dev@openvswitch.org Date: Wed, 30 Aug 2017 02:21:02 +0800 Message-Id: <1504030862-14591-3-git-send-email-yi.y.yang@intel.com> X-Mailer: git-send-email 2.1.0 In-Reply-To: <1504030862-14591-1-git-send-email-yi.y.yang@intel.com> References: <1504030862-14591-1-git-send-email-yi.y.yang@intel.com> X-Spam-Status: No, score=-2.3 required=5.0 tests=RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD autolearn=disabled version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Cc: e@erig.me, jbenc@redhat.com Subject: [ovs-dev] [PATCH v5 2/2] nsh: add dec_nsh_ttl action 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 IETF NSH spec defines a ttl field in NSH header, it is a 6-bit field ranged from 0 to 63, it should be decremented by 1 every hop, if it is 0 or it is so after decremented, the packet should be dropped and a packet-in message is sent to main controller. Signed-off-by: Yi Yang --- include/openvswitch/ofp-actions.h | 1 + lib/ofp-actions.c | 49 +++++++++++++++++++++++++++++++++++++++ ofproto/ofproto-dpif-xlate.c | 31 +++++++++++++++++++++++++ tests/nsh.at | 23 +++++++++--------- utilities/ovs-ofctl.8.in | 13 ++++++++++- 5 files changed, 105 insertions(+), 12 deletions(-) diff --git a/include/openvswitch/ofp-actions.h b/include/openvswitch/ofp-actions.h index ad8e1be..1296a9c 100644 --- a/include/openvswitch/ofp-actions.h +++ b/include/openvswitch/ofp-actions.h @@ -93,6 +93,7 @@ struct vl_mff_map; OFPACT(DEC_MPLS_TTL, ofpact_null, ofpact, "dec_mpls_ttl") \ OFPACT(PUSH_MPLS, ofpact_push_mpls, ofpact, "push_mpls") \ OFPACT(POP_MPLS, ofpact_pop_mpls, ofpact, "pop_mpls") \ + OFPACT(DEC_NSH_TTL, ofpact_null, ofpact, "dec_nsh_ttl") \ \ /* Generic encap & decap */ \ OFPACT(ENCAP, ofpact_encap, props, "encap") \ diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c index 71eb70c..1a92b95 100644 --- a/lib/ofp-actions.c +++ b/lib/ofp-actions.c @@ -348,6 +348,9 @@ enum ofp_raw_action_type { /* NX1.3+(47): struct nx_action_decap, ... */ NXAST_RAW_DECAP, + /* NX1.3+(48): void. */ + NXAST_RAW_DEC_NSH_TTL, + /* ## ------------------ ## */ /* ## Debugging actions. ## */ /* ## ------------------ ## */ @@ -480,6 +483,7 @@ ofpact_next_flattened(const struct ofpact *ofpact) case OFPACT_NAT: case OFPACT_ENCAP: case OFPACT_DECAP: + case OFPACT_DEC_NSH_TTL: return ofpact_next(ofpact); case OFPACT_CLONE: @@ -4330,6 +4334,39 @@ format_DECAP(const struct ofpact_decap *a, ds_put_format(s, "%s)%s", colors.paren, colors.end); } +/* Action dec_nsh_ttl */ + +static enum ofperr +decode_NXAST_RAW_DEC_NSH_TTL(struct ofpbuf *out) +{ + ofpact_put_DEC_NSH_TTL(out); + return 0; +} + +static void +encode_DEC_NSH_TTL(const struct ofpact_null *null OVS_UNUSED, + enum ofp_version ofp_version OVS_UNUSED, struct ofpbuf *out) +{ + put_NXAST_DEC_NSH_TTL(out); +} + +static char * OVS_WARN_UNUSED_RESULT +parse_DEC_NSH_TTL(char *arg OVS_UNUSED, + const struct ofputil_port_map *port_map OVS_UNUSED, + struct ofpbuf *ofpacts, + enum ofputil_protocol *usable_protocols OVS_UNUSED) +{ + ofpact_put_DEC_NSH_TTL(ofpacts); + return NULL; +} + +static void +format_DEC_NSH_TTL(const struct ofpact_null *a OVS_UNUSED, + const struct ofputil_port_map *port_map OVS_UNUSED, struct ds *s) +{ + ds_put_format(s, "%sdec_nsh_ttl%s", colors.special, colors.end); +} + /* Action structures for NXAST_RESUBMIT, NXAST_RESUBMIT_TABLE, and * NXAST_RESUBMIT_TABLE_CT. @@ -7114,6 +7151,7 @@ ofpact_is_set_or_move_action(const struct ofpact *a) case OFPACT_SET_VLAN_VID: case OFPACT_ENCAP: case OFPACT_DECAP: + case OFPACT_DEC_NSH_TTL: return true; case OFPACT_BUNDLE: case OFPACT_CLEAR_ACTIONS: @@ -7191,6 +7229,7 @@ ofpact_is_allowed_in_actions_set(const struct ofpact *a) case OFPACT_STRIP_VLAN: case OFPACT_ENCAP: case OFPACT_DECAP: + case OFPACT_DEC_NSH_TTL: return true; /* In general these actions are excluded because they are not part of @@ -7304,6 +7343,7 @@ ofpacts_execute_action_set(struct ofpbuf *action_list, ofpacts_copy_last(action_list, action_set, OFPACT_PUSH_VLAN); ofpacts_copy_last(action_list, action_set, OFPACT_DEC_TTL); ofpacts_copy_last(action_list, action_set, OFPACT_DEC_MPLS_TTL); + ofpacts_copy_last(action_list, action_set, OFPACT_DEC_NSH_TTL); ofpacts_copy_all(action_list, action_set, ofpact_is_set_or_move_action); ofpacts_copy_last(action_list, action_set, OFPACT_SET_QUEUE); @@ -7445,6 +7485,7 @@ ovs_instruction_type_from_ofpact_type(enum ofpact_type type) case OFPACT_NAT: case OFPACT_ENCAP: case OFPACT_DECAP: + case OFPACT_DEC_NSH_TTL: default: return OVSINST_OFPIT11_APPLY_ACTIONS; } @@ -8131,6 +8172,13 @@ ofpact_check__(enum ofputil_protocol *usable_protocols, struct ofpact *a, } return 0; + case OFPACT_DEC_NSH_TTL: + if ((flow->packet_type != htonl(PT_NSH)) && + (flow->dl_type != htons(ETH_TYPE_NSH))) { + inconsistent_match(usable_protocols); + } + return 0; + default: OVS_NOT_REACHED(); } @@ -8626,6 +8674,7 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, ofp_port_t port) case OFPACT_NAT: case OFPACT_ENCAP: case OFPACT_DECAP: + case OFPACT_DEC_NSH_TTL: default: return false; } diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index 933256e..d24e22c 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -4832,6 +4832,28 @@ compose_dec_mpls_ttl_action(struct xlate_ctx *ctx) return true; } +static bool +compose_dec_nsh_ttl_action(struct xlate_ctx *ctx) +{ + struct flow *flow = &ctx->xin->flow; + + if ((flow->packet_type == htonl(PT_NSH)) || + (flow->dl_type == htons(ETH_TYPE_NSH))) { + ctx->wc->masks.nsh.ttl = 0xff; + if (flow->nsh.ttl > 1) { + flow->nsh.ttl--; + return false; + } else { + execute_controller_action(ctx, UINT16_MAX, OFPR_INVALID_TTL, 0, + NULL, 0); + } + } + + /* Stop processing for current table. */ + xlate_report(ctx, OFT_WARN, "NSH decrement TTL exception"); + return true; +} + static void xlate_output_action(struct xlate_ctx *ctx, ofp_port_t port, uint16_t max_len, bool may_packet_in) @@ -5327,6 +5349,7 @@ reversible_actions(const struct ofpact *ofpacts, size_t ofpacts_len) case OFPACT_OUTPUT_TRUNC: case OFPACT_ENCAP: case OFPACT_DECAP: + case OFPACT_DEC_NSH_TTL: return false; } } @@ -5537,6 +5560,7 @@ freeze_unroll_actions(const struct ofpact *a, const struct ofpact *end, case OFPACT_OUTPUT: case OFPACT_CONTROLLER: case OFPACT_DEC_MPLS_TTL: + case OFPACT_DEC_NSH_TTL: case OFPACT_DEC_TTL: /* These actions may generate asynchronous messages, which include * table ID and flow cookie information. */ @@ -6082,6 +6106,7 @@ recirc_for_mpls(const struct ofpact *a, struct xlate_ctx *ctx) case OFPACT_CLONE: case OFPACT_ENCAP: case OFPACT_DECAP: + case OFPACT_DEC_NSH_TTL: case OFPACT_UNROLL_XLATE: case OFPACT_CT: case OFPACT_CT_CLEAR: @@ -6404,6 +6429,12 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, } break; + case OFPACT_DEC_NSH_TTL: + if (compose_dec_nsh_ttl_action(ctx)) { + return; + } + break; + case OFPACT_DEC_TTL: wc->masks.nw_ttl = 0xff; if (compose_dec_ttl(ctx, ofpact_get_DEC_TTL(a))) { diff --git a/tests/nsh.at b/tests/nsh.at index 93d8b42..521365b 100644 --- a/tests/nsh.at +++ b/tests/nsh.at @@ -13,7 +13,7 @@ OVS_VSWITCHD_START([dnl add-port br0 p2 -- set Interface p2 type=dummy ofport_request=2]) AT_DATA([flows.txt], [dnl - table=0,in_port=1,dl_type=0x894f,nsh_ttl=63,nsh_mdtype=1,nsh_np=3,nsh_spi=0x123456,nsh_si=255,nsh_c1=0x11223344,actions=set_field:0x2->nsh_flags,set_field:254->nsh_si,set_field:0x44332211->nsh_c1,2 + table=0,in_port=1,dl_type=0x894f,nsh_ttl=63,nsh_mdtype=1,nsh_np=3,nsh_spi=0x123456,nsh_si=255,nsh_c1=0x11223344,actions=set_field:0x2->nsh_flags,set_field:254->nsh_si,set_field:0x44332211->nsh_c1,dec_nsh_ttl,2 ]) AT_CHECK([ @@ -21,7 +21,7 @@ AT_CHECK([ ovs-ofctl -Oopenflow13 add-flows br0 flows.txt ovs-ofctl -Oopenflow13 dump-flows br0 | ofctl_strip | sort | grep actions ], [0], [dnl - in_port=1,dl_type=0x894f,nsh_ttl=63,nsh_mdtype=1,nsh_np=3,nsh_spi=0x123456,nsh_si=255,nsh_c1=0x11223344 actions=set_field:2->nsh_flags,set_field:254->nsh_si,set_field:0x44332211->nsh_c1,output:2 + in_port=1,dl_type=0x894f,nsh_ttl=63,nsh_mdtype=1,nsh_np=3,nsh_spi=0x123456,nsh_si=255,nsh_c1=0x11223344 actions=set_field:2->nsh_flags,set_field:254->nsh_si,set_field:0x44332211->nsh_c1,dec_nsh_ttl,output:2 ]) AT_CHECK([ @@ -35,11 +35,12 @@ bridge("br0") set_field:2->nsh_flags set_field:254->nsh_si set_field:0x44332211->nsh_c1 + dec_nsh_ttl output:2 -Final flow: in_port=1,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x894f,nsh_flags=2,nsh_ttl=63,nsh_mdtype=1,nsh_np=3,nsh_spi=0x123456,nsh_si=254,nsh_c1=0x44332211,nsh_c2=0x55667788,nsh_c3=0x99aabbcc,nsh_c4=0xddeeff00,nw_proto=0,nw_tos=0,nw_ecn=0,nw_ttl=0 +Final flow: in_port=1,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x894f,nsh_flags=2,nsh_ttl=62,nsh_mdtype=1,nsh_np=3,nsh_spi=0x123456,nsh_si=254,nsh_c1=0x44332211,nsh_c2=0x55667788,nsh_c3=0x99aabbcc,nsh_c4=0xddeeff00,nw_proto=0,nw_tos=0,nw_ecn=0,nw_ttl=0 Megaflow: recirc_id=0,eth,in_port=1,dl_type=0x894f,nsh_flags=0,nsh_ttl=63,nsh_mdtype=1,nsh_np=3,nsh_spi=0x123456,nsh_si=255,nsh_c1=0x11223344 -Datapath actions: set(nsh(flags=2,ttl=63,spi=0x123456,si=254,c1=0x44332211)),2 +Datapath actions: set(nsh(flags=2,ttl=62,spi=0x123456,si=254,c1=0x44332211)),2 ]) OVS_VSWITCHD_STOP @@ -539,8 +540,8 @@ AT_DATA([br-in2.txt], [dnl table=2,packet_type=(1,0x894f),nsh_spi=0x3020,nsh_si=254,actions=output:2030 table=2,packet_type=(1,0x894f),nsh_spi=0x1020,nsh_si=255,actions=encap(ethernet),set_field:77:88:99:aa:bb:cc->dl_dst,goto_table:4 table=2,packet_type=(1,0x894f),nsh_spi=0x1020,nsh_si=254,actions=output:2010 - table=4,dl_type=0x894f,dl_dst=11:22:33:44:55:66,actions=set_field:254->nsh_si,decap(),resubmit(,2) - table=4,dl_type=0x894f,dl_dst=77:88:99:aa:bb:cc,actions=set_field:254->nsh_si,decap(),resubmit(,2) + table=4,dl_type=0x894f,dl_dst=11:22:33:44:55:66,actions=set_field:254->nsh_si,dec_nsh_ttl,decap(),resubmit(,2) + table=4,dl_type=0x894f,dl_dst=77:88:99:aa:bb:cc,actions=set_field:254->nsh_si,dec_nsh_ttl,decap(),resubmit(,2) ]) # br-in3 is SFC classifier (table 1) and final SFF (tables 2,3) @@ -603,8 +604,8 @@ AT_CHECK([ table=2, packet_type=(1,0x894f),nsh_spi=0x1020,nsh_si=255 actions=encap(ethernet),set_field:77:88:99:aa:bb:cc->eth_dst,goto_table:4 table=2, packet_type=(1,0x894f),nsh_spi=0x3020,nsh_si=254 actions=output:2030 table=2, packet_type=(1,0x894f),nsh_spi=0x3020,nsh_si=255 actions=encap(ethernet),set_field:11:22:33:44:55:66->eth_dst,goto_table:4 - table=4, dl_dst=11:22:33:44:55:66,dl_type=0x894f actions=set_field:254->nsh_si,decap(),resubmit(,2) - table=4, dl_dst=77:88:99:aa:bb:cc,dl_type=0x894f actions=set_field:254->nsh_si,decap(),resubmit(,2) + table=4, dl_dst=11:22:33:44:55:66,dl_type=0x894f actions=set_field:254->nsh_si,dec_nsh_ttl,decap(),resubmit(,2) + table=4, dl_dst=77:88:99:aa:bb:cc,dl_type=0x894f actions=set_field:254->nsh_si,dec_nsh_ttl,decap(),resubmit(,2) ip,in_port=30 actions=decap(),goto_table:1 n_packets=2, n_bytes=216, packet_type=(1,0x894f),in_port=3010 actions=goto_table:2 packet_type=(1,0x800),in_port=30 actions=goto_table:1 @@ -632,7 +633,7 @@ AT_CHECK([ ovs-appctl dpctl/dump-flows dummy@ovs-dummy | strip_used | grep -v ipv6 | sort ], [0], [flow-dump from non-dpdk interfaces: recirc_id(0),in_port(4),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.20/255.255.255.248,frag=no), packets:1, bytes:98, used:0.0s, actions:pop_eth,encap_nsh(flags=0,ttl=63,mdtype=1,np=1,spi=0x3020,si=255,c1=0x0,c2=0x0,c3=0x0,c4=0x0),clone(tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=aa:55:00:00:00:02,src=aa:55:00:00:00:01,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.2,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0xc000004,vni=0x0)),out_port(1)),set(ipv4(src=20.0.0.1,dst=20.0.0.2)),tnl_pop(4789)) -tunnel(tun_id=0x0,src=20.0.0.1,dst=20.0.0.2,flags(-df-csum+key)),recirc_id(0),in_port(4789),packet_type(ns=1,id=0x894f),nsh(spi=0x3020,si=255), packets:1, bytes:108, used:0.0s, actions:push_eth(src=00:00:00:00:00:00,dst=11:22:33:44:55:66),set(nsh(spi=0x3020,si=254)),pop_eth,clone(tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=aa:55:00:00:00:03,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=20.0.0.2,dst=20.0.0.3,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0xc000004,vni=0x0)),out_port(2)),set(ipv4(src=30.0.0.2,dst=30.0.0.3)),tnl_pop(4789)) +tunnel(tun_id=0x0,src=20.0.0.1,dst=20.0.0.2,flags(-df-csum+key)),recirc_id(0),in_port(4789),packet_type(ns=1,id=0x894f),nsh(ttl=63,spi=0x3020,si=255), packets:1, bytes:108, used:0.0s, actions:push_eth(src=00:00:00:00:00:00,dst=11:22:33:44:55:66),set(nsh(ttl=62,spi=0x3020,si=254)),pop_eth,clone(tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=aa:55:00:00:00:03,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=20.0.0.2,dst=20.0.0.3,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0xc000004,vni=0x0)),out_port(2)),set(ipv4(src=30.0.0.2,dst=30.0.0.3)),tnl_pop(4789)) tunnel(tun_id=0x0,src=30.0.0.2,dst=30.0.0.3,flags(-df-csum+key)),recirc_id(0),in_port(4789),packet_type(ns=1,id=0x894f),nsh(np=1,spi=0x3020,si=254), packets:1, bytes:108, used:0.0s, actions:decap_nsh(),recirc(0x2) tunnel(tun_id=0x0,src=30.0.0.2,dst=30.0.0.3,flags(-df-csum+key)),recirc_id(0x2),in_port(4789),packet_type(ns=1,id=0x800),ipv4(frag=no), packets:1, bytes:84, used:0.0s, actions:push_eth(src=00:00:00:00:00:00,dst=aa:55:aa:55:00:03),6 ]) @@ -658,8 +659,8 @@ AT_CHECK([ table=2, n_packets=2, n_bytes=216, packet_type=(1,0x894f),nsh_spi=0x3020,nsh_si=255 actions=encap(ethernet),set_field:11:22:33:44:55:66->eth_dst,goto_table:4 table=2, packet_type=(1,0x894f),nsh_spi=0x1020,nsh_si=254 actions=output:2010 table=2, packet_type=(1,0x894f),nsh_spi=0x1020,nsh_si=255 actions=encap(ethernet),set_field:77:88:99:aa:bb:cc->eth_dst,goto_table:4 - table=4, dl_dst=77:88:99:aa:bb:cc,dl_type=0x894f actions=set_field:254->nsh_si,decap(),resubmit(,2) - table=4, n_packets=2, n_bytes=216, dl_dst=11:22:33:44:55:66,dl_type=0x894f actions=set_field:254->nsh_si,decap(),resubmit(,2) + table=4, dl_dst=77:88:99:aa:bb:cc,dl_type=0x894f actions=set_field:254->nsh_si,dec_nsh_ttl,decap(),resubmit(,2) + table=4, n_packets=2, n_bytes=216, dl_dst=11:22:33:44:55:66,dl_type=0x894f actions=set_field:254->nsh_si,dec_nsh_ttl,decap(),resubmit(,2) ip,in_port=30 actions=decap(),goto_table:1 n_packets=2, n_bytes=216, packet_type=(1,0x894f),in_port=3010 actions=goto_table:2 n_packets=2, n_bytes=216, packet_type=(1,0x894f),in_port=3020 actions=goto_table:2 diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in index c65de97..9b3e72d 100644 --- a/utilities/ovs-ofctl.8.in +++ b/utilities/ovs-ofctl.8.in @@ -1280,6 +1280,15 @@ Processing the current set of actions then stops. However, if the current set of actions was reached through ``resubmit'' then remaining actions in outer levels resume processing. . +.IP \fBdec_nsh_ttl\fR +Decrement TTL of the outer NSH header of a packet. If the TTL +is initially zero or decrementing would make it so, no decrement occurs. +Instead, a ``packet-in'' message with reason code \fBOFPR_INVALID_TTL\fR +is sent to the main controller (id zero), if it has enabled receiving them. +Processing the current set of actions then stops. However, if the current +set of actions was reached through ``resubmit'' then remaining actions in +outer levels resume processing. +. .IP \fBnote:\fR[\fIhh\fR]... Does nothing at all. Any number of bytes represented as hex digits \fIhh\fR may be included. Pairs of hex digits may be separated by @@ -1578,6 +1587,8 @@ the action set, the one written later replaces the earlier action: \fBdec_ttl\fR .IQ \fBdec_mpls_ttl\fR +.IQ +\fBdec_nsh_ttl\fR . .IP 7. \fBload\fR @@ -1638,7 +1649,7 @@ not visible.) .RE .IP Only the actions listed above may be written to the action set. -\fBencap\fR and \fBdecap\fR actions are nonstandard. +\fBencap\fR, \fBdecap\fR and \fBdec_nsh_ttl\fR actions are nonstandard. . .IP \fBwrite_metadata\fB:\fIvalue\fR[/\fImask\fR] Updates the metadata field for the flow. If \fImask\fR is omitted, the