app/test-sad: add test application for IPsec SAD
Introduce new application to provide user to evaluate and perform custom functional and performance tests for IPsec SAD implementation. According to our measurements on SKX for 1M entries average lookup cost is ~80 cycles, average add cost ~500 cycles. Signed-off-by: Vladimir Medvedkin <vladimir.medvedkin@intel.com> Acked-by: Akhil Goyal <akhil.goyal@nxp.com> Acked-by: Konstantin Ananyev <konstantin.ananyev@intel.com> Tested-by: Konstantin Ananyev <konstantin.ananyev@intel.com>
This commit is contained in:
parent
48083b4d67
commit
908be0651a
@ -1198,6 +1198,7 @@ F: app/test/test_ipsec.c
|
||||
F: doc/guides/prog_guide/ipsec_lib.rst
|
||||
M: Vladimir Medvedkin <vladimir.medvedkin@intel.com>
|
||||
F: app/test/test_ipsec_sad.c
|
||||
F: app/test-sad/
|
||||
|
||||
Flow Classify - EXPERIMENTAL
|
||||
M: Bernard Iremonger <bernard.iremonger@intel.com>
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
18
app/test-sad/Makefile
Normal file
18
app/test-sad/Makefile
Normal file
@ -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
|
667
app/test-sad/main.c
Normal file
667
app/test-sad/main.c
Normal file
@ -0,0 +1,667 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright(c) 2019 Intel Corporation
|
||||
*/
|
||||
|
||||
#include <rte_string_fns.h>
|
||||
#include <rte_ipsec_sad.h>
|
||||
#include <getopt.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <rte_cycles.h>
|
||||
#include <rte_errno.h>
|
||||
#include <rte_ip.h>
|
||||
#include <rte_random.h>
|
||||
#include <rte_malloc.h>
|
||||
|
||||
#define PRINT_USAGE_START "%s [EAL options] --\n"
|
||||
|
||||
#define GET_CB_FIELD(in, fd, base, lim, dlm) do { \
|
||||
unsigned long val; \
|
||||
char *end_fld; \
|
||||
errno = 0; \
|
||||
val = strtoul((in), &end_fld, (base)); \
|
||||
if (errno != 0 || end_fld[0] != (dlm) || val > (lim)) \
|
||||
return -EINVAL; \
|
||||
(fd) = (typeof(fd))val; \
|
||||
(in) = end_fld + 1; \
|
||||
} while (0)
|
||||
|
||||
#define DEF_RULE_NUM 0x10000
|
||||
#define DEF_TUPLES_NUM 0x100000
|
||||
#define BURST_SZ_MAX 64
|
||||
|
||||
static struct {
|
||||
const char *prgname;
|
||||
const char *rules_file;
|
||||
const char *tuples_file;
|
||||
uint32_t nb_rules;
|
||||
uint32_t nb_tuples;
|
||||
uint32_t nb_rules_32;
|
||||
uint32_t nb_rules_64;
|
||||
uint32_t nb_rules_96;
|
||||
uint32_t nb_tuples_rnd;
|
||||
uint32_t burst_sz;
|
||||
uint8_t fract_32;
|
||||
uint8_t fract_64;
|
||||
uint8_t fract_96;
|
||||
uint8_t fract_rnd_tuples;
|
||||
int ipv6;
|
||||
int verbose;
|
||||
int parallel_lookup;
|
||||
int concurrent_rw;
|
||||
} config = {
|
||||
.rules_file = NULL,
|
||||
.tuples_file = NULL,
|
||||
.nb_rules = DEF_RULE_NUM,
|
||||
.nb_tuples = DEF_TUPLES_NUM,
|
||||
.nb_rules_32 = 0,
|
||||
.nb_rules_64 = 0,
|
||||
.nb_rules_96 = 0,
|
||||
.nb_tuples_rnd = 0,
|
||||
.burst_sz = BURST_SZ_MAX,
|
||||
.fract_32 = 90,
|
||||
.fract_64 = 9,
|
||||
.fract_96 = 1,
|
||||
.fract_rnd_tuples = 0,
|
||||
.ipv6 = 0,
|
||||
.verbose = 0,
|
||||
.parallel_lookup = 0,
|
||||
.concurrent_rw = 0
|
||||
};
|
||||
|
||||
enum {
|
||||
CB_RULE_SPI,
|
||||
CB_RULE_DIP,
|
||||
CB_RULE_SIP,
|
||||
CB_RULE_LEN,
|
||||
CB_RULE_NUM,
|
||||
};
|
||||
|
||||
static char line[LINE_MAX];
|
||||
struct rule {
|
||||
union rte_ipsec_sad_key tuple;
|
||||
int rule_type;
|
||||
};
|
||||
|
||||
static struct rule *rules_tbl;
|
||||
static struct rule *tuples_tbl;
|
||||
|
||||
static int
|
||||
parse_distrib(const char *in)
|
||||
{
|
||||
int a, b, c;
|
||||
|
||||
GET_CB_FIELD(in, a, 0, UINT8_MAX, '/');
|
||||
GET_CB_FIELD(in, b, 0, UINT8_MAX, '/');
|
||||
GET_CB_FIELD(in, c, 0, UINT8_MAX, 0);
|
||||
|
||||
if ((a + b + c) != 100)
|
||||
return -EINVAL;
|
||||
|
||||
config.fract_32 = a;
|
||||
config.fract_64 = b;
|
||||
config.fract_96 = c;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
print_config(void)
|
||||
{
|
||||
fprintf(stdout,
|
||||
"Rules total: %u\n"
|
||||
"Configured rules distribution SPI/SPI_DIP/SIP_DIP_SIP:"
|
||||
"%u/%u/%u\n"
|
||||
"SPI only rules: %u\n"
|
||||
"SPI_DIP rules: %u\n"
|
||||
"SPI_DIP_SIP rules: %u\n"
|
||||
"Lookup tuples: %u\n"
|
||||
"Lookup burst size %u\n"
|
||||
"Configured fraction of random tuples: %u\n"
|
||||
"Random lookup tuples: %u\n",
|
||||
config.nb_rules, config.fract_32, config.fract_64,
|
||||
config.fract_96, config.nb_rules_32, config.nb_rules_64,
|
||||
config.nb_rules_96, config.nb_tuples, config.burst_sz,
|
||||
config.fract_rnd_tuples, config.nb_tuples_rnd);
|
||||
}
|
||||
|
||||
static void
|
||||
print_usage(void)
|
||||
{
|
||||
fprintf(stdout,
|
||||
PRINT_USAGE_START
|
||||
"[-f <rules file>]\n"
|
||||
"[-t <tuples file for lookup>]\n"
|
||||
"[-n <rules number (if -f is not specified)>]\n"
|
||||
"[-l <lookup tuples number (if -t is not specified)>]\n"
|
||||
"[-6 <ipv6 tests>]\n"
|
||||
"[-d <\"/\" separated rules length distribution"
|
||||
"(if -f is not specified)>]\n"
|
||||
"[-r <random tuples fraction to lookup"
|
||||
"(if -t is not specified)>]\n"
|
||||
"[-b <lookup burst size: 1-64 >]\n"
|
||||
"[-v <verbose, print results on lookup>]\n"
|
||||
"[-p <parallel lookup on all available cores>]\n"
|
||||
"[-c <init sad supporting read/write concurrency>]\n",
|
||||
config.prgname);
|
||||
|
||||
}
|
||||
|
||||
static int
|
||||
get_str_num(FILE *f, int num)
|
||||
{
|
||||
int n_lines = 0;
|
||||
|
||||
if (f != NULL) {
|
||||
while (fgets(line, sizeof(line), f) != NULL)
|
||||
n_lines++;
|
||||
rewind(f);
|
||||
} else {
|
||||
n_lines = num;
|
||||
}
|
||||
return n_lines;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_file(FILE *f, struct rule *tbl, int rule_tbl)
|
||||
{
|
||||
int ret, i, j = 0;
|
||||
char *s, *sp, *in[CB_RULE_NUM];
|
||||
static const char *dlm = " \t\n";
|
||||
int string_tok_nb = RTE_DIM(in);
|
||||
|
||||
string_tok_nb -= (rule_tbl == 0) ? 1 : 0;
|
||||
while (fgets(line, sizeof(line), f) != NULL) {
|
||||
s = line;
|
||||
for (i = 0; i != string_tok_nb; i++) {
|
||||
in[i] = strtok_r(s, dlm, &sp);
|
||||
if (in[i] == NULL)
|
||||
return -EINVAL;
|
||||
s = NULL;
|
||||
}
|
||||
GET_CB_FIELD(in[CB_RULE_SPI], tbl[j].tuple.v4.spi, 0,
|
||||
UINT32_MAX, 0);
|
||||
|
||||
if (config.ipv6)
|
||||
ret = inet_pton(AF_INET6, in[CB_RULE_DIP],
|
||||
&tbl[j].tuple.v6.dip);
|
||||
else
|
||||
ret = inet_pton(AF_INET, in[CB_RULE_DIP],
|
||||
&tbl[j].tuple.v4.dip);
|
||||
if (ret != 1)
|
||||
return -EINVAL;
|
||||
if (config.ipv6)
|
||||
ret = inet_pton(AF_INET6, in[CB_RULE_SIP],
|
||||
&tbl[j].tuple.v6.sip);
|
||||
else
|
||||
ret = inet_pton(AF_INET, in[CB_RULE_SIP],
|
||||
&tbl[j].tuple.v4.sip);
|
||||
if (ret != 1)
|
||||
return -EINVAL;
|
||||
if ((rule_tbl) && (in[CB_RULE_LEN] != NULL)) {
|
||||
if (strcmp(in[CB_RULE_LEN], "SPI_DIP_SIP") == 0) {
|
||||
tbl[j].rule_type = RTE_IPSEC_SAD_SPI_DIP_SIP;
|
||||
config.nb_rules_96++;
|
||||
} else if (strcmp(in[CB_RULE_LEN], "SPI_DIP") == 0) {
|
||||
tbl[j].rule_type = RTE_IPSEC_SAD_SPI_DIP;
|
||||
config.nb_rules_64++;
|
||||
} else if (strcmp(in[CB_RULE_LEN], "SPI") == 0) {
|
||||
tbl[j].rule_type = RTE_IPSEC_SAD_SPI_ONLY;
|
||||
config.nb_rules_32++;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
j++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
get_rnd_rng(uint64_t l, uint64_t u)
|
||||
{
|
||||
if (l == u)
|
||||
return l;
|
||||
else
|
||||
return (rte_rand() % (u - l) + l);
|
||||
}
|
||||
|
||||
static void
|
||||
get_random_rules(struct rule *tbl, uint32_t nb_rules, int rule_tbl)
|
||||
{
|
||||
unsigned int i, j, rnd;
|
||||
int rule_type;
|
||||
double edge = 0;
|
||||
double step;
|
||||
|
||||
step = (double)UINT32_MAX / nb_rules;
|
||||
for (i = 0; i < nb_rules; i++, edge += step) {
|
||||
rnd = rte_rand() % 100;
|
||||
if (rule_tbl) {
|
||||
tbl[i].tuple.v4.spi = get_rnd_rng((uint64_t)edge,
|
||||
(uint64_t)(edge + step));
|
||||
if (config.ipv6) {
|
||||
for (j = 0; j < 16; j++) {
|
||||
tbl[i].tuple.v6.dip[j] = rte_rand();
|
||||
tbl[i].tuple.v6.sip[j] = rte_rand();
|
||||
}
|
||||
} else {
|
||||
tbl[i].tuple.v4.dip = rte_rand();
|
||||
tbl[i].tuple.v4.sip = rte_rand();
|
||||
}
|
||||
if (rnd >= (100UL - config.fract_32)) {
|
||||
rule_type = RTE_IPSEC_SAD_SPI_ONLY;
|
||||
config.nb_rules_32++;
|
||||
} else if (rnd >= (100UL - (config.fract_32 +
|
||||
config.fract_64))) {
|
||||
rule_type = RTE_IPSEC_SAD_SPI_DIP;
|
||||
config.nb_rules_64++;
|
||||
} else {
|
||||
rule_type = RTE_IPSEC_SAD_SPI_DIP_SIP;
|
||||
config.nb_rules_96++;
|
||||
}
|
||||
tbl[i].rule_type = rule_type;
|
||||
} else {
|
||||
if (rnd >= 100UL - config.fract_rnd_tuples) {
|
||||
tbl[i].tuple.v4.spi =
|
||||
get_rnd_rng((uint64_t)edge,
|
||||
(uint64_t)(edge + step));
|
||||
if (config.ipv6) {
|
||||
for (j = 0; j < 16; j++) {
|
||||
tbl[i].tuple.v6.dip[j] =
|
||||
rte_rand();
|
||||
tbl[i].tuple.v6.sip[j] =
|
||||
rte_rand();
|
||||
}
|
||||
} else {
|
||||
tbl[i].tuple.v4.dip = rte_rand();
|
||||
tbl[i].tuple.v4.sip = rte_rand();
|
||||
}
|
||||
config.nb_tuples_rnd++;
|
||||
} else {
|
||||
tbl[i].tuple.v4.spi = rules_tbl[i %
|
||||
config.nb_rules].tuple.v4.spi;
|
||||
if (config.ipv6) {
|
||||
int r_idx = i % config.nb_rules;
|
||||
memcpy(tbl[i].tuple.v6.dip,
|
||||
rules_tbl[r_idx].tuple.v6.dip,
|
||||
sizeof(tbl[i].tuple.v6.dip));
|
||||
memcpy(tbl[i].tuple.v6.sip,
|
||||
rules_tbl[r_idx].tuple.v6.sip,
|
||||
sizeof(tbl[i].tuple.v6.sip));
|
||||
} else {
|
||||
tbl[i].tuple.v4.dip = rules_tbl[i %
|
||||
config.nb_rules].tuple.v4.dip;
|
||||
tbl[i].tuple.v4.sip = rules_tbl[i %
|
||||
config.nb_rules].tuple.v4.sip;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tbl_init(struct rule **tbl, uint32_t *n_entries,
|
||||
const char *file_name, int rule_tbl)
|
||||
{
|
||||
FILE *f = NULL;
|
||||
int ret;
|
||||
const char *rules = "rules";
|
||||
const char *tuples = "tuples";
|
||||
|
||||
if (file_name != NULL) {
|
||||
f = fopen(file_name, "r");
|
||||
if (f == NULL)
|
||||
rte_exit(-EINVAL, "failed to open file: %s\n",
|
||||
file_name);
|
||||
}
|
||||
|
||||
printf("init %s table...", (rule_tbl) ? rules : tuples);
|
||||
*n_entries = get_str_num(f, *n_entries);
|
||||
printf("%d entries\n", *n_entries);
|
||||
*tbl = rte_zmalloc(NULL, sizeof(struct rule) * *n_entries,
|
||||
RTE_CACHE_LINE_SIZE);
|
||||
if (*tbl == NULL)
|
||||
rte_exit(-ENOMEM, "failed to allocate tbl\n");
|
||||
|
||||
if (f != NULL) {
|
||||
printf("parse file %s\n", file_name);
|
||||
ret = parse_file(f, *tbl, rule_tbl);
|
||||
if (ret != 0)
|
||||
rte_exit(-EINVAL, "failed to parse file %s\n"
|
||||
"rules file must be: "
|
||||
"<uint32_t: spi> <space> "
|
||||
"<ip_addr: dip> <space> "
|
||||
"<ip_addr: sip> <space> "
|
||||
"<string: SPI|SPI_DIP|SIP_DIP_SIP>\n"
|
||||
"tuples file must be: "
|
||||
"<uint32_t: spi> <space> "
|
||||
"<ip_addr: dip> <space> "
|
||||
"<ip_addr: sip>\n",
|
||||
file_name);
|
||||
} else {
|
||||
printf("generate random values in %s table\n",
|
||||
(rule_tbl) ? rules : tuples);
|
||||
get_random_rules(*tbl, *n_entries, rule_tbl);
|
||||
}
|
||||
if (f != NULL)
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
static void
|
||||
parse_opts(int argc, char **argv)
|
||||
{
|
||||
int opt, ret;
|
||||
char *endptr;
|
||||
|
||||
while ((opt = getopt(argc, argv, "f:t:n:d:l:r:6b:vpc")) != -1) {
|
||||
switch (opt) {
|
||||
case 'f':
|
||||
config.rules_file = optarg;
|
||||
break;
|
||||
case 't':
|
||||
config.tuples_file = optarg;
|
||||
break;
|
||||
case 'n':
|
||||
errno = 0;
|
||||
config.nb_rules = strtoul(optarg, &endptr, 10);
|
||||
if ((errno != 0) || (config.nb_rules == 0) ||
|
||||
(endptr[0] != 0)) {
|
||||
print_usage();
|
||||
rte_exit(-EINVAL, "Invalid option -n\n");
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
ret = parse_distrib(optarg);
|
||||
if (ret != 0) {
|
||||
print_usage();
|
||||
rte_exit(-EINVAL, "Invalid option -d\n");
|
||||
}
|
||||
break;
|
||||
case 'b':
|
||||
errno = 0;
|
||||
config.burst_sz = strtoul(optarg, &endptr, 10);
|
||||
if ((errno != 0) || (config.burst_sz == 0) ||
|
||||
(config.burst_sz > BURST_SZ_MAX) ||
|
||||
(endptr[0] != 0)) {
|
||||
print_usage();
|
||||
rte_exit(-EINVAL, "Invalid option -b\n");
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
errno = 0;
|
||||
config.nb_tuples = strtoul(optarg, &endptr, 10);
|
||||
if ((errno != 0) || (config.nb_tuples == 0) ||
|
||||
(endptr[0] != 0)) {
|
||||
print_usage();
|
||||
rte_exit(-EINVAL, "Invalid option -l\n");
|
||||
}
|
||||
break;
|
||||
case 'r':
|
||||
errno = 0;
|
||||
config.fract_rnd_tuples = strtoul(optarg, &endptr, 10);
|
||||
if ((errno != 0) || (config.fract_rnd_tuples == 0) ||
|
||||
(config.fract_rnd_tuples >= 100) ||
|
||||
(endptr[0] != 0)) {
|
||||
print_usage();
|
||||
rte_exit(-EINVAL, "Invalid option -r\n");
|
||||
}
|
||||
break;
|
||||
case '6':
|
||||
config.ipv6 = 1;
|
||||
break;
|
||||
case 'v':
|
||||
config.verbose = 1;
|
||||
break;
|
||||
case 'p':
|
||||
config.parallel_lookup = 1;
|
||||
break;
|
||||
case 'c':
|
||||
config.concurrent_rw = 1;
|
||||
break;
|
||||
default:
|
||||
print_usage();
|
||||
rte_exit(-EINVAL, "Invalid options\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
print_addr(int af, const void *addr)
|
||||
{
|
||||
char str[INET6_ADDRSTRLEN];
|
||||
const char *ret;
|
||||
|
||||
ret = inet_ntop(af, addr, str, sizeof(str));
|
||||
if (ret != NULL)
|
||||
printf("%s", str);
|
||||
}
|
||||
|
||||
static void
|
||||
print_tuple(int af, uint32_t spi, const void *dip, const void *sip)
|
||||
{
|
||||
|
||||
printf("<SPI: %u DIP: ", spi);
|
||||
print_addr(af, dip);
|
||||
printf(" SIP: ");
|
||||
print_addr(af, sip);
|
||||
printf(">");
|
||||
}
|
||||
|
||||
static void
|
||||
print_result(const union rte_ipsec_sad_key *key, void *res)
|
||||
{
|
||||
struct rule *rule = res;
|
||||
const struct rte_ipsec_sadv4_key *v4;
|
||||
const struct rte_ipsec_sadv6_key *v6;
|
||||
const char *spi_only = "SPI_ONLY";
|
||||
const char *spi_dip = "SPI_DIP";
|
||||
const char *spi_dip_sip = "SPI_DIP_SIP";
|
||||
const char *rule_type;
|
||||
const void *dip, *sip;
|
||||
uint32_t spi;
|
||||
int af;
|
||||
|
||||
af = (config.ipv6) ? AF_INET6 : AF_INET;
|
||||
v4 = &key->v4;
|
||||
v6 = &key->v6;
|
||||
spi = (config.ipv6 == 0) ? v4->spi : v6->spi;
|
||||
dip = (config.ipv6 == 0) ? &v4->dip : (const void *)v6->dip;
|
||||
sip = (config.ipv6 == 0) ? &v4->sip : (const void *)v6->sip;
|
||||
|
||||
if (res == NULL) {
|
||||
printf("TUPLE: ");
|
||||
print_tuple(af, spi, dip, sip);
|
||||
printf(" not found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (rule->rule_type) {
|
||||
case RTE_IPSEC_SAD_SPI_ONLY:
|
||||
rule_type = spi_only;
|
||||
break;
|
||||
case RTE_IPSEC_SAD_SPI_DIP:
|
||||
rule_type = spi_dip;
|
||||
break;
|
||||
case RTE_IPSEC_SAD_SPI_DIP_SIP:
|
||||
rule_type = spi_dip_sip;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
print_tuple(af, spi, dip, sip);
|
||||
v4 = &rule->tuple.v4;
|
||||
v6 = &rule->tuple.v6;
|
||||
spi = (config.ipv6 == 0) ? v4->spi : v6->spi;
|
||||
dip = (config.ipv6 == 0) ? &v4->dip : (const void *)v6->dip;
|
||||
sip = (config.ipv6 == 0) ? &v4->sip : (const void *)v6->sip;
|
||||
printf("\n\tpoints to RULE ID %zu ",
|
||||
RTE_PTR_DIFF(res, rules_tbl)/sizeof(struct rule));
|
||||
print_tuple(af, spi, dip, sip);
|
||||
printf(" %s\n", rule_type);
|
||||
}
|
||||
|
||||
static int
|
||||
lookup(void *arg)
|
||||
{
|
||||
int ret;
|
||||
unsigned int i, j;
|
||||
const union rte_ipsec_sad_key *keys[BURST_SZ_MAX];
|
||||
void *vals[BURST_SZ_MAX];
|
||||
uint64_t start, acc = 0;
|
||||
uint32_t burst_sz;
|
||||
struct rte_ipsec_sad *sad = arg;
|
||||
|
||||
burst_sz = RTE_MIN(config.burst_sz, config.nb_tuples);
|
||||
for (i = 0; i < config.nb_tuples; i += burst_sz) {
|
||||
for (j = 0; j < burst_sz; j++)
|
||||
keys[j] = (union rte_ipsec_sad_key *)
|
||||
(&tuples_tbl[i + j].tuple);
|
||||
start = rte_rdtsc_precise();
|
||||
ret = rte_ipsec_sad_lookup(sad, keys, vals, burst_sz);
|
||||
acc += rte_rdtsc_precise() - start;
|
||||
if (ret < 0)
|
||||
rte_exit(-EINVAL, "Lookup failed\n");
|
||||
if (config.verbose) {
|
||||
for (j = 0; j < burst_sz; j++)
|
||||
print_result(keys[j], vals[j]);
|
||||
}
|
||||
}
|
||||
printf("Average lookup cycles %.2Lf, lookups/sec: %.2Lf\n",
|
||||
(long double)acc / config.nb_tuples,
|
||||
(long double)config.nb_tuples * rte_get_tsc_hz() / acc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
add_rules(struct rte_ipsec_sad *sad, uint32_t fract)
|
||||
{
|
||||
int32_t ret;
|
||||
uint32_t i, j, f, fn, n;
|
||||
uint64_t start, tm[fract + 1];
|
||||
uint32_t nm[fract + 1];
|
||||
|
||||
f = (config.nb_rules > fract) ? config.nb_rules / fract : 1;
|
||||
|
||||
for (n = 0, j = 0; n != config.nb_rules; n = fn, j++) {
|
||||
|
||||
fn = n + f;
|
||||
fn = fn > config.nb_rules ? config.nb_rules : fn;
|
||||
|
||||
start = rte_rdtsc_precise();
|
||||
for (i = n; i != fn; i++) {
|
||||
ret = rte_ipsec_sad_add(sad,
|
||||
&rules_tbl[i].tuple,
|
||||
rules_tbl[i].rule_type, &rules_tbl[i]);
|
||||
if (ret != 0)
|
||||
rte_exit(ret, "%s failed @ %u-th rule\n",
|
||||
__func__, i);
|
||||
}
|
||||
tm[j] = rte_rdtsc_precise() - start;
|
||||
nm[j] = fn - n;
|
||||
}
|
||||
|
||||
for (i = 0; i != j; i++)
|
||||
printf("ADD %u rules, %.2Lf cycles/rule, %.2Lf ADD/sec\n",
|
||||
nm[i], (long double)tm[i] / nm[i],
|
||||
(long double)nm[i] * rte_get_tsc_hz() / tm[i]);
|
||||
}
|
||||
|
||||
static void
|
||||
del_rules(struct rte_ipsec_sad *sad, uint32_t fract)
|
||||
{
|
||||
int32_t ret;
|
||||
uint32_t i, j, f, fn, n;
|
||||
uint64_t start, tm[fract + 1];
|
||||
uint32_t nm[fract + 1];
|
||||
|
||||
f = (config.nb_rules > fract) ? config.nb_rules / fract : 1;
|
||||
|
||||
for (n = 0, j = 0; n != config.nb_rules; n = fn, j++) {
|
||||
|
||||
fn = n + f;
|
||||
fn = fn > config.nb_rules ? config.nb_rules : fn;
|
||||
|
||||
start = rte_rdtsc_precise();
|
||||
for (i = n; i != fn; i++) {
|
||||
ret = rte_ipsec_sad_del(sad,
|
||||
&rules_tbl[i].tuple,
|
||||
rules_tbl[i].rule_type);
|
||||
if (ret != 0 && ret != -ENOENT)
|
||||
rte_exit(ret, "%s failed @ %u-th rule\n",
|
||||
__func__, i);
|
||||
}
|
||||
tm[j] = rte_rdtsc_precise() - start;
|
||||
nm[j] = fn - n;
|
||||
}
|
||||
|
||||
for (i = 0; i != j; i++)
|
||||
printf("DEL %u rules, %.2Lf cycles/rule, %.2Lf DEL/sec\n",
|
||||
nm[i], (long double)tm[i] / nm[i],
|
||||
(long double)nm[i] * rte_get_tsc_hz() / tm[i]);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int ret;
|
||||
struct rte_ipsec_sad *sad;
|
||||
struct rte_ipsec_sad_conf conf;
|
||||
unsigned int lcore_id;
|
||||
|
||||
ret = rte_eal_init(argc, argv);
|
||||
if (ret < 0)
|
||||
rte_panic("Cannot init EAL\n");
|
||||
|
||||
argc -= ret;
|
||||
argv += ret;
|
||||
|
||||
config.prgname = argv[0];
|
||||
|
||||
parse_opts(argc, argv);
|
||||
tbl_init(&rules_tbl, &config.nb_rules, config.rules_file, 1);
|
||||
tbl_init(&tuples_tbl, &config.nb_tuples, config.tuples_file, 0);
|
||||
if (config.rules_file != NULL) {
|
||||
config.fract_32 = (100 * config.nb_rules_32) / config.nb_rules;
|
||||
config.fract_64 = (100 * config.nb_rules_64) / config.nb_rules;
|
||||
config.fract_96 = (100 * config.nb_rules_96) / config.nb_rules;
|
||||
}
|
||||
if (config.tuples_file != NULL) {
|
||||
config.fract_rnd_tuples = 0;
|
||||
config.nb_tuples_rnd = 0;
|
||||
}
|
||||
conf.socket_id = -1;
|
||||
conf.max_sa[RTE_IPSEC_SAD_SPI_ONLY] = config.nb_rules_32 * 5 / 4;
|
||||
conf.max_sa[RTE_IPSEC_SAD_SPI_DIP] = config.nb_rules_64 * 5 / 4;
|
||||
conf.max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP] = config.nb_rules_96 * 5 / 4;
|
||||
if (config.ipv6)
|
||||
conf.flags |= RTE_IPSEC_SAD_FLAG_IPV6;
|
||||
if (config.concurrent_rw)
|
||||
conf.flags |= RTE_IPSEC_SAD_FLAG_RW_CONCURRENCY;
|
||||
sad = rte_ipsec_sad_create("test", &conf);
|
||||
if (sad == NULL)
|
||||
rte_exit(-rte_errno, "can not allocate SAD table\n");
|
||||
|
||||
print_config();
|
||||
|
||||
add_rules(sad, 10);
|
||||
if (config.parallel_lookup)
|
||||
rte_eal_mp_remote_launch(lookup, sad, SKIP_MASTER);
|
||||
|
||||
lookup(sad);
|
||||
if (config.parallel_lookup)
|
||||
RTE_LCORE_FOREACH_SLAVE(lcore_id)
|
||||
if (rte_eal_wait_lcore(lcore_id) < 0)
|
||||
return -1;
|
||||
|
||||
del_rules(sad, 10);
|
||||
|
||||
return 0;
|
||||
}
|
6
app/test-sad/meson.build
Normal file
6
app/test-sad/meson.build
Normal file
@ -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']
|
@ -138,7 +138,9 @@ New Features
|
||||
|
||||
* **Updated the IPSec library.**
|
||||
|
||||
Added SA Database API to ``librte_ipsec``.
|
||||
Added SA Database API to ``librte_ipsec``. A new test-sad application is also
|
||||
introduced to evaluate and perform custom functional and performance tests
|
||||
for IPsec SAD implementation.
|
||||
|
||||
* **Introduced FIFO for NTB PMD.**
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user