From patchwork Fri Dec 8 14:04:22 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Yang, Yi" X-Patchwork-Id: 846261 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 3ytZ8J4l9Yz9t7x for ; Sat, 9 Dec 2017 01:13:36 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id C1827D8A; Fri, 8 Dec 2017 14:10:58 +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 A6262D85 for ; Fri, 8 Dec 2017 14:10:56 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mga14.intel.com (mga14.intel.com [192.55.52.115]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id BD396F4 for ; Fri, 8 Dec 2017 14:10:52 +0000 (UTC) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga103.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 08 Dec 2017 06:10:21 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.45,377,1508828400"; d="scan'208";a="11701195" Received: from unknown (HELO localhost.localdomain.bj.intel.com) ([10.240.224.185]) by fmsmga001.fm.intel.com with ESMTP; 08 Dec 2017 06:10:02 -0800 From: Yi Yang To: dev@openvswitch.org Date: Fri, 8 Dec 2017 22:04:22 +0800 Message-Id: <1512741865-97333-2-git-send-email-yi.y.yang@intel.com> X-Mailer: git-send-email 2.1.0 In-Reply-To: <1512741865-97333-1-git-send-email-yi.y.yang@intel.com> References: <1512741865-97333-1-git-send-email-yi.y.yang@intel.com> X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, T_RP_MATCHES_RCVD autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH v6 1/4] nsh: rework NSH netlink keys and actions 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 This patch changes OVS_KEY_ATTR_NSH to nested attribute and adds three new NSH sub attribute keys: OVS_NSH_KEY_ATTR_BASE: for length-fixed NSH base header OVS_NSH_KEY_ATTR_MD1: for length-fixed MD type 1 context OVS_NSH_KEY_ATTR_MD2: for length-variable MD type 2 metadata Its intention is to align to NSH kernel implementation. NSH match fields, set and PUSH_NSH action all use the below nested attribute format: OVS_KEY_ATTR_NSH begin OVS_NSH_KEY_ATTR_BASE OVS_NSH_KEY_ATTR_MD1 OVS_KEY_ATTR_NSH end or OVS_KEY_ATTR_NSH begin OVS_NSH_KEY_ATTR_BASE OVS_NSH_KEY_ATTR_MD2 OVS_KEY_ATTR_NSH end In addition, NSH encap and decap actions are renamed as push_nsh and pop_nsh to meet action naming convention. Signed-off-by: Yi Yang --- datapath/linux/compat/include/linux/openvswitch.h | 58 +- include/openvswitch/nsh.h | 26 +- include/openvswitch/packets.h | 11 +- lib/dpif-netdev.c | 4 +- lib/dpif.c | 4 +- lib/flow.c | 40 +- lib/match.c | 12 +- lib/meta-flow.c | 13 +- lib/nx-match.c | 4 +- lib/odp-execute.c | 76 ++- lib/odp-util.c | 745 ++++++++++++++++++---- lib/odp-util.h | 4 + lib/packets.c | 26 +- lib/packets.h | 5 +- ofproto/ofproto-dpif-ipfix.c | 4 +- ofproto/ofproto-dpif-sflow.c | 4 +- ofproto/ofproto-dpif-xlate.c | 24 +- tests/nsh.at | 30 +- 18 files changed, 803 insertions(+), 287 deletions(-) diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h index 561f895..3ddb1c5 100644 --- a/datapath/linux/compat/include/linux/openvswitch.h +++ b/datapath/linux/compat/include/linux/openvswitch.h @@ -369,7 +369,7 @@ enum ovs_key_attr { #ifndef __KERNEL__ /* Only used within userspace data path. */ OVS_KEY_ATTR_PACKET_TYPE, /* be32 packet type */ - OVS_KEY_ATTR_NSH, /* struct ovs_key_nsh */ + OVS_KEY_ATTR_NSH, /* Nested set of ovs_nsh_key_* */ #endif __OVS_KEY_ATTR_MAX @@ -492,13 +492,28 @@ struct ovs_key_ct_labels { }; }; -struct ovs_key_nsh { - __u8 flags; - __u8 mdtype; - __u8 np; - __u8 pad; - __be32 path_hdr; - __be32 c[4]; +enum ovs_nsh_key_attr { + OVS_NSH_KEY_ATTR_UNSPEC, + OVS_NSH_KEY_ATTR_BASE, /* struct ovs_nsh_key_base. */ + OVS_NSH_KEY_ATTR_MD1, /* struct ovs_nsh_key_md1. */ + OVS_NSH_KEY_ATTR_MD2, /* variable-length octets. */ + __OVS_NSH_KEY_ATTR_MAX +}; + +#define OVS_NSH_KEY_ATTR_MAX (__OVS_NSH_KEY_ATTR_MAX - 1) + +struct ovs_nsh_key_base { + __u8 flags; + __u8 mdtype; + __u8 np; + __u8 pad; + __be32 path_hdr; +}; + +#define NSH_MD1_CONTEXT_SIZE 4 + +struct ovs_nsh_key_md1 { + __be32 context[NSH_MD1_CONTEXT_SIZE]; }; /* OVS_KEY_ATTR_CT_STATE flags */ @@ -793,25 +808,6 @@ struct ovs_action_push_eth { struct ovs_key_ethernet addresses; }; -#define OVS_ENCAP_NSH_MAX_MD_LEN 248 -/* - * struct ovs_action_encap_nsh - %OVS_ACTION_ATTR_ENCAP_NSH - * @flags: NSH header flags. - * @mdtype: NSH metadata type. - * @mdlen: Length of NSH metadata in bytes, including padding. - * @np: NSH next_protocol: Inner packet type. - * @path_hdr: NSH service path id and service index. - * @metadata: NSH context metadata, padded to 4-bytes - */ -struct ovs_action_encap_nsh { - uint8_t flags; - uint8_t mdtype; - uint8_t mdlen; - uint8_t np; - __be32 path_hdr; - uint8_t metadata[OVS_ENCAP_NSH_MAX_MD_LEN]; -}; - /** * enum ovs_nat_attr - Attributes for %OVS_CT_ATTR_NAT. * @@ -887,8 +883,8 @@ enum ovs_nat_attr { * @OVS_ACTION_ATTR_PUSH_ETH: Push a new outermost Ethernet header onto the * packet. * @OVS_ACTION_ATTR_POP_ETH: Pop the outermost Ethernet header off the packet. - * @OVS_ACTION_ATTR_ENCAP_NSH: encap NSH action to push NSH header. - * @OVS_ACTION_ATTR_DECAP_NSH: decap NSH action to remove NSH header. + * @OVS_ACTION_ATTR_PUSH_NSH: push NSH header to the packet. + * @OVS_ACTION_ATTR_POP_NSH: pop the outermost NSH header off the packet. * * Only a single header can be set with a single %OVS_ACTION_ATTR_SET. Not all * fields within a header are modifiable, e.g. the IPv4 protocol and fragment @@ -930,8 +926,8 @@ enum ovs_action_attr { OVS_ACTION_ATTR_TUNNEL_POP, /* u32 port number. */ OVS_ACTION_ATTR_CLONE, /* Nested OVS_CLONE_ATTR_*. */ OVS_ACTION_ATTR_METER, /* u32 meter number. */ - OVS_ACTION_ATTR_ENCAP_NSH, /* struct ovs_action_encap_nsh. */ - OVS_ACTION_ATTR_DECAP_NSH, /* No argument. */ + OVS_ACTION_ATTR_PUSH_NSH, /* Nested OVS_NSH_KEY_ATTR_*. */ + OVS_ACTION_ATTR_POP_NSH, /* No argument. */ #endif __OVS_ACTION_ATTR_MAX, /* Nothing past this will be accepted * from userspace. */ diff --git a/include/openvswitch/nsh.h b/include/openvswitch/nsh.h index a58c870..63b480e 100644 --- a/include/openvswitch/nsh.h +++ b/include/openvswitch/nsh.h @@ -199,7 +199,7 @@ extern "C" { * @nshc<1-4>: NSH Contexts. */ struct nsh_md1_ctx { - ovs_16aligned_be32 c[4]; + ovs_16aligned_be32 context[4]; }; struct nsh_md2_tlv { @@ -262,6 +262,12 @@ struct nsh_hdr { /* NSH MD Type 1 header Length. */ #define NSH_M_TYPE1_LEN 24 +/* NSH header maximum Length. */ +#define NSH_HDR_MAX_LEN 256 + +/* NSH context headers maximum Length. */ +#define NSH_CTX_HDRS_MAX_LEN 248 + static inline uint16_t nsh_hdr_len(const struct nsh_hdr *nsh) { @@ -275,16 +281,22 @@ nsh_md_type(const struct nsh_hdr *nsh) return (nsh->md_type & NSH_MDTYPE_MASK) >> NSH_MDTYPE_SHIFT; } -static inline struct nsh_md1_ctx * -nsh_md1_ctx(struct nsh_hdr *nsh) +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_flags(const struct nsh_hdr *nsh) { - return &nsh->md1; + return (ntohs(nsh->ver_flags_ttl_len) & NSH_FLAGS_MASK) >> NSH_FLAGS_SHIFT; } -static inline struct nsh_md2_tlv * -nsh_md2_ctx(struct nsh_hdr *nsh) +static inline void +nsh_reset_ver_flags_ttl_len(struct nsh_hdr *nsh) { - return &nsh->md2; + nsh->ver_flags_ttl_len = 0; } #ifdef __cplusplus diff --git a/include/openvswitch/packets.h b/include/openvswitch/packets.h index c74ce28..5f92c01 100644 --- a/include/openvswitch/packets.h +++ b/include/openvswitch/packets.h @@ -80,7 +80,16 @@ struct flow_nsh { uint8_t np; uint8_t si; ovs_be32 spi; - ovs_be32 c[4]; + ovs_be32 context[4]; +}; + +struct ovs_key_nsh { + uint8_t flags; + uint8_t mdtype; + uint8_t np; + uint8_t pad; + ovs_be32 path_hdr; + ovs_be32 context[4]; }; /* NSH flags */ diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index b1ef9a6..5dffee8 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -5658,8 +5658,8 @@ dp_execute_cb(void *aux_, struct dp_packet_batch *packets_, case OVS_ACTION_ATTR_PUSH_ETH: case OVS_ACTION_ATTR_POP_ETH: case OVS_ACTION_ATTR_CLONE: - case OVS_ACTION_ATTR_ENCAP_NSH: - case OVS_ACTION_ATTR_DECAP_NSH: + case OVS_ACTION_ATTR_PUSH_NSH: + case OVS_ACTION_ATTR_POP_NSH: case __OVS_ACTION_ATTR_MAX: OVS_NOT_REACHED(); } diff --git a/lib/dpif.c b/lib/dpif.c index 310dec1..ab2e232 100644 --- a/lib/dpif.c +++ b/lib/dpif.c @@ -1273,8 +1273,8 @@ dpif_execute_helper_cb(void *aux_, struct dp_packet_batch *packets_, case OVS_ACTION_ATTR_PUSH_ETH: case OVS_ACTION_ATTR_POP_ETH: case OVS_ACTION_ATTR_CLONE: - case OVS_ACTION_ATTR_ENCAP_NSH: - case OVS_ACTION_ATTR_DECAP_NSH: + case OVS_ACTION_ATTR_PUSH_NSH: + case OVS_ACTION_ATTR_POP_NSH: case OVS_ACTION_ATTR_UNSPEC: case __OVS_ACTION_ATTR_MAX: OVS_NOT_REACHED(); diff --git a/lib/flow.c b/lib/flow.c index bc24fe7..964f734 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -533,7 +533,6 @@ bool parse_nsh(const void **datap, size_t *sizep, struct flow_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; @@ -544,16 +543,11 @@ parse_nsh(const void **datap, size_t *sizep, struct flow_nsh *key) return false; } - memset(key, 0, sizeof(struct flow_nsh)); + version = nsh_get_ver(nsh); + flags = nsh_get_flags(nsh); + length = nsh_hdr_len(nsh); - ver_flags_len = ntohs(nsh->ver_flags_ttl_len); - version = (ver_flags_len & NSH_VER_MASK) >> NSH_VER_SHIFT; - flags = (ver_flags_len & NSH_FLAGS_MASK) >> NSH_FLAGS_SHIFT; - - /* NSH header length is in 4 byte words. */ - length = ((ver_flags_len & NSH_LEN_MASK) >> NSH_LEN_SHIFT) << 2; - - if (length > *sizep || version != 0) { + if (OVS_UNLIKELY(length > *sizep || version != 0)) { return false; } @@ -571,10 +565,17 @@ parse_nsh(const void **datap, size_t *sizep, struct flow_nsh *key) return false; } for (size_t i = 0; i < 4; i++) { - key->c[i] = get_16aligned_be32(&nsh->md1.c[i]); + key->context[i] = get_16aligned_be32(&nsh->md1.context[i]); } break; case NSH_M_TYPE2: + /* Don't support MD type 2 metedata parsing yet */ + if (length < NSH_BASE_HDR_LEN) { + return false; + } + + memset(key->context, 0, sizeof(key->context)); + break; default: /* We don't parse other context headers yet. */ break; @@ -878,16 +879,9 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst) struct flow_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 flow_nsh) / + sizeof(uint64_t)); } } goto out; @@ -1694,7 +1688,7 @@ flow_wildcards_init_for_packet(struct flow_wildcards *wc, WC_MASK_FIELD(wc, nsh.np); WC_MASK_FIELD(wc, nsh.spi); WC_MASK_FIELD(wc, nsh.si); - WC_MASK_FIELD(wc, nsh.c); + WC_MASK_FIELD(wc, nsh.context); } else { return; /* Unknown ethertype. */ } @@ -1828,7 +1822,7 @@ flow_wc_map(const struct flow *flow, struct flowmap *map) FLOWMAP_SET(map, nsh.np); FLOWMAP_SET(map, nsh.spi); FLOWMAP_SET(map, nsh.si); - FLOWMAP_SET(map, nsh.c); + FLOWMAP_SET(map, nsh.context); } } diff --git a/lib/match.c b/lib/match.c index 36c78eb..8952c99 100644 --- a/lib/match.c +++ b/lib/match.c @@ -1266,10 +1266,14 @@ format_nsh_masked(struct ds *s, const struct flow *f, const struct flow *m) 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); 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]); - format_be32_masked_hex(s, "nsh_c3", f->nsh.c[2], m->nsh.c[2]); - format_be32_masked_hex(s, "nsh_c4", f->nsh.c[3], m->nsh.c[3]); + format_be32_masked_hex(s, "nsh_c1", f->nsh.context[0], + m->nsh.context[0]); + format_be32_masked_hex(s, "nsh_c2", f->nsh.context[1], + m->nsh.context[1]); + format_be32_masked_hex(s, "nsh_c3", f->nsh.context[2], + m->nsh.context[2]); + format_be32_masked_hex(s, "nsh_c4", f->nsh.context[3], + m->nsh.context[3]); } } diff --git a/lib/meta-flow.c b/lib/meta-flow.c index 64a8cf1..beeddf1 100644 --- a/lib/meta-flow.c +++ b/lib/meta-flow.c @@ -373,7 +373,7 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc) case MFF_NSH_C2: case MFF_NSH_C3: case MFF_NSH_C4: - return !wc->masks.nsh.c[mf->id - MFF_NSH_C1]; + return !wc->masks.nsh.context[mf->id - MFF_NSH_C1]; case MFF_N_IDS: default: @@ -915,7 +915,7 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow, case MFF_NSH_C2: case MFF_NSH_C3: case MFF_NSH_C4: - value->be32 = flow->nsh.c[mf->id - MFF_NSH_C1]; + value->be32 = flow->nsh.context[mf->id - MFF_NSH_C1]; break; case MFF_N_IDS: @@ -1230,7 +1230,8 @@ mf_set_value(const struct mf_field *mf, case MFF_NSH_C2: case MFF_NSH_C3: case MFF_NSH_C4: - MATCH_SET_FIELD_BE32(match, nsh.c[mf->id - MFF_NSH_C1], value->be32); + MATCH_SET_FIELD_BE32(match, nsh.context[mf->id - MFF_NSH_C1], + value->be32); break; case MFF_N_IDS: @@ -1621,7 +1622,7 @@ mf_set_flow_value(const struct mf_field *mf, case MFF_NSH_C2: case MFF_NSH_C3: case MFF_NSH_C4: - flow->nsh.c[mf->id - MFF_NSH_C1] = value->be32; + flow->nsh.context[mf->id - MFF_NSH_C1] = value->be32; break; case MFF_N_IDS: @@ -2112,7 +2113,7 @@ mf_set_wild(const struct mf_field *mf, struct match *match, char **err_str) case MFF_NSH_C2: case MFF_NSH_C3: case MFF_NSH_C4: - MATCH_SET_FIELD_MASKED(match, nsh.c[mf->id - MFF_NSH_C1], + MATCH_SET_FIELD_MASKED(match, nsh.context[mf->id - MFF_NSH_C1], htonl(0), htonl(0)); break; @@ -2372,7 +2373,7 @@ mf_set(const struct mf_field *mf, case MFF_NSH_C2: case MFF_NSH_C3: case MFF_NSH_C4: - MATCH_SET_FIELD_MASKED(match, nsh.c[mf->id - MFF_NSH_C1], + MATCH_SET_FIELD_MASKED(match, nsh.context[mf->id - MFF_NSH_C1], value->be32, mask->be32); break; diff --git a/lib/nx-match.c b/lib/nx-match.c index b782e8c..8f2a442 100644 --- a/lib/nx-match.c +++ b/lib/nx-match.c @@ -1165,8 +1165,8 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const struct match *match, 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]); + nxm_put_32m(&ctx, MFF_NSH_C1 + i, oxm, flow->nsh.context[i], + match->wc.masks.nsh.context[i]); } /* Registers. */ diff --git a/lib/odp-execute.c b/lib/odp-execute.c index 44e6691..c3c51dd 100644 --- a/lib/odp-execute.c +++ b/lib/odp-execute.c @@ -273,20 +273,23 @@ odp_set_nd(struct dp_packet *packet, const struct ovs_key_nd *key, /* Set the NSH header. Assumes the NSH header is present and matches the * MD format of the key. The slow path must take case of that. */ static void -odp_set_nsh(struct dp_packet *packet, const struct ovs_key_nsh *key, - const struct ovs_key_nsh *mask) +odp_set_nsh(struct dp_packet *packet, const struct flow_nsh *key, + const struct flow_nsh *mask) { struct nsh_hdr *nsh = dp_packet_l3(packet); uint8_t mdtype = nsh_md_type(nsh); + ovs_be32 path_hdr; if (!mask) { nsh->ver_flags_ttl_len = htons(key->flags << NSH_FLAGS_SHIFT) | (nsh->ver_flags_ttl_len & ~htons(NSH_FLAGS_MASK)); - put_16aligned_be32(&nsh->path_hdr, key->path_hdr); + path_hdr = htonl((ntohl(key->spi) << NSH_SPI_SHIFT) | + key->si); + put_16aligned_be32(&nsh->path_hdr, path_hdr); switch (mdtype) { case NSH_M_TYPE1: for (int i = 0; i < 4; i++) { - put_16aligned_be32(&nsh->md1.c[i], key->c[i]); + put_16aligned_be32(&nsh->md1.context[i], key->context[i]); } break; case NSH_M_TYPE2: @@ -301,16 +304,24 @@ odp_set_nsh(struct dp_packet *packet, const struct ovs_key_nsh *key, nsh->ver_flags_ttl_len = htons(flags << NSH_FLAGS_SHIFT) | (nsh->ver_flags_ttl_len & ~htons(NSH_FLAGS_MASK)); - ovs_be32 path_hdr = get_16aligned_be32(&nsh->path_hdr); - path_hdr = key->path_hdr | (path_hdr & ~mask->path_hdr); + path_hdr = get_16aligned_be32(&nsh->path_hdr); + uint32_t spi = (ntohl(path_hdr) & NSH_SPI_MASK) >> NSH_SPI_SHIFT; + uint8_t si = (ntohl(path_hdr) & NSH_SI_MASK) >> NSH_SI_SHIFT; + uint32_t spi_mask = ntohl(mask->spi); + if (spi_mask == 0x00ffffff) { + spi_mask = UINT32_MAX; + } + spi = ntohl(key->spi) | (spi & ~spi_mask); + si = key->si | (si & ~mask->si); + path_hdr = htonl((spi << NSH_SPI_SHIFT) | si); put_16aligned_be32(&nsh->path_hdr, path_hdr); switch (mdtype) { case NSH_M_TYPE1: for (int i = 0; i < 4; i++) { - ovs_be32 p = get_16aligned_be32(&nsh->md1.c[i]); - ovs_be32 k = key->c[i]; - ovs_be32 m = mask->c[i]; - put_16aligned_be32(&nsh->md1.c[i], k | (p & ~m)); + ovs_be32 p = get_16aligned_be32(&nsh->md1.context[i]); + ovs_be32 k = key->context[i]; + ovs_be32 m = mask->context[i]; + put_16aligned_be32(&nsh->md1.context[i], k | (p & ~m)); } break; case NSH_M_TYPE2: @@ -346,9 +357,12 @@ odp_execute_set_action(struct dp_packet *packet, const struct nlattr *a) odp_eth_set_addrs(packet, nl_attr_get(a), NULL); break; - case OVS_KEY_ATTR_NSH: - odp_set_nsh(packet, nl_attr_get(a), NULL); + case OVS_KEY_ATTR_NSH: { + struct flow_nsh nsh; + odp_nsh_key_from_attr(a, &nsh); + odp_set_nsh(packet, &nsh, NULL); break; + } case OVS_KEY_ATTR_IPV4: ipv4_key = nl_attr_get_unspec(a, sizeof(struct ovs_key_ipv4)); @@ -474,10 +488,25 @@ odp_execute_masked_set_action(struct dp_packet *packet, get_mask(a, struct ovs_key_ethernet)); break; - case OVS_KEY_ATTR_NSH: - odp_set_nsh(packet, nl_attr_get(a), - get_mask(a, struct ovs_key_nsh)); + case OVS_KEY_ATTR_NSH: { + struct flow_nsh nsh, nsh_mask; + size_t size = nl_attr_get_size(a) / 2; + struct { + struct nlattr nla; + uint8_t data[size]; + } attr, mask; + + mask.nla.nla_type = attr.nla.nla_type = nl_attr_type(a); + mask.nla.nla_len = attr.nla.nla_len = NLA_HDRLEN + size; + memcpy(attr.data, (char *)(a + 1), size); + memcpy(mask.data, (char *)(a + 1) + size, size); + + odp_nsh_key_from_attr(&attr.nla, &nsh); + odp_nsh_key_from_attr(&mask.nla, &nsh_mask); + odp_set_nsh(packet, &nsh, &nsh_mask); + break; + } case OVS_KEY_ATTR_IPV4: odp_set_ipv4(packet, nl_attr_get(a), @@ -653,8 +682,8 @@ requires_datapath_assistance(const struct nlattr *a) case OVS_ACTION_ATTR_PUSH_ETH: case OVS_ACTION_ATTR_POP_ETH: case OVS_ACTION_ATTR_CLONE: - case OVS_ACTION_ATTR_ENCAP_NSH: - case OVS_ACTION_ATTR_DECAP_NSH: + case OVS_ACTION_ATTR_PUSH_NSH: + case OVS_ACTION_ATTR_POP_NSH: return false; case OVS_ACTION_ATTR_UNSPEC: @@ -832,19 +861,22 @@ odp_execute_actions(void *dp, struct dp_packet_batch *batch, bool steal, } break; - case OVS_ACTION_ATTR_ENCAP_NSH: { - const struct ovs_action_encap_nsh *enc_nsh = nl_attr_get(a); + case OVS_ACTION_ATTR_PUSH_NSH: { + uint8_t buffer[NSH_HDR_MAX_LEN]; + struct nsh_hdr *nsh_hdr = ALIGNED_CAST(struct nsh_hdr *, buffer); + nsh_reset_ver_flags_ttl_len(nsh_hdr); + odp_nsh_hdr_from_attr(nl_attr_get(a), nsh_hdr, NSH_HDR_MAX_LEN); DP_PACKET_BATCH_FOR_EACH (packet, batch) { - encap_nsh(packet, enc_nsh); + push_nsh(packet, nsh_hdr); } break; } - case OVS_ACTION_ATTR_DECAP_NSH: { + case OVS_ACTION_ATTR_POP_NSH: { size_t i; const size_t num = dp_packet_batch_size(batch); DP_PACKET_BATCH_REFILL_FOR_EACH (i, num, packet, batch) { - if (decap_nsh(packet)) { + if (pop_nsh(packet)) { dp_packet_batch_refill(batch, packet, i); } else { dp_packet_delete(packet); diff --git a/lib/odp-util.c b/lib/odp-util.c index a321111..16a7751 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -120,8 +120,8 @@ odp_action_len(uint16_t type) case OVS_ACTION_ATTR_PUSH_ETH: return sizeof(struct ovs_action_push_eth); case OVS_ACTION_ATTR_POP_ETH: return 0; case OVS_ACTION_ATTR_CLONE: return ATTR_LEN_VARIABLE; - case OVS_ACTION_ATTR_ENCAP_NSH: return ATTR_LEN_VARIABLE; - case OVS_ACTION_ATTR_DECAP_NSH: return 0; + case OVS_ACTION_ATTR_PUSH_NSH: return ATTR_LEN_VARIABLE; + case OVS_ACTION_ATTR_POP_NSH: return 0; case OVS_ACTION_ATTR_UNSPEC: case __OVS_ACTION_ATTR_MAX: @@ -255,7 +255,7 @@ format_nsh_key(struct ds *ds, const struct ovs_key_nsh *key) switch (key->mdtype) { case NSH_M_TYPE1: for (int i = 0; i < 4; i++) { - ds_put_format(ds, ",c%d=0x%x", i + 1, ntohl(key->c[i])); + ds_put_format(ds, ",c%d=0x%x", i + 1, ntohl(key->context[i])); } break; case NSH_M_TYPE2: @@ -325,41 +325,48 @@ format_nsh_key_mask(struct ds *ds, const struct ovs_key_nsh *key, format_uint8_masked(ds, &first, "np", key->np, mask->np); format_be32_masked(ds, &first, "spi", htonl(spi), htonl(spi_mask)); format_uint8_masked(ds, &first, "si", si, si_mask); - format_be32_masked(ds, &first, "c1", key->c[0], mask->c[0]); - format_be32_masked(ds, &first, "c2", key->c[1], mask->c[1]); - format_be32_masked(ds, &first, "c3", key->c[2], mask->c[2]); - format_be32_masked(ds, &first, "c4", key->c[3], mask->c[3]); + format_be32_masked(ds, &first, "c1", key->context[0], + mask->context[0]); + format_be32_masked(ds, &first, "c2", key->context[1], + mask->context[1]); + format_be32_masked(ds, &first, "c3", key->context[2], + mask->context[2]); + format_be32_masked(ds, &first, "c4", key->context[3], + mask->context[3]); } } static void -format_odp_encap_nsh_action(struct ds *ds, - const struct ovs_action_encap_nsh *encap_nsh) +format_odp_push_nsh_action(struct ds *ds, + const struct nsh_hdr *nsh_hdr) { - uint32_t path_hdr = ntohl(encap_nsh->path_hdr); + size_t mdlen = nsh_hdr_len(nsh_hdr) - NSH_BASE_HDR_LEN; + uint32_t path_hdr = ntohl(get_16aligned_be32(&nsh_hdr->path_hdr)); uint32_t spi = (path_hdr & NSH_SPI_MASK) >> NSH_SPI_SHIFT; uint8_t si = (path_hdr & NSH_SI_MASK) >> NSH_SI_SHIFT; + uint8_t flags = nsh_get_flags(nsh_hdr); - ds_put_cstr(ds, "encap_nsh("); - ds_put_format(ds, "flags=%d", encap_nsh->flags); - ds_put_format(ds, ",mdtype=%d", encap_nsh->mdtype); - ds_put_format(ds, ",np=%d", encap_nsh->np); + ds_put_cstr(ds, "push_nsh("); + ds_put_format(ds, "flags=%d", flags); + ds_put_format(ds, ",mdtype=%d", nsh_hdr->md_type); + ds_put_format(ds, ",np=%d", nsh_hdr->next_proto); ds_put_format(ds, ",spi=0x%x", spi); ds_put_format(ds, ",si=%d", si); - switch (encap_nsh->mdtype) { + switch (nsh_hdr->md_type) { case NSH_M_TYPE1: { - struct nsh_md1_ctx *md1_ctx = - ALIGNED_CAST(struct nsh_md1_ctx *, encap_nsh->metadata); + const struct nsh_md1_ctx *md1_ctx = &nsh_hdr->md1; for (int i = 0; i < 4; i++) { ds_put_format(ds, ",c%d=0x%x", i + 1, - ntohl(get_16aligned_be32(&md1_ctx->c[i]))); + ntohl(get_16aligned_be32(&md1_ctx->context[i]))); } break; } - case NSH_M_TYPE2: + case NSH_M_TYPE2: { + const struct nsh_md2_tlv *md2_ctx = &nsh_hdr->md2; ds_put_cstr(ds, ",md2="); - ds_put_hex(ds, encap_nsh->metadata, encap_nsh->mdlen); + ds_put_hex(ds, md2_ctx, mdlen); break; + } default: OVS_NOT_REACHED(); } @@ -1048,11 +1055,16 @@ format_odp_action(struct ds *ds, const struct nlattr *a, case OVS_ACTION_ATTR_CLONE: format_odp_clone_action(ds, a, portno_names); break; - case OVS_ACTION_ATTR_ENCAP_NSH: - format_odp_encap_nsh_action(ds, nl_attr_get(a)); + case OVS_ACTION_ATTR_PUSH_NSH: { + uint8_t buffer[NSH_HDR_MAX_LEN]; + struct nsh_hdr *nsh_hdr = ALIGNED_CAST(struct nsh_hdr *, buffer); + nsh_reset_ver_flags_ttl_len(nsh_hdr); + odp_nsh_hdr_from_attr(nl_attr_get(a), nsh_hdr, NSH_HDR_MAX_LEN); + format_odp_push_nsh_action(ds, nsh_hdr); break; - case OVS_ACTION_ATTR_DECAP_NSH: - ds_put_cstr(ds, "decap_nsh()"); + } + case OVS_ACTION_ATTR_POP_NSH: + ds_put_cstr(ds, "pop_nsh()"); break; case OVS_ACTION_ATTR_UNSPEC: case __OVS_ACTION_ATTR_MAX: @@ -1771,27 +1783,74 @@ find_end: return s - s_; } +static void +nsh_key_to_attr(struct ofpbuf *buf, const struct flow_nsh *nsh, + uint8_t * metadata, size_t md_size, + bool is_mask) +{ + size_t nsh_key_ofs; + struct ovs_nsh_key_base base; + struct ovs_nsh_key_md1 md1; + + base.flags = nsh->flags; + base.mdtype = nsh->mdtype; + base.np = nsh->np; + base.path_hdr = htonl((ntohl(nsh->spi) << NSH_SPI_SHIFT) | + nsh->si); + + nsh_key_ofs = nl_msg_start_nested(buf, OVS_KEY_ATTR_NSH); + nl_msg_put_unspec(buf, OVS_NSH_KEY_ATTR_BASE, &base, sizeof base); + + if (is_mask) { + for (int i = 0; i < 4; i++) { + md1.context[i] = nsh->context[i]; + } + nl_msg_put_unspec(buf, OVS_NSH_KEY_ATTR_MD1, &md1, sizeof md1); + } else { + switch (nsh->mdtype) { + case NSH_M_TYPE1: + for (int i = 0; i < 4; i++) { + md1.context[i] = nsh->context[i]; + } + nl_msg_put_unspec(buf, OVS_NSH_KEY_ATTR_MD1, &md1, sizeof md1); + break; + case NSH_M_TYPE2: + if (metadata && md_size > 0) { + nl_msg_put_unspec(buf, OVS_NSH_KEY_ATTR_MD2, metadata, + md_size); + } + break; + default: + /* No match support for other MD formats yet. */ + break; + } + } + nl_msg_end_nested(buf, nsh_key_ofs); +} + + static int -parse_odp_encap_nsh_action(const char *s, struct ofpbuf *actions) +parse_odp_push_nsh_action(const char *s, struct ofpbuf *actions) { int n = 0; int ret = 0; - struct ovs_action_encap_nsh encap_nsh; - uint32_t spi; - uint8_t si; uint32_t cd; + struct flow_nsh nsh; + uint8_t *metadata = NULL; + uint8_t md_size = 0; - if (!ovs_scan_len(s, &n, "encap_nsh(")) { + if (!ovs_scan_len(s, &n, "push_nsh(")) { ret = -EINVAL; goto out; } /* 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); + nsh.flags = 0; + nsh.mdtype = NSH_M_TYPE1; + nsh.np = NSH_P_ETHERNET; + nsh.spi = 0; + nsh.si = 255; + memset(nsh.context, 0, NSH_M_TYPE1_MDLEN); for (;;) { n += strspn(s + n, delimiters); @@ -1799,17 +1858,17 @@ 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, &nsh.flags)) { continue; } - if (ovs_scan_len(s, &n, "mdtype=%"SCNi8, &encap_nsh.mdtype)) { - switch (encap_nsh.mdtype) { + if (ovs_scan_len(s, &n, "mdtype=%"SCNi8, &nsh.mdtype)) { + switch (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; + md_size = 0; break; default: ret = -EINVAL; @@ -1817,55 +1876,49 @@ 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, &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 (ovs_scan_len(s, &n, "spi=0x%"SCNx32, &nsh.spi)) { + nsh.spi = htonl(nsh.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)); + if (ovs_scan_len(s, &n, "si=%"SCNi8, &nsh.si)) { continue; } - if (encap_nsh.mdtype == NSH_M_TYPE1) { - struct nsh_md1_ctx *md1 = - ALIGNED_CAST(struct nsh_md1_ctx *, encap_nsh.metadata); + if (nsh.mdtype == NSH_M_TYPE1) { if (ovs_scan_len(s, &n, "c1=0x%"SCNx32, &cd)) { - put_16aligned_be32(&md1->c[0], htonl(cd)); + nsh.context[0] = htonl(cd); continue; } if (ovs_scan_len(s, &n, "c2=0x%"SCNx32, &cd)) { - put_16aligned_be32(&md1->c[1], htonl(cd)); + nsh.context[1] = htonl(cd); continue; } if (ovs_scan_len(s, &n, "c3=0x%"SCNx32, &cd)) { - put_16aligned_be32(&md1->c[2], htonl(cd)); + nsh.context[2] = htonl(cd); continue; } if (ovs_scan_len(s, &n, "c4=0x%"SCNx32, &cd)) { - put_16aligned_be32(&md1->c[3], htonl(cd)); + nsh.context[3] = htonl(cd); continue; } } - else if (encap_nsh.mdtype == NSH_M_TYPE2) { + else if (nsh.mdtype == NSH_M_TYPE2) { struct ofpbuf b; char buf[512]; size_t mdlen, padding; 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); + metadata = xmalloc(NSH_CTX_HDRS_MAX_LEN); + ofpbuf_use_stub(&b, metadata, + NSH_CTX_HDRS_MAX_LEN); ofpbuf_put_hex(&b, buf, &mdlen); /* Pad metadata to 4 bytes. */ padding = PAD_SIZE(mdlen, 4); if (padding > 0) { ofpbuf_push_zeros(&b, padding); } - encap_nsh.mdlen = mdlen + padding; + md_size = mdlen + padding; ofpbuf_uninit(&b); continue; } @@ -1875,15 +1928,16 @@ parse_odp_encap_nsh_action(const char *s, struct ofpbuf *actions) goto out; } out: - if (ret < 0) { - return ret; - } else { - size_t size = offsetof(struct ovs_action_encap_nsh, metadata) - + ROUND_UP(encap_nsh.mdlen, 4); - nl_msg_put_unspec(actions, OVS_ACTION_ATTR_ENCAP_NSH, - &encap_nsh, size); - return n; + if (ret >= 0) { + size_t offset = nl_msg_start_nested(actions, OVS_ACTION_ATTR_PUSH_NSH); + nsh_key_to_attr(actions, &nsh, metadata, md_size, false); + nl_msg_end_nested(actions, offset); + ret = n; + } + if (metadata != NULL) { + free(metadata); } + return ret; } static int @@ -2097,8 +2151,8 @@ parse_odp_action(const char *s, const struct simap *port_names, } { - if (!strncmp(s, "encap_nsh(", 10)) { - int retval = parse_odp_encap_nsh_action(s, actions); + if (!strncmp(s, "push_nsh(", 9)) { + int retval = parse_odp_push_nsh_action(s, actions); if (retval < 0) { return retval; } @@ -2108,8 +2162,8 @@ parse_odp_action(const char *s, const struct simap *port_names, { int n; - if (ovs_scan(s, "decap_nsh()%n", &n)) { - nl_msg_put_flag(actions, OVS_ACTION_ATTR_DECAP_NSH); + if (ovs_scan(s, "pop_nsh()%n", &n)) { + nl_msg_put_flag(actions, OVS_ACTION_ATTR_POP_NSH); return n; } } @@ -2206,6 +2260,13 @@ static const struct attr_len_tbl ovs_tun_key_attr_lens[OVS_TUNNEL_KEY_ATTR_MAX + [OVS_TUNNEL_KEY_ATTR_IPV6_DST] = { .len = 16 }, }; +static const struct attr_len_tbl +ovs_nsh_key_attr_lens[OVS_NSH_KEY_ATTR_MAX + 1] = { + [OVS_NSH_KEY_ATTR_BASE] = { .len = 8 }, + [OVS_NSH_KEY_ATTR_MD1] = { .len = 16 }, + [OVS_NSH_KEY_ATTR_MD2] = { .len = ATTR_LEN_VARIABLE }, +}; + const struct attr_len_tbl ovs_flow_key_attr_lens[OVS_KEY_ATTR_MAX + 1] = { [OVS_KEY_ATTR_ENCAP] = { .len = ATTR_LEN_NESTED }, [OVS_KEY_ATTR_PRIORITY] = { .len = 4 }, @@ -2237,7 +2298,9 @@ const struct attr_len_tbl ovs_flow_key_attr_lens[OVS_KEY_ATTR_MAX + 1] = { [OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4] = { .len = sizeof(struct ovs_key_ct_tuple_ipv4) }, [OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6] = { .len = sizeof(struct ovs_key_ct_tuple_ipv6) }, [OVS_KEY_ATTR_PACKET_TYPE] = { .len = 4 }, - [OVS_KEY_ATTR_NSH] = { .len = sizeof(struct ovs_key_nsh) }, + [OVS_KEY_ATTR_NSH] = { .len = ATTR_LEN_NESTED, + .next = ovs_nsh_key_attr_lens, + .next_max = OVS_NSH_KEY_ATTR_MAX }, }; /* Returns the correct length of the payload for a flow key attribute of the @@ -2288,6 +2351,142 @@ ovs_frag_type_to_string(enum ovs_frag_type type) } } +enum odp_key_fitness +odp_nsh_hdr_from_attr(const struct nlattr *attr, + struct nsh_hdr *nsh_hdr, size_t size) +{ + unsigned int left; + const struct nlattr *a; + bool unknown = false; + uint8_t flags = 0; + size_t mdlen = 0; + bool has_md1 = false; + bool has_md2 = false; + + NL_NESTED_FOR_EACH (a, left, attr) { + uint16_t type = nl_attr_type(a); + size_t len = nl_attr_get_size(a); + int expected_len = odp_key_attr_len(ovs_nsh_key_attr_lens, + OVS_NSH_KEY_ATTR_MAX, type); + + if (len != expected_len && expected_len >= 0) { + return ODP_FIT_ERROR; + } + + switch (type) { + case OVS_NSH_KEY_ATTR_BASE: { + const struct ovs_nsh_key_base *base = nl_attr_get(a); + nsh_hdr->next_proto = base->np; + nsh_hdr->md_type = base->mdtype; + put_16aligned_be32(&nsh_hdr->path_hdr, base->path_hdr); + flags = base->flags; + break; + } + case OVS_NSH_KEY_ATTR_MD1: { + const struct ovs_nsh_key_md1 *md1 = nl_attr_get(a); + struct nsh_md1_ctx *md1_dst = &nsh_hdr->md1; + has_md1 = true; + mdlen = nl_attr_get_size(a); + if ((mdlen + NSH_BASE_HDR_LEN != NSH_M_TYPE1_LEN) || + (mdlen + NSH_BASE_HDR_LEN > size)) { + return ODP_FIT_ERROR; + } + memcpy(md1_dst, md1, mdlen); + break; + } + case OVS_NSH_KEY_ATTR_MD2: { + struct nsh_md2_tlv *md2_dst = &nsh_hdr->md2; + const uint8_t *md2 = nl_attr_get(a); + has_md2 = true; + mdlen = nl_attr_get_size(a); + if (mdlen + NSH_BASE_HDR_LEN > size) { + return ODP_FIT_ERROR; + } + memcpy(md2_dst, md2, mdlen); + break; + } + default: + /* Allow this to show up as unexpected, if there are unknown + * tunnel attribute, eventually resulting in ODP_FIT_TOO_MUCH. */ + unknown = true; + break; + } + } + + if (unknown) { + return ODP_FIT_TOO_MUCH; + } + + if ((has_md1 && nsh_hdr->md_type != NSH_M_TYPE1) + || (has_md2 && nsh_hdr->md_type != NSH_M_TYPE2)) { + return ODP_FIT_ERROR; + } + + /* nsh header length = NSH_BASE_HDR_LEN + mdlen */ + nsh_hdr->ver_flags_ttl_len = htons(flags << NSH_FLAGS_SHIFT | + (NSH_BASE_HDR_LEN + mdlen) >> 2); + + return ODP_FIT_PERFECT; +} + +enum odp_key_fitness +odp_nsh_key_from_attr(const struct nlattr *attr, struct flow_nsh *nsh) +{ + unsigned int left; + const struct nlattr *a; + bool unknown = false; + bool has_md1 = false; + + NL_NESTED_FOR_EACH (a, left, attr) { + uint16_t type = nl_attr_type(a); + size_t len = nl_attr_get_size(a); + int expected_len = odp_key_attr_len(ovs_nsh_key_attr_lens, + OVS_NSH_KEY_ATTR_MAX, type); + + if (len != expected_len && expected_len >= 0) { + return ODP_FIT_ERROR; + } + + switch (type) { + case OVS_NSH_KEY_ATTR_BASE: { + const struct ovs_nsh_key_base *base = nl_attr_get(a); + nsh->flags = base->flags; + nsh->mdtype = base->mdtype; + nsh->np = base->np; + nsh->spi = htonl((ntohl(base->path_hdr) & NSH_SPI_MASK) >> + NSH_SPI_SHIFT); + nsh->si = (ntohl(base->path_hdr) & NSH_SI_MASK) >> NSH_SI_SHIFT; + break; + } + case OVS_NSH_KEY_ATTR_MD1: { + const struct ovs_nsh_key_md1 *md1 = nl_attr_get(a); + has_md1 = true; + nsh->context[0] = md1->context[0]; + nsh->context[1] = md1->context[1]; + nsh->context[2] = md1->context[2]; + nsh->context[3] = md1->context[3]; + break; + } + case OVS_NSH_KEY_ATTR_MD2: + default: + /* Allow this to show up as unexpected, if there are unknown + * tunnel attribute, eventually resulting in ODP_FIT_TOO_MUCH. */ + unknown = true; + break; + } + } + + if (unknown) { + return ODP_FIT_TOO_MUCH; + } + + if (has_md1 && nsh->mdtype != NSH_M_TYPE1) { + return ODP_FIT_ERROR; + } + + return ODP_FIT_PERFECT; +} + static enum odp_key_fitness odp_tun_key_from_attr__(const struct nlattr *attr, bool is_mask, struct flow_tnl *tun) @@ -2979,6 +3178,82 @@ format_odp_tun_geneve(const struct nlattr *attr, } static void +format_odp_nsh_attr(const struct nlattr *attr, const struct nlattr *mask_attr, + struct ds *ds) +{ + unsigned int left; + const struct nlattr *a; + struct ovs_key_nsh nsh; + struct ovs_key_nsh nsh_mask; + + memset(&nsh, 0, sizeof nsh); + memset(&nsh_mask, 0xff, sizeof nsh_mask); + + NL_NESTED_FOR_EACH (a, left, attr) { + enum ovs_nsh_key_attr type = nl_attr_type(a); + const struct nlattr *ma = NULL; + + if (mask_attr) { + ma = nl_attr_find__(nl_attr_get(mask_attr), + nl_attr_get_size(mask_attr), type); + } + + if (!check_attr_len(ds, a, ma, ovs_nsh_key_attr_lens, + OVS_NSH_KEY_ATTR_MAX, true)) { + continue; + } + + switch (type) { + case OVS_NSH_KEY_ATTR_UNSPEC: + break; + case OVS_NSH_KEY_ATTR_BASE: { + const struct ovs_nsh_key_base * base = nl_attr_get(a); + const struct ovs_nsh_key_base * base_mask + = ma ? nl_attr_get(ma) : NULL; + nsh.flags = base->flags; + nsh.mdtype = base->mdtype; + nsh.np = base->np; + nsh.path_hdr = base->path_hdr; + if (base_mask) { + nsh_mask.flags = base_mask->flags; + nsh_mask.mdtype = base_mask->mdtype; + nsh_mask.np = base_mask->np; + nsh_mask.path_hdr = base_mask->path_hdr; + } + break; + } + case OVS_NSH_KEY_ATTR_MD1: { + const struct ovs_nsh_key_md1 * md1 = nl_attr_get(a); + const struct ovs_nsh_key_md1 * md1_mask + = ma ? nl_attr_get(ma) : NULL; + nsh.context[0] = md1->context[0]; + nsh.context[1] = md1->context[1]; + nsh.context[2] = md1->context[2]; + nsh.context[3] = md1->context[3]; + if (md1_mask) { + nsh_mask.context[0] = md1_mask->context[0]; + nsh_mask.context[1] = md1_mask->context[1]; + nsh_mask.context[2] = md1_mask->context[2]; + nsh_mask.context[3] = md1_mask->context[3]; + } + break; + } + case OVS_NSH_KEY_ATTR_MD2: + case __OVS_NSH_KEY_ATTR_MAX: + default: + /* No support for matching other metadata formats yet. */ + break; + } + } + + if (mask_attr) { + format_nsh_key_mask(ds, &nsh, &nsh_mask); + } else { + format_nsh_key(ds, &nsh); + } +} + +static void format_odp_tun_attr(const struct nlattr *attr, const struct nlattr *mask_attr, struct ds *ds, bool verbose) { @@ -3456,9 +3731,7 @@ format_odp_key_attr__(const struct nlattr *a, const struct nlattr *ma, break; } case OVS_KEY_ATTR_NSH: { - const struct ovs_key_nsh *mask = ma ? nl_attr_get(ma) : NULL; - const struct ovs_key_nsh *key = nl_attr_get(a); - format_nsh_key_mask(ds, key, mask); + format_odp_nsh_attr(a, ma, ds); break; } case OVS_KEY_ATTR_UNSPEC: @@ -4557,6 +4830,129 @@ geneve_to_attr(struct ofpbuf *a, const void *data_) } SCAN_END_SINGLE(ATTR) static int +parse_odp_nsh_key_mask_attr(const char *s, struct ofpbuf *key, + struct ofpbuf *mask) +{ + if (strncmp(s, "nsh(", 4) == 0) { + const char *start = s; + int len; + struct flow_nsh skey, smask; + + s += 4; + + memset(&skey, 0, sizeof skey); + memset(&smask, 0, sizeof smask); + do { + len = 0; + + if (strncmp(s, "flags=", 6) == 0) { + s += 6; + len = scan_u8(s, &skey.flags, mask ? &smask.flags : NULL); + if (len == 0) { + return -EINVAL; + } + s += len; + continue; + } + + if (strncmp(s, "mdtype=", 7) == 0) { + s += 7; + len = scan_u8(s, &skey.mdtype, mask ? &smask.mdtype : NULL); + if (len == 0) { + return -EINVAL; + } + s += len; + continue; + } + + if (strncmp(s, "np=", 3) == 0) { + s += 3; + len = scan_u8(s, &skey.np, mask ? &smask.np : NULL); + if (len == 0) { + return -EINVAL; + } + s += len; + continue; + } + + if (strncmp(s, "spi=", 4) == 0) { + s += 4; + len = scan_be32(s, &skey.spi, mask ? &smask.spi : NULL); + if (len == 0) { + return -EINVAL; + } + s += len; + continue; + } + + if (strncmp(s, "si=", 3) == 0) { + s += 3; + len = scan_u8(s, &skey.si, mask ? &smask.si : NULL); + if (len == 0) { + return -EINVAL; + } + s += len; + continue; + } + + if (strncmp(s, "c1=", 3) == 0) { + s += 3; + len = scan_be32(s, &skey.context[0], + mask ? &smask.context[0] : NULL); + if (len == 0) { + return -EINVAL; + } + s += len; + continue; + } + + if (strncmp(s, "c2=", 3) == 0) { + s += 3; + len = scan_be32(s, &skey.context[1], + mask ? &smask.context[1] : NULL); + if (len == 0) { + return -EINVAL; + } + s += len; + continue; + } + + if (strncmp(s, "c3=", 3) == 0) { + s += 3; + len = scan_be32(s, &skey.context[2], + mask ? &smask.context[2] : NULL); + if (len == 0) { + return -EINVAL; + } + s += len; + continue; + } + + if (strncmp(s, "c4=", 3) == 0) { + s += 3; + len = scan_be32(s, &skey.context[3], + mask ? &smask.context[3] : NULL); + if (len == 0) { + return -EINVAL; + } + s += len; + continue; + } + } while (*s++ == ',' && len != 0); + if (s[-1] != ')') { + return -EINVAL; + } + + nsh_key_to_attr(key, &skey, NULL, 0, false); + if (mask) { + nsh_key_to_attr(mask, &smask, NULL, 0, true); + } + return s - start; + } + return 0; +} + +static int parse_odp_key_mask_attr(const char *s, const struct simap *port_names, struct ofpbuf *key, struct ofpbuf *mask) { @@ -4702,16 +5098,13 @@ parse_odp_key_mask_attr(const char *s, const struct simap *port_names, SCAN_FIELD("id=", be16, id); } SCAN_END(OVS_KEY_ATTR_PACKET_TYPE); - SCAN_BEGIN("nsh(", struct ovs_key_nsh) { - SCAN_FIELD("flags=", u8, flags); - SCAN_FIELD("mdtype=", u8, mdtype); - SCAN_FIELD("np=", u8, np); - SCAN_FIELD("path_hdr=", be32, path_hdr); - SCAN_FIELD("c1=", be32, c[0]); - SCAN_FIELD("c2=", be32, c[1]); - SCAN_FIELD("c3=", be32, c[2]); - SCAN_FIELD("c4=", be32, c[2]); - } SCAN_END(OVS_KEY_ATTR_NSH); + /* nsh is nested, it needs special process */ + int ret = parse_odp_nsh_key_mask_attr(s, key, mask); + if (ret < 0) { + return ret; + } else { + s += ret; + } /* Encap open-coded. */ if (!strncmp(s, "encap(", 6)) { @@ -5002,11 +5395,7 @@ odp_flow_key_from_flow__(const struct odp_flow_key_parms *parms, mpls_key[i].mpls_lse = data->mpls_lse[i]; } } else if (flow->dl_type == htons(ETH_TYPE_NSH)) { - struct ovs_key_nsh *nsh_key; - - nsh_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_NSH, - sizeof *nsh_key); - get_nsh_key(data, nsh_key, export_mask); + nsh_key_to_attr(buf, &data->nsh, NULL, 0, export_mask); } if (is_ip_any(flow) && !(flow->nw_frag & FLOW_NW_FRAG_LATER)) { @@ -5566,13 +5955,10 @@ parse_l2_5_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1], expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_NSH; } if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_NSH)) { - const struct ovs_key_nsh *nsh_key; - - nsh_key = nl_attr_get(attrs[OVS_KEY_ATTR_NSH]); - put_nsh_key(nsh_key, flow, false); + odp_nsh_key_from_attr(attrs[OVS_KEY_ATTR_NSH], &flow->nsh); if (is_mask) { - check_start = nsh_key; - check_len = sizeof *nsh_key; + check_start = nl_attr_get(attrs[OVS_KEY_ATTR_NSH]); + check_len = nl_attr_get_size(attrs[OVS_KEY_ATTR_NSH]); expected_bit = OVS_KEY_ATTR_NSH; } } @@ -6628,13 +7014,13 @@ get_nsh_key(const struct flow *flow, struct ovs_key_nsh *nsh, bool is_mask) flow->nsh.si); if (is_mask) { for (int i = 0; i < 4; i++) { - nsh->c[i] = flow->nsh.c[i]; + nsh->context[i] = flow->nsh.context[i]; } } else { switch (nsh->mdtype) { case NSH_M_TYPE1: for (int i = 0; i < 4; i++) { - nsh->c[i] = flow->nsh.c[i]; + nsh->context[i] = flow->nsh.context[i]; } break; case NSH_M_TYPE2: @@ -6658,15 +7044,123 @@ put_nsh_key(const struct ovs_key_nsh *nsh, struct flow *flow, switch (nsh->mdtype) { case NSH_M_TYPE1: for (int i = 0; i < 4; i++) { - flow->nsh.c[i] = nsh->c[i]; + flow->nsh.context[i] = nsh->context[i]; + } + break; + case NSH_M_TYPE2: + default: + /* No match support for other MD formats yet. */ + memset(flow->nsh.context, 0, sizeof flow->nsh.context); + break; + } +} + +static bool +commit_nsh(const struct flow_nsh * flow_nsh, bool use_masked_set, + const struct ovs_key_nsh *key, struct ovs_key_nsh *base, + struct ovs_key_nsh *mask, size_t size, + struct ofpbuf *odp_actions) +{ + enum ovs_key_attr attr = OVS_KEY_ATTR_NSH; + + if (memcmp(key, base, size) == 0) { + /* Mask bits are set when we have either read or set the corresponding + * values. Masked bits will be exact-matched, no need to set them + * if the value did not actually change. */ + return false; + } + + bool fully_masked = odp_mask_is_exact(attr, mask, size); + + if (use_masked_set && !fully_masked) { + size_t nsh_key_ofs; + struct ovs_nsh_key_base nsh_base; + struct ovs_nsh_key_base nsh_base_mask; + struct ovs_nsh_key_md1 md1; + struct ovs_nsh_key_md1 md1_mask; + size_t offset = nl_msg_start_nested(odp_actions, + OVS_ACTION_ATTR_SET_MASKED); + + nsh_base.flags = key->flags; + nsh_base.mdtype = key->mdtype; + nsh_base.np = key->np; + nsh_base.path_hdr = key->path_hdr; + + nsh_base_mask.flags = mask->flags; + nsh_base_mask.mdtype = mask->mdtype; + nsh_base_mask.np = mask->np; + nsh_base_mask.path_hdr = mask->path_hdr; + + /* OVS_KEY_ATTR_NSH keys */ + nsh_key_ofs = nl_msg_start_nested(odp_actions, OVS_KEY_ATTR_NSH); + + char *data = nl_msg_put_unspec_uninit(odp_actions, + OVS_NSH_KEY_ATTR_BASE, + sizeof(nsh_base)); + const char *lkey = (char *)&nsh_base, *lmask = (char *)&nsh_base_mask; + size_t lkey_size = sizeof(nsh_base); + + while (lkey_size--) { + *data++ = *lkey++ & *lmask++; + } + + switch (key->mdtype) { + case NSH_M_TYPE1: + for (int i = 0; i < 4; i++) { + md1.context[i] = key->context[i]; + md1_mask.context[i] = mask->context[i]; + } + data = nl_msg_put_unspec_uninit(odp_actions, + OVS_NSH_KEY_ATTR_MD1, + sizeof(md1)); + lkey = (char *)&md1; + lmask = (char *)&md1_mask; + lkey_size = sizeof(md1); + + while (lkey_size--) { + *data++ = *lkey++ & *lmask++; } break; case NSH_M_TYPE2: default: /* No match support for other MD formats yet. */ - memset(flow->nsh.c, 0, sizeof flow->nsh.c); break; + } + + /* OVS_KEY_ATTR_NSH masks */ + data = nl_msg_put_unspec_uninit(odp_actions, + OVS_NSH_KEY_ATTR_BASE, + sizeof(nsh_base_mask)); + lmask = (char *)&nsh_base_mask; + + memcpy(data, lmask, sizeof(nsh_base_mask)); + + switch (key->mdtype) { + case NSH_M_TYPE1: + data = nl_msg_put_unspec_uninit(odp_actions, + OVS_NSH_KEY_ATTR_MD1, + sizeof(md1_mask)); + lmask = (char *)&md1_mask; + memcpy(data, lmask, sizeof(md1_mask)); + break; + case NSH_M_TYPE2: + default: + /* No match support for other MD formats yet. */ + break; + } + nl_msg_end_nested(odp_actions, nsh_key_ofs); + + nl_msg_end_nested(odp_actions, offset); + } else { + if (!fully_masked) { + memset(mask, 0xff, size); + } + size_t offset = nl_msg_start_nested(odp_actions, OVS_ACTION_ATTR_SET); + nsh_key_to_attr(odp_actions, flow_nsh, NULL, 0, false); + nl_msg_end_nested(odp_actions, offset); } + memcpy(base, key, size); + return true; } static void @@ -6692,8 +7186,8 @@ commit_set_nsh_action(const struct flow *flow, struct flow *base_flow, mask.mdtype = 0; /* Not writable. */ mask.np = 0; /* Not writable. */ - if (commit(OVS_KEY_ATTR_NSH, use_masked, &key, &base, &mask, sizeof key, - odp_actions)) { + if (commit_nsh(&base_flow->nsh, use_masked, &key, &base, &mask, + sizeof key, odp_actions)) { put_nsh_key(&base, base_flow, false); if (mask.mdtype != 0) { /* Mask was changed by commit(). */ put_nsh_key(&mask, &wc->masks, true); @@ -6796,49 +7290,36 @@ commit_set_pkt_mark_action(const struct flow *flow, struct flow *base_flow, } static void -odp_put_decap_nsh_action(struct ofpbuf *odp_actions) +odp_put_pop_nsh_action(struct ofpbuf *odp_actions) { - nl_msg_put_flag(odp_actions, OVS_ACTION_ATTR_DECAP_NSH); + nl_msg_put_flag(odp_actions, OVS_ACTION_ATTR_POP_NSH); } static void -odp_put_encap_nsh_action(struct ofpbuf *odp_actions, +odp_put_push_nsh_action(struct ofpbuf *odp_actions, const struct flow *flow, struct ofpbuf *encap_data) { - struct ovs_action_encap_nsh encap_nsh; - - 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); + uint8_t * metadata = NULL; + uint8_t md_size = 0; - 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]); - } - break; - } + switch (flow->nsh.mdtype) { 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); + metadata = encap_data->data; + md_size = encap_data->size; } else { - encap_nsh.mdlen = 0; + md_size = 0; } break; default: - encap_nsh.mdlen = 0; + md_size = 0; break; } - nl_msg_put_unspec(odp_actions, OVS_ACTION_ATTR_ENCAP_NSH, - &encap_nsh, sizeof(encap_nsh)); + size_t offset = nl_msg_start_nested(odp_actions, OVS_ACTION_ATTR_PUSH_NSH); + nsh_key_to_attr(odp_actions, &flow->nsh, metadata, md_size, false); + nl_msg_end_nested(odp_actions, offset); } static void @@ -6865,8 +7346,8 @@ commit_packet_type_change(const struct flow *flow, break; } case PT_NSH: - /* encap_nsh */ - odp_put_encap_nsh_action(odp_actions, flow, encap_data); + /* push_nsh */ + odp_put_push_nsh_action(odp_actions, flow, encap_data); base_flow->packet_type = flow->packet_type; /* Update all packet headers in base_flow. */ memcpy(&base_flow->dl_dst, &flow->dl_dst, @@ -6891,8 +7372,8 @@ commit_packet_type_change(const struct flow *flow, * No need to update the base flow here. */ switch (ntohl(base_flow->packet_type)) { case PT_NSH: - /* decap_nsh. */ - odp_put_decap_nsh_action(odp_actions); + /* pop_nsh. */ + odp_put_pop_nsh_action(odp_actions); break; default: /* Checks are done during translation. */ diff --git a/lib/odp-util.h b/lib/odp-util.h index 72a3c30..f7ce206 100644 --- a/lib/odp-util.h +++ b/lib/odp-util.h @@ -158,6 +158,10 @@ struct odputil_keybuf { enum odp_key_fitness odp_tun_key_from_attr(const struct nlattr *, struct flow_tnl *); +enum odp_key_fitness odp_nsh_key_from_attr(const struct nlattr *, + struct flow_nsh *); +enum odp_key_fitness odp_nsh_hdr_from_attr(const struct nlattr *, + struct nsh_hdr *, size_t size); int odp_ufid_from_string(const char *s_, ovs_u128 *ufid); void odp_format_ufid(const ovs_u128 *ufid, struct ds *); diff --git a/lib/packets.c b/lib/packets.c index f589370..8b63b9d 100644 --- a/lib/packets.c +++ b/lib/packets.c @@ -405,10 +405,10 @@ pop_mpls(struct dp_packet *packet, ovs_be16 ethtype) } void -encap_nsh(struct dp_packet *packet, const struct ovs_action_encap_nsh *encap) +push_nsh(struct dp_packet *packet, const struct nsh_hdr *nsh_hdr_src) { struct nsh_hdr *nsh; - size_t length = NSH_BASE_HDR_LEN + encap->mdlen; + size_t length = nsh_hdr_len(nsh_hdr_src); uint8_t next_proto; switch (ntohl(packet->packet_type)) { @@ -429,33 +429,15 @@ 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_ttl_len = - htons(((encap->flags << NSH_FLAGS_SHIFT) & NSH_FLAGS_MASK) - | (63 << NSH_TTL_SHIFT) - | ((length >> 2) << NSH_LEN_SHIFT)); - nsh->md_type = (encap->mdtype << NSH_MDTYPE_SHIFT) & NSH_MDTYPE_MASK; + memcpy(nsh, nsh_hdr_src, length); nsh->next_proto = next_proto; - put_16aligned_be32(&nsh->path_hdr, encap->path_hdr); - switch (encap->mdtype) { - case NSH_M_TYPE1: - nsh->md1 = *ALIGNED_CAST(struct nsh_md1_ctx *, encap->metadata); - break; - case NSH_M_TYPE2: { - /* The MD2 metadata in encap is already padded to 4 bytes. */ - memcpy(&nsh->md2, encap->metadata, encap->mdlen); - break; - } - default: - OVS_NOT_REACHED(); - } - packet->packet_type = htonl(PT_NSH); dp_packet_reset_offsets(packet); packet->l3_ofs = 0; } bool -decap_nsh(struct dp_packet *packet) +pop_nsh(struct dp_packet *packet) { struct nsh_hdr *nsh = (struct nsh_hdr *) dp_packet_l3(packet); size_t length; diff --git a/lib/packets.h b/lib/packets.h index 13ea46d..078cfe5 100644 --- a/lib/packets.h +++ b/lib/packets.h @@ -434,9 +434,8 @@ void push_eth(struct dp_packet *packet, const struct eth_addr *dst, const struct eth_addr *src); void pop_eth(struct dp_packet *packet); -void encap_nsh(struct dp_packet *packet, - const struct ovs_action_encap_nsh *encap_nsh); -bool decap_nsh(struct dp_packet *packet); +void push_nsh(struct dp_packet *packet, const struct nsh_hdr *nsh_hdr_src); +bool pop_nsh(struct dp_packet *packet); #define LLC_DSAP_SNAP 0xaa #define LLC_SSAP_SNAP 0xaa diff --git a/ofproto/ofproto-dpif-ipfix.c b/ofproto/ofproto-dpif-ipfix.c index 4d16878..2a43537 100644 --- a/ofproto/ofproto-dpif-ipfix.c +++ b/ofproto/ofproto-dpif-ipfix.c @@ -2822,8 +2822,8 @@ dpif_ipfix_read_actions(const struct flow *flow, case OVS_ACTION_ATTR_POP_MPLS: case OVS_ACTION_ATTR_PUSH_ETH: case OVS_ACTION_ATTR_POP_ETH: - case OVS_ACTION_ATTR_ENCAP_NSH: - case OVS_ACTION_ATTR_DECAP_NSH: + case OVS_ACTION_ATTR_PUSH_NSH: + case OVS_ACTION_ATTR_POP_NSH: case OVS_ACTION_ATTR_UNSPEC: case __OVS_ACTION_ATTR_MAX: default: diff --git a/ofproto/ofproto-dpif-sflow.c b/ofproto/ofproto-dpif-sflow.c index ccf8964..2be5869 100644 --- a/ofproto/ofproto-dpif-sflow.c +++ b/ofproto/ofproto-dpif-sflow.c @@ -1199,8 +1199,8 @@ dpif_sflow_read_actions(const struct flow *flow, break; case OVS_ACTION_ATTR_SAMPLE: case OVS_ACTION_ATTR_CLONE: - case OVS_ACTION_ATTR_ENCAP_NSH: - case OVS_ACTION_ATTR_DECAP_NSH: + case OVS_ACTION_ATTR_PUSH_NSH: + case OVS_ACTION_ATTR_POP_NSH: case OVS_ACTION_ATTR_UNSPEC: case __OVS_ACTION_ATTR_MAX: default: diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index fcced34..4fe87ec 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -4384,8 +4384,8 @@ xlate_fixup_actions(struct ofpbuf *b, const struct nlattr *actions, case OVS_ACTION_ATTR_CT: case OVS_ACTION_ATTR_PUSH_ETH: case OVS_ACTION_ATTR_POP_ETH: - case OVS_ACTION_ATTR_ENCAP_NSH: - case OVS_ACTION_ATTR_DECAP_NSH: + case OVS_ACTION_ATTR_PUSH_NSH: + case OVS_ACTION_ATTR_POP_NSH: case OVS_ACTION_ATTR_METER: ofpbuf_put(b, a, nl_attr_len_pad(a, left)); break; @@ -5820,17 +5820,17 @@ rewrite_flow_encap_ethernet(struct xlate_ctx *ctx, /* For an MD2 NSH header returns a pointer to an ofpbuf with the encoded * MD2 TLVs provided as encap properties to the encap operation. This - * will be stored as encap_data in the ctx and copied into the encap_nsh + * will be stored as encap_data in the ctx and copied into the push_nsh * action at the next commit. */ static struct ofpbuf * -rewrite_flow_encap_nsh(struct xlate_ctx *ctx, - const struct ofpact_encap *encap, - struct flow *flow, - struct flow_wildcards *wc) +rewrite_flow_push_nsh(struct xlate_ctx *ctx, + const struct ofpact_encap *encap, + struct flow *flow, + struct flow_wildcards *wc) { 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; @@ -5870,7 +5870,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; } @@ -5915,7 +5915,7 @@ rewrite_flow_encap_nsh(struct xlate_ctx *ctx, if (md_type == NSH_M_TYPE1) { flow->nsh.mdtype = NSH_M_TYPE1; - memset(flow->nsh.c, 0, sizeof flow->nsh.c); + memset(flow->nsh.context, 0, sizeof flow->nsh.context); if (buf) { /* Drop any MD2 context TLVs. */ ofpbuf_delete(buf); @@ -5946,7 +5946,7 @@ xlate_generic_encap_action(struct xlate_ctx *ctx, rewrite_flow_encap_ethernet(ctx, flow, wc); break; case PT_NSH: - encap_data = rewrite_flow_encap_nsh(ctx, encap, flow, wc); + encap_data = rewrite_flow_push_nsh(ctx, encap, flow, wc); break; default: /* New packet type was checked during decoding. */ @@ -5988,7 +5988,7 @@ xlate_generic_decap_action(struct xlate_ctx *ctx, } return false; case PT_NSH: - /* The decap_nsh action is generated at the commit executed as + /* The pop_nsh action is generated at the commit executed as * part of freezing the ctx for recirculation. Here we just set * the new packet type based on the NSH next protocol field. */ switch (flow->nsh.np) { diff --git a/tests/nsh.at b/tests/nsh.at index aa80a2a..bec6e87 100644 --- a/tests/nsh.at +++ b/tests/nsh.at @@ -105,7 +105,7 @@ bridge("br0") 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 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: push_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,pop_nsh(),set(eth(dst=11:22:33:44:55:66)),recirc(0x1) ]) AT_CHECK([ @@ -121,7 +121,7 @@ bridge("br0") Final flow: unchanged Megaflow: recirc_id=0,eth,in_port=4,dl_type=0x894f,nsh_mdtype=1,nsh_np=3,nsh_spi=0x1234,nsh_c1=0x11223344 -Datapath actions: pop_eth,decap_nsh(),recirc(0x2) +Datapath actions: pop_eth,pop_nsh(),recirc(0x2) ]) # Now send two real ICMP echo request packets in on port p1 @@ -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:push_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,pop_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 ]) @@ -166,11 +166,13 @@ AT_CHECK([ ], [0], [ignore]) ovs-appctl time/warp 1000 +ovs-appctl time/warp 1000 +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),push_nsh(flags=0,mdtype=1,np=3,spi=0x0,si=255,c1=0x0,c2=0x0,c3=0x0,c4=0x0),pop_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 +197,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 +207,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 +218,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 @@ -230,7 +232,7 @@ bridge("br0") 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 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: push_nsh(flags=0,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,pop_nsh(),set(eth(dst=11:22:33:44:55:66)),recirc(0x1) ]) AT_CHECK([ @@ -246,7 +248,7 @@ bridge("br0") Final flow: unchanged Megaflow: recirc_id=0,eth,in_port=4,dl_type=0x894f,nsh_mdtype=2,nsh_np=3,nsh_spi=0x1234 -Datapath actions: pop_eth,decap_nsh(),recirc(0x2) +Datapath actions: pop_eth,pop_nsh(),recirc(0x2) ]) # Now send two real ICMP echo request packets in on port p1 @@ -264,7 +266,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:push_nsh(flags=0,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,pop_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,8 +579,8 @@ 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)) -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) +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,push_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)) +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:pop_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,9 +633,9 @@ 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,push_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)) 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(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:pop_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 Fri Dec 8 14:04:23 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Yang, Yi" X-Patchwork-Id: 846256 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 3ytZ7L1gpCz9s71 for ; Sat, 9 Dec 2017 01:12:46 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 2B7BCD86; Fri, 8 Dec 2017 14:10:57 +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 67E90D85 for ; Fri, 8 Dec 2017 14:10:56 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mga02.intel.com (mga02.intel.com [134.134.136.20]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 372193FB for ; Fri, 8 Dec 2017 14:10:53 +0000 (UTC) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by orsmga101.jf.intel.com with ESMTP; 08 Dec 2017 06:10:28 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.45,377,1508828400"; d="scan'208";a="11701233" Received: from unknown (HELO localhost.localdomain.bj.intel.com) ([10.240.224.185]) by fmsmga001.fm.intel.com with ESMTP; 08 Dec 2017 06:10:17 -0800 From: Yi Yang To: dev@openvswitch.org Date: Fri, 8 Dec 2017 22:04:23 +0800 Message-Id: <1512741865-97333-3-git-send-email-yi.y.yang@intel.com> X-Mailer: git-send-email 2.1.0 In-Reply-To: <1512741865-97333-1-git-send-email-yi.y.yang@intel.com> References: <1512741865-97333-1-git-send-email-yi.y.yang@intel.com> X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, T_RP_MATCHES_RCVD autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH v6 2/4] 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 added a new filed ttl in NSH header, this patch is to add new nsh key 'ttl' for it. Signed-off-by: Yi Yang --- datapath/linux/compat/include/linux/openvswitch.h | 2 +- include/openvswitch/flow.h | 6 +- include/openvswitch/meta-flow.h | 31 +++- include/openvswitch/nsh.h | 96 +++++++++++ include/openvswitch/packets.h | 12 +- lib/flow.c | 23 ++- lib/flow.h | 2 +- lib/match.c | 12 +- lib/meta-flow.c | 56 +++++-- lib/meta-flow.xml | 6 +- lib/nx-match.c | 16 +- lib/odp-execute.c | 40 ++--- lib/odp-util.c | 186 ++++++++-------------- lib/odp-util.h | 2 +- lib/packets.c | 1 + ofproto/ofproto-dpif-xlate.c | 7 +- tests/nsh.at | 41 ++--- 17 files changed, 318 insertions(+), 221 deletions(-) diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h index 3ddb1c5..c7142b6 100644 --- a/datapath/linux/compat/include/linux/openvswitch.h +++ b/datapath/linux/compat/include/linux/openvswitch.h @@ -504,9 +504,9 @@ enum ovs_nsh_key_attr { struct ovs_nsh_key_base { __u8 flags; + __u8 ttl; __u8 mdtype; __u8 np; - __u8 pad; __be32 path_hdr; }; 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/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 63b480e..d12fca4 100644 --- a/include/openvswitch/nsh.h +++ b/include/openvswitch/nsh.h @@ -299,6 +299,102 @@ nsh_reset_ver_flags_ttl_len(struct nsh_hdr *nsh) nsh->ver_flags_ttl_len = 0; } +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_flags_and_ttl(struct nsh_hdr *nsh, uint8_t flags, uint8_t ttl) +{ + nsh->ver_flags_ttl_len + = htons((ntohs(nsh->ver_flags_ttl_len) + & ~(NSH_FLAGS_MASK | NSH_TTL_MASK)) + | ((flags << NSH_FLAGS_SHIFT)& NSH_FLAGS_MASK) + | ((ttl << NSH_TTL_SHIFT) & NSH_TTL_MASK)); +} + +static inline void +nsh_set_flags_ttl_len(struct nsh_hdr *nsh, uint8_t flags, uint8_t ttl, + uint16_t len) +{ + nsh->ver_flags_ttl_len + = htons((ntohs(nsh->ver_flags_ttl_len) + & ~(NSH_FLAGS_MASK | NSH_TTL_MASK | NSH_LEN_MASK)) + | ((flags << NSH_FLAGS_SHIFT)& NSH_FLAGS_MASK) + | ((ttl << NSH_TTL_SHIFT) & NSH_TTL_MASK) + | (((len >> 2) << NSH_LEN_SHIFT) & 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 5f92c01..313ba9f 100644 --- a/include/openvswitch/packets.h +++ b/include/openvswitch/packets.h @@ -73,21 +73,11 @@ union flow_vlan_hdr { }; }; -/* Network Service Header keys */ -struct flow_nsh { - uint8_t flags; - uint8_t mdtype; - uint8_t np; - uint8_t si; - ovs_be32 spi; - ovs_be32 context[4]; -}; - struct ovs_key_nsh { uint8_t flags; + uint8_t ttl; uint8_t mdtype; uint8_t np; - uint8_t pad; ovs_be32 path_hdr; ovs_be32 context[4]; }; diff --git a/lib/flow.c b/lib/flow.c index 964f734..f9d7c2a 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -530,11 +530,10 @@ 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; - uint8_t version, length, flags; - uint32_t path_hdr; + uint8_t version, length, flags, ttl; /* Check if it is long enough for NSH header, doesn't support * MD type 2 yet @@ -546,18 +545,17 @@ parse_nsh(const void **datap, size_t *sizep, struct flow_nsh *key) version = nsh_get_ver(nsh); flags = nsh_get_flags(nsh); length = nsh_hdr_len(nsh); + ttl = nsh_get_ttl(nsh); if (OVS_UNLIKELY(length > *sizep || version != 0)) { 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 = nsh_get_path_hdr(nsh); switch (key->mdtype) { case NSH_M_TYPE1: @@ -876,11 +874,11 @@ 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))) { miniflow_push_words(mf, nsh, &nsh, - sizeof(struct flow_nsh) / + sizeof(struct ovs_key_nsh) / sizeof(uint64_t)); } } @@ -1684,10 +1682,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.context); } else { return; /* Unknown ethertype. */ @@ -1820,8 +1818,7 @@ flow_wc_map(const struct flow *flow, struct flowmap *map) FLOWMAP_SET(map, nsh.flags); 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.context); } } diff --git a/lib/flow.h b/lib/flow.h index b3128da..eb1e2bf 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 8952c99..b880492 100644 --- a/lib/match.c +++ b/lib/match.c @@ -1260,11 +1260,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.context[0], m->nsh.context[0]); diff --git a/lib/meta-flow.c b/lib/meta-flow.c index beeddf1..ed41f50 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: @@ -606,6 +609,8 @@ mf_is_value_valid(const struct mf_field *mf, const union mf_value *value) case MFF_NSH_FLAGS: return true; + case MFF_NSH_TTL: + return (value->u8 <= 63); case MFF_NSH_MDTYPE: return (value->u8 == 1 || value->u8 == 2); case MFF_NSH_NP: @@ -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,13 @@ 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); + if (value->be32 == htonl(NSH_SPI_MASK >> NSH_SPI_SHIFT)) { + value->be32 = OVS_BE32_MAX; + } 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 +1225,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 +1235,12 @@ 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->wc.masks.nsh.path_hdr |= htonl(NSH_SPI_MASK); + nsh_path_hdr_set_spi(&match->flow.nsh.path_hdr, value->be32); break; case MFF_NSH_SI: - MATCH_SET_FIELD_UINT8(match, nsh.si, value->u8); + match->wc.masks.nsh.path_hdr |= htonl(NSH_SI_MASK); + nsh_path_hdr_set_si(&match->flow.nsh.path_hdr, value->u8); break; case MFF_NSH_C1: case MFF_NSH_C2: @@ -1606,6 +1622,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; @@ -1613,10 +1632,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: @@ -1752,6 +1771,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: @@ -2097,6 +2117,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; @@ -2104,10 +2127,12 @@ 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->wc.masks.nsh.path_hdr &= ~htonl(NSH_SPI_MASK); + nsh_path_hdr_set_spi(&match->flow.nsh.path_hdr, htonl(0)); break; case MFF_NSH_SI: - MATCH_SET_FIELD_MASKED(match, nsh.si, 0, 0); + match->wc.masks.nsh.path_hdr &= ~htonl(NSH_SI_MASK); + nsh_path_hdr_set_si(&match->flow.nsh.path_hdr, 0); break; case MFF_NSH_C1: case MFF_NSH_C2: @@ -2357,6 +2382,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; @@ -2364,10 +2392,14 @@ 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->wc.masks.nsh.path_hdr |= mask->be32; + nsh_path_hdr_set_spi(&match->flow.nsh.path_hdr, + value->be32 & mask->be32); break; case MFF_NSH_SI: - MATCH_SET_FIELD_MASKED(match, nsh.si, value->u8, mask->u8); + match->wc.masks.nsh.path_hdr |= htonl(mask->u8); + nsh_path_hdr_set_si(&match->flow.nsh.path_hdr, + 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 08ee0ec..8e00c68 100644 --- a/lib/meta-flow.xml +++ b/lib/meta-flow.xml @@ -1311,7 +1311,9 @@ tcp,tp_src=0x07c0/0xfff0 + title="flags field (2 bits)"/> + 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 8f2a442..aa7691a 100644 --- a/lib/nx-match.c +++ b/lib/nx-match.c @@ -1022,6 +1022,7 @@ 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); + ovs_be32 spi_mask; int match_len; int i; @@ -1157,13 +1158,22 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const struct match *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_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); - 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); + spi_mask = nsh_path_hdr_to_spi(match->wc.masks.nsh.path_hdr); + if (spi_mask == htonl(NSH_SPI_MASK >> NSH_SPI_SHIFT)) { + spi_mask = OVS_BE32_MAX; + } + nxm_put_32m(&ctx, MFF_NSH_SPI, oxm, + nsh_path_hdr_to_spi(flow->nsh.path_hdr), + spi_mask); + 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.context[i], match->wc.masks.nsh.context[i]); diff --git a/lib/odp-execute.c b/lib/odp-execute.c index c3c51dd..221c4d6 100644 --- a/lib/odp-execute.c +++ b/lib/odp-execute.c @@ -273,19 +273,16 @@ odp_set_nd(struct dp_packet *packet, const struct ovs_key_nd *key, /* Set the NSH header. Assumes the NSH header is present and matches the * MD format of the key. The slow path must take case of that. */ static void -odp_set_nsh(struct dp_packet *packet, const struct flow_nsh *key, - const struct flow_nsh *mask) +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); uint8_t mdtype = nsh_md_type(nsh); ovs_be32 path_hdr; if (!mask) { - nsh->ver_flags_ttl_len = htons(key->flags << NSH_FLAGS_SHIFT) | - (nsh->ver_flags_ttl_len & ~htons(NSH_FLAGS_MASK)); - path_hdr = htonl((ntohl(key->spi) << NSH_SPI_SHIFT) | - key->si); - put_16aligned_be32(&nsh->path_hdr, path_hdr); + nsh_set_flags_and_ttl(nsh, key->flags, key->ttl); + put_16aligned_be32(&nsh->path_hdr, key->path_hdr); switch (mdtype) { case NSH_M_TYPE1: for (int i = 0; i < 4; i++) { @@ -298,22 +295,25 @@ odp_set_nsh(struct dp_packet *packet, const struct flow_nsh *key, break; } } else { - uint8_t flags = (ntohs(nsh->ver_flags_ttl_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_ttl_len = htons(flags << NSH_FLAGS_SHIFT) | - (nsh->ver_flags_ttl_len & ~htons(NSH_FLAGS_MASK)); + ttl = key->ttl | (ttl & ~mask->ttl); + nsh_set_flags_and_ttl(nsh, flags, ttl); - path_hdr = get_16aligned_be32(&nsh->path_hdr); - uint32_t spi = (ntohl(path_hdr) & NSH_SPI_MASK) >> NSH_SPI_SHIFT; - uint8_t si = (ntohl(path_hdr) & NSH_SI_MASK) >> NSH_SI_SHIFT; - uint32_t spi_mask = ntohl(mask->spi); + uint32_t spi = ntohl(nsh_get_spi(nsh)); + uint8_t si = nsh_get_si(nsh); + uint32_t spi_mask = nsh_path_hdr_to_spi_uint32(mask->path_hdr); + uint8_t si_mask = nsh_path_hdr_to_si(mask->path_hdr); if (spi_mask == 0x00ffffff) { spi_mask = UINT32_MAX; } - spi = ntohl(key->spi) | (spi & ~spi_mask); - si = key->si | (si & ~mask->si); - path_hdr = htonl((spi << NSH_SPI_SHIFT) | si); + spi = nsh_path_hdr_to_spi_uint32(key->path_hdr) | (spi & ~spi_mask); + si = nsh_path_hdr_to_si(key->path_hdr) | (si & ~si_mask); + path_hdr = nsh_get_path_hdr(nsh); + nsh_path_hdr_set_spi(&path_hdr, htonl(spi)); + nsh_path_hdr_set_si(&path_hdr, si); put_16aligned_be32(&nsh->path_hdr, path_hdr); switch (mdtype) { case NSH_M_TYPE1: @@ -358,7 +358,7 @@ odp_execute_set_action(struct dp_packet *packet, const struct nlattr *a) break; case OVS_KEY_ATTR_NSH: { - struct flow_nsh nsh; + struct ovs_key_nsh nsh; odp_nsh_key_from_attr(a, &nsh); odp_set_nsh(packet, &nsh, NULL); break; @@ -489,7 +489,7 @@ odp_execute_masked_set_action(struct dp_packet *packet, break; case OVS_KEY_ATTR_NSH: { - struct flow_nsh nsh, nsh_mask; + struct ovs_key_nsh nsh, nsh_mask; size_t size = nl_attr_get_size(a) / 2; struct { struct nlattr nla; diff --git a/lib/odp-util.c b/lib/odp-util.c index 16a7751..7597814 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -245,12 +245,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: @@ -310,17 +311,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)); @@ -341,13 +341,14 @@ format_odp_push_nsh_action(struct ds *ds, const struct nsh_hdr *nsh_hdr) { size_t mdlen = nsh_hdr_len(nsh_hdr) - NSH_BASE_HDR_LEN; - uint32_t path_hdr = ntohl(get_16aligned_be32(&nsh_hdr->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 = ntohl(nsh_get_spi(nsh_hdr)); + uint8_t si = nsh_get_si(nsh_hdr); uint8_t flags = nsh_get_flags(nsh_hdr); + uint8_t ttl = nsh_get_ttl(nsh_hdr); ds_put_cstr(ds, "push_nsh("); ds_put_format(ds, "flags=%d", flags); + ds_put_format(ds, ",ttl=%d", ttl); ds_put_format(ds, ",mdtype=%d", nsh_hdr->md_type); ds_put_format(ds, ",np=%d", nsh_hdr->next_proto); ds_put_format(ds, ",spi=0x%x", spi); @@ -1784,7 +1785,7 @@ find_end: } static void -nsh_key_to_attr(struct ofpbuf *buf, const struct flow_nsh *nsh, +nsh_key_to_attr(struct ofpbuf *buf, const struct ovs_key_nsh *nsh, uint8_t * metadata, size_t md_size, bool is_mask) { @@ -1792,26 +1793,18 @@ nsh_key_to_attr(struct ofpbuf *buf, const struct flow_nsh *nsh, struct ovs_nsh_key_base base; struct ovs_nsh_key_md1 md1; - base.flags = nsh->flags; - base.mdtype = nsh->mdtype; - base.np = nsh->np; - base.path_hdr = htonl((ntohl(nsh->spi) << NSH_SPI_SHIFT) | - nsh->si); + memcpy(&base, nsh, sizeof(base)); nsh_key_ofs = nl_msg_start_nested(buf, OVS_KEY_ATTR_NSH); nl_msg_put_unspec(buf, OVS_NSH_KEY_ATTR_BASE, &base, sizeof base); if (is_mask) { - for (int i = 0; i < 4; i++) { - md1.context[i] = nsh->context[i]; - } + memcpy(&md1.context, &nsh->context, sizeof(md1)); nl_msg_put_unspec(buf, OVS_NSH_KEY_ATTR_MD1, &md1, sizeof md1); } else { switch (nsh->mdtype) { case NSH_M_TYPE1: - for (int i = 0; i < 4; i++) { - md1.context[i] = nsh->context[i]; - } + memcpy(&md1.context, &nsh->context, sizeof(md1)); nl_msg_put_unspec(buf, OVS_NSH_KEY_ATTR_MD1, &md1, sizeof md1); break; case NSH_M_TYPE2: @@ -1835,9 +1828,11 @@ parse_odp_push_nsh_action(const char *s, struct ofpbuf *actions) int n = 0; int ret = 0; uint32_t cd; - struct flow_nsh nsh; + struct ovs_key_nsh nsh; uint8_t *metadata = NULL; uint8_t md_size = 0; + uint32_t spi = 0; + uint8_t si = 255; if (!ovs_scan_len(s, &n, "push_nsh(")) { ret = -EINVAL; @@ -1846,10 +1841,10 @@ parse_odp_push_nsh_action(const char *s, struct ofpbuf *actions) /* The default is NSH_M_TYPE1 */ nsh.flags = 0; + nsh.ttl = 63; nsh.mdtype = NSH_M_TYPE1; nsh.np = NSH_P_ETHERNET; - nsh.spi = 0; - nsh.si = 255; + nsh.path_hdr = nsh_spi_si_to_path_hdr(0, 255); memset(nsh.context, 0, NSH_M_TYPE1_MDLEN); for (;;) { @@ -1861,6 +1856,9 @@ parse_odp_push_nsh_action(const char *s, struct ofpbuf *actions) if (ovs_scan_len(s, &n, "flags=%"SCNi8, &nsh.flags)) { continue; } + if (ovs_scan_len(s, &n, "ttl=%"SCNi8, &nsh.ttl)) { + continue; + } if (ovs_scan_len(s, &n, "mdtype=%"SCNi8, &nsh.mdtype)) { switch (nsh.mdtype) { case NSH_M_TYPE1: @@ -1879,11 +1877,10 @@ parse_odp_push_nsh_action(const char *s, struct ofpbuf *actions) if (ovs_scan_len(s, &n, "np=%"SCNi8, &nsh.np)) { continue; } - if (ovs_scan_len(s, &n, "spi=0x%"SCNx32, &nsh.spi)) { - nsh.spi = htonl(nsh.spi); + if (ovs_scan_len(s, &n, "spi=0x%"SCNx32, &spi)) { continue; } - if (ovs_scan_len(s, &n, "si=%"SCNi8, &nsh.si)) { + if (ovs_scan_len(s, &n, "si=%"SCNi8, &si)) { continue; } if (nsh.mdtype == NSH_M_TYPE1) { @@ -1929,6 +1926,7 @@ parse_odp_push_nsh_action(const char *s, struct ofpbuf *actions) } out: if (ret >= 0) { + nsh.path_hdr = nsh_spi_si_to_path_hdr(spi, si); size_t offset = nl_msg_start_nested(actions, OVS_ACTION_ATTR_PUSH_NSH); nsh_key_to_attr(actions, &nsh, metadata, md_size, false); nl_msg_end_nested(actions, offset); @@ -2359,6 +2357,7 @@ odp_nsh_hdr_from_attr(const struct nlattr *attr, const struct nlattr *a; bool unknown = false; uint8_t flags = 0; + uint8_t ttl = 63; size_t mdlen = 0; bool has_md1 = false; bool has_md2 = false; @@ -2380,6 +2379,7 @@ odp_nsh_hdr_from_attr(const struct nlattr *attr, nsh_hdr->md_type = base->mdtype; put_16aligned_be32(&nsh_hdr->path_hdr, base->path_hdr); flags = base->flags; + ttl = base->ttl; break; } case OVS_NSH_KEY_ATTR_MD1: { @@ -2423,14 +2423,13 @@ odp_nsh_hdr_from_attr(const struct nlattr *attr, } /* nsh header length = NSH_BASE_HDR_LEN + mdlen */ - nsh_hdr->ver_flags_ttl_len = htons(flags << NSH_FLAGS_SHIFT | - (NSH_BASE_HDR_LEN + mdlen) >> 2); + nsh_set_flags_ttl_len(nsh_hdr, flags, ttl, NSH_BASE_HDR_LEN + mdlen); return ODP_FIT_PERFECT; } enum odp_key_fitness -odp_nsh_key_from_attr(const struct nlattr *attr, struct flow_nsh *nsh) +odp_nsh_key_from_attr(const struct nlattr *attr, struct ovs_key_nsh *nsh) { unsigned int left; const struct nlattr *a; @@ -2450,21 +2449,13 @@ odp_nsh_key_from_attr(const struct nlattr *attr, struct flow_nsh *nsh) switch (type) { case OVS_NSH_KEY_ATTR_BASE: { const struct ovs_nsh_key_base *base = nl_attr_get(a); - nsh->flags = base->flags; - nsh->mdtype = base->mdtype; - nsh->np = base->np; - nsh->spi = htonl((ntohl(base->path_hdr) & NSH_SPI_MASK) >> - NSH_SPI_SHIFT); - nsh->si = (ntohl(base->path_hdr) & NSH_SI_MASK) >> NSH_SI_SHIFT; + memcpy(nsh, base, sizeof(*base)); break; } case OVS_NSH_KEY_ATTR_MD1: { const struct ovs_nsh_key_md1 *md1 = nl_attr_get(a); has_md1 = true; - nsh->context[0] = md1->context[0]; - nsh->context[1] = md1->context[1]; - nsh->context[2] = md1->context[2]; - nsh->context[3] = md1->context[3]; + memcpy(&nsh->context, &md1->context, sizeof(*md1)); break; } case OVS_NSH_KEY_ATTR_MD2: @@ -3204,37 +3195,24 @@ format_odp_nsh_attr(const struct nlattr *attr, const struct nlattr *mask_attr, } switch (type) { - case OVS_NSH_KEY_ATTR_UNSPEC: - break; case OVS_NSH_KEY_ATTR_BASE: { - const struct ovs_nsh_key_base * base = nl_attr_get(a); - const struct ovs_nsh_key_base * base_mask + const struct ovs_nsh_key_base *base = nl_attr_get(a); + const struct ovs_nsh_key_base *base_mask = ma ? nl_attr_get(ma) : NULL; - nsh.flags = base->flags; - nsh.mdtype = base->mdtype; - nsh.np = base->np; - nsh.path_hdr = base->path_hdr; + memcpy(&nsh, base, sizeof(*base)); if (base_mask) { - nsh_mask.flags = base_mask->flags; - nsh_mask.mdtype = base_mask->mdtype; - nsh_mask.np = base_mask->np; - nsh_mask.path_hdr = base_mask->path_hdr; + memcpy(&nsh_mask, base_mask, sizeof(*base_mask)); } break; } case OVS_NSH_KEY_ATTR_MD1: { - const struct ovs_nsh_key_md1 * md1 = nl_attr_get(a); - const struct ovs_nsh_key_md1 * md1_mask + const struct ovs_nsh_key_md1 *md1 = nl_attr_get(a); + const struct ovs_nsh_key_md1 *md1_mask = ma ? nl_attr_get(ma) : NULL; - nsh.context[0] = md1->context[0]; - nsh.context[1] = md1->context[1]; - nsh.context[2] = md1->context[2]; - nsh.context[3] = md1->context[3]; + memcpy(&nsh.context, &md1->context, sizeof(*md1)); if (md1_mask) { - nsh_mask.context[0] = md1_mask->context[0]; - nsh_mask.context[1] = md1_mask->context[1]; - nsh_mask.context[2] = md1_mask->context[2]; - nsh_mask.context[3] = md1_mask->context[3]; + memcpy(&nsh_mask.context, &md1_mask->context, + sizeof(*md1_mask)); } break; } @@ -4836,7 +4814,9 @@ parse_odp_nsh_key_mask_attr(const char *s, struct ofpbuf *key, if (strncmp(s, "nsh(", 4) == 0) { const char *start = s; int len; - struct flow_nsh skey, smask; + struct ovs_key_nsh skey, smask; + uint32_t spi = 0, spi_mask = 0; + uint8_t si = 0, si_mask = 0; s += 4; @@ -4877,7 +4857,7 @@ parse_odp_nsh_key_mask_attr(const char *s, struct ofpbuf *key, if (strncmp(s, "spi=", 4) == 0) { s += 4; - len = scan_be32(s, &skey.spi, mask ? &smask.spi : NULL); + len = scan_be32(s, &spi, mask ? &spi_mask : NULL); if (len == 0) { return -EINVAL; } @@ -4887,7 +4867,7 @@ parse_odp_nsh_key_mask_attr(const char *s, struct ofpbuf *key, if (strncmp(s, "si=", 3) == 0) { s += 3; - len = scan_u8(s, &skey.si, mask ? &smask.si : NULL); + len = scan_u8(s, &si, mask ? &si_mask : NULL); if (len == 0) { return -EINVAL; } @@ -4943,6 +4923,9 @@ parse_odp_nsh_key_mask_attr(const char *s, struct ofpbuf *key, return -EINVAL; } + skey.path_hdr = nsh_spi_si_to_path_hdr(spi, si); + smask.path_hdr = nsh_spi_si_to_path_hdr(spi_mask, si_mask); + nsh_key_to_attr(key, &skey, NULL, 0, false); if (mask) { nsh_key_to_attr(mask, &smask, NULL, 0, true); @@ -7004,59 +6987,29 @@ commit_set_nw_action(const struct flow *flow, struct flow *base, return 0; } -static void +static inline 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->context[i] = flow->nsh.context[i]; - } - } else { - switch (nsh->mdtype) { - case NSH_M_TYPE1: - for (int i = 0; i < 4; i++) { - nsh->context[i] = flow->nsh.context[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->context)); } } } -static void +static inline 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.context[i] = nsh->context[i]; - } - break; - case NSH_M_TYPE2: - default: - /* No match support for other MD formats yet. */ - memset(flow->nsh.context, 0, sizeof flow->nsh.context); - break; + memcpy(&flow->nsh, nsh, sizeof(*nsh)); + if (flow->nsh.mdtype != NSH_M_TYPE1) { + memset(flow->nsh.context, 0, sizeof(flow->nsh.context)); } } static bool -commit_nsh(const struct flow_nsh * flow_nsh, bool use_masked_set, +commit_nsh(const struct ovs_key_nsh * flow_nsh, bool use_masked_set, const struct ovs_key_nsh *key, struct ovs_key_nsh *base, struct ovs_key_nsh *mask, size_t size, struct ofpbuf *odp_actions) @@ -7081,15 +7034,8 @@ commit_nsh(const struct flow_nsh * flow_nsh, bool use_masked_set, size_t offset = nl_msg_start_nested(odp_actions, OVS_ACTION_ATTR_SET_MASKED); - nsh_base.flags = key->flags; - nsh_base.mdtype = key->mdtype; - nsh_base.np = key->np; - nsh_base.path_hdr = key->path_hdr; - - nsh_base_mask.flags = mask->flags; - nsh_base_mask.mdtype = mask->mdtype; - nsh_base_mask.np = mask->np; - nsh_base_mask.path_hdr = mask->path_hdr; + memcpy(&nsh_base, key, sizeof(nsh_base)); + memcpy(&nsh_base_mask, mask, sizeof(nsh_base_mask)); /* OVS_KEY_ATTR_NSH keys */ nsh_key_ofs = nl_msg_start_nested(odp_actions, OVS_KEY_ATTR_NSH); @@ -7106,10 +7052,8 @@ commit_nsh(const struct flow_nsh * flow_nsh, bool use_masked_set, switch (key->mdtype) { case NSH_M_TYPE1: - for (int i = 0; i < 4; i++) { - md1.context[i] = key->context[i]; - md1_mask.context[i] = mask->context[i]; - } + memcpy(&md1.context, &key->context, sizeof(md1)); + memcpy(&md1_mask.context, &mask->context, sizeof(md1_mask)); data = nl_msg_put_unspec_uninit(odp_actions, OVS_NSH_KEY_ATTR_MD1, sizeof(md1)); diff --git a/lib/odp-util.h b/lib/odp-util.h index f7ce206..fafea62 100644 --- a/lib/odp-util.h +++ b/lib/odp-util.h @@ -159,7 +159,7 @@ struct odputil_keybuf { enum odp_key_fitness odp_tun_key_from_attr(const struct nlattr *, struct flow_tnl *); enum odp_key_fitness odp_nsh_key_from_attr(const struct nlattr *, - struct flow_nsh *); + struct ovs_key_nsh *); enum odp_key_fitness odp_nsh_hdr_from_attr(const struct nlattr *, struct nsh_hdr *, size_t size); diff --git a/lib/packets.c b/lib/packets.c index 8b63b9d..7694489 100644 --- a/lib/packets.c +++ b/lib/packets.c @@ -431,6 +431,7 @@ push_nsh(struct dp_packet *packet, const struct nsh_hdr *nsh_hdr_src) nsh = (struct nsh_hdr *) dp_packet_push_uninit(packet, length); memcpy(nsh, nsh_hdr_src, length); nsh->next_proto = next_proto; + nsh->md_type &= NSH_MDTYPE_MASK; packet->packet_type = htonl(PT_NSH); dp_packet_reset_offsets(packet); packet->l3_ofs = 0; diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index 4fe87ec..3de13b8 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -5908,10 +5908,10 @@ rewrite_flow_push_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; + flow->nsh.path_hdr = htonl(255); if (md_type == NSH_M_TYPE1) { flow->nsh.mdtype = NSH_M_TYPE1; @@ -5924,6 +5924,7 @@ rewrite_flow_push_nsh(struct xlate_ctx *ctx, } else if (md_type == NSH_M_TYPE2) { flow->nsh.mdtype = NSH_M_TYPE2; } + flow->nsh.mdtype &= NSH_MDTYPE_MASK; return buf; } diff --git a/tests/nsh.at b/tests/nsh.at index bec6e87..6177cea 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: push_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,pop_nsh(),set(eth(dst=11:22:33:44:55:66)),recirc(0x1) +Datapath actions: push_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,pop_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:push_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,pop_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:push_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,pop_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 ]) @@ -172,7 +172,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),push_nsh(flags=0,mdtype=1,np=3,spi=0x0,si=255,c1=0x0,c2=0x0,c3=0x0,c4=0x0),pop_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),push_nsh(flags=0,ttl=63,mdtype=1,np=3,spi=0x0,si=255,c1=0x0,c2=0x0,c3=0x0,c4=0x0),pop_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 ]) @@ -230,15 +230,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: push_nsh(flags=0,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,pop_nsh(),set(eth(dst=11:22:33:44:55:66)),recirc(0x1) +Datapath actions: push_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,pop_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") ------------- @@ -266,7 +266,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:push_nsh(flags=0,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,pop_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:push_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,pop_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 ]) @@ -575,11 +575,12 @@ AT_CHECK([ ovs-appctl time/warp 1000 ovs-appctl time/warp 1000 +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,push_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,push_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:pop_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 ]) @@ -633,7 +634,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,push_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,push_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:pop_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 Fri Dec 8 14:04:24 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Yang, Yi" X-Patchwork-Id: 846253 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 3ytZ564zcLz9t7x for ; Sat, 9 Dec 2017 01:10:50 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 48FEBD72; Fri, 8 Dec 2017 14:10:45 +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 8EF6AD70 for ; Fri, 8 Dec 2017 14:10:43 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mga17.intel.com (mga17.intel.com [192.55.52.151]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id A7BD83FB for ; Fri, 8 Dec 2017 14:10:42 +0000 (UTC) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga107.fm.intel.com with ESMTP; 08 Dec 2017 06:10:35 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.45,377,1508828400"; d="scan'208";a="11701258" Received: from unknown (HELO localhost.localdomain.bj.intel.com) ([10.240.224.185]) by fmsmga001.fm.intel.com with ESMTP; 08 Dec 2017 06:10:25 -0800 From: Yi Yang To: dev@openvswitch.org Date: Fri, 8 Dec 2017 22:04:24 +0800 Message-Id: <1512741865-97333-4-git-send-email-yi.y.yang@intel.com> X-Mailer: git-send-email 2.1.0 In-Reply-To: <1512741865-97333-1-git-send-email-yi.y.yang@intel.com> References: <1512741865-97333-1-git-send-email-yi.y.yang@intel.com> X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00, T_RP_MATCHES_RCVD autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH v6 3/4] nsh: fix nested mask for OVS_KEY_ATTR_NSH 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 NSH kernel implementation used nested mask for OVS_KEY_ATTR_NSH, so NSH userspace must adapt to it, OVS hasn't used nested mask for any key attribute so far, OVS_KEY_ATTR_NSH is the first use case. Signed-off-by: Yi Yang --- lib/odp-execute.c | 54 +++++++++-------------- lib/odp-util.c | 129 ++++++++++++++++++++++++++++++++++++++++-------------- lib/odp-util.h | 3 +- 3 files changed, 120 insertions(+), 66 deletions(-) diff --git a/lib/odp-execute.c b/lib/odp-execute.c index 221c4d6..10d960b 100644 --- a/lib/odp-execute.c +++ b/lib/odp-execute.c @@ -273,20 +273,25 @@ odp_set_nd(struct dp_packet *packet, const struct ovs_key_nd *key, /* Set the NSH header. Assumes the NSH header is present and matches the * MD format of the key. The slow path must take case of that. */ static void -odp_set_nsh(struct dp_packet *packet, const struct ovs_key_nsh *key, - const struct ovs_key_nsh *mask) +odp_set_nsh(struct dp_packet *packet, const struct nlattr *a, bool has_mask) { + struct ovs_key_nsh key, mask; struct nsh_hdr *nsh = dp_packet_l3(packet); uint8_t mdtype = nsh_md_type(nsh); ovs_be32 path_hdr; - if (!mask) { - nsh_set_flags_and_ttl(nsh, key->flags, key->ttl); - put_16aligned_be32(&nsh->path_hdr, key->path_hdr); + if (has_mask) + odp_nsh_key_from_attr(a, &key, &mask); + else + odp_nsh_key_from_attr(a, &key, NULL); + + if (!has_mask) { + nsh_set_flags_and_ttl(nsh, key.flags, key.ttl); + put_16aligned_be32(&nsh->path_hdr, key.path_hdr); switch (mdtype) { case NSH_M_TYPE1: for (int i = 0; i < 4; i++) { - put_16aligned_be32(&nsh->md1.context[i], key->context[i]); + put_16aligned_be32(&nsh->md1.context[i], key.context[i]); } break; case NSH_M_TYPE2: @@ -298,19 +303,19 @@ odp_set_nsh(struct dp_packet *packet, const struct ovs_key_nsh *key, uint8_t flags = nsh_get_flags(nsh); uint8_t ttl = nsh_get_ttl(nsh); - flags = key->flags | (flags & ~mask->flags); - ttl = key->ttl | (ttl & ~mask->ttl); + flags = key.flags | (flags & ~mask.flags); + ttl = key.ttl | (ttl & ~mask.ttl); nsh_set_flags_and_ttl(nsh, flags, ttl); uint32_t spi = ntohl(nsh_get_spi(nsh)); uint8_t si = nsh_get_si(nsh); - uint32_t spi_mask = nsh_path_hdr_to_spi_uint32(mask->path_hdr); - uint8_t si_mask = nsh_path_hdr_to_si(mask->path_hdr); + uint32_t spi_mask = nsh_path_hdr_to_spi_uint32(mask.path_hdr); + uint8_t si_mask = nsh_path_hdr_to_si(mask.path_hdr); if (spi_mask == 0x00ffffff) { spi_mask = UINT32_MAX; } - spi = nsh_path_hdr_to_spi_uint32(key->path_hdr) | (spi & ~spi_mask); - si = nsh_path_hdr_to_si(key->path_hdr) | (si & ~si_mask); + spi = nsh_path_hdr_to_spi_uint32(key.path_hdr) | (spi & ~spi_mask); + si = nsh_path_hdr_to_si(key.path_hdr) | (si & ~si_mask); path_hdr = nsh_get_path_hdr(nsh); nsh_path_hdr_set_spi(&path_hdr, htonl(spi)); nsh_path_hdr_set_si(&path_hdr, si); @@ -319,8 +324,8 @@ odp_set_nsh(struct dp_packet *packet, const struct ovs_key_nsh *key, case NSH_M_TYPE1: for (int i = 0; i < 4; i++) { ovs_be32 p = get_16aligned_be32(&nsh->md1.context[i]); - ovs_be32 k = key->context[i]; - ovs_be32 m = mask->context[i]; + ovs_be32 k = key.context[i]; + ovs_be32 m = mask.context[i]; put_16aligned_be32(&nsh->md1.context[i], k | (p & ~m)); } break; @@ -358,9 +363,7 @@ odp_execute_set_action(struct dp_packet *packet, const struct nlattr *a) break; case OVS_KEY_ATTR_NSH: { - struct ovs_key_nsh nsh; - odp_nsh_key_from_attr(a, &nsh); - odp_set_nsh(packet, &nsh, NULL); + odp_set_nsh(packet, a, false); break; } @@ -489,22 +492,7 @@ odp_execute_masked_set_action(struct dp_packet *packet, break; case OVS_KEY_ATTR_NSH: { - struct ovs_key_nsh nsh, nsh_mask; - size_t size = nl_attr_get_size(a) / 2; - struct { - struct nlattr nla; - uint8_t data[size]; - } attr, mask; - - mask.nla.nla_type = attr.nla.nla_type = nl_attr_type(a); - mask.nla.nla_len = attr.nla.nla_len = NLA_HDRLEN + size; - memcpy(attr.data, (char *)(a + 1), size); - memcpy(mask.data, (char *)(a + 1) + size, size); - - odp_nsh_key_from_attr(&attr.nla, &nsh); - odp_nsh_key_from_attr(&mask.nla, &nsh_mask); - odp_set_nsh(packet, &nsh, &nsh_mask); - + odp_set_nsh(packet, a, true); break; } diff --git a/lib/odp-util.c b/lib/odp-util.c index 7597814..922667f 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -937,6 +937,68 @@ format_odp_conntrack_action(struct ds *ds, const struct nlattr *attr) } } +static const struct attr_len_tbl +ovs_nsh_key_attr_lens[OVS_NSH_KEY_ATTR_MAX + 1] = { + [OVS_NSH_KEY_ATTR_BASE] = { .len = 8 }, + [OVS_NSH_KEY_ATTR_MD1] = { .len = 16 }, + [OVS_NSH_KEY_ATTR_MD2] = { .len = ATTR_LEN_VARIABLE }, +}; + +static void +format_odp_set_nsh(struct ds *ds, const struct nlattr *attr) +{ + unsigned int left; + const struct nlattr *a; + struct ovs_key_nsh nsh; + struct ovs_key_nsh nsh_mask; + + memset(&nsh, 0, sizeof nsh); + memset(&nsh_mask, 0xff, sizeof nsh_mask); + + NL_NESTED_FOR_EACH (a, left, attr) { + enum ovs_nsh_key_attr type = nl_attr_type(a); + size_t len = nl_attr_get_size(a); + + if (type >= OVS_NSH_KEY_ATTR_MAX) { + return; + } + + int expected_len = ovs_nsh_key_attr_lens[type].len; + if ((expected_len != ATTR_LEN_VARIABLE) && (len != 2 * expected_len)) { + return; + } + + switch (type) { + case OVS_NSH_KEY_ATTR_UNSPEC: + break; + case OVS_NSH_KEY_ATTR_BASE: { + const struct ovs_nsh_key_base *base = nl_attr_get(a); + const struct ovs_nsh_key_base *base_mask = base + 1; + memcpy(&nsh, base, sizeof(*base)); + memcpy(&nsh_mask, base_mask, sizeof(*base_mask)); + break; + } + case OVS_NSH_KEY_ATTR_MD1: { + const struct ovs_nsh_key_md1 *md1 = nl_attr_get(a); + const struct ovs_nsh_key_md1 *md1_mask = md1 + 1; + memcpy(&nsh.context, &md1->context, sizeof(*md1)); + memcpy(&nsh_mask.context, &md1_mask->context, sizeof(*md1_mask)); + break; + } + case OVS_NSH_KEY_ATTR_MD2: + case __OVS_NSH_KEY_ATTR_MAX: + default: + /* No support for matching other metadata formats yet. */ + break; + } + } + + ds_put_cstr(ds, "set(nsh("); + format_nsh_key_mask(ds, &nsh, &nsh_mask); + ds_put_cstr(ds, "))"); +} + + static void format_odp_action(struct ds *ds, const struct nlattr *a, const struct hmap *portno_names) @@ -987,6 +1049,11 @@ format_odp_action(struct ds *ds, const struct nlattr *a, break; case OVS_ACTION_ATTR_SET_MASKED: a = nl_attr_get(a); + /* OVS_KEY_ATTR_NSH is nested attribute, so it needs special process */ + if (nl_attr_type(a) == OVS_KEY_ATTR_NSH) { + format_odp_set_nsh(ds, a); + break; + } size = nl_attr_get_size(a) / 2; ds_put_cstr(ds, "set("); @@ -2258,13 +2325,6 @@ static const struct attr_len_tbl ovs_tun_key_attr_lens[OVS_TUNNEL_KEY_ATTR_MAX + [OVS_TUNNEL_KEY_ATTR_IPV6_DST] = { .len = 16 }, }; -static const struct attr_len_tbl -ovs_nsh_key_attr_lens[OVS_NSH_KEY_ATTR_MAX + 1] = { - [OVS_NSH_KEY_ATTR_BASE] = { .len = 8 }, - [OVS_NSH_KEY_ATTR_MD1] = { .len = 16 }, - [OVS_NSH_KEY_ATTR_MD2] = { .len = ATTR_LEN_VARIABLE }, -}; - const struct attr_len_tbl ovs_flow_key_attr_lens[OVS_KEY_ATTR_MAX + 1] = { [OVS_KEY_ATTR_ENCAP] = { .len = ATTR_LEN_NESTED }, [OVS_KEY_ATTR_PRIORITY] = { .len = 4 }, @@ -2429,7 +2489,8 @@ odp_nsh_hdr_from_attr(const struct nlattr *attr, } enum odp_key_fitness -odp_nsh_key_from_attr(const struct nlattr *attr, struct ovs_key_nsh *nsh) +odp_nsh_key_from_attr(const struct nlattr *attr, struct ovs_key_nsh *nsh, + struct ovs_key_nsh *nsh_mask) { unsigned int left; const struct nlattr *a; @@ -2442,7 +2503,14 @@ odp_nsh_key_from_attr(const struct nlattr *attr, struct ovs_key_nsh *nsh) int expected_len = odp_key_attr_len(ovs_nsh_key_attr_lens, OVS_NSH_KEY_ATTR_MAX, type); - if (len != expected_len && expected_len >= 0) { + /* the attribute can have mask, len is 2 * expected_len for that case. */ + if ((len != expected_len) && (len != 2 * expected_len) && + (expected_len >= 0)) { + return ODP_FIT_ERROR; + } + + if ((nsh_mask && (expected_len >= 0) && (len != 2 * expected_len)) || + (!nsh_mask && (expected_len >= 0) && (len == 2 * expected_len))) { return ODP_FIT_ERROR; } @@ -2450,12 +2518,21 @@ odp_nsh_key_from_attr(const struct nlattr *attr, struct ovs_key_nsh *nsh) case OVS_NSH_KEY_ATTR_BASE: { const struct ovs_nsh_key_base *base = nl_attr_get(a); memcpy(nsh, base, sizeof(*base)); + if (nsh_mask && (len == 2 * sizeof(*base))) { + const struct ovs_nsh_key_base *base_mask = base + 1; + memcpy(nsh_mask, base_mask, sizeof(*base_mask)); + } break; } case OVS_NSH_KEY_ATTR_MD1: { const struct ovs_nsh_key_md1 *md1 = nl_attr_get(a); has_md1 = true; memcpy(&nsh->context, &md1->context, sizeof(*md1)); + if (len == 2 * sizeof(*md1)) { + const struct ovs_nsh_key_md1 *md1_mask = md1 + 1; + memcpy(&nsh_mask->context, &md1_mask->context, + sizeof(*md1_mask)); + } break; } case OVS_NSH_KEY_ATTR_MD2: @@ -3195,6 +3272,8 @@ format_odp_nsh_attr(const struct nlattr *attr, const struct nlattr *mask_attr, } switch (type) { + case OVS_NSH_KEY_ATTR_UNSPEC: + break; case OVS_NSH_KEY_ATTR_BASE: { const struct ovs_nsh_key_base *base = nl_attr_get(a); const struct ovs_nsh_key_base *base_mask @@ -5938,7 +6017,7 @@ parse_l2_5_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1], expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_NSH; } if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_NSH)) { - odp_nsh_key_from_attr(attrs[OVS_KEY_ATTR_NSH], &flow->nsh); + odp_nsh_key_from_attr(attrs[OVS_KEY_ATTR_NSH], &flow->nsh, NULL); if (is_mask) { check_start = nl_attr_get(attrs[OVS_KEY_ATTR_NSH]); check_len = nl_attr_get_size(attrs[OVS_KEY_ATTR_NSH]); @@ -7040,23 +7119,28 @@ commit_nsh(const struct ovs_key_nsh * flow_nsh, bool use_masked_set, /* OVS_KEY_ATTR_NSH keys */ nsh_key_ofs = nl_msg_start_nested(odp_actions, OVS_KEY_ATTR_NSH); + /* put value and mask for OVS_NSH_KEY_ATTR_BASE */ char *data = nl_msg_put_unspec_uninit(odp_actions, OVS_NSH_KEY_ATTR_BASE, - sizeof(nsh_base)); + 2 * sizeof(nsh_base)); const char *lkey = (char *)&nsh_base, *lmask = (char *)&nsh_base_mask; size_t lkey_size = sizeof(nsh_base); while (lkey_size--) { *data++ = *lkey++ & *lmask++; } + lmask = (char *)&nsh_base_mask; + memcpy(data, lmask, sizeof(nsh_base_mask)); switch (key->mdtype) { case NSH_M_TYPE1: memcpy(&md1.context, &key->context, sizeof(md1)); memcpy(&md1_mask.context, &mask->context, sizeof(md1_mask)); + + /* put value and mask for OVS_NSH_KEY_ATTR_MD1 */ data = nl_msg_put_unspec_uninit(odp_actions, OVS_NSH_KEY_ATTR_MD1, - sizeof(md1)); + 2 * sizeof(md1)); lkey = (char *)&md1; lmask = (char *)&md1_mask; lkey_size = sizeof(md1); @@ -7064,26 +7148,6 @@ commit_nsh(const struct ovs_key_nsh * flow_nsh, bool use_masked_set, while (lkey_size--) { *data++ = *lkey++ & *lmask++; } - break; - case NSH_M_TYPE2: - default: - /* No match support for other MD formats yet. */ - break; - } - - /* OVS_KEY_ATTR_NSH masks */ - data = nl_msg_put_unspec_uninit(odp_actions, - OVS_NSH_KEY_ATTR_BASE, - sizeof(nsh_base_mask)); - lmask = (char *)&nsh_base_mask; - - memcpy(data, lmask, sizeof(nsh_base_mask)); - - switch (key->mdtype) { - case NSH_M_TYPE1: - data = nl_msg_put_unspec_uninit(odp_actions, - OVS_NSH_KEY_ATTR_MD1, - sizeof(md1_mask)); lmask = (char *)&md1_mask; memcpy(data, lmask, sizeof(md1_mask)); break; @@ -7092,6 +7156,7 @@ commit_nsh(const struct ovs_key_nsh * flow_nsh, bool use_masked_set, /* No match support for other MD formats yet. */ break; } + nl_msg_end_nested(odp_actions, nsh_key_ofs); nl_msg_end_nested(odp_actions, offset); diff --git a/lib/odp-util.h b/lib/odp-util.h index fafea62..d99727b 100644 --- a/lib/odp-util.h +++ b/lib/odp-util.h @@ -159,9 +159,10 @@ struct odputil_keybuf { enum odp_key_fitness odp_tun_key_from_attr(const struct nlattr *, struct flow_tnl *); enum odp_key_fitness odp_nsh_key_from_attr(const struct nlattr *, + struct ovs_key_nsh *, struct ovs_key_nsh *); enum odp_key_fitness odp_nsh_hdr_from_attr(const struct nlattr *, - struct nsh_hdr *, size_t size); + struct nsh_hdr *, size_t); int odp_ufid_from_string(const char *s_, ovs_u128 *ufid); void odp_format_ufid(const ovs_u128 *ufid, struct ds *); From patchwork Fri Dec 8 14:04:25 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Yang, Yi" X-Patchwork-Id: 846254 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 3ytZ646WKbz9s71 for ; Sat, 9 Dec 2017 01:11:40 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 20ABDD7E; Fri, 8 Dec 2017 14:10:51 +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 E5CB4D73 for ; Fri, 8 Dec 2017 14:10:49 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mga17.intel.com (mga17.intel.com [192.55.52.151]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id E8305F4 for ; Fri, 8 Dec 2017 14:10:48 +0000 (UTC) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga107.fm.intel.com with ESMTP; 08 Dec 2017 06:10:42 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.45,377,1508828400"; d="scan'208";a="11701282" Received: from unknown (HELO localhost.localdomain.bj.intel.com) ([10.240.224.185]) by fmsmga001.fm.intel.com with ESMTP; 08 Dec 2017 06:10:32 -0800 From: Yi Yang To: dev@openvswitch.org Date: Fri, 8 Dec 2017 22:04:25 +0800 Message-Id: <1512741865-97333-5-git-send-email-yi.y.yang@intel.com> X-Mailer: git-send-email 2.1.0 In-Reply-To: <1512741865-97333-1-git-send-email-yi.y.yang@intel.com> References: <1512741865-97333-1-git-send-email-yi.y.yang@intel.com> X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00, T_RP_MATCHES_RCVD autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH v6 4/4] 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 NSH ttl 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 | 6 ++--- utilities/ovs-ofctl.8.in | 13 ++++++++++- 5 files changed, 96 insertions(+), 4 deletions(-) diff --git a/include/openvswitch/ofp-actions.h b/include/openvswitch/ofp-actions.h index 25f61ef..40f04d5 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 e5d03e1..67261a4 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. @@ -7113,6 +7150,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: @@ -7190,6 +7228,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 @@ -7303,6 +7342,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); @@ -7444,6 +7484,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; } @@ -8130,6 +8171,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(); } @@ -8625,6 +8673,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 3de13b8..c090adc 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -4825,6 +4825,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, @@ -5331,6 +5353,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; } } @@ -5558,6 +5581,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. */ @@ -6105,6 +6129,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: @@ -6429,6 +6454,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 6177cea..e6a8345 100644 --- a/tests/nsh.at +++ b/tests/nsh.at @@ -542,7 +542,7 @@ AT_DATA([br-in2.txt], [dnl 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=77:88:99:aa:bb:cc,actions=dec_nsh_ttl,decap(),resubmit(,2) ]) # br-in3 is SFC classifier (table 1) and final SFF (tables 2,3) @@ -607,7 +607,7 @@ AT_CHECK([ 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=77:88:99:aa:bb:cc,dl_type=0x894f actions=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 @@ -661,7 +661,7 @@ 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, dl_dst=77:88:99:aa:bb:cc,dl_type=0x894f actions=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,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 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