From patchwork Tue Sep 3 16:55:28 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Medvedkin X-Patchwork-Id: 58537 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 7D4671EC19; Tue, 3 Sep 2019 18:55:54 +0200 (CEST) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by dpdk.org (Postfix) with ESMTP id DE9831E9AE for ; Tue, 3 Sep 2019 18:55:50 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by orsmga106.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 03 Sep 2019 09:55:50 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.64,463,1559545200"; d="scan'208";a="212063914" Received: from silpixa00400072.ir.intel.com ([10.237.222.213]) by fmsmga002.fm.intel.com with ESMTP; 03 Sep 2019 09:55:48 -0700 From: Vladimir Medvedkin To: dev@dpdk.org Cc: konstantin.ananyev@intel.com, bernard.iremonger@intel.com, akhil.goyal@nxp.com Date: Tue, 3 Sep 2019 17:55:28 +0100 Message-Id: X-Mailer: git-send-email 2.7.4 In-Reply-To: References: In-Reply-To: References: <1565709186-273340-1-git-send-email-vladimir.medvedkin@intel.com> Subject: [dpdk-dev] [PATCH v1 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 --- 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 | 174 +++++++++++++++++++++++++++++++++ lib/librte_ipsec/rte_ipsec_version.map | 7 ++ 5 files changed, 235 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/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..cae46df --- /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 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 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 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_free(__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 uint32_t n, __rte_unused void *sa[]) +{ + 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..d7301f5 --- /dev/null +++ b/lib/librte_ipsec/rte_ipsec_sad.h @@ -0,0 +1,174 @@ + +/* 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. + * It is not recommended to include this file directly, + * include instead. + * 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; +}; + +#define RTE_IPSEC_SAD_FLAG_IPV4 0x1 +#define RTE_IPSEC_SAD_FLAG_IPV6 0x2 +/** Flag to support reader writer concurrency */ +#define RTE_IPSEC_SAD_FLAG_RW_CONCURRENCY 0x4 + +/** IPsec SAD configuration structure */ +struct rte_ipsec_sad_conf { + int socket_id; + /** maximum number of SA for each type key */ + uint32_t max_sa[RTE_IPSEC_SAD_KEY_TYPE_MASK]; + 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, 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, 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, struct rte_ipsec_sad_conf *conf); + +/** + * Find an existing SAD object and return a pointer to it. + * + * @param name + * Name of the rib 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); + +/** + * Free SAD object. + * + * @param sad + * pointer to the SAD object + * @return + * None + */ +__rte_experimental +void +rte_ipsec_sad_free(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 0 + */ +__rte_experimental +int +rte_ipsec_sad_lookup(const struct rte_ipsec_sad *sad, + const union rte_ipsec_sad_key *keys[], + uint32_t n, void *sa[]); + +#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..56c38ec 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_free; + rte_ipsec_sad_lookup; + local: *; }; From patchwork Tue Sep 3 16:55:29 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Medvedkin X-Patchwork-Id: 58538 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 2409B1EC45; Tue, 3 Sep 2019 18:56:00 +0200 (CEST) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by dpdk.org (Postfix) with ESMTP id BE8701EB68 for ; Tue, 3 Sep 2019 18:55:51 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by orsmga106.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 03 Sep 2019 09:55:51 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.64,463,1559545200"; d="scan'208";a="212063924" Received: from silpixa00400072.ir.intel.com ([10.237.222.213]) by fmsmga002.fm.intel.com with ESMTP; 03 Sep 2019 09:55:50 -0700 From: Vladimir Medvedkin To: dev@dpdk.org Cc: konstantin.ananyev@intel.com, bernard.iremonger@intel.com, akhil.goyal@nxp.com Date: Tue, 3 Sep 2019 17:55:29 +0100 Message-Id: <19809d0541aa8fd36156987f0925b498032a1a42.1567529480.git.vladimir.medvedkin@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: References: In-Reply-To: References: <1565709186-273340-1-git-send-email-vladimir.medvedkin@intel.com> Subject: [dpdk-dev] [PATCH v1 2/5] ipsec: add SAD create/free 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" Replace rte_ipsec_sad_create(), rte_ipsec_sad_free() and rte_ipsec_sad_find_existing() API stubs with actual implementation. Signed-off-by: Vladimir Medvedkin --- lib/librte_ipsec/Makefile | 2 +- lib/librte_ipsec/ipsec_sad.c | 221 +++++++++++++++++++++++++++++++++++++++++-- lib/librte_ipsec/meson.build | 2 +- 3 files changed, 216 insertions(+), 9 deletions(-) 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 cae46df..7797628 100644 --- a/lib/librte_ipsec/ipsec_sad.c +++ b/lib/librte_ipsec/ipsec_sad.c @@ -2,10 +2,41 @@ * Copyright(c) 2019 Intel Corporation */ +#include #include +#include +#include +#include +#include +#include +#include #include "rte_ipsec_sad.h" +#define IPSEC_SAD_NAMESIZE 64 +#define SAD_PREFIX "SAD_" +/* "SAD_" */ +#define SAD_FORMAT SAD_PREFIX "%s" + +#define DEFAULT_HASH_FUNC rte_jhash + +struct hash_cnt { + uint32_t cnt_2; + uint32_t cnt_3; +}; + +struct rte_ipsec_sad { + char name[IPSEC_SAD_NAMESIZE]; + struct rte_hash *hash[RTE_IPSEC_SAD_KEY_TYPE_MASK]; + __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 union rte_ipsec_sad_key *key, @@ -23,22 +54,198 @@ 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 struct rte_ipsec_sad_conf *conf) +rte_ipsec_sad_create(const char *name, struct rte_ipsec_sad_conf *conf) { - return NULL; + char hash_name[RTE_HASH_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) || + /* check that either IPv4 or IPv6 type flags + * are configured + */ + ((!!(conf->flags & RTE_IPSEC_SAD_FLAG_IPV4) ^ + !!(conf->flags & RTE_IPSEC_SAD_FLAG_IPV6)) == 0)) { + rte_errno = EINVAL; + return NULL; + } + + /** Init SAD*/ + sa_sum = conf->max_sa[RTE_IPSEC_SAD_SPI_ONLY] + + conf->max_sa[RTE_IPSEC_SAD_SPI_DIP] + + 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; + } + + ret = snprintf(sad->name, sizeof(sad->name), SAD_FORMAT, name); + if (ret < 0 || ret >= (int)sizeof(sad->name)) { + rte_errno = ENAMETOOLONG; + return NULL; + } + + 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 */ + ret = snprintf(hash_name, sizeof(hash_name), + "sad_%p_1", sad); + if (ret < 0 || ret >= (int)sizeof(hash_name)) { + rte_errno = ENAMETOOLONG; + return NULL; + } + 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_free(sad); + return NULL; + } + + /** Init hash_2 for SPI + DIP */ + ret = snprintf(hash_name, sizeof(hash_name), + "sad_%p_2", sad); + if (ret < 0 || ret >= (int)sizeof(hash_name)) { + rte_errno = ENAMETOOLONG; + rte_ipsec_sad_free(sad); + return NULL; + } + if (conf->flags & RTE_IPSEC_SAD_FLAG_IPV4) + hash_params.key_len += + sizeof(((struct rte_ipsec_sadv4_key *)0)->dip); + else + hash_params.key_len += + sizeof(((struct rte_ipsec_sadv6_key *)0)->dip); + hash_params.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_free(sad); + return NULL; + } + + /** Init hash_3 for SPI + DIP + SIP */ + ret = snprintf(hash_name, sizeof(hash_name), + "sad_%p_3", name); + if (ret < 0 || ret >= (int)sizeof(hash_name)) { + rte_errno = ENAMETOOLONG; + rte_ipsec_sad_free(sad); + return NULL; + } + if (conf->flags & RTE_IPSEC_SAD_FLAG_IPV4) + hash_params.key_len += + sizeof(((struct rte_ipsec_sadv4_key *)0)->sip); + else + hash_params.key_len += + sizeof(((struct rte_ipsec_sadv6_key *)0)->sip); + hash_params.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_free(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(name, tmp_sad->name, IPSEC_SAD_NAMESIZE) == 0) + break; + } + if (te != NULL) { + rte_mcfg_tailq_write_unlock(); + rte_errno = EEXIST; + rte_ipsec_sad_free(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_free(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; + struct rte_ipsec_sad *sad = NULL; + struct rte_tailq_entry *te; + struct rte_ipsec_sad_list *sad_list; + + + 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(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_free(__rte_unused struct rte_ipsec_sad *sad) +rte_ipsec_sad_free(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 Tue Sep 3 16:55:30 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Medvedkin X-Patchwork-Id: 58539 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 51D571EC65; Tue, 3 Sep 2019 18:56:03 +0200 (CEST) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by dpdk.org (Postfix) with ESMTP id D92861EC0D for ; Tue, 3 Sep 2019 18:55:53 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by orsmga106.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 03 Sep 2019 09:55:52 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.64,463,1559545200"; d="scan'208";a="212063931" Received: from silpixa00400072.ir.intel.com ([10.237.222.213]) by fmsmga002.fm.intel.com with ESMTP; 03 Sep 2019 09:55:51 -0700 From: Vladimir Medvedkin To: dev@dpdk.org Cc: konstantin.ananyev@intel.com, bernard.iremonger@intel.com, akhil.goyal@nxp.com Date: Tue, 3 Sep 2019 17:55:30 +0100 Message-Id: <35869a61ec4294e0c991eb145c385b05f2db1e0d.1567529480.git.vladimir.medvedkin@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: References: In-Reply-To: References: <1565709186-273340-1-git-send-email-vladimir.medvedkin@intel.com> Subject: [dpdk-dev] [PATCH v1 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 --- lib/librte_ipsec/ipsec_sad.c | 245 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 233 insertions(+), 12 deletions(-) diff --git a/lib/librte_ipsec/ipsec_sad.c b/lib/librte_ipsec/ipsec_sad.c index 7797628..4bf2206 100644 --- a/lib/librte_ipsec/ipsec_sad.c +++ b/lib/librte_ipsec/ipsec_sad.c @@ -13,6 +13,13 @@ #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_" */ @@ -37,20 +44,158 @@ 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, void *key, + int key_type, void *sa) +{ + void *tmp_val; + int ret, notexist; + + ret = rte_hash_lookup(sad->hash[key_type], key); + notexist = (ret == -ENOENT); + ret = rte_hash_add_key_data(sad->hash[key_type], key, sa); + if (ret != 0) + return ret; + 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); + ret = rte_hash_add_key_data(sad->hash[RTE_IPSEC_SAD_SPI_ONLY], + key, tmp_val); + if (ret != 0) + return ret; + 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_2 += notexist; + else + sad->cnt_arr[ret].cnt_3 += notexist; + + return 0; +} + int -rte_ipsec_sad_add(__rte_unused struct rte_ipsec_sad *sad, - __rte_unused union rte_ipsec_sad_key *key, - __rte_unused int key_type, __rte_unused void *sa) +rte_ipsec_sad_add(struct rte_ipsec_sad *sad, union rte_ipsec_sad_key *key, + int key_type, void *sa) +{ + 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, void *key, int key_type) { - return -ENOTSUP; + void *tmp_val; + int ret; + uint32_t *cnt; + + ret = rte_hash_del_key(sad->hash[key_type], key); + if (ret < 0) + return ret; + 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_2 : + &sad->cnt_arr[ret].cnt_3; + if (--(*cnt) != 0) + return 0; + + tmp_val = CLEAR_BIT(tmp_val, key_type); + 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 union rte_ipsec_sad_key *key, - __rte_unused int key_type) +rte_ipsec_sad_del(struct rte_ipsec_sad *sad, 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) { + RTE_ASSERT((cnt_2 == 0) && (cnt_3 == 0)); + ret = rte_hash_del_key(sad->hash[key_type], + key); + } 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 * @@ -248,10 +393,86 @@ rte_ipsec_sad_free(struct rte_ipsec_sad *sad) rte_free(te); } +static int +__ipsec_sad_lookup(const struct rte_ipsec_sad *sad, + const union rte_ipsec_sad_key *keys[], uint32_t n, void *sa[]) +{ + 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 n_pkts = 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]; + } + sa[i] = CLEAR_BIT(sa[i], RTE_IPSEC_SAD_KEY_TYPE_MASK); + } + + 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]; + } + } + 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++) + n_pkts += (sa[i] != NULL); + + return n_pkts; +} + int -rte_ipsec_sad_lookup(__rte_unused const struct rte_ipsec_sad *sad, - __rte_unused const union rte_ipsec_sad_key *keys[], - __rte_unused uint32_t n, __rte_unused void *sa[]) +rte_ipsec_sad_lookup(const struct rte_ipsec_sad *sad, + const union rte_ipsec_sad_key *keys[], uint32_t n, void *sa[]) { - return -ENOTSUP; + uint32_t num, i = 0; + int n_pkts = 0; + + if (unlikely((sad == NULL) || (keys == NULL) || (sa == NULL))) + return -EINVAL; + + do { + num = RTE_MIN(n - i, (uint32_t)RTE_HASH_LOOKUP_BULK_MAX); + n_pkts += __ipsec_sad_lookup(sad, + &keys[i], num, &sa[i]); + i += num; + } while (i != n); + + return n_pkts; } From patchwork Tue Sep 3 16:55:31 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Medvedkin X-Patchwork-Id: 58540 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 9C3D11EC9E; Tue, 3 Sep 2019 18:56:06 +0200 (CEST) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by dpdk.org (Postfix) with ESMTP id 145B01EC45 for ; Tue, 3 Sep 2019 18:55:54 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by orsmga106.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 03 Sep 2019 09:55:54 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.64,463,1559545200"; d="scan'208";a="212063956" Received: from silpixa00400072.ir.intel.com ([10.237.222.213]) by fmsmga002.fm.intel.com with ESMTP; 03 Sep 2019 09:55:52 -0700 From: Vladimir Medvedkin To: dev@dpdk.org Cc: konstantin.ananyev@intel.com, bernard.iremonger@intel.com, akhil.goyal@nxp.com Date: Tue, 3 Sep 2019 17:55:31 +0100 Message-Id: X-Mailer: git-send-email 2.7.4 In-Reply-To: References: In-Reply-To: References: <1565709186-273340-1-git-send-email-vladimir.medvedkin@intel.com> Subject: [dpdk-dev] [PATCH v1 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" Signed-off-by: Vladimir Medvedkin --- app/test/Makefile | 1 + app/test/autotest_data.py | 6 + app/test/meson.build | 1 + app/test/test_ipsec_sad.c | 874 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 882 insertions(+) create mode 100644 app/test/test_ipsec_sad.c diff --git a/app/test/Makefile b/app/test/Makefile index 26ba6fe..e4da070 100644 --- a/app/test/Makefile +++ b/app/test/Makefile @@ -223,6 +223,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 ec40943..b13ec74 100644 --- a/app/test/meson.build +++ b/app/test/meson.build @@ -57,6 +57,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..79d6673 --- /dev/null +++ b/app/test/test_ipsec_sad.c @@ -0,0 +1,874 @@ +/* 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_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 = RTE_IPSEC_SAD_FLAG_IPV4; + + /* name == NULL */ + sad = rte_ipsec_sad_create(NULL, &config); + RTE_TEST_ASSERT(sad == NULL, + "Call succeeded with invalid parameters\n"); + + /* max_sa[SPI_ONLY] = 0 */ + config.max_sa[RTE_IPSEC_SAD_SPI_ONLY] = 0; + sad = rte_ipsec_sad_create(__func__, &config); + RTE_TEST_ASSERT(sad == NULL, + "Call succeeded with invalid parameters\n"); + + /* max_sa[SPI_DIP] = 0 */ + config.max_sa[RTE_IPSEC_SAD_SPI_ONLY] = MAX_SA; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP] = 0; + sad = rte_ipsec_sad_create(__func__, &config); + RTE_TEST_ASSERT(sad == NULL, + "Call succeeded with invalid parameters\n"); + + /* max_sa[SPI_DIP_SIP] = 0 */ + config.max_sa[RTE_IPSEC_SAD_SPI_DIP] = MAX_SA; + 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_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; + + /* invalid flags */ + config.flags = 0; + sad = rte_ipsec_sad_create(__func__, &config); + RTE_TEST_ASSERT(sad == NULL, + "Call succeeded with invalid parameters\n"); + config.flags = RTE_IPSEC_SAD_FLAG_IPV4|RTE_IPSEC_SAD_FLAG_IPV6; + sad = rte_ipsec_sad_create(__func__, &config); + RTE_TEST_ASSERT(sad == NULL, + "Call succeeded with invalid parameters\n"); + + 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.flags = RTE_IPSEC_SAD_FLAG_IPV4; + 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_free(sad); + } + return TEST_SUCCESS; +} + +static int32_t +__test_add_invalid(int ipv4, 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; + if (ipv4) + config.flags = RTE_IPSEC_SAD_FLAG_IPV4; + else + 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_free(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(1, (union rte_ipsec_sad_key *)&tuple_v4); + if (status != TEST_SUCCESS) + return status; + + status = __test_add_invalid(0, (union rte_ipsec_sad_key *)&tuple_v6); + + return status; + +} + +static int32_t +__test_delete_invalid(int ipv4, 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; + if (ipv4) + config.flags = RTE_IPSEC_SAD_FLAG_IPV4; + else + 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_free(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(1, (union rte_ipsec_sad_key *)&tuple_v4); + if (status != TEST_SUCCESS) + return status; + + status = __test_delete_invalid(0, (union rte_ipsec_sad_key *)&tuple_v6); + + return status; +} + +static int32_t +__test_lookup_invalid(int ipv4, 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, 1, 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; + if (ipv4) + config.flags = RTE_IPSEC_SAD_FLAG_IPV4; + else + 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, 1, sa); + RTE_TEST_ASSERT(status < 0, + "Call succeeded with invalid parameters\n"); + + status = rte_ipsec_sad_lookup(sad, key_arr, 1, NULL); + RTE_TEST_ASSERT(status < 0, + "Call succeeded with invalid parameters\n"); + + rte_ipsec_sad_free(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(1, + (union rte_ipsec_sad_key *)&tuple_v4); + if (status != TEST_SUCCESS) + return status; + + status = __test_lookup_invalid(0, + (union rte_ipsec_sad_key *)&tuple_v6); + + return status; +} + +static int32_t +__test_lookup_basic(int ipv4, 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; + if (ipv4) + config.flags = RTE_IPSEC_SAD_FLAG_IPV4; + else + 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, 1, sa); + 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, 1, sa); + 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, 1, sa); + 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, 1, sa); + RTE_TEST_ASSERT((status == 0) && (sa[0] == NULL), + "Lookup returns an unexpected result\n"); + + rte_ipsec_sad_free(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(1, (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(0, (union rte_ipsec_sad_key *)&tuple_v6, + (union rte_ipsec_sad_key *)&tuple_v6_1); + + return status; +} + +static int32_t +__test_lookup_adv(int ipv4, 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; + if (ipv4) + config.flags = RTE_IPSEC_SAD_FLAG_IPV4; + else + 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, 4, sa); + 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, 4, sa); + 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, 4, sa); + 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, 4, sa); + 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, 4, sa); + 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, 4, sa); + 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, 4, sa); + 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, 4, sa); + 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_free(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(1, (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(0, (union rte_ipsec_sad_key *)&tuple_v6, + key_arr); + + return status; +} + + +static int32_t +__test_lookup_order(int ipv4, 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; + if (ipv4) + config.flags = RTE_IPSEC_SAD_FLAG_IPV4; + else + 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, 3, sa); + 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, 3, sa); + 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, 3, sa); + 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, 3, sa); + 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, 3, sa); + 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, 3, sa); + 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, 3, sa); + 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, 3, sa); + 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, 3, sa); + 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_free(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(1, (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(0, (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_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 Tue Sep 3 16:55:32 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Medvedkin X-Patchwork-Id: 58541 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 353A71ECB5; Tue, 3 Sep 2019 18:56:08 +0200 (CEST) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by dpdk.org (Postfix) with ESMTP id 8F0AD1EC0D for ; Tue, 3 Sep 2019 18:55:56 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by orsmga106.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 03 Sep 2019 09:55:56 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.64,463,1559545200"; d="scan'208";a="212063968" Received: from silpixa00400072.ir.intel.com ([10.237.222.213]) by fmsmga002.fm.intel.com with ESMTP; 03 Sep 2019 09:55:54 -0700 From: Vladimir Medvedkin To: dev@dpdk.org Cc: konstantin.ananyev@intel.com, bernard.iremonger@intel.com, akhil.goyal@nxp.com Date: Tue, 3 Sep 2019 17:55:32 +0100 Message-Id: X-Mailer: git-send-email 2.7.4 In-Reply-To: References: In-Reply-To: References: <1565709186-273340-1-git-send-email-vladimir.medvedkin@intel.com> Subject: [dpdk-dev] [PATCH v1 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" Usage example and performance evaluation for the ipsec SAD library Signed-off-by: Vladimir Medvedkin --- app/Makefile | 1 + app/meson.build | 3 +- app/test-sad/Makefile | 18 ++ app/test-sad/main.c | 420 +++++++++++++++++++++++++++++++++++++++++++++++ app/test-sad/meson.build | 6 + 5 files changed, 447 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/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..039397f --- /dev/null +++ b/app/test-sad/main.c @@ -0,0 +1,420 @@ +/* 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 + +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; + uint8_t fract_32; + uint8_t fract_64; + uint8_t fract_96; + uint8_t fract_rnd_tuples; +} 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, + .fract_32 = 90, + .fract_64 = 9, + .fract_96 = 1, + .fract_rnd_tuples = 0 +}; + +enum { + CB_RULE_SPI, + CB_RULE_DIP, + CB_RULE_SIP, + CB_RULE_LEN, + CB_RULE_NUM, +}; + +static char line[LINE_MAX]; +struct rule { + struct rte_ipsec_sadv4_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" + "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.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" + "[-d <\"/\" separated rules length distribution" + "(if -f is not specified)>]\n" + "[-r ]\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.spi, 0, + UINT32_MAX, 0); + + ret = inet_pton(AF_INET, in[CB_RULE_DIP], &tbl[j].tuple.dip); + if (ret != 1) + return -EINVAL; + ret = inet_pton(AF_INET, in[CB_RULE_SIP], &tbl[j].tuple.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 void +get_random_rules(struct rule *tbl, uint32_t nb_rules, int rule_tbl) +{ + unsigned i, rnd; + int rule_type; + + for (i = 0; i < nb_rules; i++) { + rnd = rte_rand() % 100; + if (rule_tbl) { + tbl[i].tuple.spi = rte_rand(); + tbl[i].tuple.dip = rte_rand(); + tbl[i].tuple.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.spi = rte_rand(); + tbl[i].tuple.dip = rte_rand(); + tbl[i].tuple.sip = rte_rand(); + config.nb_tuples_rnd++; + } else { + tbl[i].tuple.spi = rules_tbl[i % + config.nb_rules].tuple.spi; + tbl[i].tuple.dip = rules_tbl[i % + config.nb_rules].tuple.dip; + tbl[i].tuple.sip = rules_tbl[i % + config.nb_rules].tuple.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:")) != -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)) { + 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 'l': + errno = 0; + config.nb_tuples = strtoul(optarg, &endptr, 10); + if ((errno != 0) || (config.nb_tuples == 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)) { + print_usage(); + rte_exit(-EINVAL, "Invalid option -r\n"); + } + break; + default: + print_usage(); + rte_exit(-EINVAL, "Invalid options\n"); + } + } +} + +#define BURST_SZ 64 +static void +lookup(struct rte_ipsec_sad *sad) +{ + int ret, j; + unsigned i; + const union rte_ipsec_sad_key *keys[BURST_SZ]; + void *vals[BURST_SZ]; + uint64_t start, acc = 0; + + 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(); + ret = rte_ipsec_sad_lookup(sad, keys, BURST_SZ, vals); + acc += rte_rdtsc() - start; + if (ret < 0) + rte_exit(-EINVAL, "Lookup failed\n"); + } + printf("Average lookup cycles %lu\n", acc / config.nb_tuples); +} + +int +main(int argc, char **argv) +{ + int ret; + unsigned i; + struct rte_ipsec_sad *sad; + struct rte_ipsec_sad_conf conf; + uint64_t start; + + 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 * 2; + conf.max_sa[RTE_IPSEC_SAD_SPI_DIP] = config.nb_rules * 2; + conf.max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP] = config.nb_rules * 2; + conf.flags = RTE_IPSEC_SAD_FLAG_IPV4|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(); + + start = rte_rdtsc(); + for (i = 0; i < config.nb_rules; i++) { + ret = rte_ipsec_sad_add(sad, + (union rte_ipsec_sad_key *)&rules_tbl[i].tuple, + rules_tbl[i].rule_type, &rules_tbl[i]); + if (ret != 0) + rte_exit(ret, "can not add rule to SAD table\n"); + } + printf("Average ADD cycles: %lu\n", + (rte_rdtsc() - start) / config.nb_rules); + + lookup(sad); + + 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']