get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/61431/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 61431,
    "url": "http://patches.dpdk.org/api/patches/61431/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/c4a7e686a7ab8a4b90834e212a44559550b43da9.1571322983.git.vladimir.medvedkin@intel.com/",
    "project": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<c4a7e686a7ab8a4b90834e212a44559550b43da9.1571322983.git.vladimir.medvedkin@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/c4a7e686a7ab8a4b90834e212a44559550b43da9.1571322983.git.vladimir.medvedkin@intel.com",
    "date": "2019-10-17T15:48:02",
    "name": "[v6,5/6] app: add test-sad application",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "b3b88d6e61ed264500b99c4ff4a59a10b8ec291d",
    "submitter": {
        "id": 1216,
        "url": "http://patches.dpdk.org/api/people/1216/?format=api",
        "name": "Vladimir Medvedkin",
        "email": "vladimir.medvedkin@intel.com"
    },
    "delegate": {
        "id": 6690,
        "url": "http://patches.dpdk.org/api/users/6690/?format=api",
        "username": "akhil",
        "first_name": "akhil",
        "last_name": "goyal",
        "email": "gakhil@marvell.com"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/c4a7e686a7ab8a4b90834e212a44559550b43da9.1571322983.git.vladimir.medvedkin@intel.com/mbox/",
    "series": [
        {
            "id": 6917,
            "url": "http://patches.dpdk.org/api/series/6917/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=6917",
            "date": "2019-10-17T15:47:57",
            "name": "ipsec: add inbound SAD",
            "version": 6,
            "mbox": "http://patches.dpdk.org/series/6917/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/61431/comments/",
    "check": "warning",
    "checks": "http://patches.dpdk.org/api/patches/61431/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id ADDE31EA35;\n\tThu, 17 Oct 2019 17:48:28 +0200 (CEST)",
            "from mga12.intel.com (mga12.intel.com [192.55.52.136])\n\tby dpdk.org (Postfix) with ESMTP id 261BB1E9F1\n\tfor <dev@dpdk.org>; Thu, 17 Oct 2019 17:48:16 +0200 (CEST)",
            "from orsmga005.jf.intel.com ([10.7.209.41])\n\tby fmsmga106.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t17 Oct 2019 08:48:16 -0700",
            "from silpixa00400072.ir.intel.com ([10.237.222.213])\n\tby orsmga005.jf.intel.com with ESMTP; 17 Oct 2019 08:48:14 -0700"
        ],
        "X-Amp-Result": "SKIPPED(no attachment in message)",
        "X-Amp-File-Uploaded": "False",
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.67,308,1566889200\"; d=\"scan'208\";a=\"371174156\"",
        "From": "Vladimir Medvedkin <vladimir.medvedkin@intel.com>",
        "To": "dev@dpdk.org",
        "Cc": "konstantin.ananyev@intel.com, bernard.iremonger@intel.com,\n\takhil.goyal@nxp.com",
        "Date": "Thu, 17 Oct 2019 16:48:02 +0100",
        "Message-Id": "<c4a7e686a7ab8a4b90834e212a44559550b43da9.1571322983.git.vladimir.medvedkin@intel.com>",
        "X-Mailer": "git-send-email 2.7.4",
        "In-Reply-To": [
            "<cover.1571322982.git.vladimir.medvedkin@intel.com>",
            "<cover.1571322982.git.vladimir.medvedkin@intel.com>"
        ],
        "References": [
            "<cover.1571322982.git.vladimir.medvedkin@intel.com>",
            "<cover.1570725871.git.vladimir.medvedkin@intel.com>\n\t<cover.1571322982.git.vladimir.medvedkin@intel.com>"
        ],
        "Subject": "[dpdk-dev] [PATCH v6 5/6] app: add test-sad application",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "Introduce new application to provide user to evaluate and perform\ncustom functional and performance tests for IPsec SAD implementation.\n\nSigned-off-by: Vladimir Medvedkin <vladimir.medvedkin@intel.com>\nAcked-by: Akhil Goyal <akhil.goyal@nxp.com>\nAcked-by: Konstantin Ananyev <konstantin.ananyev@intel.com>\nTested-by: Konstantin Ananyev <konstantin.ananyev@intel.com>\n---\n app/Makefile             |   1 +\n app/meson.build          |   3 +-\n app/test-sad/Makefile    |  18 ++\n app/test-sad/main.c      | 668 +++++++++++++++++++++++++++++++++++++++++++++++\n app/test-sad/meson.build |   6 +\n 5 files changed, 695 insertions(+), 1 deletion(-)\n create mode 100644 app/test-sad/Makefile\n create mode 100644 app/test-sad/main.c\n create mode 100644 app/test-sad/meson.build",
    "diff": "diff --git a/app/Makefile b/app/Makefile\nindex 28acbce..db9d2d5 100644\n--- a/app/Makefile\n+++ b/app/Makefile\n@@ -10,6 +10,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += pdump\n DIRS-$(CONFIG_RTE_LIBRTE_ACL) += test-acl\n DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) += test-cmdline\n DIRS-$(CONFIG_RTE_LIBRTE_PIPELINE) += test-pipeline\n+DIRS-$(CONFIG_RTE_LIBRTE_IPSEC) += test-sad\n \n ifeq ($(CONFIG_RTE_LIBRTE_BBDEV),y)\n DIRS-$(CONFIG_RTE_TEST_BBDEV) += test-bbdev\ndiff --git a/app/meson.build b/app/meson.build\nindex b0e6afb..71109cc 100644\n--- a/app/meson.build\n+++ b/app/meson.build\n@@ -15,7 +15,8 @@ apps = [\n \t'test-crypto-perf',\n \t'test-eventdev',\n \t'test-pipeline',\n-\t'test-pmd']\n+\t'test-pmd',\n+\t'test-sad']\n \n # for BSD only\n lib_execinfo = cc.find_library('execinfo', required: false)\ndiff --git a/app/test-sad/Makefile b/app/test-sad/Makefile\nnew file mode 100644\nindex 0000000..9b35413\n--- /dev/null\n+++ b/app/test-sad/Makefile\n@@ -0,0 +1,18 @@\n+# SPDX-License-Identifier: BSD-3-Clause\n+# Copyright(c) 2010-2014 Intel Corporation\n+\n+include $(RTE_SDK)/mk/rte.vars.mk\n+\n+ifeq ($(CONFIG_RTE_LIBRTE_IPSEC),y)\n+\n+APP = testsad\n+\n+CFLAGS += $(WERROR_FLAGS)\n+CFLAGS += -DALLOW_EXPERIMENTAL_API\n+\n+# all source are stored in SRCS-y\n+SRCS-y := main.c\n+\n+include $(RTE_SDK)/mk/rte.app.mk\n+\n+endif\ndiff --git a/app/test-sad/main.c b/app/test-sad/main.c\nnew file mode 100644\nindex 0000000..34044a2\n--- /dev/null\n+++ b/app/test-sad/main.c\n@@ -0,0 +1,668 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2019 Intel Corporation\n+ */\n+\n+#include <rte_string_fns.h>\n+#include <rte_ipsec_sad.h>\n+#include <getopt.h>\n+#include <string.h>\n+#include <stdio.h>\n+#include <sys/types.h>\n+#include <sys/socket.h>\n+#include <netinet/in.h>\n+#include <arpa/inet.h>\n+\n+#include <rte_cycles.h>\n+#include <rte_errno.h>\n+#include <rte_ip.h>\n+#include <rte_random.h>\n+#include <rte_malloc.h>\n+#include <rte_ipsec_sad.h>\n+\n+#define\tPRINT_USAGE_START\t\"%s [EAL options] --\\n\"\n+\n+#define GET_CB_FIELD(in, fd, base, lim, dlm)\tdo {\t\t\\\n+\tunsigned long val;\t\t\t\t\t\\\n+\tchar *end_fld;\t\t\t\t\t\t\\\n+\terrno = 0;\t\t\t\t\t\t\\\n+\tval = strtoul((in), &end_fld, (base));\t\t\t\\\n+\tif (errno != 0 || end_fld[0] != (dlm) || val > (lim))\t\\\n+\t\treturn -EINVAL;\t\t\t\t\t\\\n+\t(fd) = (typeof(fd))val;\t\t\t\t\t\\\n+\t(in) = end_fld + 1;\t\t\t\t\t\\\n+} while (0)\n+\n+#define\tDEF_RULE_NUM\t\t0x10000\n+#define\tDEF_TUPLES_NUM\t0x100000\n+#define BURST_SZ_MAX\t64\n+\n+static struct {\n+\tconst char\t*prgname;\n+\tconst char\t*rules_file;\n+\tconst char\t*tuples_file;\n+\tuint32_t\tnb_rules;\n+\tuint32_t\tnb_tuples;\n+\tuint32_t\tnb_rules_32;\n+\tuint32_t\tnb_rules_64;\n+\tuint32_t\tnb_rules_96;\n+\tuint32_t\tnb_tuples_rnd;\n+\tuint32_t\tburst_sz;\n+\tuint8_t\t\tfract_32;\n+\tuint8_t\t\tfract_64;\n+\tuint8_t\t\tfract_96;\n+\tuint8_t\t\tfract_rnd_tuples;\n+\tint\t\tipv6;\n+\tint\t\tverbose;\n+\tint\t\tparallel_lookup;\n+\tint\t\tconcurrent_rw;\n+} config = {\n+\t.rules_file = NULL,\n+\t.tuples_file = NULL,\n+\t.nb_rules = DEF_RULE_NUM,\n+\t.nb_tuples = DEF_TUPLES_NUM,\n+\t.nb_rules_32 = 0,\n+\t.nb_rules_64 = 0,\n+\t.nb_rules_96 = 0,\n+\t.nb_tuples_rnd = 0,\n+\t.burst_sz = BURST_SZ_MAX,\n+\t.fract_32 = 90,\n+\t.fract_64 = 9,\n+\t.fract_96 = 1,\n+\t.fract_rnd_tuples = 0,\n+\t.ipv6 = 0,\n+\t.verbose = 0,\n+\t.parallel_lookup = 0,\n+\t.concurrent_rw = 0\n+};\n+\n+enum {\n+\tCB_RULE_SPI,\n+\tCB_RULE_DIP,\n+\tCB_RULE_SIP,\n+\tCB_RULE_LEN,\n+\tCB_RULE_NUM,\n+};\n+\n+static char line[LINE_MAX];\n+struct rule {\n+\tunion rte_ipsec_sad_key\ttuple;\n+\tint rule_type;\n+};\n+\n+static struct rule *rules_tbl;\n+static struct rule *tuples_tbl;\n+\n+static int\n+parse_distrib(const char *in)\n+{\n+\tint a, b, c;\n+\n+\tGET_CB_FIELD(in, a, 0, UINT8_MAX, '/');\n+\tGET_CB_FIELD(in, b, 0, UINT8_MAX, '/');\n+\tGET_CB_FIELD(in, c, 0, UINT8_MAX, 0);\n+\n+\tif ((a + b + c) != 100)\n+\t\treturn -EINVAL;\n+\n+\tconfig.fract_32 = a;\n+\tconfig.fract_64 = b;\n+\tconfig.fract_96 = c;\n+\n+\treturn 0;\n+}\n+\n+static void\n+print_config(void)\n+{\n+\tfprintf(stdout,\n+\t\t\"Rules total: %u\\n\"\n+\t\t\"Configured rules distribution SPI/SPI_DIP/SIP_DIP_SIP:\"\n+\t\t\"%u/%u/%u\\n\"\n+\t\t\"SPI only rules: %u\\n\"\n+\t\t\"SPI_DIP  rules: %u\\n\"\n+\t\t\"SPI_DIP_SIP rules: %u\\n\"\n+\t\t\"Lookup tuples: %u\\n\"\n+\t\t\"Lookup burst size %u\\n\"\n+\t\t\"Configured fraction of random tuples: %u\\n\"\n+\t\t\"Random lookup tuples: %u\\n\",\n+\t\tconfig.nb_rules, config.fract_32, config.fract_64,\n+\t\tconfig.fract_96, config.nb_rules_32, config.nb_rules_64,\n+\t\tconfig.nb_rules_96, config.nb_tuples, config.burst_sz,\n+\t\tconfig.fract_rnd_tuples, config.nb_tuples_rnd);\n+}\n+\n+static void\n+print_usage(void)\n+{\n+\tfprintf(stdout,\n+\t\tPRINT_USAGE_START\n+\t\t\"[-f <rules file>]\\n\"\n+\t\t\"[-t <tuples file for lookup>]\\n\"\n+\t\t\"[-n <rules number (if -f is not specified)>]\\n\"\n+\t\t\"[-l <lookup tuples number (if -t is not specified)>]\\n\"\n+\t\t\"[-6 <ipv6 tests>]\\n\"\n+\t\t\"[-d <\\\"/\\\" separated rules length distribution\"\n+\t\t\"(if -f is not specified)>]\\n\"\n+\t\t\"[-r <random tuples fraction to lookup\"\n+\t\t\"(if -t is not specified)>]\\n\"\n+\t\t\"[-b <lookup burst size: 1-64 >]\\n\"\n+\t\t\"[-v <verbose, print results on lookup>]\\n\"\n+\t\t\"[-p <parallel lookup on all availible cores>]\\n\"\n+\t\t\"[-c <init sad supporting read/write concurrency>]\\n\",\n+\t\tconfig.prgname);\n+\n+}\n+\n+static int\n+get_str_num(FILE *f, int num)\n+{\n+\tint n_lines = 0;\n+\n+\tif (f != NULL) {\n+\t\twhile (fgets(line, sizeof(line), f) != NULL)\n+\t\t\tn_lines++;\n+\t\trewind(f);\n+\t} else {\n+\t\tn_lines = num;\n+\t}\n+\treturn n_lines;\n+}\n+\n+static int\n+parse_file(FILE *f, struct rule *tbl, int rule_tbl)\n+{\n+\tint ret, i, j = 0;\n+\tchar *s, *sp, *in[CB_RULE_NUM];\n+\tstatic const char *dlm = \" \\t\\n\";\n+\tint string_tok_nb = RTE_DIM(in);\n+\n+\tstring_tok_nb -= (rule_tbl == 0) ? 1 : 0;\n+\twhile (fgets(line, sizeof(line), f) != NULL) {\n+\t\ts = line;\n+\t\tfor (i = 0; i != string_tok_nb; i++) {\n+\t\t\tin[i] = strtok_r(s, dlm, &sp);\n+\t\t\tif (in[i] == NULL)\n+\t\t\t\treturn -EINVAL;\n+\t\t\ts = NULL;\n+\t\t}\n+\t\tGET_CB_FIELD(in[CB_RULE_SPI], tbl[j].tuple.v4.spi, 0,\n+\t\t\t\tUINT32_MAX, 0);\n+\n+\t\tif (config.ipv6)\n+\t\t\tret = inet_pton(AF_INET6, in[CB_RULE_DIP],\n+\t\t\t\t&tbl[j].tuple.v6.dip);\n+\t\telse\n+\t\t\tret = inet_pton(AF_INET, in[CB_RULE_DIP],\n+\t\t\t\t&tbl[j].tuple.v4.dip);\n+\t\tif (ret != 1)\n+\t\t\treturn -EINVAL;\n+\t\tif (config.ipv6)\n+\t\t\tret = inet_pton(AF_INET6, in[CB_RULE_SIP],\n+\t\t\t\t&tbl[j].tuple.v6.sip);\n+\t\telse\n+\t\t\tret = inet_pton(AF_INET, in[CB_RULE_SIP],\n+\t\t\t\t&tbl[j].tuple.v4.sip);\n+\t\tif (ret != 1)\n+\t\t\treturn -EINVAL;\n+\t\tif ((rule_tbl) && (in[CB_RULE_LEN] != NULL)) {\n+\t\t\tif (strcmp(in[CB_RULE_LEN], \"SPI_DIP_SIP\") == 0) {\n+\t\t\t\ttbl[j].rule_type = RTE_IPSEC_SAD_SPI_DIP_SIP;\n+\t\t\t\tconfig.nb_rules_96++;\n+\t\t\t} else if (strcmp(in[CB_RULE_LEN], \"SPI_DIP\") == 0) {\n+\t\t\t\ttbl[j].rule_type = RTE_IPSEC_SAD_SPI_DIP;\n+\t\t\t\tconfig.nb_rules_64++;\n+\t\t\t} else if (strcmp(in[CB_RULE_LEN], \"SPI\") == 0) {\n+\t\t\t\ttbl[j].rule_type = RTE_IPSEC_SAD_SPI_ONLY;\n+\t\t\t\tconfig.nb_rules_32++;\n+\t\t\t} else {\n+\t\t\t\treturn -EINVAL;\n+\t\t\t}\n+\t\t}\n+\t\tj++;\n+\t}\n+\treturn 0;\n+}\n+\n+static uint64_t\n+get_rnd_rng(uint64_t l, uint64_t u)\n+{\n+\tif (l == u)\n+\t\treturn l;\n+\telse\n+\t\treturn (rte_rand() % (u - l) + l);\n+}\n+\n+static void\n+get_random_rules(struct rule *tbl, uint32_t nb_rules, int rule_tbl)\n+{\n+\tunsigned i, j, rnd;\n+\tint rule_type;\n+\tdouble edge = 0;\n+\tdouble step;\n+\n+\tstep = (double)UINT32_MAX / nb_rules;\n+\tfor (i = 0; i < nb_rules; i++, edge += step) {\n+\t\trnd = rte_rand() % 100;\n+\t\tif (rule_tbl) {\n+\t\t\ttbl[i].tuple.v4.spi = get_rnd_rng((uint64_t)edge,\n+\t\t\t\t\t\t(uint64_t)(edge + step));\n+\t\t\tif (config.ipv6) {\n+\t\t\t\tfor (j = 0; j < 16; j++) {\n+\t\t\t\t\ttbl[i].tuple.v6.dip[j] = rte_rand();\n+\t\t\t\t\ttbl[i].tuple.v6.sip[j] = rte_rand();\n+\t\t\t\t}\n+\t\t\t} else {\n+\t\t\t\ttbl[i].tuple.v4.dip = rte_rand();\n+\t\t\t\ttbl[i].tuple.v4.sip = rte_rand();\n+\t\t\t}\n+\t\t\tif (rnd >= (100UL - config.fract_32)) {\n+\t\t\t\trule_type = RTE_IPSEC_SAD_SPI_ONLY;\n+\t\t\t\tconfig.nb_rules_32++;\n+\t\t\t} else if (rnd >= (100UL - (config.fract_32 +\n+\t\t\t\t\tconfig.fract_64))) {\n+\t\t\t\trule_type = RTE_IPSEC_SAD_SPI_DIP;\n+\t\t\t\tconfig.nb_rules_64++;\n+\t\t\t} else {\n+\t\t\t\trule_type = RTE_IPSEC_SAD_SPI_DIP_SIP;\n+\t\t\t\tconfig.nb_rules_96++;\n+\t\t\t}\n+\t\t\ttbl[i].rule_type = rule_type;\n+\t\t} else {\n+\t\t\tif (rnd >= 100UL - config.fract_rnd_tuples) {\n+\t\t\t\ttbl[i].tuple.v4.spi =\n+\t\t\t\t\tget_rnd_rng((uint64_t)edge,\n+\t\t\t\t\t(uint64_t)(edge + step));\n+\t\t\t\tif (config.ipv6) {\n+\t\t\t\t\tfor (j = 0; j < 16; j++) {\n+\t\t\t\t\t\ttbl[i].tuple.v6.dip[j] =\n+\t\t\t\t\t\t\t\trte_rand();\n+\t\t\t\t\t\ttbl[i].tuple.v6.sip[j] =\n+\t\t\t\t\t\t\t\trte_rand();\n+\t\t\t\t\t}\n+\t\t\t\t} else {\n+\t\t\t\t\ttbl[i].tuple.v4.dip = rte_rand();\n+\t\t\t\t\ttbl[i].tuple.v4.sip = rte_rand();\n+\t\t\t\t}\n+\t\t\t\tconfig.nb_tuples_rnd++;\n+\t\t\t} else {\n+\t\t\t\ttbl[i].tuple.v4.spi = rules_tbl[i %\n+\t\t\t\t\tconfig.nb_rules].tuple.v4.spi;\n+\t\t\t\tif (config.ipv6) {\n+\t\t\t\t\tint r_idx = i % config.nb_rules;\n+\t\t\t\t\tmemcpy(tbl[i].tuple.v6.dip,\n+\t\t\t\t\t\trules_tbl[r_idx].tuple.v6.dip,\n+\t\t\t\t\t\tsizeof(tbl[i].tuple.v6.dip));\n+\t\t\t\t\tmemcpy(tbl[i].tuple.v6.sip,\n+\t\t\t\t\t\trules_tbl[r_idx].tuple.v6.sip,\n+\t\t\t\t\t\tsizeof(tbl[i].tuple.v6.sip));\n+\t\t\t\t} else {\n+\t\t\t\t\ttbl[i].tuple.v4.dip = rules_tbl[i %\n+\t\t\t\t\t\tconfig.nb_rules].tuple.v4.dip;\n+\t\t\t\t\ttbl[i].tuple.v4.sip = rules_tbl[i %\n+\t\t\t\t\t\tconfig.nb_rules].tuple.v4.sip;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t}\n+}\n+\n+static void\n+tbl_init(struct rule **tbl, uint32_t *n_entries,\n+\tconst char *file_name, int rule_tbl)\n+{\n+\tFILE *f = NULL;\n+\tint ret;\n+\tconst char *rules = \"rules\";\n+\tconst char *tuples = \"tuples\";\n+\n+\tif (file_name != NULL) {\n+\t\tf = fopen(file_name, \"r\");\n+\t\tif (f == NULL)\n+\t\t\trte_exit(-EINVAL, \"failed to open file: %s\\n\",\n+\t\t\t\tfile_name);\n+\t}\n+\n+\tprintf(\"init %s table...\", (rule_tbl) ? rules : tuples);\n+\t*n_entries = get_str_num(f, *n_entries);\n+\tprintf(\"%d entries\\n\", *n_entries);\n+\t*tbl = rte_zmalloc(NULL, sizeof(struct rule) * *n_entries,\n+\t\tRTE_CACHE_LINE_SIZE);\n+\tif (*tbl == NULL)\n+\t\trte_exit(-ENOMEM, \"failed to allocate tbl\\n\");\n+\n+\tif (f != NULL) {\n+\t\tprintf(\"parse file %s\\n\", file_name);\n+\t\tret = parse_file(f, *tbl, rule_tbl);\n+\t\tif (ret != 0)\n+\t\t\trte_exit(-EINVAL, \"failed to parse file %s\\n\"\n+\t\t\t\t\"rules file must be: \"\n+\t\t\t\t\"<uint32_t: spi> <space> \"\n+\t\t\t\t\"<ip_addr: dip> <space> \"\n+\t\t\t\t\"<ip_addr: sip> <space> \"\n+\t\t\t\t\"<string: SPI|SPI_DIP|SIP_DIP_SIP>\\n\"\n+\t\t\t\t\"tuples file must be: \"\n+\t\t\t\t\"<uint32_t: spi> <space> \"\n+\t\t\t\t\"<ip_addr: dip> <space> \"\n+\t\t\t\t\"<ip_addr: sip>\\n\",\n+\t\t\t\tfile_name);\n+\t} else {\n+\t\tprintf(\"generate random values in %s table\\n\",\n+\t\t\t(rule_tbl) ? rules : tuples);\n+\t\tget_random_rules(*tbl, *n_entries, rule_tbl);\n+\t}\n+\tif (f != NULL)\n+\t\tfclose(f);\n+}\n+\n+static void\n+parse_opts(int argc, char **argv)\n+{\n+\tint opt, ret;\n+\tchar *endptr;\n+\n+\twhile ((opt = getopt(argc, argv, \"f:t:n:d:l:r:6b:vpc\")) != -1) {\n+\t\tswitch (opt) {\n+\t\tcase 'f':\n+\t\t\tconfig.rules_file = optarg;\n+\t\t\tbreak;\n+\t\tcase 't':\n+\t\t\tconfig.tuples_file = optarg;\n+\t\t\tbreak;\n+\t\tcase 'n':\n+\t\t\terrno = 0;\n+\t\t\tconfig.nb_rules = strtoul(optarg, &endptr, 10);\n+\t\t\tif ((errno != 0) || (config.nb_rules == 0) ||\n+\t\t\t\t\t(endptr[0] != 0)) {\n+\t\t\t\tprint_usage();\n+\t\t\t\trte_exit(-EINVAL, \"Invalid option -n\\n\");\n+\t\t\t}\n+\t\t\tbreak;\n+\t\tcase 'd':\n+\t\t\tret = parse_distrib(optarg);\n+\t\t\tif (ret != 0) {\n+\t\t\t\tprint_usage();\n+\t\t\t\trte_exit(-EINVAL, \"Invalid option -d\\n\");\n+\t\t\t}\n+\t\t\tbreak;\n+\t\tcase 'b':\n+\t\t\terrno = 0;\n+\t\t\tconfig.burst_sz = strtoul(optarg, &endptr, 10);\n+\t\t\tif ((errno != 0) || (config.burst_sz == 0) ||\n+\t\t\t\t\t(config.burst_sz > BURST_SZ_MAX) ||\n+\t\t\t\t\t(endptr[0] != 0)) {\n+\t\t\t\tprint_usage();\n+\t\t\t\trte_exit(-EINVAL, \"Invalid option -b\\n\");\n+\t\t\t}\n+\t\t\tbreak;\n+\t\tcase 'l':\n+\t\t\terrno = 0;\n+\t\t\tconfig.nb_tuples = strtoul(optarg, &endptr, 10);\n+\t\t\tif ((errno != 0) || (config.nb_tuples == 0) ||\n+\t\t\t\t\t(endptr[0] != 0)) {\n+\t\t\t\tprint_usage();\n+\t\t\t\trte_exit(-EINVAL, \"Invalid option -l\\n\");\n+\t\t\t}\n+\t\t\tbreak;\n+\t\tcase 'r':\n+\t\t\terrno = 0;\n+\t\t\tconfig.fract_rnd_tuples = strtoul(optarg, &endptr, 10);\n+\t\t\tif ((errno != 0) || (config.fract_rnd_tuples == 0) ||\n+\t\t\t\t\t(config.fract_rnd_tuples >= 100) ||\n+\t\t\t\t\t(endptr[0] != 0)) {\n+\t\t\t\tprint_usage();\n+\t\t\t\trte_exit(-EINVAL, \"Invalid option -r\\n\");\n+\t\t\t}\n+\t\t\tbreak;\n+\t\tcase '6':\n+\t\t\tconfig.ipv6 = 1;\n+\t\t\tbreak;\n+\t\tcase 'v':\n+\t\t\tconfig.verbose = 1;\n+\t\t\tbreak;\n+\t\tcase 'p':\n+\t\t\tconfig.parallel_lookup = 1;\n+\t\t\tbreak;\n+\t\tcase 'c':\n+\t\t\tconfig.concurrent_rw = 1;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tprint_usage();\n+\t\t\trte_exit(-EINVAL, \"Invalid options\\n\");\n+\t\t}\n+\t}\n+}\n+\n+static void\n+print_addr(int af, const void *addr)\n+{\n+\tchar str[INET6_ADDRSTRLEN];\n+\tconst char *ret;\n+\n+\tret = inet_ntop(af, addr, str, sizeof(str));\n+\tif (ret != NULL)\n+\t\tprintf(\"%s\", str);\n+}\n+\n+static void\n+print_tuple(int af, uint32_t spi, const void *dip, const void *sip)\n+{\n+\n+\tprintf(\"<SPI: %u DIP: \", spi);\n+\tprint_addr(af, dip);\n+\tprintf(\" SIP: \");\n+\tprint_addr(af, sip);\n+\tprintf(\">\");\n+}\n+\n+static void\n+print_result(const union rte_ipsec_sad_key *key, void *res)\n+{\n+\tstruct rule *rule = res;\n+\tconst struct rte_ipsec_sadv4_key *v4;\n+\tconst struct rte_ipsec_sadv6_key *v6;\n+\tconst char *spi_only = \"SPI_ONLY\";\n+\tconst char *spi_dip = \"SPI_DIP\";\n+\tconst char *spi_dip_sip = \"SPI_DIP_SIP\";\n+\tconst char *rule_type;\n+\tconst void *dip, *sip;\n+\tuint32_t spi;\n+\tint af;\n+\n+\taf = (config.ipv6) ? AF_INET6 : AF_INET;\n+\tv4 = &key->v4;\n+\tv6 = &key->v6;\n+\tspi = (config.ipv6 == 0) ? v4->spi : v6->spi;\n+\tdip = (config.ipv6 == 0) ? &v4->dip : (const void *)v6->dip;\n+\tsip = (config.ipv6 == 0) ? &v4->sip : (const void *)v6->sip;\n+\n+\tif (res == NULL) {\n+\t\tprintf(\"TUPLE: \");\n+\t\tprint_tuple(af, spi, dip, sip);\n+\t\tprintf(\" not found\\n\");\n+\t\treturn;\n+\t}\n+\n+\tswitch (rule->rule_type) {\n+\tcase RTE_IPSEC_SAD_SPI_ONLY:\n+\t\trule_type = spi_only;\n+\t\tbreak;\n+\tcase RTE_IPSEC_SAD_SPI_DIP:\n+\t\trule_type = spi_dip;\n+\t\tbreak;\n+\tcase RTE_IPSEC_SAD_SPI_DIP_SIP:\n+\t\trule_type = spi_dip_sip;\n+\t\tbreak;\n+\tdefault:\n+\t\treturn;\n+\t}\n+\n+\tprint_tuple(af, spi, dip, sip);\n+\tv4 = &rule->tuple.v4;\n+\tv6 = &rule->tuple.v6;\n+\tspi = (config.ipv6 == 0) ? v4->spi : v6->spi;\n+\tdip = (config.ipv6 == 0) ? &v4->dip : (const void *)v6->dip;\n+\tsip = (config.ipv6 == 0) ? &v4->sip : (const void *)v6->sip;\n+\tprintf(\"\\n\\tpoints to RULE ID %zu \",\n+\t\tRTE_PTR_DIFF(res, rules_tbl)/sizeof(struct rule));\n+\tprint_tuple(af, spi, dip, sip);\n+\tprintf(\" %s\\n\", rule_type);\n+}\n+\n+static int\n+lookup(void *arg)\n+{\n+\tint ret;\n+\tunsigned int i, j;\n+\tconst union rte_ipsec_sad_key *keys[BURST_SZ_MAX];\n+\tvoid *vals[BURST_SZ_MAX];\n+\tuint64_t start, acc = 0;\n+\tuint32_t burst_sz;\n+\tstruct rte_ipsec_sad *sad = arg;\n+\n+\tburst_sz = RTE_MIN(config.burst_sz, config.nb_tuples);\n+\tfor (i = 0; i < config.nb_tuples; i += burst_sz) {\n+\t\tfor (j = 0; j < burst_sz; j++)\n+\t\t\tkeys[j] = (union rte_ipsec_sad_key *)\n+\t\t\t\t(&tuples_tbl[i + j].tuple);\n+\t\tstart = rte_rdtsc_precise();\n+\t\tret = rte_ipsec_sad_lookup(sad, keys, vals, burst_sz);\n+\t\tacc += rte_rdtsc_precise() - start;\n+\t\tif (ret < 0)\n+\t\t\trte_exit(-EINVAL, \"Lookup failed\\n\");\n+\t\tif (config.verbose) {\n+\t\t\tfor (j = 0; j < burst_sz; j++)\n+\t\t\t\tprint_result(keys[j], vals[j]);\n+\t\t}\n+\t}\n+\tprintf(\"Average lookup cycles %.2Lf, lookups/sec: %.2Lf\\n\",\n+\t\t(long double)acc / config.nb_tuples,\n+\t\t(long double)config.nb_tuples * rte_get_tsc_hz() / acc);\n+\n+\treturn 0;\n+}\n+\n+static void\n+add_rules(struct rte_ipsec_sad *sad, uint32_t fract)\n+{\n+\tint32_t ret;\n+\tuint32_t i, j, f, fn, n;\n+\tuint64_t start, tm[fract + 1];\n+\tuint32_t nm[fract + 1];\n+\n+\tf = (config.nb_rules > fract) ? config.nb_rules / fract : 1;\n+\n+\tfor (n = 0, j = 0; n != config.nb_rules; n = fn, j++) {\n+\n+\t\tfn = n + f;\n+\t\tfn = fn > config.nb_rules ? config.nb_rules : fn;\n+\n+\t\tstart = rte_rdtsc_precise();\n+\t\tfor (i = n; i != fn; i++) {\n+\t\t\tret = rte_ipsec_sad_add(sad,\n+\t\t\t\t&rules_tbl[i].tuple,\n+\t\t\t\trules_tbl[i].rule_type, &rules_tbl[i]);\n+\t\t\tif (ret != 0)\n+\t\t\t\trte_exit(ret, \"%s failed @ %u-th rule\\n\",\n+\t\t\t\t\t__func__, i);\n+\t\t}\n+\t\ttm[j] = rte_rdtsc_precise() - start;\n+\t\tnm[j] = fn - n;\n+\t}\n+\n+\tfor (i = 0; i != j; i++)\n+\t\tprintf(\"ADD %u rules, %.2Lf cycles/rule, %.2Lf ADD/sec\\n\",\n+\t\t\tnm[i], (long double)tm[i] / nm[i],\n+\t\t\t(long double)nm[i] * rte_get_tsc_hz() / tm[i]);\n+}\n+\n+static void\n+del_rules(struct rte_ipsec_sad *sad, uint32_t fract)\n+{\n+\tint32_t ret;\n+\tuint32_t i, j, f, fn, n;\n+\tuint64_t start, tm[fract + 1];\n+\tuint32_t nm[fract + 1];\n+\n+\tf = (config.nb_rules > fract) ? config.nb_rules / fract : 1;\n+\n+\tfor (n = 0, j = 0; n != config.nb_rules; n = fn, j++) {\n+\n+\t\tfn = n + f;\n+\t\tfn = fn > config.nb_rules ? config.nb_rules : fn;\n+\n+\t\tstart = rte_rdtsc_precise();\n+\t\tfor (i = n; i != fn; i++) {\n+\t\t\tret = rte_ipsec_sad_del(sad,\n+\t\t\t\t&rules_tbl[i].tuple,\n+\t\t\t\trules_tbl[i].rule_type);\n+\t\t\tif (ret != 0 && ret != -ENOENT)\n+\t\t\t\trte_exit(ret, \"%s failed @ %u-th rule\\n\",\n+\t\t\t\t\t__func__, i);\n+\t\t}\n+\t\ttm[j] = rte_rdtsc_precise() - start;\n+\t\tnm[j] = fn - n;\n+\t}\n+\n+\tfor (i = 0; i != j; i++)\n+\t\tprintf(\"DEL %u rules, %.2Lf cycles/rule, %.2Lf DEL/sec\\n\",\n+\t\t\tnm[i], (long double)tm[i] / nm[i],\n+\t\t\t(long double)nm[i] * rte_get_tsc_hz() / tm[i]);\n+}\n+\n+int\n+main(int argc, char **argv)\n+{\n+\tint ret;\n+\tstruct rte_ipsec_sad *sad;\n+\tstruct rte_ipsec_sad_conf conf;\n+\tunsigned int lcore_id;\n+\n+\tret = rte_eal_init(argc, argv);\n+\tif (ret < 0)\n+\t\trte_panic(\"Cannot init EAL\\n\");\n+\n+\targc -= ret;\n+\targv += ret;\n+\n+\tconfig.prgname = argv[0];\n+\n+\tparse_opts(argc, argv);\n+\ttbl_init(&rules_tbl, &config.nb_rules, config.rules_file, 1);\n+\ttbl_init(&tuples_tbl, &config.nb_tuples, config.tuples_file, 0);\n+\tif (config.rules_file != NULL) {\n+\t\tconfig.fract_32 = (100 * config.nb_rules_32) / config.nb_rules;\n+\t\tconfig.fract_64 = (100 * config.nb_rules_64) / config.nb_rules;\n+\t\tconfig.fract_96 = (100 * config.nb_rules_96) / config.nb_rules;\n+\t}\n+\tif (config.tuples_file != NULL) {\n+\t\tconfig.fract_rnd_tuples = 0;\n+\t\tconfig.nb_tuples_rnd = 0;\n+\t}\n+\tconf.socket_id = -1;\n+\tconf.max_sa[RTE_IPSEC_SAD_SPI_ONLY] = config.nb_rules_32 * 5 / 4;\n+\tconf.max_sa[RTE_IPSEC_SAD_SPI_DIP] = config.nb_rules_64 * 5 / 4;\n+\tconf.max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP] = config.nb_rules_96 * 5 / 4;\n+\tif (config.ipv6)\n+\t\tconf.flags |= RTE_IPSEC_SAD_FLAG_IPV6;\n+\tif (config.concurrent_rw)\n+\t\tconf.flags |= RTE_IPSEC_SAD_FLAG_RW_CONCURRENCY;\n+\tsad = rte_ipsec_sad_create(\"test\", &conf);\n+\tif (sad == NULL)\n+\t\trte_exit(-rte_errno, \"can not allocate SAD table\\n\");\n+\n+\tprint_config();\n+\n+\tadd_rules(sad, 10);\n+\tif (config.parallel_lookup)\n+\t\trte_eal_mp_remote_launch(lookup, sad, SKIP_MASTER);\n+\n+\tlookup(sad);\n+\tif (config.parallel_lookup)\n+\t\tRTE_LCORE_FOREACH_SLAVE(lcore_id)\n+\t\t\tif (rte_eal_wait_lcore(lcore_id) < 0)\n+\t\t\t\treturn -1;\n+\n+\tdel_rules(sad, 10);\n+\n+\treturn 0;\n+}\ndiff --git a/app/test-sad/meson.build b/app/test-sad/meson.build\nnew file mode 100644\nindex 0000000..31f9aab\n--- /dev/null\n+++ b/app/test-sad/meson.build\n@@ -0,0 +1,6 @@\n+# SPDX-License-Identifier: BSD-3-Clause\n+# Copyright(c) 2019 Intel Corporation\n+\n+allow_experimental_apis = true\n+sources = files('main.c')\n+deps += ['ipsec', 'net']\n",
    "prefixes": [
        "v6",
        "5/6"
    ]
}