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 *);