From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.0 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS, UNWANTED_LANGUAGE_BODY autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id B8457C35280 for ; Wed, 2 Oct 2019 13:27:51 +0000 (UTC) Received: from dpdk.org (dpdk.org [92.243.14.124]) by mail.kernel.org (Postfix) with ESMTP id 130CC21783 for ; Wed, 2 Oct 2019 13:27:50 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 130CC21783 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=dev-bounces@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 6E9C11BEF6; Wed, 2 Oct 2019 15:27:49 +0200 (CEST) Received: from mga07.intel.com (mga07.intel.com [134.134.136.100]) by dpdk.org (Postfix) with ESMTP id 80C041BEEC for ; Wed, 2 Oct 2019 15:27:47 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by orsmga105.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 02 Oct 2019 06:27:46 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.64,574,1559545200"; d="scan'208";a="216450357" Received: from irsmsx152.ger.corp.intel.com ([163.33.192.66]) by fmsmga004.fm.intel.com with ESMTP; 02 Oct 2019 06:27:45 -0700 Received: from irsmsx105.ger.corp.intel.com ([169.254.7.164]) by IRSMSX152.ger.corp.intel.com ([169.254.6.150]) with mapi id 14.03.0439.000; Wed, 2 Oct 2019 14:27:44 +0100 From: "Ananyev, Konstantin" To: "Medvedkin, Vladimir" , "dev@dpdk.org" CC: "Iremonger, Bernard" , "akhil.goyal@nxp.com" Thread-Topic: [PATCH v2 5/5] app: add test-sad application Thread-Index: AQHVeH1UseTUNGKGaEusukyhJCtcS6dHVwFA Date: Wed, 2 Oct 2019 13:27:42 +0000 Message-ID: <2601191342CEEE43887BDE71AB977258019196FE09@irsmsx105.ger.corp.intel.com> References: <6219bf15a9f0f474f1d25f9237db4dbe4b95d08a.1569867491.git.vladimir.medvedkin@intel.com> In-Reply-To: <6219bf15a9f0f474f1d25f9237db4dbe4b95d08a.1569867491.git.vladimir.medvedkin@intel.com> Accept-Language: en-IE, en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-titus-metadata-40: eyJDYXRlZ29yeUxhYmVscyI6IiIsIk1ldGFkYXRhIjp7Im5zIjoiaHR0cDpcL1wvd3d3LnRpdHVzLmNvbVwvbnNcL0ludGVsMyIsImlkIjoiNzViYjljNWUtMWMzZC00N2ExLWI5ODAtZTZlNDc2NGExYTllIiwicHJvcHMiOlt7Im4iOiJDVFBDbGFzc2lmaWNhdGlvbiIsInZhbHMiOlt7InZhbHVlIjoiQ1RQX05UIn1dfV19LCJTdWJqZWN0TGFiZWxzIjpbXSwiVE1DVmVyc2lvbiI6IjE3LjEwLjE4MDQuNDkiLCJUcnVzdGVkTGFiZWxIYXNoIjoidlhQdFFYKzBsbWpSOVwvVG5tV3VRMjJkRHdkU0hoR1wvV1hoR0RYalwvMUUzZ21UXC9TVmlcLytSMDVcL1N3QmhsbHVPUiJ9 x-ctpclassification: CTP_NT dlp-product: dlpe-windows dlp-version: 11.2.0.6 dlp-reaction: no-action x-originating-ip: [163.33.239.180] Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Subject: Re: [dpdk-dev] [PATCH v2 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" >=20 > Usage example and performance evaluation for the ipsec SAD library That's seems way too laconic :) May be at least: "Introduce new application to provide user to evaluate and perform custom functional and performance tests for IPsec SAD implementation."=20 ? Few more nits inline. >=20 > Signed-off-by: Vladimir Medvedkin > --- > app/Makefile | 1 + > app/meson.build | 3 +- > app/test-sad/Makefile | 18 ++ > app/test-sad/main.c | 662 +++++++++++++++++++++++++++++++++++++++++= ++++++ > app/test-sad/meson.build | 6 + > 5 files changed, 689 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 >=20 > 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) +=3D pdump > DIRS-$(CONFIG_RTE_LIBRTE_ACL) +=3D test-acl > DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) +=3D test-cmdline > DIRS-$(CONFIG_RTE_LIBRTE_PIPELINE) +=3D test-pipeline > +DIRS-$(CONFIG_RTE_LIBRTE_IPSEC) +=3D test-sad >=20 > ifeq ($(CONFIG_RTE_LIBRTE_BBDEV),y) > DIRS-$(CONFIG_RTE_TEST_BBDEV) +=3D 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 =3D [ > 'test-crypto-perf', > 'test-eventdev', > 'test-pipeline', > - 'test-pmd'] > + 'test-pmd', > + 'test-sad'] >=20 > # for BSD only > lib_execinfo =3D 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 =3D testsad > + > +CFLAGS +=3D $(WERROR_FLAGS) > +CFLAGS +=3D -DALLOW_EXPERIMENTAL_API > + > +# all source are stored in SRCS-y > +SRCS-y :=3D 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..753721e > --- /dev/null > +++ b/app/test-sad/main.c > @@ -0,0 +1,662 @@ > +/* 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 =3D 0; \ > + val =3D strtoul((in), &end_fld, (base)); \ > + if (errno !=3D 0 || end_fld[0] !=3D (dlm) || val > (lim)) \ > + return -EINVAL; \ > + (fd) =3D (typeof(fd))val; \ > + (in) =3D end_fld + 1; \ > +} while (0) > + > +#define DEF_RULE_NUM 0x10000 > +#define DEF_TUPLES_NUM 0x100000 > +#define BURST_SZ 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; > +} config =3D { > + .rules_file =3D NULL, > + .tuples_file =3D NULL, > + .nb_rules =3D DEF_RULE_NUM, > + .nb_tuples =3D DEF_TUPLES_NUM, > + .nb_rules_32 =3D 0, > + .nb_rules_64 =3D 0, > + .nb_rules_96 =3D 0, > + .nb_tuples_rnd =3D 0, > + .burst_sz =3D BURST_SZ, > + .fract_32 =3D 90, > + .fract_64 =3D 9, > + .fract_96 =3D 1, > + .fract_rnd_tuples =3D 0, > + .ipv6 =3D 0, > + .verbose =3D 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) !=3D 100) > + return -EINVAL; > + > + config.fract_32 =3D a; > + config.fract_64 =3D b; > + config.fract_96 =3D 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 + "(if -t is not specified)>]\n" > + "[-b ]\n" > + "[-v ]\n", > + config.prgname); > + > +} > + > +static int > +get_str_num(FILE *f, int num) > +{ > + int n_lines =3D 0; > + > + if (f !=3D NULL) { > + while (fgets(line, sizeof(line), f) !=3D NULL) > + n_lines++; > + rewind(f); > + } else { > + n_lines =3D num; > + } > + return n_lines; > +} > + > +static int > +parse_file(FILE *f, struct rule *tbl, int rule_tbl) > +{ > + int ret, i, j =3D 0; > + char *s, *sp, *in[CB_RULE_NUM]; > + static const char *dlm =3D " \t\n"; > + int string_tok_nb =3D RTE_DIM(in); > + > + string_tok_nb -=3D (rule_tbl =3D=3D 0) ? 1 : 0; > + while (fgets(line, sizeof(line), f) !=3D NULL) { > + s =3D line; > + for (i =3D 0; i !=3D string_tok_nb; i++) { > + in[i] =3D strtok_r(s, dlm, &sp); > + if (in[i] =3D=3D NULL) > + return -EINVAL; > + s =3D NULL; > + } > + GET_CB_FIELD(in[CB_RULE_SPI], tbl[j].tuple.v4.spi, 0, > + UINT32_MAX, 0); > + > + if (config.ipv6) > + ret =3D inet_pton(AF_INET6, in[CB_RULE_DIP], > + &tbl[j].tuple.v6.dip); > + else > + ret =3D inet_pton(AF_INET, in[CB_RULE_DIP], > + &tbl[j].tuple.v4.dip); > + if (ret !=3D 1) > + return -EINVAL; > + if (config.ipv6) > + ret =3D inet_pton(AF_INET6, in[CB_RULE_SIP], > + &tbl[j].tuple.v6.sip); > + else > + ret =3D inet_pton(AF_INET, in[CB_RULE_SIP], > + &tbl[j].tuple.v4.sip); > + if (ret !=3D 1) > + return -EINVAL; > + if ((rule_tbl) && (in[CB_RULE_LEN] !=3D NULL)) { > + if (strcmp(in[CB_RULE_LEN], "SPI_DIP_SIP") =3D=3D 0) { > + tbl[j].rule_type =3D RTE_IPSEC_SAD_SPI_DIP_SIP; > + config.nb_rules_96++; > + } else if (strcmp(in[CB_RULE_LEN], "SPI_DIP") =3D=3D 0) { > + tbl[j].rule_type =3D RTE_IPSEC_SAD_SPI_DIP; > + config.nb_rules_64++; > + } else if (strcmp(in[CB_RULE_LEN], "SPI") =3D=3D 0) { > + tbl[j].rule_type =3D 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 =3D=3D 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 i, j, rnd; > + int rule_type; > + double edge =3D 0; > + double step; > + > + step =3D (double)UINT32_MAX / nb_rules; > + for (i =3D 0; i < nb_rules; i++, edge +=3D step) { > + rnd =3D rte_rand() % 100; > + if (rule_tbl) { > + tbl[i].tuple.v4.spi =3D get_rnd_rng((uint64_t)edge, > + (uint64_t)(edge + step)); > + if (config.ipv6) { > + for (j =3D 0; j < 16; j++) { > + tbl[i].tuple.v6.dip[j] =3D rte_rand(); > + tbl[i].tuple.v6.sip[j] =3D rte_rand(); > + } > + } else { > + tbl[i].tuple.v4.dip =3D rte_rand(); > + tbl[i].tuple.v4.sip =3D rte_rand(); > + } > + if (rnd >=3D (100UL - config.fract_32)) { > + rule_type =3D RTE_IPSEC_SAD_SPI_ONLY; > + config.nb_rules_32++; > + } else if (rnd >=3D (100UL - (config.fract_32 + > + config.fract_64))) { > + rule_type =3D RTE_IPSEC_SAD_SPI_DIP; > + config.nb_rules_64++; > + } else { > + rule_type =3D RTE_IPSEC_SAD_SPI_DIP_SIP; > + config.nb_rules_96++; > + } > + tbl[i].rule_type =3D rule_type; > + } else { > + if (rnd >=3D 100UL - config.fract_rnd_tuples) { > + tbl[i].tuple.v4.spi =3D > + get_rnd_rng((uint64_t)edge, > + (uint64_t)(edge + step)); > + if (config.ipv6) { > + for (j =3D 0; j < 16; j++) { > + tbl[i].tuple.v6.dip[j] =3D > + rte_rand(); > + tbl[i].tuple.v6.sip[j] =3D > + rte_rand(); > + } > + } else { > + tbl[i].tuple.v4.dip =3D rte_rand(); > + tbl[i].tuple.v4.sip =3D rte_rand(); > + } > + config.nb_tuples_rnd++; > + } else { > + tbl[i].tuple.v4.spi =3D rules_tbl[i % > + config.nb_rules].tuple.v4.spi; > + if (config.ipv6) { > + int r_idx =3D 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 =3D rules_tbl[i % > + config.nb_rules].tuple.v4.dip; > + tbl[i].tuple.v4.sip =3D 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 =3D NULL; > + int ret; > + const char *rules =3D "rules"; > + const char *tuples =3D "tuples"; > + > + if (file_name !=3D NULL) { > + f =3D fopen(file_name, "r"); > + if (f =3D=3D NULL) > + rte_exit(-EINVAL, "failed to open file: %s\n", > + file_name); > + } > + > + printf("init %s table...", (rule_tbl) ? rules : tuples); > + *n_entries =3D get_str_num(f, *n_entries); > + printf("%d entries\n", *n_entries); > + *tbl =3D rte_zmalloc(NULL, sizeof(struct rule) * *n_entries, > + RTE_CACHE_LINE_SIZE); > + if (*tbl =3D=3D NULL) > + rte_exit(-ENOMEM, "failed to allocate tbl\n"); > + > + if (f !=3D NULL) { > + printf("parse file %s\n", file_name); > + ret =3D parse_file(f, *tbl, rule_tbl); > + if (ret !=3D 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 !=3D NULL) > + fclose(f); > +} > + > +static void > +parse_opts(int argc, char **argv) > +{ > + int opt, ret; > + char *endptr; > + > + while ((opt =3D getopt(argc, argv, "f:t:n:d:l:r:6b:v")) !=3D -1) { > + switch (opt) { > + case 'f': > + config.rules_file =3D optarg; > + break; > + case 't': > + config.tuples_file =3D optarg; > + break; > + case 'n': > + errno =3D 0; > + config.nb_rules =3D strtoul(optarg, &endptr, 10); > + if ((errno !=3D 0) || (config.nb_rules =3D=3D 0) || > + (endptr[0] !=3D 0)) { > + print_usage(); > + rte_exit(-EINVAL, "Invalid option -n\n"); > + } > + break; > + case 'd': > + ret =3D parse_distrib(optarg); > + if (ret !=3D 0) { > + print_usage(); > + rte_exit(-EINVAL, "Invalid option -d\n"); > + } > + break; > + case 'b': > + errno =3D 0; > + config.burst_sz =3D strtoul(optarg, &endptr, 10); > + if ((errno !=3D 0) || (config.burst_sz =3D=3D 0) || > + (config.burst_sz > 64) || > + (endptr[0] !=3D 0)) { > + print_usage(); > + rte_exit(-EINVAL, "Invalid option -b\n"); > + } > + break; > + case 'l': > + errno =3D 0; > + config.nb_tuples =3D strtoul(optarg, &endptr, 10); > + if ((errno !=3D 0) || (config.nb_tuples =3D=3D 0) || > + (endptr[0] !=3D 0)) { > + print_usage(); > + rte_exit(-EINVAL, "Invalid option -l\n"); > + } > + break; > + case 'r': > + errno =3D 0; > + config.fract_rnd_tuples =3D strtoul(optarg, &endptr, 10); > + if ((errno !=3D 0) || (config.fract_rnd_tuples =3D=3D 0) || > + (config.fract_rnd_tuples >=3D 100) || > + (endptr[0] !=3D 0)) { > + print_usage(); > + rte_exit(-EINVAL, "Invalid option -r\n"); > + } > + break; > + case '6': > + config.ipv6 =3D 1; > + break; > + case 'v': > + config.verbose =3D 1; > + break; > + default: > + print_usage(); > + rte_exit(-EINVAL, "Invalid options\n"); > + } > + } > +} > + > +static void > +print_addr(int af, const uint8_t *addr) > +{ > + int i; Why not use inet_ntop inside that function? > + > + if (af =3D=3D AF_INET) { > + for (i =3D 0; i < 3; i++) > + printf("%d.", addr[i]); > + printf("%d", addr[i]); > + } else { > + for (i =3D 0; i < 7; i++) > + printf("%04x:", addr[2 * i] << 8 | addr[2 * i + 1]); > + printf("%04x", addr[2 * i] << 8 | addr[2 * i + 1]); > + } > + > +} > + > +static void > +print_result(const union rte_ipsec_sad_key *key, void *res) > +{ > + struct rule *rule =3D res; > + const struct rte_ipsec_sadv4_key *v4; > + const struct rte_ipsec_sadv6_key *v6; > + const char *spi_only =3D "SPI_ONLY"; > + const char *spi_dip =3D "SPI_DIP"; > + const char *spi_dip_sip =3D "SPI_DIP_SIP"; > + const char *rule_type; > + > + if (res =3D=3D NULL) { > + if (config.ipv6) { > + v6 =3D &key->v6; > + printf("TUPLE: < SPI: %u DIP: ", v6->spi); > + print_addr(AF_INET6, v6->dip); > + printf(" SIP: "); > + print_addr(AF_INET6, v6->sip); > + printf(" > not found\n"); > + } else { > + v4 =3D &key->v4; > + printf("TUPLE: < SPI: %u DIP: ", v4->spi); > + print_addr(AF_INET, (const uint8_t *)&v4->dip); > + printf(" SIP: "); > + print_addr(AF_INET, (const uint8_t *)&v4->sip); > + printf(" > not found\n"); > + } > + return; > + } > + > + switch (rule->rule_type) { > + case RTE_IPSEC_SAD_SPI_ONLY: > + rule_type =3D spi_only; > + break; > + case RTE_IPSEC_SAD_SPI_DIP: > + rule_type =3D spi_dip; > + break; > + case RTE_IPSEC_SAD_SPI_DIP_SIP: > + rule_type =3D spi_dip_sip; > + break; > + default: > + return; > + } > + > + if (config.ipv6) { > + v6 =3D &key->v6; > + printf("TUPLE: < SPI: %u DIP: ", v6->spi); > + print_addr(AF_INET6, v6->dip); > + printf(" SIP: "); > + print_addr(AF_INET6, v6->sip); > + printf(" >\n"); That looks identical to the code above for NULL result. Could be squeezed together I think. Another alternative: define 2 new fucntions (print_tuple, print_rule) and u= se it here to reduce code duplication. > + v6 =3D &rule->tuple.v6; > + printf("\tpoints to RULE ID %zu < SPI: %u DIP: ", > + RTE_PTR_DIFF(res, rules_tbl)/sizeof(struct rule), > + v6->spi); > + print_addr(AF_INET6, v6->dip); > + printf(" SIP: "); > + print_addr(AF_INET6, v6->sip); > + printf("/%s >\n", rule_type); > + } else { > + v4 =3D &key->v4; > + printf("TUPLE: < SPI: %u DIP: ", v4->spi); > + print_addr(AF_INET, (const uint8_t *)&v4->dip); > + printf(" SIP: "); > + print_addr(AF_INET, (const uint8_t *)&v4->sip); > + printf(" >\n"); > + v4 =3D &rule->tuple.v4; > + printf("\tpoints to RULE ID %zu < SPI: %u DIP: ", > + RTE_PTR_DIFF(res, rules_tbl)/sizeof(struct rule), > + v4->spi); > + print_addr(AF_INET, (const uint8_t *)&v4->dip); > + printf(" SIP: "); > + print_addr(AF_INET, (const uint8_t *)&v4->sip); > + printf("/%s >\n", rule_type); > + } > +} > + > +static void > +lookup(struct rte_ipsec_sad *sad, uint32_t burst_sz) > +{ > + int ret; > + unsigned int i, j; > + const union rte_ipsec_sad_key *keys[burst_sz]; > + void *vals[burst_sz]; > + uint64_t start, acc =3D 0; > + > + burst_sz =3D RTE_MIN(burst_sz, config.nb_tuples); > + for (i =3D 0; i < config.nb_tuples; i +=3D burst_sz) { > + for (j =3D 0; j < burst_sz; j++) > + keys[j] =3D (union rte_ipsec_sad_key *) > + (&tuples_tbl[i + j].tuple); > + start =3D rte_rdtsc_precise(); > + ret =3D rte_ipsec_sad_lookup(sad, keys, vals, burst_sz); > + acc +=3D rte_rdtsc_precise() - start; > + if (ret < 0) > + rte_exit(-EINVAL, "Lookup failed\n"); > + if (config.verbose) { > + for (j =3D 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); > +} > + > +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 =3D (config.nb_rules > fract) ? config.nb_rules / fract : 1; > + > + for (n =3D 0, j =3D 0; n !=3D config.nb_rules; n =3D fn, j++) { > + > + fn =3D n + f; > + fn =3D fn > config.nb_rules ? config.nb_rules : fn; > + > + start =3D rte_rdtsc_precise(); > + for (i =3D n; i !=3D fn; i++) { > + ret =3D rte_ipsec_sad_add(sad, > + &rules_tbl[i].tuple, > + rules_tbl[i].rule_type, &rules_tbl[i]); > + if (ret !=3D 0) > + rte_exit(ret, "%s failed @ %u-th rule\n", > + __func__, i); > + } > + tm[j] =3D rte_rdtsc_precise() - start; > + nm[j] =3D fn - n; > + } > + > + for (i =3D 0; i !=3D 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 =3D (config.nb_rules > fract) ? config.nb_rules / fract : 1; > + > + for (n =3D 0, j =3D 0; n !=3D config.nb_rules; n =3D fn, j++) { > + > + fn =3D n + f; > + fn =3D fn > config.nb_rules ? config.nb_rules : fn; > + > + start =3D rte_rdtsc_precise(); > + for (i =3D n; i !=3D fn; i++) { > + ret =3D rte_ipsec_sad_del(sad, > + &rules_tbl[i].tuple, > + rules_tbl[i].rule_type); > + if (ret !=3D 0 && ret !=3D -ENOENT) > + rte_exit(ret, "%s failed @ %u-th rule\n", > + __func__, i); > + } > + tm[j] =3D rte_rdtsc_precise() - start; > + nm[j] =3D fn - n; > + } > + > + for (i =3D 0; i !=3D 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; > + > + ret =3D rte_eal_init(argc, argv); > + if (ret < 0) > + rte_panic("Cannot init EAL\n"); > + > + argc -=3D ret; > + argv +=3D ret; > + > + config.prgname =3D 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 !=3D NULL) { > + config.fract_32 =3D (100 * config.nb_rules_32) / config.nb_rules; > + config.fract_64 =3D (100 * config.nb_rules_64) / config.nb_rules; > + config.fract_96 =3D (100 * config.nb_rules_96) / config.nb_rules; > + } > + if (config.tuples_file !=3D NULL) { > + config.fract_rnd_tuples =3D 0; > + config.nb_tuples_rnd =3D 0; > + } > + conf.socket_id =3D -1; > + conf.max_sa[RTE_IPSEC_SAD_SPI_ONLY] =3D config.nb_rules_32 * 5 / 4; > + conf.max_sa[RTE_IPSEC_SAD_SPI_DIP] =3D config.nb_rules_64 * 5 / 4; > + conf.max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP] =3D config.nb_rules_96 * 5 / 4; > + if (config.ipv6) > + conf.flags =3D RTE_IPSEC_SAD_FLAG_IPV6| > + RTE_IPSEC_SAD_FLAG_RW_CONCURRENCY; > + else > + conf.flags =3D RTE_IPSEC_SAD_FLAG_RW_CONCURRENCY; > + sad =3D rte_ipsec_sad_create("test", &conf); > + if (sad =3D=3D NULL) > + rte_exit(-rte_errno, "can not allocate SAD table\n"); > + > + print_config(); > + > + add_rules(sad, 10); > + lookup(sad, config.burst_sz); > + 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 =3D true > +sources =3D files('main.c') > +deps +=3D ['ipsec', 'net'] > -- Apart from the nits above: Acked-by: Konstantin Ananyev Tested-by: Konstantin Ananyev > 2.7.4