From patchwork Mon Oct 21 14:35:42 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Medvedkin X-Patchwork-Id: 61607 X-Patchwork-Delegate: gakhil@marvell.com Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 620CF1BF73; Mon, 21 Oct 2019 16:36:00 +0200 (CEST) Received: from mga06.intel.com (mga06.intel.com [134.134.136.31]) by dpdk.org (Postfix) with ESMTP id 6BAD71BF4C for ; Mon, 21 Oct 2019 16:35:52 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga104.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 21 Oct 2019 07:35:51 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.67,323,1566889200"; d="scan'208";a="372194503" Received: from silpixa00400072.ir.intel.com ([10.237.222.213]) by orsmga005.jf.intel.com with ESMTP; 21 Oct 2019 07:35:49 -0700 From: Vladimir Medvedkin To: dev@dpdk.org Cc: konstantin.ananyev@intel.com, bernard.iremonger@intel.com, akhil.goyal@nxp.com Date: Mon, 21 Oct 2019 15:35:42 +0100 Message-Id: <3c34e91a765fd774b56da54de49fc06fc92c76d3.1571668033.git.vladimir.medvedkin@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: References: In-Reply-To: References: Subject: [dpdk-dev] [PATCH v7 1/5] ipsec: add inbound SAD API X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Add inbound security association database (SAD) API and stub implementation. Signed-off-by: Vladimir Medvedkin Acked-by: Akhil Goyal Acked-by: Konstantin Ananyev --- doc/guides/prog_guide/ipsec_lib.rst | 15 +++ doc/guides/rel_notes/release_19_11.rst | 3 + lib/librte_ipsec/Makefile | 2 + lib/librte_ipsec/ipsec_sad.c | 50 ++++++++++ lib/librte_ipsec/meson.build | 4 +- lib/librte_ipsec/rte_ipsec_sad.h | 176 +++++++++++++++++++++++++++++++++ lib/librte_ipsec/rte_ipsec_version.map | 7 ++ 7 files changed, 255 insertions(+), 2 deletions(-) create mode 100644 lib/librte_ipsec/ipsec_sad.c create mode 100644 lib/librte_ipsec/rte_ipsec_sad.h diff --git a/doc/guides/prog_guide/ipsec_lib.rst b/doc/guides/prog_guide/ipsec_lib.rst index 63b75b6..b53b64e 100644 --- a/doc/guides/prog_guide/ipsec_lib.rst +++ b/doc/guides/prog_guide/ipsec_lib.rst @@ -143,6 +143,21 @@ In that mode the library functions perform To accommodate future custom implementations function pointers model is used for both *crypto_prepare* and *process* implementations. +SA database API +---------------- + +SA database(SAD) is a table with pairs. + +Value is an opaque user provided pointer to the user defined SA data structure. + +According to RFC4301 each SA can be uniquely identified by a key +which is either: + + - security parameter index(SPI) + - or SPI and destination IP(DIP) + - or SPI, DIP and source IP(SIP) + +In case of multiple matches, longest matching key will be returned. Supported features ------------------ diff --git a/doc/guides/rel_notes/release_19_11.rst b/doc/guides/rel_notes/release_19_11.rst index 85953b9..581f311 100644 --- a/doc/guides/rel_notes/release_19_11.rst +++ b/doc/guides/rel_notes/release_19_11.rst @@ -115,6 +115,9 @@ New Features Added eBPF JIT support for arm64 architecture to improve the eBPF program performance. +* **Updated the IPSec library.** + + Added SA Database API to ``librte_ipsec`` Removed Items ------------- diff --git a/lib/librte_ipsec/Makefile b/lib/librte_ipsec/Makefile index 22f29d9..5aaab72 100644 --- a/lib/librte_ipsec/Makefile +++ b/lib/librte_ipsec/Makefile @@ -21,10 +21,12 @@ SRCS-$(CONFIG_RTE_LIBRTE_IPSEC) += esp_inb.c SRCS-$(CONFIG_RTE_LIBRTE_IPSEC) += esp_outb.c SRCS-$(CONFIG_RTE_LIBRTE_IPSEC) += sa.c SRCS-$(CONFIG_RTE_LIBRTE_IPSEC) += ses.c +SRCS-$(CONFIG_RTE_LIBRTE_IPSEC) += ipsec_sad.c # install header files SYMLINK-$(CONFIG_RTE_LIBRTE_IPSEC)-include += rte_ipsec.h SYMLINK-$(CONFIG_RTE_LIBRTE_IPSEC)-include += rte_ipsec_group.h SYMLINK-$(CONFIG_RTE_LIBRTE_IPSEC)-include += rte_ipsec_sa.h +SYMLINK-$(CONFIG_RTE_LIBRTE_IPSEC)-include += rte_ipsec_sad.h include $(RTE_SDK)/mk/rte.lib.mk diff --git a/lib/librte_ipsec/ipsec_sad.c b/lib/librte_ipsec/ipsec_sad.c new file mode 100644 index 0000000..703be65 --- /dev/null +++ b/lib/librte_ipsec/ipsec_sad.c @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2019 Intel Corporation + */ + +#include + +#include "rte_ipsec_sad.h" + +int +rte_ipsec_sad_add(__rte_unused struct rte_ipsec_sad *sad, + __rte_unused const union rte_ipsec_sad_key *key, + __rte_unused int key_type, __rte_unused void *sa) +{ + return -ENOTSUP; +} + +int +rte_ipsec_sad_del(__rte_unused struct rte_ipsec_sad *sad, + __rte_unused const union rte_ipsec_sad_key *key, + __rte_unused int key_type) +{ + return -ENOTSUP; +} + +struct rte_ipsec_sad * +rte_ipsec_sad_create(__rte_unused const char *name, + __rte_unused const struct rte_ipsec_sad_conf *conf) +{ + return NULL; +} + +struct rte_ipsec_sad * +rte_ipsec_sad_find_existing(__rte_unused const char *name) +{ + return NULL; +} + +void +rte_ipsec_sad_destroy(__rte_unused struct rte_ipsec_sad *sad) +{ + return; +} + +int +rte_ipsec_sad_lookup(__rte_unused const struct rte_ipsec_sad *sad, + __rte_unused const union rte_ipsec_sad_key *keys[], + __rte_unused void *sa[], __rte_unused uint32_t n) +{ + return -ENOTSUP; +} diff --git a/lib/librte_ipsec/meson.build b/lib/librte_ipsec/meson.build index 7ea0c7d..91b9867 100644 --- a/lib/librte_ipsec/meson.build +++ b/lib/librte_ipsec/meson.build @@ -3,8 +3,8 @@ allow_experimental_apis = true -sources = files('esp_inb.c', 'esp_outb.c', 'sa.c', 'ses.c') +sources = files('esp_inb.c', 'esp_outb.c', 'sa.c', 'ses.c', 'ipsec_sad.c') -headers = files('rte_ipsec.h', 'rte_ipsec_group.h', 'rte_ipsec_sa.h') +headers = files('rte_ipsec.h', 'rte_ipsec_group.h', 'rte_ipsec_sa.h', 'rte_ipsec_sad.h') deps += ['mbuf', 'net', 'cryptodev', 'security'] diff --git a/lib/librte_ipsec/rte_ipsec_sad.h b/lib/librte_ipsec/rte_ipsec_sad.h new file mode 100644 index 0000000..8386f73 --- /dev/null +++ b/lib/librte_ipsec/rte_ipsec_sad.h @@ -0,0 +1,176 @@ + +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2019 Intel Corporation + */ + +#ifndef _RTE_IPSEC_SAD_H_ +#define _RTE_IPSEC_SAD_H_ + +#include + +/** + * @file rte_ipsec_sad.h + * @b EXPERIMENTAL: this API may change without prior notice + * + * RTE IPsec security association database (SAD) support. + * Contains helper functions to lookup and maintain SAD + */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct rte_ipsec_sad; + +/** Type of key */ +enum { + RTE_IPSEC_SAD_SPI_ONLY = 0, + RTE_IPSEC_SAD_SPI_DIP, + RTE_IPSEC_SAD_SPI_DIP_SIP, + RTE_IPSEC_SAD_KEY_TYPE_MASK, +}; + +struct rte_ipsec_sadv4_key { + uint32_t spi; + uint32_t dip; + uint32_t sip; +}; + +struct rte_ipsec_sadv6_key { + uint32_t spi; + uint8_t dip[16]; + uint8_t sip[16]; +}; + +union rte_ipsec_sad_key { + struct rte_ipsec_sadv4_key v4; + struct rte_ipsec_sadv6_key v6; +}; + +/** Flag to create SAD with ipv6 dip and sip addresses */ +#define RTE_IPSEC_SAD_FLAG_IPV6 0x1 +/** Flag to support reader writer concurrency */ +#define RTE_IPSEC_SAD_FLAG_RW_CONCURRENCY 0x2 + +/** IPsec SAD configuration structure */ +struct rte_ipsec_sad_conf { + /** CPU socket ID where rte_ipsec_sad should be allocated */ + int socket_id; + /** maximum number of SA for each type of key */ + uint32_t max_sa[RTE_IPSEC_SAD_KEY_TYPE_MASK]; + /** RTE_IPSEC_SAD_FLAG_* flags */ + uint32_t flags; +}; + +/** + * Add a rule into the SAD. Could be safely called with concurrent lookups + * if RTE_IPSEC_SAD_FLAG_RW_CONCURRENCY flag was configured on creation time. + * While with this flag multi-reader - one-writer model Is MT safe, + * multi-writer model is not and required extra synchronisation. + * + * @param sad + * SAD object handle + * @param key + * pointer to the key + * @param key_type + * key type (spi only/spi+dip/spi+dip+sip) + * @param sa + * Pointer associated with the key to save in a SAD + * Must be 4 bytes aligned. + * @return + * 0 on success, negative value otherwise + */ +__rte_experimental +int +rte_ipsec_sad_add(struct rte_ipsec_sad *sad, + const union rte_ipsec_sad_key *key, + int key_type, void *sa); + +/** + * Delete a rule from the SAD. Could be safely called with concurrent lookups + * if RTE_IPSEC_SAD_FLAG_RW_CONCURRENCY flag was configured on creation time. + * While with this flag multi-reader - one-writer model Is MT safe, + * multi-writer model is not and required extra synchronisation. + * + * @param sad + * SAD object handle + * @param key + * pointer to the key + * @param key_type + * key type (spi only/spi+dip/spi+dip+sip) + * @return + * 0 on success, negative value otherwise + */ +__rte_experimental +int +rte_ipsec_sad_del(struct rte_ipsec_sad *sad, + const union rte_ipsec_sad_key *key, + int key_type); +/* + * Create SAD + * + * @param name + * SAD name + * @param conf + * Structure containing the configuration + * @return + * Handle to SAD object on success + * NULL otherwise with rte_errno set to an appropriate values. + */ +__rte_experimental +struct rte_ipsec_sad * +rte_ipsec_sad_create(const char *name, const struct rte_ipsec_sad_conf *conf); + +/** + * Find an existing SAD object and return a pointer to it. + * + * @param name + * Name of the SAD object as passed to rte_ipsec_sad_create() + * @return + * Pointer to sad object or NULL if object not found with rte_errno + * set appropriately. Possible rte_errno values include: + * - ENOENT - required entry not available to return. + */ +__rte_experimental +struct rte_ipsec_sad * +rte_ipsec_sad_find_existing(const char *name); + +/** + * Destroy SAD object. + * + * @param sad + * pointer to the SAD object + * @return + * None + */ +__rte_experimental +void +rte_ipsec_sad_destroy(struct rte_ipsec_sad *sad); + +/** + * Lookup multiple keys in the SAD. + * + * @param sad + * SAD object handle + * @param keys + * Array of keys to be looked up in the SAD + * @param sa + * Pointer assocoated with the keys. + * If the lookup for the given key failed, then corresponding sa + * will be NULL + * @param n + * Number of elements in keys array to lookup. + * @return + * -EINVAL for incorrect arguments, otherwise number of successful lookups. + */ +__rte_experimental +int +rte_ipsec_sad_lookup(const struct rte_ipsec_sad *sad, + const union rte_ipsec_sad_key *keys[], + void *sa[], uint32_t n); + +#ifdef __cplusplus +} +#endif + +#endif /* _RTE_IPSEC_SAD_H_ */ diff --git a/lib/librte_ipsec/rte_ipsec_version.map b/lib/librte_ipsec/rte_ipsec_version.map index ee9f196..3c6c630 100644 --- a/lib/librte_ipsec/rte_ipsec_version.map +++ b/lib/librte_ipsec/rte_ipsec_version.map @@ -11,5 +11,12 @@ EXPERIMENTAL { rte_ipsec_ses_from_crypto; rte_ipsec_session_prepare; + rte_ipsec_sad_add; + rte_ipsec_sad_create; + rte_ipsec_sad_del; + rte_ipsec_sad_find_existing; + rte_ipsec_sad_destroy; + rte_ipsec_sad_lookup; + local: *; }; From patchwork Mon Oct 21 14:35:43 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Medvedkin X-Patchwork-Id: 61608 X-Patchwork-Delegate: gakhil@marvell.com Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id D103F1BF87; Mon, 21 Oct 2019 16:36:02 +0200 (CEST) Received: from mga06.intel.com (mga06.intel.com [134.134.136.31]) by dpdk.org (Postfix) with ESMTP id 83C5C1BF5C for ; Mon, 21 Oct 2019 16:35:53 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga104.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 21 Oct 2019 07:35:53 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.67,323,1566889200"; d="scan'208";a="372194511" Received: from silpixa00400072.ir.intel.com ([10.237.222.213]) by orsmga005.jf.intel.com with ESMTP; 21 Oct 2019 07:35:51 -0700 From: Vladimir Medvedkin To: dev@dpdk.org Cc: konstantin.ananyev@intel.com, bernard.iremonger@intel.com, akhil.goyal@nxp.com Date: Mon, 21 Oct 2019 15:35:43 +0100 Message-Id: X-Mailer: git-send-email 2.7.4 In-Reply-To: References: In-Reply-To: References: Subject: [dpdk-dev] [PATCH v7 2/5] ipsec: add SAD create/destroy implementation X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Replace rte_ipsec_sad_create(), rte_ipsec_sad_destroy() and rte_ipsec_sad_find_existing() API stubs with actual implementation. Signed-off-by: Vladimir Medvedkin Acked-by: Akhil Goyal Acked-by: Konstantin Ananyev Tested-by: Konstantin Ananyev --- doc/guides/prog_guide/ipsec_lib.rst | 27 +++++ lib/librte_ipsec/Makefile | 2 +- lib/librte_ipsec/ipsec_sad.c | 225 ++++++++++++++++++++++++++++++++++-- lib/librte_ipsec/meson.build | 2 +- 4 files changed, 247 insertions(+), 9 deletions(-) diff --git a/doc/guides/prog_guide/ipsec_lib.rst b/doc/guides/prog_guide/ipsec_lib.rst index b53b64e..b69c153 100644 --- a/doc/guides/prog_guide/ipsec_lib.rst +++ b/doc/guides/prog_guide/ipsec_lib.rst @@ -159,6 +159,33 @@ which is either: In case of multiple matches, longest matching key will be returned. +Create/destroy +~~~~~~~~~~~~~~ + +librte_ipsec SAD implementation provides ability to create/destroy SAD tables. + +To create SAD table user has to specify how many entries of each key type is +required and IP protocol type (IPv4/IPv6). +As an example: + + +.. code-block:: c + + struct rte_ipsec_sad *sad; + struct rte_ipsec_sad_conf conf; + + conf.socket_id = -1; + conf.max_sa[RTE_IPSEC_SAD_SPI_ONLY] = some_nb_rules_spi_only; + conf.max_sa[RTE_IPSEC_SAD_SPI_DIP] = some_nb_rules_spi_dip; + conf.max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP] = some_nb_rules_spi_dip_sip; + conf.flags = RTE_IPSEC_SAD_FLAG_RW_CONCURRENCY; + + sad = rte_ipsec_sad_create("test", &conf); + +.. note:: + + for more information please refer to ipsec library API reference + Supported features ------------------ diff --git a/lib/librte_ipsec/Makefile b/lib/librte_ipsec/Makefile index 5aaab72..81fb999 100644 --- a/lib/librte_ipsec/Makefile +++ b/lib/librte_ipsec/Makefile @@ -10,7 +10,7 @@ CFLAGS += -O3 CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) CFLAGS += -DALLOW_EXPERIMENTAL_API LDLIBS += -lrte_eal -lrte_mempool -lrte_mbuf -lrte_net -LDLIBS += -lrte_cryptodev -lrte_security +LDLIBS += -lrte_cryptodev -lrte_security -lrte_hash EXPORT_MAP := rte_ipsec_version.map diff --git a/lib/librte_ipsec/ipsec_sad.c b/lib/librte_ipsec/ipsec_sad.c index 703be65..e16c7d9 100644 --- a/lib/librte_ipsec/ipsec_sad.c +++ b/lib/librte_ipsec/ipsec_sad.c @@ -2,10 +2,53 @@ * Copyright(c) 2019 Intel Corporation */ +#include #include +#include +#include +#include +#include +#include +#include #include "rte_ipsec_sad.h" +/* + * Rules are stored in three hash tables depending on key_type. + * Each rule will also be stored in SPI_ONLY table. + * for each data entry within this table last two bits are reserved to + * indicate presence of entries with the same SPI in DIP and DIP+SIP tables. + */ + +#define IPSEC_SAD_NAMESIZE 64 +#define SAD_PREFIX "SAD_" +/* "SAD_" */ +#define SAD_FORMAT SAD_PREFIX "%s" + +#define DEFAULT_HASH_FUNC rte_jhash +#define MIN_HASH_ENTRIES 8U /* From rte_cuckoo_hash.h */ + +struct hash_cnt { + uint32_t cnt_dip; + uint32_t cnt_dip_sip; +}; + +struct rte_ipsec_sad { + char name[IPSEC_SAD_NAMESIZE]; + struct rte_hash *hash[RTE_IPSEC_SAD_KEY_TYPE_MASK]; + /* Array to track number of more specific rules + * (spi_dip or spi_dip_sip). Used only in add/delete + * as a helper struct. + */ + __extension__ struct hash_cnt cnt_arr[]; +}; + +TAILQ_HEAD(rte_ipsec_sad_list, rte_tailq_entry); +static struct rte_tailq_elem rte_ipsec_sad_tailq = { + .name = "RTE_IPSEC_SAD", +}; +EAL_REGISTER_TAILQ(rte_ipsec_sad_tailq) + int rte_ipsec_sad_add(__rte_unused struct rte_ipsec_sad *sad, __rte_unused const union rte_ipsec_sad_key *key, @@ -23,22 +66,190 @@ rte_ipsec_sad_del(__rte_unused struct rte_ipsec_sad *sad, } struct rte_ipsec_sad * -rte_ipsec_sad_create(__rte_unused const char *name, - __rte_unused const struct rte_ipsec_sad_conf *conf) +rte_ipsec_sad_create(const char *name, const struct rte_ipsec_sad_conf *conf) { - return NULL; + char hash_name[RTE_HASH_NAMESIZE]; + char sad_name[IPSEC_SAD_NAMESIZE]; + struct rte_tailq_entry *te; + struct rte_ipsec_sad_list *sad_list; + struct rte_ipsec_sad *sad, *tmp_sad = NULL; + struct rte_hash_parameters hash_params = {0}; + int ret; + uint32_t sa_sum; + + RTE_BUILD_BUG_ON(RTE_IPSEC_SAD_KEY_TYPE_MASK != 3); + + if ((name == NULL) || (conf == NULL) || + ((conf->max_sa[RTE_IPSEC_SAD_SPI_ONLY] == 0) && + (conf->max_sa[RTE_IPSEC_SAD_SPI_DIP] == 0) && + (conf->max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP] == 0))) { + rte_errno = EINVAL; + return NULL; + } + + ret = snprintf(sad_name, IPSEC_SAD_NAMESIZE, SAD_FORMAT, name); + if (ret < 0 || ret >= IPSEC_SAD_NAMESIZE) { + rte_errno = ENAMETOOLONG; + return NULL; + } + + /** Init SAD*/ + sa_sum = RTE_MAX(MIN_HASH_ENTRIES, + conf->max_sa[RTE_IPSEC_SAD_SPI_ONLY]) + + RTE_MAX(MIN_HASH_ENTRIES, + conf->max_sa[RTE_IPSEC_SAD_SPI_DIP]) + + RTE_MAX(MIN_HASH_ENTRIES, + conf->max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP]); + sad = rte_zmalloc_socket(NULL, sizeof(*sad) + + (sizeof(struct hash_cnt) * sa_sum), + RTE_CACHE_LINE_SIZE, conf->socket_id); + if (sad == NULL) { + rte_errno = ENOMEM; + return NULL; + } + memcpy(sad->name, sad_name, sizeof(sad_name)); + + hash_params.hash_func = DEFAULT_HASH_FUNC; + hash_params.hash_func_init_val = rte_rand(); + hash_params.socket_id = conf->socket_id; + hash_params.name = hash_name; + if (conf->flags & RTE_IPSEC_SAD_FLAG_RW_CONCURRENCY) + hash_params.extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY; + + /** Init hash[RTE_IPSEC_SAD_SPI_ONLY] for SPI only */ + snprintf(hash_name, sizeof(hash_name), "sad_1_%p", sad); + hash_params.key_len = sizeof(((struct rte_ipsec_sadv4_key *)0)->spi); + hash_params.entries = sa_sum; + sad->hash[RTE_IPSEC_SAD_SPI_ONLY] = rte_hash_create(&hash_params); + if (sad->hash[RTE_IPSEC_SAD_SPI_ONLY] == NULL) { + rte_ipsec_sad_destroy(sad); + return NULL; + } + + /** Init hash[RTE_IPSEC_SAD_SPI_DIP] for SPI + DIP */ + snprintf(hash_name, sizeof(hash_name), "sad_2_%p", sad); + if (conf->flags & RTE_IPSEC_SAD_FLAG_IPV6) + hash_params.key_len += + sizeof(((struct rte_ipsec_sadv6_key *)0)->dip); + else + hash_params.key_len += + sizeof(((struct rte_ipsec_sadv4_key *)0)->dip); + hash_params.entries = RTE_MAX(MIN_HASH_ENTRIES, + conf->max_sa[RTE_IPSEC_SAD_SPI_DIP]); + sad->hash[RTE_IPSEC_SAD_SPI_DIP] = rte_hash_create(&hash_params); + if (sad->hash[RTE_IPSEC_SAD_SPI_DIP] == NULL) { + rte_ipsec_sad_destroy(sad); + return NULL; + } + + /** Init hash[[RTE_IPSEC_SAD_SPI_DIP_SIP] for SPI + DIP + SIP */ + snprintf(hash_name, sizeof(hash_name), "sad_3_%p", sad); + if (conf->flags & RTE_IPSEC_SAD_FLAG_IPV6) + hash_params.key_len += + sizeof(((struct rte_ipsec_sadv6_key *)0)->sip); + else + hash_params.key_len += + sizeof(((struct rte_ipsec_sadv4_key *)0)->sip); + hash_params.entries = RTE_MAX(MIN_HASH_ENTRIES, + conf->max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP]); + sad->hash[RTE_IPSEC_SAD_SPI_DIP_SIP] = rte_hash_create(&hash_params); + if (sad->hash[RTE_IPSEC_SAD_SPI_DIP_SIP] == NULL) { + rte_ipsec_sad_destroy(sad); + return NULL; + } + + sad_list = RTE_TAILQ_CAST(rte_ipsec_sad_tailq.head, + rte_ipsec_sad_list); + rte_mcfg_tailq_write_lock(); + /* guarantee there's no existing */ + TAILQ_FOREACH(te, sad_list, next) { + tmp_sad = (struct rte_ipsec_sad *)te->data; + if (strncmp(sad_name, tmp_sad->name, IPSEC_SAD_NAMESIZE) == 0) + break; + } + if (te != NULL) { + rte_mcfg_tailq_write_unlock(); + rte_errno = EEXIST; + rte_ipsec_sad_destroy(sad); + return NULL; + } + + /* allocate tailq entry */ + te = rte_zmalloc("IPSEC_SAD_TAILQ_ENTRY", sizeof(*te), 0); + if (te == NULL) { + rte_mcfg_tailq_write_unlock(); + rte_errno = ENOMEM; + rte_ipsec_sad_destroy(sad); + return NULL; + } + + te->data = (void *)sad; + TAILQ_INSERT_TAIL(sad_list, te, next); + rte_mcfg_tailq_write_unlock(); + return sad; } struct rte_ipsec_sad * -rte_ipsec_sad_find_existing(__rte_unused const char *name) +rte_ipsec_sad_find_existing(const char *name) { - return NULL; + char sad_name[IPSEC_SAD_NAMESIZE]; + struct rte_ipsec_sad *sad = NULL; + struct rte_tailq_entry *te; + struct rte_ipsec_sad_list *sad_list; + int ret; + + ret = snprintf(sad_name, IPSEC_SAD_NAMESIZE, SAD_FORMAT, name); + if (ret < 0 || ret >= IPSEC_SAD_NAMESIZE) { + rte_errno = ENAMETOOLONG; + return NULL; + } + + sad_list = RTE_TAILQ_CAST(rte_ipsec_sad_tailq.head, + rte_ipsec_sad_list); + + rte_mcfg_tailq_read_lock(); + TAILQ_FOREACH(te, sad_list, next) { + sad = (struct rte_ipsec_sad *) te->data; + if (strncmp(sad_name, sad->name, IPSEC_SAD_NAMESIZE) == 0) + break; + } + rte_mcfg_tailq_read_unlock(); + + if (te == NULL) { + rte_errno = ENOENT; + return NULL; + } + + return sad; } void -rte_ipsec_sad_destroy(__rte_unused struct rte_ipsec_sad *sad) +rte_ipsec_sad_destroy(struct rte_ipsec_sad *sad) { - return; + struct rte_tailq_entry *te; + struct rte_ipsec_sad_list *sad_list; + + if (sad == NULL) + return; + + sad_list = RTE_TAILQ_CAST(rte_ipsec_sad_tailq.head, + rte_ipsec_sad_list); + rte_mcfg_tailq_write_lock(); + TAILQ_FOREACH(te, sad_list, next) { + if (te->data == (void *)sad) + break; + } + if (te != NULL) + TAILQ_REMOVE(sad_list, te, next); + + rte_mcfg_tailq_write_unlock(); + + rte_hash_free(sad->hash[RTE_IPSEC_SAD_SPI_ONLY]); + rte_hash_free(sad->hash[RTE_IPSEC_SAD_SPI_DIP]); + rte_hash_free(sad->hash[RTE_IPSEC_SAD_SPI_DIP_SIP]); + rte_free(sad); + if (te != NULL) + rte_free(te); } int diff --git a/lib/librte_ipsec/meson.build b/lib/librte_ipsec/meson.build index 91b9867..7035852 100644 --- a/lib/librte_ipsec/meson.build +++ b/lib/librte_ipsec/meson.build @@ -7,4 +7,4 @@ sources = files('esp_inb.c', 'esp_outb.c', 'sa.c', 'ses.c', 'ipsec_sad.c') headers = files('rte_ipsec.h', 'rte_ipsec_group.h', 'rte_ipsec_sa.h', 'rte_ipsec_sad.h') -deps += ['mbuf', 'net', 'cryptodev', 'security'] +deps += ['mbuf', 'net', 'cryptodev', 'security', 'hash'] From patchwork Mon Oct 21 14:35:44 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Medvedkin X-Patchwork-Id: 61609 X-Patchwork-Delegate: gakhil@marvell.com Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 589051BF99; Mon, 21 Oct 2019 16:36:05 +0200 (CEST) Received: from mga06.intel.com (mga06.intel.com [134.134.136.31]) by dpdk.org (Postfix) with ESMTP id 130FA1BF60 for ; Mon, 21 Oct 2019 16:35:54 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga104.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 21 Oct 2019 07:35:54 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.67,323,1566889200"; d="scan'208";a="372194517" Received: from silpixa00400072.ir.intel.com ([10.237.222.213]) by orsmga005.jf.intel.com with ESMTP; 21 Oct 2019 07:35:53 -0700 From: Vladimir Medvedkin To: dev@dpdk.org Cc: konstantin.ananyev@intel.com, bernard.iremonger@intel.com, akhil.goyal@nxp.com Date: Mon, 21 Oct 2019 15:35:44 +0100 Message-Id: <2b2e270c6ceb5fe99b47b3920f99c06835b33034.1571668033.git.vladimir.medvedkin@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: References: In-Reply-To: References: Subject: [dpdk-dev] [PATCH v7 3/5] ipsec: add SAD add/delete/lookup implementation X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Replace rte_ipsec_sad_add(), rte_ipsec_sad_del() and rte_ipsec_sad_lookup() stubs with actual implementation. It uses three librte_hash tables each of which contains an entries for a specific SA type (either it is addressed by SPI only or SPI+DIP or SPI+DIP+SIP) Signed-off-by: Vladimir Medvedkin Acked-by: Akhil Goyal Acked-by: Konstantin Ananyev Tested-by: Konstantin Ananyev --- doc/guides/prog_guide/ipsec_lib.rst | 110 ++++++++++++++ lib/librte_ipsec/ipsec_sad.c | 278 ++++++++++++++++++++++++++++++++++-- 2 files changed, 376 insertions(+), 12 deletions(-) diff --git a/doc/guides/prog_guide/ipsec_lib.rst b/doc/guides/prog_guide/ipsec_lib.rst index b69c153..4487e4c 100644 --- a/doc/guides/prog_guide/ipsec_lib.rst +++ b/doc/guides/prog_guide/ipsec_lib.rst @@ -186,6 +186,116 @@ As an example: for more information please refer to ipsec library API reference +Add/delete rules +~~~~~~~~~~~~~~~~ + +Library also provides methods to add or delete key/value pairs from the SAD. +To add user has to specify key, key type and a value which is an opaque pointer to SA. +The key type reflects a set of tuple fields that will be used for lookup of the SA. +As mentioned above there are 3 types of a key and the representation of a key type is: + +.. code-block:: c + + RTE_IPSEC_SAD_SPI_ONLY, + RTE_IPSEC_SAD_SPI_DIP, + RTE_IPSEC_SAD_SPI_DIP_SIP, + +As an example, to add new entry into the SAD for IPv4 addresses: + +.. code-block:: c + + struct rte_ipsec_sa *sa; + union rte_ipsec_sad_key key; + + key.v4.spi = rte_cpu_to_be_32(spi_val); + if (key_type >= RTE_IPSEC_SAD_SPI_DIP) /* DIP is optional*/ + key.v4.dip = rte_cpu_to_be_32(dip_val); + if (key_type == RTE_IPSEC_SAD_SPI_DIP_SIP) /* SIP is optional*/ + key.v4.sip = rte_cpu_to_be_32(sip_val); + + rte_ipsec_sad_add(sad, &key, key_type, sa); + +.. note:: + + By performance reason it is better to keep spi/dip/sip in net byte order + to eliminate byteswap on lookup + +To delete user has to specify key and key type. + +Delete code would look like: + +.. code-block:: c + + union rte_ipsec_sad_key key; + + key.v4.spi = rte_cpu_to_be_32(necessary_spi); + if (key_type >= RTE_IPSEC_SAD_SPI_DIP) /* DIP is optional*/ + key.v4.dip = rte_cpu_to_be_32(necessary_dip); + if (key_type == RTE_IPSEC_SAD_SPI_DIP_SIP) /* SIP is optional*/ + key.v4.sip = rte_cpu_to_be_32(necessary_sip); + + rte_ipsec_sad_del(sad, &key, key_type); + + +Lookup +~~~~~~ +Library provides lookup by the given {SPI,DIP,SIP} tuple of +inbound ipsec packet as a key. + +The search key is represented by: + +.. code-block:: c + + union rte_ipsec_sad_key { + struct rte_ipsec_sadv4_key v4; + struct rte_ipsec_sadv6_key v6; + }; + +where v4 is a tuple for IPv4: + +.. code-block:: c + + struct rte_ipsec_sadv4_key { + uint32_t spi; + uint32_t dip; + uint32_t sip; + }; + +and v6 is a tuple for IPv6: + +.. code-block:: c + + struct rte_ipsec_sadv6_key { + uint32_t spi; + uint8_t dip[16]; + uint8_t sip[16]; + }; + +As an example, lookup related code could look like that: + +.. code-block:: c + + int i; + union rte_ipsec_sad_key keys[BURST_SZ]; + const union rte_ipsec_sad_key *keys_p[BURST_SZ]; + void *vals[BURST_SZ]; + + for (i = 0; i < BURST_SZ_MAX; i++) { + keys[i].v4.spi = esp_hdr[i]->spi; + keys[i].v4.dip = ipv4_hdr[i]->dst_addr; + keys[i].v4.sip = ipv4_hdr[i]->src_addr; + keys_p[i] = &keys[i]; + } + rte_ipsec_sad_lookup(sad, keys_p, vals, BURST_SZ); + + for (i = 0; i < BURST_SZ_MAX; i++) { + if (vals[i] == NULL) + printf("SA not found for key index %d\n", i); + else + printf("SA pointer is %p\n", vals[i]); + } + + Supported features ------------------ diff --git a/lib/librte_ipsec/ipsec_sad.c b/lib/librte_ipsec/ipsec_sad.c index e16c7d9..db2c44c 100644 --- a/lib/librte_ipsec/ipsec_sad.c +++ b/lib/librte_ipsec/ipsec_sad.c @@ -49,20 +49,182 @@ static struct rte_tailq_elem rte_ipsec_sad_tailq = { }; EAL_REGISTER_TAILQ(rte_ipsec_sad_tailq) +#define SET_BIT(ptr, bit) (void *)((uintptr_t)(ptr) | (uintptr_t)(bit)) +#define CLEAR_BIT(ptr, bit) (void *)((uintptr_t)(ptr) & ~(uintptr_t)(bit)) +#define GET_BIT(ptr, bit) (void *)((uintptr_t)(ptr) & (uintptr_t)(bit)) + +/* + * @internal helper function + * Add a rule of type SPI_DIP or SPI_DIP_SIP. + * Inserts a rule into an appropriate hash table, + * updates the value for a given SPI in SPI_ONLY hash table + * reflecting presence of more specific rule type in two LSBs. + * Updates a counter that reflects the number of rules whith the same SPI. + */ +static inline int +add_specific(struct rte_ipsec_sad *sad, const void *key, + int key_type, void *sa) +{ + void *tmp_val; + int ret, notexist; + + /* Check if the key is present in the table. + * Need for further accaunting in cnt_arr + */ + ret = rte_hash_lookup(sad->hash[key_type], key); + notexist = (ret == -ENOENT); + + /* Add an SA to the corresponding table.*/ + ret = rte_hash_add_key_data(sad->hash[key_type], key, sa); + if (ret != 0) + return ret; + + /* Check if there is an entry in SPI only table with the same SPI */ + ret = rte_hash_lookup_data(sad->hash[RTE_IPSEC_SAD_SPI_ONLY], + key, &tmp_val); + if (ret < 0) + tmp_val = NULL; + tmp_val = SET_BIT(tmp_val, key_type); + + /* Add an entry into SPI only table */ + ret = rte_hash_add_key_data(sad->hash[RTE_IPSEC_SAD_SPI_ONLY], + key, tmp_val); + if (ret != 0) + return ret; + + /* Update a counter for a given SPI */ + ret = rte_hash_lookup(sad->hash[RTE_IPSEC_SAD_SPI_ONLY], key); + if (key_type == RTE_IPSEC_SAD_SPI_DIP) + sad->cnt_arr[ret].cnt_dip += notexist; + else + sad->cnt_arr[ret].cnt_dip_sip += notexist; + + return 0; +} + int -rte_ipsec_sad_add(__rte_unused struct rte_ipsec_sad *sad, - __rte_unused const union rte_ipsec_sad_key *key, - __rte_unused int key_type, __rte_unused void *sa) +rte_ipsec_sad_add(struct rte_ipsec_sad *sad, + const union rte_ipsec_sad_key *key, + int key_type, void *sa) { - return -ENOTSUP; + void *tmp_val; + int ret; + + if ((sad == NULL) || (key == NULL) || (sa == NULL) || + /* sa must be 4 byte aligned */ + (GET_BIT(sa, RTE_IPSEC_SAD_KEY_TYPE_MASK) != 0)) + return -EINVAL; + + /* + * Rules are stored in three hash tables depending on key_type. + * All rules will also have an entry in SPI_ONLY table, with entry + * value's two LSB's also indicating presence of rule with this SPI + * in other tables. + */ + switch (key_type) { + case(RTE_IPSEC_SAD_SPI_ONLY): + ret = rte_hash_lookup_data(sad->hash[key_type], + key, &tmp_val); + if (ret >= 0) + tmp_val = SET_BIT(sa, GET_BIT(tmp_val, + RTE_IPSEC_SAD_KEY_TYPE_MASK)); + else + tmp_val = sa; + ret = rte_hash_add_key_data(sad->hash[key_type], + key, tmp_val); + return ret; + case(RTE_IPSEC_SAD_SPI_DIP): + case(RTE_IPSEC_SAD_SPI_DIP_SIP): + return add_specific(sad, key, key_type, sa); + default: + return -EINVAL; + } +} + +/* + * @internal helper function + * Delete a rule of type SPI_DIP or SPI_DIP_SIP. + * Deletes an entry from an appropriate hash table and decrements + * an entry counter for given SPI. + * If entry to remove is the last one with given SPI within the table, + * then it will also update related entry in SPI_ONLY table. + * Removes an entry from SPI_ONLY hash table if there no rule left + * for this SPI in any table. + */ +static inline int +del_specific(struct rte_ipsec_sad *sad, const void *key, int key_type) +{ + void *tmp_val; + int ret; + uint32_t *cnt; + + /* Remove an SA from the corresponding table.*/ + ret = rte_hash_del_key(sad->hash[key_type], key); + if (ret < 0) + return ret; + + /* Get an index of cnt_arr entry for a given SPI */ + ret = rte_hash_lookup_data(sad->hash[RTE_IPSEC_SAD_SPI_ONLY], + key, &tmp_val); + if (ret < 0) + return ret; + cnt = (key_type == RTE_IPSEC_SAD_SPI_DIP) ? + &sad->cnt_arr[ret].cnt_dip : + &sad->cnt_arr[ret].cnt_dip_sip; + if (--(*cnt) != 0) + return 0; + + /* corresponding counter is 0, clear the bit indicating + * the presence of more specific rule for a given SPI. + */ + tmp_val = CLEAR_BIT(tmp_val, key_type); + + /* if there are no rules left with same SPI, + * remove an entry from SPI_only table + */ + if (tmp_val == NULL) + ret = rte_hash_del_key(sad->hash[RTE_IPSEC_SAD_SPI_ONLY], key); + else + ret = rte_hash_add_key_data(sad->hash[RTE_IPSEC_SAD_SPI_ONLY], + key, tmp_val); + if (ret < 0) + return ret; + return 0; } int -rte_ipsec_sad_del(__rte_unused struct rte_ipsec_sad *sad, - __rte_unused const union rte_ipsec_sad_key *key, - __rte_unused int key_type) +rte_ipsec_sad_del(struct rte_ipsec_sad *sad, + const union rte_ipsec_sad_key *key, + int key_type) { - return -ENOTSUP; + void *tmp_val; + int ret; + + if ((sad == NULL) || (key == NULL)) + return -EINVAL; + switch (key_type) { + case(RTE_IPSEC_SAD_SPI_ONLY): + ret = rte_hash_lookup_data(sad->hash[key_type], + key, &tmp_val); + if (ret < 0) + return ret; + if (GET_BIT(tmp_val, RTE_IPSEC_SAD_KEY_TYPE_MASK) == 0) { + ret = rte_hash_del_key(sad->hash[key_type], + key); + ret = ret < 0 ? ret : 0; + } else { + tmp_val = GET_BIT(tmp_val, + RTE_IPSEC_SAD_KEY_TYPE_MASK); + ret = rte_hash_add_key_data(sad->hash[key_type], + key, tmp_val); + } + return ret; + case(RTE_IPSEC_SAD_SPI_DIP): + case(RTE_IPSEC_SAD_SPI_DIP_SIP): + return del_specific(sad, key, key_type); + default: + return -EINVAL; + } } struct rte_ipsec_sad * @@ -252,10 +414,102 @@ rte_ipsec_sad_destroy(struct rte_ipsec_sad *sad) rte_free(te); } +/* + * @internal helper function + * Lookup a batch of keys in three hash tables. + * First lookup key in SPI_ONLY table. + * If there is an entry for the corresponding SPI check its value. + * Two least significant bits of the value indicate + * the presence of more specific rule in other tables. + * Perform additional lookup in corresponding hash tables + * and update the value if lookup succeeded. + */ +static int +__ipsec_sad_lookup(const struct rte_ipsec_sad *sad, + const union rte_ipsec_sad_key *keys[], void *sa[], uint32_t n) +{ + const void *keys_2[RTE_HASH_LOOKUP_BULK_MAX]; + const void *keys_3[RTE_HASH_LOOKUP_BULK_MAX]; + void *vals_2[RTE_HASH_LOOKUP_BULK_MAX] = {NULL}; + void *vals_3[RTE_HASH_LOOKUP_BULK_MAX] = {NULL}; + uint32_t idx_2[RTE_HASH_LOOKUP_BULK_MAX]; + uint32_t idx_3[RTE_HASH_LOOKUP_BULK_MAX]; + uint64_t mask_1, mask_2, mask_3; + uint64_t map, map_spec; + uint32_t n_2 = 0; + uint32_t n_3 = 0; + uint32_t i; + int found = 0; + + for (i = 0; i < n; i++) + sa[i] = NULL; + + /* + * Lookup keys in SPI only hash table first. + */ + rte_hash_lookup_bulk_data(sad->hash[RTE_IPSEC_SAD_SPI_ONLY], + (const void **)keys, n, &mask_1, sa); + for (map = mask_1; map; map &= (map - 1)) { + i = rte_bsf64(map); + /* + * if returned value indicates presence of a rule in other + * tables save a key for further lookup. + */ + if ((uintptr_t)sa[i] & RTE_IPSEC_SAD_SPI_DIP_SIP) { + idx_3[n_3] = i; + keys_3[n_3++] = keys[i]; + } + if ((uintptr_t)sa[i] & RTE_IPSEC_SAD_SPI_DIP) { + idx_2[n_2] = i; + keys_2[n_2++] = keys[i]; + } + /* clear 2 LSB's which indicate the presence + * of more specific rules + */ + sa[i] = CLEAR_BIT(sa[i], RTE_IPSEC_SAD_KEY_TYPE_MASK); + } + + /* Lookup for more specific rules in SPI_DIP table */ + if (n_2 != 0) { + rte_hash_lookup_bulk_data(sad->hash[RTE_IPSEC_SAD_SPI_DIP], + keys_2, n_2, &mask_2, vals_2); + for (map_spec = mask_2; map_spec; map_spec &= (map_spec - 1)) { + i = rte_bsf64(map_spec); + sa[idx_2[i]] = vals_2[i]; + } + } + /* Lookup for more specific rules in SPI_DIP_SIP table */ + if (n_3 != 0) { + rte_hash_lookup_bulk_data(sad->hash[RTE_IPSEC_SAD_SPI_DIP_SIP], + keys_3, n_3, &mask_3, vals_3); + for (map_spec = mask_3; map_spec; map_spec &= (map_spec - 1)) { + i = rte_bsf64(map_spec); + sa[idx_3[i]] = vals_3[i]; + } + } + + for (i = 0; i < n; i++) + found += (sa[i] != NULL); + + return found; +} + int -rte_ipsec_sad_lookup(__rte_unused const struct rte_ipsec_sad *sad, - __rte_unused const union rte_ipsec_sad_key *keys[], - __rte_unused void *sa[], __rte_unused uint32_t n) +rte_ipsec_sad_lookup(const struct rte_ipsec_sad *sad, + const union rte_ipsec_sad_key *keys[], void *sa[], uint32_t n) { - return -ENOTSUP; + uint32_t num, i = 0; + int found = 0; + + if (unlikely((sad == NULL) || (keys == NULL) || (sa == NULL))) + return -EINVAL; + + do { + num = RTE_MIN(n - i, (uint32_t)RTE_HASH_LOOKUP_BULK_MAX); + found += __ipsec_sad_lookup(sad, + &keys[i], &sa[i], num); + i += num; + } while (i != n); + + return found; } From patchwork Mon Oct 21 14:35:45 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Medvedkin X-Patchwork-Id: 61610 X-Patchwork-Delegate: gakhil@marvell.com Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id E76061BFA2; Mon, 21 Oct 2019 16:36:07 +0200 (CEST) Received: from mga06.intel.com (mga06.intel.com [134.134.136.31]) by dpdk.org (Postfix) with ESMTP id 2B5CB1BF67 for ; Mon, 21 Oct 2019 16:35:57 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga104.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 21 Oct 2019 07:35:56 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.67,323,1566889200"; d="scan'208";a="372194526" Received: from silpixa00400072.ir.intel.com ([10.237.222.213]) by orsmga005.jf.intel.com with ESMTP; 21 Oct 2019 07:35:54 -0700 From: Vladimir Medvedkin To: dev@dpdk.org Cc: konstantin.ananyev@intel.com, bernard.iremonger@intel.com, akhil.goyal@nxp.com Date: Mon, 21 Oct 2019 15:35:45 +0100 Message-Id: <2d8472ca8093c870d9f45b4d5894fbdc49edd853.1571668033.git.vladimir.medvedkin@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: References: In-Reply-To: References: Subject: [dpdk-dev] [PATCH v7 4/5] test/ipsec: add ipsec SAD autotests X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" add unittests for ipsec SAD library Signed-off-by: Vladimir Medvedkin Acked-by: Akhil Goyal Acked-by: Konstantin Ananyev Tested-by: Konstantin Ananyev --- MAINTAINERS | 2 + app/test/Makefile | 1 + app/test/autotest_data.py | 6 + app/test/meson.build | 1 + app/test/test_ipsec_sad.c | 887 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 897 insertions(+) create mode 100644 app/test/test_ipsec_sad.c diff --git a/MAINTAINERS b/MAINTAINERS index f8a56e2..18df233 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1189,6 +1189,8 @@ F: lib/librte_ipsec/ M: Bernard Iremonger F: app/test/test_ipsec.c F: doc/guides/prog_guide/ipsec_lib.rst +M: Vladimir Medvedkin +F: app/test/test_ipsec_sad.c Flow Classify - EXPERIMENTAL M: Bernard Iremonger diff --git a/app/test/Makefile b/app/test/Makefile index df7f77f..e2832fb 100644 --- a/app/test/Makefile +++ b/app/test/Makefile @@ -224,6 +224,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_BPF) += test_bpf.c SRCS-$(CONFIG_RTE_LIBRTE_RCU) += test_rcu_qsbr.c test_rcu_qsbr_perf.c SRCS-$(CONFIG_RTE_LIBRTE_IPSEC) += test_ipsec.c +SRCS-$(CONFIG_RTE_LIBRTE_IPSEC) += test_ipsec_sad.c ifeq ($(CONFIG_RTE_LIBRTE_IPSEC),y) LDLIBS += -lrte_ipsec endif diff --git a/app/test/autotest_data.py b/app/test/autotest_data.py index 7405149..a4f2882 100644 --- a/app/test/autotest_data.py +++ b/app/test/autotest_data.py @@ -518,6 +518,12 @@ "Func": default_autotest, "Report": None, }, + { + "Name": "IPsec_SAD", + "Command": "ipsec_sad_autotest", + "Func": default_autotest, + "Report": None, + }, # #Please always keep all dump tests at the end and together! # diff --git a/app/test/meson.build b/app/test/meson.build index 2c23c63..94f6b49 100644 --- a/app/test/meson.build +++ b/app/test/meson.build @@ -58,6 +58,7 @@ test_sources = files('commands.c', 'test_hash_readwrite_lf.c', 'test_interrupts.c', 'test_ipsec.c', + 'test_ipsec_sad.c', 'test_kni.c', 'test_kvargs.c', 'test_latencystats.c', diff --git a/app/test/test_ipsec_sad.c b/app/test/test_ipsec_sad.c new file mode 100644 index 0000000..4911646 --- /dev/null +++ b/app/test/test_ipsec_sad.c @@ -0,0 +1,887 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2014 Intel Corporation + */ + +#include +#include +#include +#include + +#include +#include + +#include "test.h" +#include "test_xmmt_ops.h" + +typedef int32_t (*rte_ipsec_sad_test)(void); + +static int32_t test_create_invalid(void); +static int32_t test_find_existing(void); +static int32_t test_multiple_create(void); +static int32_t test_add_invalid(void); +static int32_t test_delete_invalid(void); +static int32_t test_lookup_invalid(void); +static int32_t test_lookup_basic(void); +static int32_t test_lookup_adv(void); +static int32_t test_lookup_order(void); + +#define MAX_SA 100000 +#define PASS 0 +#define SPI 0xdead /* spi to install */ +#define DIP 0xbeef /* dip to install */ +#define SIP 0xf00d /* sip to install */ +#define BAD 0xbad /* some random value not installed into the table */ + +/* + * Check that rte_ipsec_sad_create fails gracefully for incorrect user input + * arguments + */ +int32_t +test_create_invalid(void) +{ + struct rte_ipsec_sad *sad = NULL; + struct rte_ipsec_sad_conf config; + + config.max_sa[RTE_IPSEC_SAD_SPI_ONLY] = MAX_SA; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP] = MAX_SA; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP] = MAX_SA; + config.socket_id = SOCKET_ID_ANY; + config.flags = 0; + + /* name == NULL */ + sad = rte_ipsec_sad_create(NULL, &config); + RTE_TEST_ASSERT(sad == NULL, + "Call succeeded with invalid parameters\n"); + + /* max_sa for every type = 0 */ + config.max_sa[RTE_IPSEC_SAD_SPI_ONLY] = 0; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP] = 0; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP] = 0; + sad = rte_ipsec_sad_create(__func__, &config); + RTE_TEST_ASSERT(sad == NULL, + "Call succeeded with invalid parameters\n"); + config.max_sa[RTE_IPSEC_SAD_SPI_ONLY] = MAX_SA; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP] = MAX_SA; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP] = MAX_SA; + + /* socket_id < -1 is invalid */ + config.max_sa[RTE_IPSEC_SAD_SPI_ONLY] = MAX_SA; + config.socket_id = -2; + sad = rte_ipsec_sad_create(__func__, &config); + RTE_TEST_ASSERT(sad == NULL, + "Call succeeded with invalid parameters\n"); + config.socket_id = SOCKET_ID_ANY; + + return TEST_SUCCESS; +} + +/* + * Test rte_ipsec_sad_find_existing() + * Create SAD and try to find it by it's name + */ +int32_t +test_find_existing(void) +{ + const char *name1 = "sad_one"; + const char *name2 = "sad_two"; + struct rte_ipsec_sad *one, *two, *tmp; + struct rte_ipsec_sad_conf config; + + config.socket_id = SOCKET_ID_ANY; + config.max_sa[RTE_IPSEC_SAD_SPI_ONLY] = MAX_SA; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP] = 0; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP] = 0; + one = rte_ipsec_sad_create(name1, &config); + RTE_TEST_ASSERT_NOT_NULL(one, "Failed to create SAD\n"); + two = rte_ipsec_sad_create(name2, &config); + RTE_TEST_ASSERT_NOT_NULL(two, "Failed to create SAD\n"); + + /* Find non existing */ + tmp = rte_ipsec_sad_find_existing("sad_three"); + RTE_TEST_ASSERT(tmp == NULL, + "rte_ipsec_sad_find_existing returns invalid SAD\n"); + + tmp = rte_ipsec_sad_find_existing(name1); + RTE_TEST_ASSERT(tmp == one, + "rte_ipsec_sad_find_existing returns invalid SAD\n"); + + tmp = rte_ipsec_sad_find_existing(name2); + RTE_TEST_ASSERT(tmp == two, + "rte_ipsec_sad_find_existing returns invalid SAD\n"); + + rte_ipsec_sad_destroy(one); + rte_ipsec_sad_destroy(two); + return TEST_SUCCESS; +} + +/* + * Create ipsec sad then delete it 10 times + * Use a slightly different max_sa each time + */ +int32_t +test_multiple_create(void) +{ + int i; + struct rte_ipsec_sad *sad = NULL; + struct rte_ipsec_sad_conf config; + + config.socket_id = SOCKET_ID_ANY; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP] = MAX_SA; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP] = MAX_SA; + + for (i = 0; i < 10; i++) { + config.max_sa[RTE_IPSEC_SAD_SPI_ONLY] = MAX_SA - i; + sad = rte_ipsec_sad_create(__func__, &config); + RTE_TEST_ASSERT_NOT_NULL(sad, "Failed to create SAD\n"); + rte_ipsec_sad_destroy(sad); + } + return TEST_SUCCESS; +} + +static int32_t +__test_add_invalid(int ipv6, union rte_ipsec_sad_key *tuple) +{ + int status; + struct rte_ipsec_sad *sad = NULL; + struct rte_ipsec_sad_conf config; + uint64_t tmp; + void *sa = &tmp; + + /* sad == NULL*/ + status = rte_ipsec_sad_add(NULL, tuple, + RTE_IPSEC_SAD_SPI_DIP_SIP, sa); + RTE_TEST_ASSERT(status < 0, + "Call succeeded with invalid parameters\n"); + + config.max_sa[RTE_IPSEC_SAD_SPI_ONLY] = MAX_SA; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP] = MAX_SA; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP] = MAX_SA; + config.socket_id = SOCKET_ID_ANY; + config.flags = 0; + if (ipv6) + config.flags = RTE_IPSEC_SAD_FLAG_IPV6; + + sad = rte_ipsec_sad_create(__func__, &config); + RTE_TEST_ASSERT_NOT_NULL(sad, "Failed to create SAD\n"); + + /* key == NULL*/ + status = rte_ipsec_sad_add(sad, NULL, RTE_IPSEC_SAD_SPI_DIP_SIP, sa); + RTE_TEST_ASSERT(status < 0, + "Call succeeded with invalid parameters\n"); + + /* len is incorrect*/ + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_DIP_SIP + 1, sa); + RTE_TEST_ASSERT(status < 0, + "Call succeeded with invalid parameters\n"); + + /* sa == NULL*/ + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_DIP_SIP, NULL); + RTE_TEST_ASSERT(status < 0, + "Call succeeded with invalid parameters\n"); + + /* sa is not aligned*/ + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_DIP_SIP, (void *)((uint8_t *)sa + 1)); + RTE_TEST_ASSERT(status < 0, + "Call succeeded with invalid parameters\n"); + + rte_ipsec_sad_destroy(sad); + + return TEST_SUCCESS; +} + +/* + * Check that rte_ipsec_sad_add fails gracefully + * for incorrect user input arguments + */ +int32_t +test_add_invalid(void) +{ + int status; + struct rte_ipsec_sadv4_key tuple_v4 = {10, 20, 30}; + struct rte_ipsec_sadv6_key tuple_v6 = {10, {20, }, {30, } }; + + status = __test_add_invalid(0, (union rte_ipsec_sad_key *)&tuple_v4); + if (status != TEST_SUCCESS) + return status; + + status = __test_add_invalid(1, (union rte_ipsec_sad_key *)&tuple_v6); + + return status; + +} + +static int32_t +__test_delete_invalid(int ipv6, union rte_ipsec_sad_key *tuple) +{ + int status; + struct rte_ipsec_sad *sad = NULL; + struct rte_ipsec_sad_conf config; + + /* sad == NULL*/ + status = rte_ipsec_sad_del(NULL, tuple, RTE_IPSEC_SAD_SPI_DIP_SIP); + RTE_TEST_ASSERT(status < 0, + "Call succeeded with invalid parameters\n"); + + config.max_sa[RTE_IPSEC_SAD_SPI_ONLY] = MAX_SA; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP] = MAX_SA; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP] = MAX_SA; + config.socket_id = SOCKET_ID_ANY; + config.flags = 0; + if (ipv6) + config.flags = RTE_IPSEC_SAD_FLAG_IPV6; + + sad = rte_ipsec_sad_create(__func__, &config); + RTE_TEST_ASSERT_NOT_NULL(sad, "Failed to create SAD\n"); + + /* key == NULL*/ + status = rte_ipsec_sad_del(sad, NULL, RTE_IPSEC_SAD_SPI_DIP_SIP); + RTE_TEST_ASSERT(status < 0, + "Call succeeded with invalid parameters\n"); + + /* len is incorrect */ + status = rte_ipsec_sad_del(sad, tuple, RTE_IPSEC_SAD_SPI_DIP_SIP + 1); + RTE_TEST_ASSERT(status < 0, + "Call succeeded with invalid parameters\n"); + + rte_ipsec_sad_destroy(sad); + + return TEST_SUCCESS; +} + +/* + * Check that rte_ipsec_sad_delete fails gracefully for incorrect user input + * arguments + */ +int32_t +test_delete_invalid(void) +{ + int status; + struct rte_ipsec_sadv4_key tuple_v4 = {SPI, DIP, SIP}; + struct rte_ipsec_sadv6_key tuple_v6 = {SPI, {0xbe, 0xef, }, + {0xf0, 0x0d, } }; + + status = __test_delete_invalid(0, (union rte_ipsec_sad_key *)&tuple_v4); + if (status != TEST_SUCCESS) + return status; + + status = __test_delete_invalid(1, (union rte_ipsec_sad_key *)&tuple_v6); + + return status; +} + +static int32_t +__test_lookup_invalid(int ipv6, union rte_ipsec_sad_key *tuple) +{ + int status; + struct rte_ipsec_sad *sad = NULL; + struct rte_ipsec_sad_conf config; + const union rte_ipsec_sad_key *key_arr[] = {tuple}; + void *sa[1]; + + status = rte_ipsec_sad_lookup(NULL, key_arr, sa, 1); + RTE_TEST_ASSERT(status < 0, + "Call succeeded with invalid parameters\n"); + + config.max_sa[RTE_IPSEC_SAD_SPI_ONLY] = MAX_SA; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP] = MAX_SA; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP] = MAX_SA; + config.socket_id = SOCKET_ID_ANY; + config.flags = 0; + if (ipv6) + config.flags = RTE_IPSEC_SAD_FLAG_IPV6; + + sad = rte_ipsec_sad_create(__func__, &config); + RTE_TEST_ASSERT_NOT_NULL(sad, "Failed to create SAD\n"); + + status = rte_ipsec_sad_lookup(sad, NULL, sa, 1); + RTE_TEST_ASSERT(status < 0, + "Call succeeded with invalid parameters\n"); + + status = rte_ipsec_sad_lookup(sad, key_arr, NULL, 1); + RTE_TEST_ASSERT(status < 0, + "Call succeeded with invalid parameters\n"); + + rte_ipsec_sad_destroy(sad); + + return TEST_SUCCESS; +} + +/* + * Check that rte_ipsec_sad_lookup fails gracefully for incorrect user input + * arguments + */ +int32_t +test_lookup_invalid(void) +{ + int status; + struct rte_ipsec_sadv4_key tuple_v4 = {10, 20, 30}; + struct rte_ipsec_sadv6_key tuple_v6 = {10, {20, }, {30, } }; + + status = __test_lookup_invalid(0, + (union rte_ipsec_sad_key *)&tuple_v4); + if (status != TEST_SUCCESS) + return status; + + status = __test_lookup_invalid(1, + (union rte_ipsec_sad_key *)&tuple_v6); + + return status; +} + +static int32_t +__test_lookup_basic(int ipv6, union rte_ipsec_sad_key *tuple, + union rte_ipsec_sad_key *tuple_1) +{ + int status; + struct rte_ipsec_sad *sad = NULL; + struct rte_ipsec_sad_conf config; + const union rte_ipsec_sad_key *key_arr[] = {tuple}; + + uint64_t tmp; + void *sa[1]; + + config.max_sa[RTE_IPSEC_SAD_SPI_ONLY] = MAX_SA; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP] = MAX_SA; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP] = MAX_SA; + config.socket_id = SOCKET_ID_ANY; + config.flags = 0; + if (ipv6) + config.flags = RTE_IPSEC_SAD_FLAG_IPV6; + + sad = rte_ipsec_sad_create(__func__, &config); + RTE_TEST_ASSERT_NOT_NULL(sad, "Failed to create SAD\n"); + + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 1); + RTE_TEST_ASSERT((status == 0) && (sa[0] == NULL), + "Lookup returns an unexpected result\n"); + + sa[0] = &tmp; + status = rte_ipsec_sad_add(sad, tuple, RTE_IPSEC_SAD_SPI_ONLY, sa[0]); + RTE_TEST_ASSERT(status == 0, "Failed to add a rule\n"); + + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 1); + RTE_TEST_ASSERT((status == 1) && (sa[0] == &tmp), + "Lookup returns an unexpected result\n"); + + key_arr[0] = tuple_1; + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 1); + RTE_TEST_ASSERT((status == 1) && (sa[0] == &tmp), + "Lookup returns an unexpected result\n"); + key_arr[0] = tuple; + + status = rte_ipsec_sad_del(sad, tuple, RTE_IPSEC_SAD_SPI_ONLY); + RTE_TEST_ASSERT(status == 0, "Failed to delete a rule\n"); + + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 1); + RTE_TEST_ASSERT((status == 0) && (sa[0] == NULL), + "Lookup returns an unexpected result\n"); + + rte_ipsec_sad_destroy(sad); + + return TEST_SUCCESS; +} + +/* + * Lookup missing key, then add it as RTE_IPSEC_SAD_SPI_ONLY, lookup it again, + * lookup different key with the same SPI, then delete it and repeat lookup + */ +int32_t +test_lookup_basic(void) +{ + int status; + struct rte_ipsec_sadv4_key tuple_v4 = {SPI, DIP, SIP}; + struct rte_ipsec_sadv4_key tuple_v4_1 = {SPI, BAD, BAD}; + struct rte_ipsec_sadv6_key tuple_v6 = {SPI, {0xbe, 0xef, }, + {0xf0, 0x0d, } }; + struct rte_ipsec_sadv6_key tuple_v6_1 = {SPI, {0x0b, 0xad, }, + {0x0b, 0xad, } }; + + status = __test_lookup_basic(0, (union rte_ipsec_sad_key *)&tuple_v4, + (union rte_ipsec_sad_key *)&tuple_v4_1); + if (status != TEST_SUCCESS) + return status; + + status = __test_lookup_basic(1, (union rte_ipsec_sad_key *)&tuple_v6, + (union rte_ipsec_sad_key *)&tuple_v6_1); + + return status; +} + +static int32_t +__test_lookup_adv(int ipv6, union rte_ipsec_sad_key *tuple, + const union rte_ipsec_sad_key **key_arr) +{ + int status; + struct rte_ipsec_sad *sad = NULL; + struct rte_ipsec_sad_conf config; + uint64_t tmp1, tmp2, tmp3; + void *install_sa; + void *sa[4]; + + config.max_sa[RTE_IPSEC_SAD_SPI_ONLY] = MAX_SA; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP] = MAX_SA; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP] = MAX_SA; + config.socket_id = SOCKET_ID_ANY; + config.flags = 0; + if (ipv6) + config.flags = RTE_IPSEC_SAD_FLAG_IPV6; + sad = rte_ipsec_sad_create(__func__, &config); + RTE_TEST_ASSERT_NOT_NULL(sad, "Failed to create SAD\n"); + + /* lookup with empty table */ + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 4); + RTE_TEST_ASSERT(status == 0, "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[0] == NULL, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[1] == NULL, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[2] == NULL, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[3] == NULL, + "Lookup returns an unexpected result\n"); + + /* lookup with one RTE_IPSEC_SAD_SPI_ONLY rule */ + install_sa = &tmp1; + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_ONLY, install_sa); + RTE_TEST_ASSERT(status == 0, "Failed to add a rule\n"); + + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 4); + RTE_TEST_ASSERT(status == 3, "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[0] == &tmp1, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[1] == &tmp1, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[2] == &tmp1, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[3] == NULL, + "Lookup returns an unexpected result\n"); + + status = rte_ipsec_sad_del(sad, tuple, RTE_IPSEC_SAD_SPI_ONLY); + RTE_TEST_ASSERT(status == 0, "Failde to delete a rule\n"); + + /* lookup with one RTE_IPSEC_SAD_SPI_DIP rule */ + install_sa = &tmp2; + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_DIP, install_sa); + RTE_TEST_ASSERT(status == 0, "failed to add a rule\n"); + + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 4); + RTE_TEST_ASSERT(status == 2, "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[0] == &tmp2, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[1] == &tmp2, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[2] == NULL, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[3] == NULL, + "Lookup returns an unexpected result\n"); + + status = rte_ipsec_sad_del(sad, tuple, RTE_IPSEC_SAD_SPI_DIP); + RTE_TEST_ASSERT(status == 0, "Failed to delete a rule\n"); + + /* lookup with one RTE_IPSEC_SAD_SPI_DIP_SIP rule */ + install_sa = &tmp3; + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_DIP_SIP, install_sa); + RTE_TEST_ASSERT(status == 0, "Failed to add a rule\n"); + + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 4); + RTE_TEST_ASSERT(status == 1, "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[0] == &tmp3, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[1] == NULL, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[2] == NULL, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[3] == NULL, + "Lookup returns an unexpected result\n"); + + status = rte_ipsec_sad_del(sad, tuple, RTE_IPSEC_SAD_SPI_DIP_SIP); + RTE_TEST_ASSERT(status == 0, "Failed to delete a rule\n"); + + /* lookup with two RTE_IPSEC_SAD_ONLY and RTE_IPSEC_SAD_DIP rules */ + install_sa = &tmp1; + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_ONLY, install_sa); + RTE_TEST_ASSERT(status == 0, "Failed to add a rule\n"); + install_sa = &tmp2; + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_DIP, install_sa); + RTE_TEST_ASSERT(status == 0, "Failed to add a rule\n"); + + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 4); + RTE_TEST_ASSERT(status == 3, "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[0] == &tmp2, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[1] == &tmp2, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[2] == &tmp1, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[3] == NULL, + "Lookup returns an unexpected result\n"); + + status = rte_ipsec_sad_del(sad, tuple, RTE_IPSEC_SAD_SPI_ONLY); + RTE_TEST_ASSERT(status == 0, "Failed to delete a rule\n"); + status = rte_ipsec_sad_del(sad, tuple, RTE_IPSEC_SAD_SPI_DIP); + RTE_TEST_ASSERT(status == 0, "Failed to delete a rule\n"); + + /* lookup with two RTE_IPSEC_SAD_ONLY and RTE_IPSEC_SAD_DIP_SIP rules */ + install_sa = &tmp1; + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_ONLY, install_sa); + RTE_TEST_ASSERT(status == 0, "Failed to add a rule\n"); + install_sa = &tmp3; + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_DIP_SIP, install_sa); + RTE_TEST_ASSERT(status == 0, "Failed to add a rule\n"); + + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 4); + RTE_TEST_ASSERT(status == 3, "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[0] == &tmp3, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[1] == &tmp1, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[2] == &tmp1, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[3] == NULL, + "Lookup returns an unexpected result\n"); + + status = rte_ipsec_sad_del(sad, tuple, RTE_IPSEC_SAD_SPI_ONLY); + RTE_TEST_ASSERT(status == 0, "Failed to delete a rule\n"); + status = rte_ipsec_sad_del(sad, tuple, RTE_IPSEC_SAD_SPI_DIP_SIP); + RTE_TEST_ASSERT(status == 0, "Failed to delete a rule\n"); + + /* lookup with two RTE_IPSEC_SAD_DIP and RTE_IPSEC_SAD_DIP_SIP rules */ + install_sa = &tmp2; + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_DIP, install_sa); + RTE_TEST_ASSERT(status == 0, "Failed to add a rule\n"); + install_sa = &tmp3; + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_DIP_SIP, install_sa); + RTE_TEST_ASSERT(status == 0, "Failed to add a rule\n"); + + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 4); + RTE_TEST_ASSERT(status == 2, "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[0] == &tmp3, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[1] == &tmp2, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[2] == NULL, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[3] == NULL, + "Lookup returns an unexpected result\n"); + + status = rte_ipsec_sad_del(sad, tuple, RTE_IPSEC_SAD_SPI_DIP); + RTE_TEST_ASSERT(status == 0, "Failed to delete a rule\n"); + status = rte_ipsec_sad_del(sad, tuple, RTE_IPSEC_SAD_SPI_DIP_SIP); + RTE_TEST_ASSERT(status == 0, "Failed to delete a rule\n"); + + /* + * lookup with three RTE_IPSEC_SAD_DIP, RTE_IPSEC_SAD_DIP and + * RTE_IPSEC_SAD_DIP_SIP rules + */ + install_sa = &tmp1; + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_ONLY, install_sa); + RTE_TEST_ASSERT(status == 0, "Failed to add a rule\n"); + install_sa = &tmp2; + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_DIP, install_sa); + RTE_TEST_ASSERT(status == 0, "Failed to add a rule\n"); + install_sa = &tmp3; + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_DIP_SIP, install_sa); + RTE_TEST_ASSERT(status == 0, "Failed to add a rule\n"); + + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 4); + RTE_TEST_ASSERT(status == 3, "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[0] == &tmp3, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[1] == &tmp2, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[2] == &tmp1, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[3] == NULL, + "Lookup returns an unexpected result\n"); + + status = rte_ipsec_sad_del(sad, tuple, RTE_IPSEC_SAD_SPI_ONLY); + RTE_TEST_ASSERT(status == 0, "Failed to delete a rule\n"); + status = rte_ipsec_sad_del(sad, tuple, RTE_IPSEC_SAD_SPI_DIP); + RTE_TEST_ASSERT(status == 0, "Failed to delete a rule\n"); + status = rte_ipsec_sad_del(sad, tuple, RTE_IPSEC_SAD_SPI_DIP_SIP); + RTE_TEST_ASSERT(status == 0, "Failed to delete a rule\n"); + + rte_ipsec_sad_destroy(sad); + + return TEST_SUCCESS; +} + +/* + * Lookup different keys in a table with: + * - RTE_IPSEC_SAD_SPI_ONLY + * - RTE_IPSEC_SAD_SPI_DIP + * - RTE_IPSEC_SAD_SPI_SIP + * - RTE_IPSEC_SAD_SPI_ONLY/RTE_IPSEC_SAD_SPI_DIP + * - RTE_IPSEC_SAD_SPI_ONLY/RTE_IPSEC_SAD_SPI_DIP_SIP + * - RTE_IPSEC_SAD_SPI_DIP/RTE_IPSEC_SAD_SPI_DIP_SIP + * - RTE_IPSEC_SAD_SPI_ONLY/RTE_IPSEC_SAD_SPI_DIP/RTE_IPSEC_SAD_SPI_DIP_SIP + * length of rule installed. + */ +int32_t +test_lookup_adv(void) +{ + int status; + /* key to install*/ + struct rte_ipsec_sadv4_key tuple_v4 = {SPI, DIP, SIP}; + struct rte_ipsec_sadv4_key tuple_v4_1 = {SPI, DIP, BAD}; + struct rte_ipsec_sadv4_key tuple_v4_2 = {SPI, BAD, SIP}; + struct rte_ipsec_sadv4_key tuple_v4_3 = {BAD, DIP, SIP}; + + /* key to install*/ + struct rte_ipsec_sadv6_key tuple_v6 = {SPI, {0xbe, 0xef, }, + {0xf0, 0x0d, } }; + struct rte_ipsec_sadv6_key tuple_v6_1 = {SPI, {0xbe, 0xef, }, + {0x0b, 0xad, } }; + struct rte_ipsec_sadv6_key tuple_v6_2 = {SPI, {0x0b, 0xad, }, + {0xf0, 0x0d, } }; + struct rte_ipsec_sadv6_key tuple_v6_3 = {BAD, {0xbe, 0xef, }, + {0xf0, 0x0d, } }; + + const union rte_ipsec_sad_key *key_arr[] = { + (union rte_ipsec_sad_key *)&tuple_v4, + (union rte_ipsec_sad_key *)&tuple_v4_1, + (union rte_ipsec_sad_key *)&tuple_v4_2, + (union rte_ipsec_sad_key *)&tuple_v4_3 + }; + + status = __test_lookup_adv(0, (union rte_ipsec_sad_key *)&tuple_v4, + key_arr); + if (status != TEST_SUCCESS) + return status; + key_arr[0] = (union rte_ipsec_sad_key *)&tuple_v6; + key_arr[1] = (union rte_ipsec_sad_key *)&tuple_v6_1; + key_arr[2] = (union rte_ipsec_sad_key *)&tuple_v6_2; + key_arr[3] = (union rte_ipsec_sad_key *)&tuple_v6_3; + status = __test_lookup_adv(1, (union rte_ipsec_sad_key *)&tuple_v6, + key_arr); + + return status; +} + + +static int32_t +__test_lookup_order(int ipv6, union rte_ipsec_sad_key *tuple, + union rte_ipsec_sad_key *tuple_1, union rte_ipsec_sad_key *tuple_2) +{ + int status; + struct rte_ipsec_sad *sad = NULL; + struct rte_ipsec_sad_conf config; + const union rte_ipsec_sad_key *key_arr[] = {tuple, tuple_1, tuple_2,}; + uint64_t tmp1, tmp2, tmp3; + void *install_sa; + void *sa[3]; + + config.max_sa[RTE_IPSEC_SAD_SPI_ONLY] = MAX_SA; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP] = MAX_SA; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP] = MAX_SA; + config.socket_id = SOCKET_ID_ANY; + config.flags = 0; + if (ipv6) + config.flags = RTE_IPSEC_SAD_FLAG_IPV6; + sad = rte_ipsec_sad_create(__func__, &config); + RTE_TEST_ASSERT_NOT_NULL(sad, "Failed to create SAD\n"); + + /* install RTE_IPSEC_SAD_SPI_ONLY */ + install_sa = &tmp1; + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_ONLY, install_sa); + RTE_TEST_ASSERT(status == 0, "Failed to add a rule\n"); + + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 3); + RTE_TEST_ASSERT(status == 3, "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[0] == &tmp1, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[1] == &tmp1, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[2] == &tmp1, + "Lookup returns an unexpected result\n"); + + /* add RTE_IPSEC_SAD_SPI_DIP */ + install_sa = &tmp2; + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_DIP, install_sa); + RTE_TEST_ASSERT(status == 0, "Failed to add a rule\n"); + + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 3); + RTE_TEST_ASSERT(status == 3, "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[0] == &tmp2, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[1] == &tmp2, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[2] == &tmp1, + "Lookup returns an unexpected result\n"); + + /* add RTE_IPSEC_SAD_SPI_DIP_SIP */ + install_sa = &tmp3; + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_DIP_SIP, install_sa); + RTE_TEST_ASSERT(status == 0, "Failed to add a rule\n"); + + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 3); + RTE_TEST_ASSERT(status == 3, "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[0] == &tmp3, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[1] == &tmp2, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[2] == &tmp1, + "Lookup returns an unexpected result\n"); + + /* delete RTE_IPSEC_SAD_SPI_ONLY */ + status = rte_ipsec_sad_del(sad, tuple, RTE_IPSEC_SAD_SPI_ONLY); + RTE_TEST_ASSERT(status == 0, "Failed to delete a rule\n"); + + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 3); + RTE_TEST_ASSERT(status == 2, "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[0] == &tmp3, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[1] == &tmp2, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[2] == NULL, + "Lookup returns an unexpected result\n"); + + /* delete RTE_IPSEC_SAD_SPI_DIP */ + status = rte_ipsec_sad_del(sad, tuple, RTE_IPSEC_SAD_SPI_DIP); + RTE_TEST_ASSERT(status == 0, "Failed to delete a rule\n"); + + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 3); + RTE_TEST_ASSERT(status == 1, "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[0] == &tmp3, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[1] == NULL, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[2] == NULL, + "Lookup returns an unexpected result\n"); + + /* delete RTE_IPSEC_SAD_SPI_DIP_SIP */ + status = rte_ipsec_sad_del(sad, tuple, RTE_IPSEC_SAD_SPI_DIP_SIP); + RTE_TEST_ASSERT(status == 0, "Failed to delete a rule\n"); + + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 3); + RTE_TEST_ASSERT(status == 0, "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[0] == NULL, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[1] == NULL, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[2] == NULL, + "Lookup returns an unexpected result\n"); + + /* add RTE_IPSEC_SAD_SPI_DIP_SIP */ + install_sa = &tmp3; + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_DIP_SIP, install_sa); + RTE_TEST_ASSERT(status == 0, "Failed to add a rule\n"); + + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 3); + RTE_TEST_ASSERT(status == 1, "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[0] == &tmp3, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[1] == NULL, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[2] == NULL, + "Lookup returns an unexpected result\n"); + + /* add RTE_IPSEC_SAD_SPI_DIP */ + install_sa = &tmp2; + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_DIP, install_sa); + RTE_TEST_ASSERT(status == 0, "Failed to add a rule\n"); + + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 3); + RTE_TEST_ASSERT(status == 2, "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[0] == &tmp3, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[1] == &tmp2, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[2] == NULL, + "Lookup returns an unexpected result\n"); + + /* add RTE_IPSEC_SAD_SPI_ONLY */ + install_sa = &tmp1; + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_ONLY, install_sa); + RTE_TEST_ASSERT(status == 0, "Failed to add a rule\n"); + + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 3); + RTE_TEST_ASSERT(status == 3, "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[0] == &tmp3, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[1] == &tmp2, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[2] == &tmp1, + "Lookup returns an unexpected result\n"); + + rte_ipsec_sad_destroy(sad); + return TEST_SUCCESS; +} + +/* + * Check an order of add and delete + */ +int32_t +test_lookup_order(void) +{ + int status; + /* key to install*/ + struct rte_ipsec_sadv4_key tuple_v4 = {SPI, DIP, SIP}; + struct rte_ipsec_sadv4_key tuple_v4_1 = {SPI, DIP, BAD}; + struct rte_ipsec_sadv4_key tuple_v4_2 = {SPI, BAD, SIP}; + /* key to install*/ + struct rte_ipsec_sadv6_key tuple_v6 = {SPI, {0xbe, 0xef, }, + {0xf0, 0x0d, } }; + struct rte_ipsec_sadv6_key tuple_v6_1 = {SPI, {0xbe, 0xef, }, + {0x0b, 0xad, } }; + struct rte_ipsec_sadv6_key tuple_v6_2 = {SPI, {0x0b, 0xad, }, + {0xf0, 0x0d, } }; + + status = __test_lookup_order(0, (union rte_ipsec_sad_key *)&tuple_v4, + (union rte_ipsec_sad_key *)&tuple_v4_1, + (union rte_ipsec_sad_key *)&tuple_v4_2); + if (status != TEST_SUCCESS) + return status; + + status = __test_lookup_order(1, (union rte_ipsec_sad_key *)&tuple_v6, + (union rte_ipsec_sad_key *)&tuple_v6_1, + (union rte_ipsec_sad_key *)&tuple_v6_2); + return status; +} + +static struct unit_test_suite ipsec_sad_tests = { + .suite_name = "ipsec sad autotest", + .setup = NULL, + .teardown = NULL, + .unit_test_cases = { + TEST_CASE(test_create_invalid), + TEST_CASE(test_find_existing), + TEST_CASE(test_multiple_create), + TEST_CASE(test_add_invalid), + TEST_CASE(test_delete_invalid), + TEST_CASE(test_lookup_invalid), + TEST_CASE(test_lookup_basic), + TEST_CASE(test_lookup_adv), + TEST_CASE(test_lookup_order), + TEST_CASES_END() + } +}; + +static int +test_ipsec_sad(void) +{ + return unit_test_suite_runner(&ipsec_sad_tests); +} + +REGISTER_TEST_COMMAND(ipsec_sad_autotest, test_ipsec_sad); From patchwork Mon Oct 21 14:35:46 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Medvedkin X-Patchwork-Id: 61611 X-Patchwork-Delegate: gakhil@marvell.com Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id C4E961BFC2; Mon, 21 Oct 2019 16:36:24 +0200 (CEST) Received: from mga06.intel.com (mga06.intel.com [134.134.136.31]) by dpdk.org (Postfix) with ESMTP id 0F5961BF67 for ; Mon, 21 Oct 2019 16:35:58 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga104.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 21 Oct 2019 07:35:58 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.67,323,1566889200"; d="scan'208";a="372194534" Received: from silpixa00400072.ir.intel.com ([10.237.222.213]) by orsmga005.jf.intel.com with ESMTP; 21 Oct 2019 07:35:57 -0700 From: Vladimir Medvedkin To: dev@dpdk.org Cc: konstantin.ananyev@intel.com, bernard.iremonger@intel.com, akhil.goyal@nxp.com Date: Mon, 21 Oct 2019 15:35:46 +0100 Message-Id: <8390043ce6f994bfdd12d43d112b7c13e5c8f2bb.1571668033.git.vladimir.medvedkin@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: References: In-Reply-To: References: Subject: [dpdk-dev] [PATCH v7 5/5] app: add test-sad application X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Introduce new application to provide user to evaluate and perform custom functional and performance tests for IPsec SAD implementation. Signed-off-by: Vladimir Medvedkin Acked-by: Akhil Goyal Acked-by: Konstantin Ananyev Tested-by: Konstantin Ananyev --- MAINTAINERS | 1 + app/Makefile | 1 + app/meson.build | 3 +- app/test-sad/Makefile | 18 ++ app/test-sad/main.c | 668 +++++++++++++++++++++++++++++++++++++++++++++++ app/test-sad/meson.build | 6 + 6 files changed, 696 insertions(+), 1 deletion(-) create mode 100644 app/test-sad/Makefile create mode 100644 app/test-sad/main.c create mode 100644 app/test-sad/meson.build diff --git a/MAINTAINERS b/MAINTAINERS index 18df233..f0bcabd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1191,6 +1191,7 @@ F: app/test/test_ipsec.c F: doc/guides/prog_guide/ipsec_lib.rst M: Vladimir Medvedkin F: app/test/test_ipsec_sad.c +F: app/test-sad/ Flow Classify - EXPERIMENTAL M: Bernard Iremonger diff --git a/app/Makefile b/app/Makefile index 28acbce..db9d2d5 100644 --- a/app/Makefile +++ b/app/Makefile @@ -10,6 +10,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += pdump DIRS-$(CONFIG_RTE_LIBRTE_ACL) += test-acl DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) += test-cmdline DIRS-$(CONFIG_RTE_LIBRTE_PIPELINE) += test-pipeline +DIRS-$(CONFIG_RTE_LIBRTE_IPSEC) += test-sad ifeq ($(CONFIG_RTE_LIBRTE_BBDEV),y) DIRS-$(CONFIG_RTE_TEST_BBDEV) += test-bbdev diff --git a/app/meson.build b/app/meson.build index b0e6afb..71109cc 100644 --- a/app/meson.build +++ b/app/meson.build @@ -15,7 +15,8 @@ apps = [ 'test-crypto-perf', 'test-eventdev', 'test-pipeline', - 'test-pmd'] + 'test-pmd', + 'test-sad'] # for BSD only lib_execinfo = cc.find_library('execinfo', required: false) diff --git a/app/test-sad/Makefile b/app/test-sad/Makefile new file mode 100644 index 0000000..9b35413 --- /dev/null +++ b/app/test-sad/Makefile @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2010-2014 Intel Corporation + +include $(RTE_SDK)/mk/rte.vars.mk + +ifeq ($(CONFIG_RTE_LIBRTE_IPSEC),y) + +APP = testsad + +CFLAGS += $(WERROR_FLAGS) +CFLAGS += -DALLOW_EXPERIMENTAL_API + +# all source are stored in SRCS-y +SRCS-y := main.c + +include $(RTE_SDK)/mk/rte.app.mk + +endif diff --git a/app/test-sad/main.c b/app/test-sad/main.c new file mode 100644 index 0000000..bd05638 --- /dev/null +++ b/app/test-sad/main.c @@ -0,0 +1,668 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2019 Intel Corporation + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define PRINT_USAGE_START "%s [EAL options] --\n" + +#define GET_CB_FIELD(in, fd, base, lim, dlm) do { \ + unsigned long val; \ + char *end_fld; \ + errno = 0; \ + val = strtoul((in), &end_fld, (base)); \ + if (errno != 0 || end_fld[0] != (dlm) || val > (lim)) \ + return -EINVAL; \ + (fd) = (typeof(fd))val; \ + (in) = end_fld + 1; \ +} while (0) + +#define DEF_RULE_NUM 0x10000 +#define DEF_TUPLES_NUM 0x100000 +#define BURST_SZ_MAX 64 + +static struct { + const char *prgname; + const char *rules_file; + const char *tuples_file; + uint32_t nb_rules; + uint32_t nb_tuples; + uint32_t nb_rules_32; + uint32_t nb_rules_64; + uint32_t nb_rules_96; + uint32_t nb_tuples_rnd; + uint32_t burst_sz; + uint8_t fract_32; + uint8_t fract_64; + uint8_t fract_96; + uint8_t fract_rnd_tuples; + int ipv6; + int verbose; + int parallel_lookup; + int concurrent_rw; +} config = { + .rules_file = NULL, + .tuples_file = NULL, + .nb_rules = DEF_RULE_NUM, + .nb_tuples = DEF_TUPLES_NUM, + .nb_rules_32 = 0, + .nb_rules_64 = 0, + .nb_rules_96 = 0, + .nb_tuples_rnd = 0, + .burst_sz = BURST_SZ_MAX, + .fract_32 = 90, + .fract_64 = 9, + .fract_96 = 1, + .fract_rnd_tuples = 0, + .ipv6 = 0, + .verbose = 0, + .parallel_lookup = 0, + .concurrent_rw = 0 +}; + +enum { + CB_RULE_SPI, + CB_RULE_DIP, + CB_RULE_SIP, + CB_RULE_LEN, + CB_RULE_NUM, +}; + +static char line[LINE_MAX]; +struct rule { + union rte_ipsec_sad_key tuple; + int rule_type; +}; + +static struct rule *rules_tbl; +static struct rule *tuples_tbl; + +static int +parse_distrib(const char *in) +{ + int a, b, c; + + GET_CB_FIELD(in, a, 0, UINT8_MAX, '/'); + GET_CB_FIELD(in, b, 0, UINT8_MAX, '/'); + GET_CB_FIELD(in, c, 0, UINT8_MAX, 0); + + if ((a + b + c) != 100) + return -EINVAL; + + config.fract_32 = a; + config.fract_64 = b; + config.fract_96 = c; + + return 0; +} + +static void +print_config(void) +{ + fprintf(stdout, + "Rules total: %u\n" + "Configured rules distribution SPI/SPI_DIP/SIP_DIP_SIP:" + "%u/%u/%u\n" + "SPI only rules: %u\n" + "SPI_DIP rules: %u\n" + "SPI_DIP_SIP rules: %u\n" + "Lookup tuples: %u\n" + "Lookup burst size %u\n" + "Configured fraction of random tuples: %u\n" + "Random lookup tuples: %u\n", + config.nb_rules, config.fract_32, config.fract_64, + config.fract_96, config.nb_rules_32, config.nb_rules_64, + config.nb_rules_96, config.nb_tuples, config.burst_sz, + config.fract_rnd_tuples, config.nb_tuples_rnd); +} + +static void +print_usage(void) +{ + fprintf(stdout, + PRINT_USAGE_START + "[-f ]\n" + "[-t ]\n" + "[-n ]\n" + "[-l ]\n" + "[-6 ]\n" + "[-d <\"/\" separated rules length distribution" + "(if -f is not specified)>]\n" + "[-r ]\n" + "[-b ]\n" + "[-v ]\n" + "[-p ]\n" + "[-c ]\n", + config.prgname); + +} + +static int +get_str_num(FILE *f, int num) +{ + int n_lines = 0; + + if (f != NULL) { + while (fgets(line, sizeof(line), f) != NULL) + n_lines++; + rewind(f); + } else { + n_lines = num; + } + return n_lines; +} + +static int +parse_file(FILE *f, struct rule *tbl, int rule_tbl) +{ + int ret, i, j = 0; + char *s, *sp, *in[CB_RULE_NUM]; + static const char *dlm = " \t\n"; + int string_tok_nb = RTE_DIM(in); + + string_tok_nb -= (rule_tbl == 0) ? 1 : 0; + while (fgets(line, sizeof(line), f) != NULL) { + s = line; + for (i = 0; i != string_tok_nb; i++) { + in[i] = strtok_r(s, dlm, &sp); + if (in[i] == NULL) + return -EINVAL; + s = NULL; + } + GET_CB_FIELD(in[CB_RULE_SPI], tbl[j].tuple.v4.spi, 0, + UINT32_MAX, 0); + + if (config.ipv6) + ret = inet_pton(AF_INET6, in[CB_RULE_DIP], + &tbl[j].tuple.v6.dip); + else + ret = inet_pton(AF_INET, in[CB_RULE_DIP], + &tbl[j].tuple.v4.dip); + if (ret != 1) + return -EINVAL; + if (config.ipv6) + ret = inet_pton(AF_INET6, in[CB_RULE_SIP], + &tbl[j].tuple.v6.sip); + else + ret = inet_pton(AF_INET, in[CB_RULE_SIP], + &tbl[j].tuple.v4.sip); + if (ret != 1) + return -EINVAL; + if ((rule_tbl) && (in[CB_RULE_LEN] != NULL)) { + if (strcmp(in[CB_RULE_LEN], "SPI_DIP_SIP") == 0) { + tbl[j].rule_type = RTE_IPSEC_SAD_SPI_DIP_SIP; + config.nb_rules_96++; + } else if (strcmp(in[CB_RULE_LEN], "SPI_DIP") == 0) { + tbl[j].rule_type = RTE_IPSEC_SAD_SPI_DIP; + config.nb_rules_64++; + } else if (strcmp(in[CB_RULE_LEN], "SPI") == 0) { + tbl[j].rule_type = RTE_IPSEC_SAD_SPI_ONLY; + config.nb_rules_32++; + } else { + return -EINVAL; + } + } + j++; + } + return 0; +} + +static uint64_t +get_rnd_rng(uint64_t l, uint64_t u) +{ + if (l == u) + return l; + else + return (rte_rand() % (u - l) + l); +} + +static void +get_random_rules(struct rule *tbl, uint32_t nb_rules, int rule_tbl) +{ + unsigned int i, j, rnd; + int rule_type; + double edge = 0; + double step; + + step = (double)UINT32_MAX / nb_rules; + for (i = 0; i < nb_rules; i++, edge += step) { + rnd = rte_rand() % 100; + if (rule_tbl) { + tbl[i].tuple.v4.spi = get_rnd_rng((uint64_t)edge, + (uint64_t)(edge + step)); + if (config.ipv6) { + for (j = 0; j < 16; j++) { + tbl[i].tuple.v6.dip[j] = rte_rand(); + tbl[i].tuple.v6.sip[j] = rte_rand(); + } + } else { + tbl[i].tuple.v4.dip = rte_rand(); + tbl[i].tuple.v4.sip = rte_rand(); + } + if (rnd >= (100UL - config.fract_32)) { + rule_type = RTE_IPSEC_SAD_SPI_ONLY; + config.nb_rules_32++; + } else if (rnd >= (100UL - (config.fract_32 + + config.fract_64))) { + rule_type = RTE_IPSEC_SAD_SPI_DIP; + config.nb_rules_64++; + } else { + rule_type = RTE_IPSEC_SAD_SPI_DIP_SIP; + config.nb_rules_96++; + } + tbl[i].rule_type = rule_type; + } else { + if (rnd >= 100UL - config.fract_rnd_tuples) { + tbl[i].tuple.v4.spi = + get_rnd_rng((uint64_t)edge, + (uint64_t)(edge + step)); + if (config.ipv6) { + for (j = 0; j < 16; j++) { + tbl[i].tuple.v6.dip[j] = + rte_rand(); + tbl[i].tuple.v6.sip[j] = + rte_rand(); + } + } else { + tbl[i].tuple.v4.dip = rte_rand(); + tbl[i].tuple.v4.sip = rte_rand(); + } + config.nb_tuples_rnd++; + } else { + tbl[i].tuple.v4.spi = rules_tbl[i % + config.nb_rules].tuple.v4.spi; + if (config.ipv6) { + int r_idx = i % config.nb_rules; + memcpy(tbl[i].tuple.v6.dip, + rules_tbl[r_idx].tuple.v6.dip, + sizeof(tbl[i].tuple.v6.dip)); + memcpy(tbl[i].tuple.v6.sip, + rules_tbl[r_idx].tuple.v6.sip, + sizeof(tbl[i].tuple.v6.sip)); + } else { + tbl[i].tuple.v4.dip = rules_tbl[i % + config.nb_rules].tuple.v4.dip; + tbl[i].tuple.v4.sip = rules_tbl[i % + config.nb_rules].tuple.v4.sip; + } + } + } + } +} + +static void +tbl_init(struct rule **tbl, uint32_t *n_entries, + const char *file_name, int rule_tbl) +{ + FILE *f = NULL; + int ret; + const char *rules = "rules"; + const char *tuples = "tuples"; + + if (file_name != NULL) { + f = fopen(file_name, "r"); + if (f == NULL) + rte_exit(-EINVAL, "failed to open file: %s\n", + file_name); + } + + printf("init %s table...", (rule_tbl) ? rules : tuples); + *n_entries = get_str_num(f, *n_entries); + printf("%d entries\n", *n_entries); + *tbl = rte_zmalloc(NULL, sizeof(struct rule) * *n_entries, + RTE_CACHE_LINE_SIZE); + if (*tbl == NULL) + rte_exit(-ENOMEM, "failed to allocate tbl\n"); + + if (f != NULL) { + printf("parse file %s\n", file_name); + ret = parse_file(f, *tbl, rule_tbl); + if (ret != 0) + rte_exit(-EINVAL, "failed to parse file %s\n" + "rules file must be: " + " " + " " + " " + "\n" + "tuples file must be: " + " " + " " + "\n", + file_name); + } else { + printf("generate random values in %s table\n", + (rule_tbl) ? rules : tuples); + get_random_rules(*tbl, *n_entries, rule_tbl); + } + if (f != NULL) + fclose(f); +} + +static void +parse_opts(int argc, char **argv) +{ + int opt, ret; + char *endptr; + + while ((opt = getopt(argc, argv, "f:t:n:d:l:r:6b:vpc")) != -1) { + switch (opt) { + case 'f': + config.rules_file = optarg; + break; + case 't': + config.tuples_file = optarg; + break; + case 'n': + errno = 0; + config.nb_rules = strtoul(optarg, &endptr, 10); + if ((errno != 0) || (config.nb_rules == 0) || + (endptr[0] != 0)) { + print_usage(); + rte_exit(-EINVAL, "Invalid option -n\n"); + } + break; + case 'd': + ret = parse_distrib(optarg); + if (ret != 0) { + print_usage(); + rte_exit(-EINVAL, "Invalid option -d\n"); + } + break; + case 'b': + errno = 0; + config.burst_sz = strtoul(optarg, &endptr, 10); + if ((errno != 0) || (config.burst_sz == 0) || + (config.burst_sz > BURST_SZ_MAX) || + (endptr[0] != 0)) { + print_usage(); + rte_exit(-EINVAL, "Invalid option -b\n"); + } + break; + case 'l': + errno = 0; + config.nb_tuples = strtoul(optarg, &endptr, 10); + if ((errno != 0) || (config.nb_tuples == 0) || + (endptr[0] != 0)) { + print_usage(); + rte_exit(-EINVAL, "Invalid option -l\n"); + } + break; + case 'r': + errno = 0; + config.fract_rnd_tuples = strtoul(optarg, &endptr, 10); + if ((errno != 0) || (config.fract_rnd_tuples == 0) || + (config.fract_rnd_tuples >= 100) || + (endptr[0] != 0)) { + print_usage(); + rte_exit(-EINVAL, "Invalid option -r\n"); + } + break; + case '6': + config.ipv6 = 1; + break; + case 'v': + config.verbose = 1; + break; + case 'p': + config.parallel_lookup = 1; + break; + case 'c': + config.concurrent_rw = 1; + break; + default: + print_usage(); + rte_exit(-EINVAL, "Invalid options\n"); + } + } +} + +static void +print_addr(int af, const void *addr) +{ + char str[INET6_ADDRSTRLEN]; + const char *ret; + + ret = inet_ntop(af, addr, str, sizeof(str)); + if (ret != NULL) + printf("%s", str); +} + +static void +print_tuple(int af, uint32_t spi, const void *dip, const void *sip) +{ + + printf(""); +} + +static void +print_result(const union rte_ipsec_sad_key *key, void *res) +{ + struct rule *rule = res; + const struct rte_ipsec_sadv4_key *v4; + const struct rte_ipsec_sadv6_key *v6; + const char *spi_only = "SPI_ONLY"; + const char *spi_dip = "SPI_DIP"; + const char *spi_dip_sip = "SPI_DIP_SIP"; + const char *rule_type; + const void *dip, *sip; + uint32_t spi; + int af; + + af = (config.ipv6) ? AF_INET6 : AF_INET; + v4 = &key->v4; + v6 = &key->v6; + spi = (config.ipv6 == 0) ? v4->spi : v6->spi; + dip = (config.ipv6 == 0) ? &v4->dip : (const void *)v6->dip; + sip = (config.ipv6 == 0) ? &v4->sip : (const void *)v6->sip; + + if (res == NULL) { + printf("TUPLE: "); + print_tuple(af, spi, dip, sip); + printf(" not found\n"); + return; + } + + switch (rule->rule_type) { + case RTE_IPSEC_SAD_SPI_ONLY: + rule_type = spi_only; + break; + case RTE_IPSEC_SAD_SPI_DIP: + rule_type = spi_dip; + break; + case RTE_IPSEC_SAD_SPI_DIP_SIP: + rule_type = spi_dip_sip; + break; + default: + return; + } + + print_tuple(af, spi, dip, sip); + v4 = &rule->tuple.v4; + v6 = &rule->tuple.v6; + spi = (config.ipv6 == 0) ? v4->spi : v6->spi; + dip = (config.ipv6 == 0) ? &v4->dip : (const void *)v6->dip; + sip = (config.ipv6 == 0) ? &v4->sip : (const void *)v6->sip; + printf("\n\tpoints to RULE ID %zu ", + RTE_PTR_DIFF(res, rules_tbl)/sizeof(struct rule)); + print_tuple(af, spi, dip, sip); + printf(" %s\n", rule_type); +} + +static int +lookup(void *arg) +{ + int ret; + unsigned int i, j; + const union rte_ipsec_sad_key *keys[BURST_SZ_MAX]; + void *vals[BURST_SZ_MAX]; + uint64_t start, acc = 0; + uint32_t burst_sz; + struct rte_ipsec_sad *sad = arg; + + burst_sz = RTE_MIN(config.burst_sz, config.nb_tuples); + for (i = 0; i < config.nb_tuples; i += burst_sz) { + for (j = 0; j < burst_sz; j++) + keys[j] = (union rte_ipsec_sad_key *) + (&tuples_tbl[i + j].tuple); + start = rte_rdtsc_precise(); + ret = rte_ipsec_sad_lookup(sad, keys, vals, burst_sz); + acc += rte_rdtsc_precise() - start; + if (ret < 0) + rte_exit(-EINVAL, "Lookup failed\n"); + if (config.verbose) { + for (j = 0; j < burst_sz; j++) + print_result(keys[j], vals[j]); + } + } + printf("Average lookup cycles %.2Lf, lookups/sec: %.2Lf\n", + (long double)acc / config.nb_tuples, + (long double)config.nb_tuples * rte_get_tsc_hz() / acc); + + return 0; +} + +static void +add_rules(struct rte_ipsec_sad *sad, uint32_t fract) +{ + int32_t ret; + uint32_t i, j, f, fn, n; + uint64_t start, tm[fract + 1]; + uint32_t nm[fract + 1]; + + f = (config.nb_rules > fract) ? config.nb_rules / fract : 1; + + for (n = 0, j = 0; n != config.nb_rules; n = fn, j++) { + + fn = n + f; + fn = fn > config.nb_rules ? config.nb_rules : fn; + + start = rte_rdtsc_precise(); + for (i = n; i != fn; i++) { + ret = rte_ipsec_sad_add(sad, + &rules_tbl[i].tuple, + rules_tbl[i].rule_type, &rules_tbl[i]); + if (ret != 0) + rte_exit(ret, "%s failed @ %u-th rule\n", + __func__, i); + } + tm[j] = rte_rdtsc_precise() - start; + nm[j] = fn - n; + } + + for (i = 0; i != j; i++) + printf("ADD %u rules, %.2Lf cycles/rule, %.2Lf ADD/sec\n", + nm[i], (long double)tm[i] / nm[i], + (long double)nm[i] * rte_get_tsc_hz() / tm[i]); +} + +static void +del_rules(struct rte_ipsec_sad *sad, uint32_t fract) +{ + int32_t ret; + uint32_t i, j, f, fn, n; + uint64_t start, tm[fract + 1]; + uint32_t nm[fract + 1]; + + f = (config.nb_rules > fract) ? config.nb_rules / fract : 1; + + for (n = 0, j = 0; n != config.nb_rules; n = fn, j++) { + + fn = n + f; + fn = fn > config.nb_rules ? config.nb_rules : fn; + + start = rte_rdtsc_precise(); + for (i = n; i != fn; i++) { + ret = rte_ipsec_sad_del(sad, + &rules_tbl[i].tuple, + rules_tbl[i].rule_type); + if (ret != 0 && ret != -ENOENT) + rte_exit(ret, "%s failed @ %u-th rule\n", + __func__, i); + } + tm[j] = rte_rdtsc_precise() - start; + nm[j] = fn - n; + } + + for (i = 0; i != j; i++) + printf("DEL %u rules, %.2Lf cycles/rule, %.2Lf DEL/sec\n", + nm[i], (long double)tm[i] / nm[i], + (long double)nm[i] * rte_get_tsc_hz() / tm[i]); +} + +int +main(int argc, char **argv) +{ + int ret; + struct rte_ipsec_sad *sad; + struct rte_ipsec_sad_conf conf; + unsigned int lcore_id; + + ret = rte_eal_init(argc, argv); + if (ret < 0) + rte_panic("Cannot init EAL\n"); + + argc -= ret; + argv += ret; + + config.prgname = argv[0]; + + parse_opts(argc, argv); + tbl_init(&rules_tbl, &config.nb_rules, config.rules_file, 1); + tbl_init(&tuples_tbl, &config.nb_tuples, config.tuples_file, 0); + if (config.rules_file != NULL) { + config.fract_32 = (100 * config.nb_rules_32) / config.nb_rules; + config.fract_64 = (100 * config.nb_rules_64) / config.nb_rules; + config.fract_96 = (100 * config.nb_rules_96) / config.nb_rules; + } + if (config.tuples_file != NULL) { + config.fract_rnd_tuples = 0; + config.nb_tuples_rnd = 0; + } + conf.socket_id = -1; + conf.max_sa[RTE_IPSEC_SAD_SPI_ONLY] = config.nb_rules_32 * 5 / 4; + conf.max_sa[RTE_IPSEC_SAD_SPI_DIP] = config.nb_rules_64 * 5 / 4; + conf.max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP] = config.nb_rules_96 * 5 / 4; + if (config.ipv6) + conf.flags |= RTE_IPSEC_SAD_FLAG_IPV6; + if (config.concurrent_rw) + conf.flags |= RTE_IPSEC_SAD_FLAG_RW_CONCURRENCY; + sad = rte_ipsec_sad_create("test", &conf); + if (sad == NULL) + rte_exit(-rte_errno, "can not allocate SAD table\n"); + + print_config(); + + add_rules(sad, 10); + if (config.parallel_lookup) + rte_eal_mp_remote_launch(lookup, sad, SKIP_MASTER); + + lookup(sad); + if (config.parallel_lookup) + RTE_LCORE_FOREACH_SLAVE(lcore_id) + if (rte_eal_wait_lcore(lcore_id) < 0) + return -1; + + del_rules(sad, 10); + + return 0; +} diff --git a/app/test-sad/meson.build b/app/test-sad/meson.build new file mode 100644 index 0000000..31f9aab --- /dev/null +++ b/app/test-sad/meson.build @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2019 Intel Corporation + +allow_experimental_apis = true +sources = files('main.c') +deps += ['ipsec', 'net']