dpdk/app/test-sad/main.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright(c) 2019 Intel Corporation
   3 */
   4
   5#include <rte_string_fns.h>
   6#include <rte_ipsec_sad.h>
   7#include <getopt.h>
   8#include <string.h>
   9#include <stdio.h>
  10#include <sys/types.h>
  11#include <sys/socket.h>
  12#include <netinet/in.h>
  13#include <arpa/inet.h>
  14
  15#include <rte_cycles.h>
  16#include <rte_errno.h>
  17#include <rte_ip.h>
  18#include <rte_random.h>
  19#include <rte_malloc.h>
  20
  21#define PRINT_USAGE_START       "%s [EAL options] --\n"
  22
  23#define GET_CB_FIELD(in, fd, base, lim, dlm)    do {            \
  24        unsigned long val;                                      \
  25        char *end_fld;                                          \
  26        errno = 0;                                              \
  27        val = strtoul((in), &end_fld, (base));                  \
  28        if (errno != 0 || end_fld[0] != (dlm) || val > (lim))   \
  29                return -EINVAL;                                 \
  30        (fd) = (typeof(fd))val;                                 \
  31        (in) = end_fld + 1;                                     \
  32} while (0)
  33
  34#define DEF_RULE_NUM            0x10000
  35#define DEF_TUPLES_NUM  0x100000
  36#define BURST_SZ_MAX    64
  37
  38static struct {
  39        const char      *prgname;
  40        const char      *rules_file;
  41        const char      *tuples_file;
  42        uint32_t        nb_rules;
  43        uint32_t        nb_tuples;
  44        uint32_t        nb_rules_32;
  45        uint32_t        nb_rules_64;
  46        uint32_t        nb_rules_96;
  47        uint32_t        nb_tuples_rnd;
  48        uint32_t        burst_sz;
  49        uint8_t         fract_32;
  50        uint8_t         fract_64;
  51        uint8_t         fract_96;
  52        uint8_t         fract_rnd_tuples;
  53        int             ipv6;
  54        int             verbose;
  55        int             parallel_lookup;
  56        int             concurrent_rw;
  57} config = {
  58        .rules_file = NULL,
  59        .tuples_file = NULL,
  60        .nb_rules = DEF_RULE_NUM,
  61        .nb_tuples = DEF_TUPLES_NUM,
  62        .nb_rules_32 = 0,
  63        .nb_rules_64 = 0,
  64        .nb_rules_96 = 0,
  65        .nb_tuples_rnd = 0,
  66        .burst_sz = BURST_SZ_MAX,
  67        .fract_32 = 90,
  68        .fract_64 = 9,
  69        .fract_96 = 1,
  70        .fract_rnd_tuples = 0,
  71        .ipv6 = 0,
  72        .verbose = 0,
  73        .parallel_lookup = 0,
  74        .concurrent_rw = 0
  75};
  76
  77enum {
  78        CB_RULE_SPI,
  79        CB_RULE_DIP,
  80        CB_RULE_SIP,
  81        CB_RULE_LEN,
  82        CB_RULE_NUM,
  83};
  84
  85static char line[LINE_MAX];
  86struct rule {
  87        union rte_ipsec_sad_key tuple;
  88        int rule_type;
  89};
  90
  91static struct rule *rules_tbl;
  92static struct rule *tuples_tbl;
  93
  94static int
  95parse_distrib(const char *in)
  96{
  97        int a, b, c;
  98
  99        GET_CB_FIELD(in, a, 0, UINT8_MAX, '/');
 100        GET_CB_FIELD(in, b, 0, UINT8_MAX, '/');
 101        GET_CB_FIELD(in, c, 0, UINT8_MAX, 0);
 102
 103        if ((a + b + c) != 100)
 104                return -EINVAL;
 105
 106        config.fract_32 = a;
 107        config.fract_64 = b;
 108        config.fract_96 = c;
 109
 110        return 0;
 111}
 112
 113static void
 114print_config(void)
 115{
 116        fprintf(stdout,
 117                "Rules total: %u\n"
 118                "Configured rules distribution SPI/SPI_DIP/SIP_DIP_SIP:"
 119                "%u/%u/%u\n"
 120                "SPI only rules: %u\n"
 121                "SPI_DIP  rules: %u\n"
 122                "SPI_DIP_SIP rules: %u\n"
 123                "Lookup tuples: %u\n"
 124                "Lookup burst size %u\n"
 125                "Configured fraction of random tuples: %u\n"
 126                "Random lookup tuples: %u\n",
 127                config.nb_rules, config.fract_32, config.fract_64,
 128                config.fract_96, config.nb_rules_32, config.nb_rules_64,
 129                config.nb_rules_96, config.nb_tuples, config.burst_sz,
 130                config.fract_rnd_tuples, config.nb_tuples_rnd);
 131}
 132
 133static void
 134print_usage(void)
 135{
 136        fprintf(stdout,
 137                PRINT_USAGE_START
 138                "[-f <rules file>]\n"
 139                "[-t <tuples file for lookup>]\n"
 140                "[-n <rules number (if -f is not specified)>]\n"
 141                "[-l <lookup tuples number (if -t is not specified)>]\n"
 142                "[-6 <ipv6 tests>]\n"
 143                "[-d <\"/\" separated rules length distribution"
 144                "(if -f is not specified)>]\n"
 145                "[-r <random tuples fraction to lookup"
 146                "(if -t is not specified)>]\n"
 147                "[-b <lookup burst size: 1-64 >]\n"
 148                "[-v <verbose, print results on lookup>]\n"
 149                "[-p <parallel lookup on all available cores>]\n"
 150                "[-c <init sad supporting read/write concurrency>]\n",
 151                config.prgname);
 152
 153}
 154
 155static int
 156get_str_num(FILE *f, int num)
 157{
 158        int n_lines = 0;
 159
 160        if (f != NULL) {
 161                while (fgets(line, sizeof(line), f) != NULL)
 162                        n_lines++;
 163                rewind(f);
 164        } else {
 165                n_lines = num;
 166        }
 167        return n_lines;
 168}
 169
 170static int
 171parse_file(FILE *f, struct rule *tbl, int rule_tbl)
 172{
 173        int ret, i, j = 0;
 174        char *s, *sp, *in[CB_RULE_NUM];
 175        static const char *dlm = " \t\n";
 176        int string_tok_nb = RTE_DIM(in);
 177
 178        string_tok_nb -= (rule_tbl == 0) ? 1 : 0;
 179        while (fgets(line, sizeof(line), f) != NULL) {
 180                s = line;
 181                for (i = 0; i != string_tok_nb; i++) {
 182                        in[i] = strtok_r(s, dlm, &sp);
 183                        if (in[i] == NULL)
 184                                return -EINVAL;
 185                        s = NULL;
 186                }
 187                GET_CB_FIELD(in[CB_RULE_SPI], tbl[j].tuple.v4.spi, 0,
 188                                UINT32_MAX, 0);
 189
 190                if (config.ipv6)
 191                        ret = inet_pton(AF_INET6, in[CB_RULE_DIP],
 192                                &tbl[j].tuple.v6.dip);
 193                else
 194                        ret = inet_pton(AF_INET, in[CB_RULE_DIP],
 195                                &tbl[j].tuple.v4.dip);
 196                if (ret != 1)
 197                        return -EINVAL;
 198                if (config.ipv6)
 199                        ret = inet_pton(AF_INET6, in[CB_RULE_SIP],
 200                                &tbl[j].tuple.v6.sip);
 201                else
 202                        ret = inet_pton(AF_INET, in[CB_RULE_SIP],
 203                                &tbl[j].tuple.v4.sip);
 204                if (ret != 1)
 205                        return -EINVAL;
 206                if ((rule_tbl) && (in[CB_RULE_LEN] != NULL)) {
 207                        if (strcmp(in[CB_RULE_LEN], "SPI_DIP_SIP") == 0) {
 208                                tbl[j].rule_type = RTE_IPSEC_SAD_SPI_DIP_SIP;
 209                                config.nb_rules_96++;
 210                        } else if (strcmp(in[CB_RULE_LEN], "SPI_DIP") == 0) {
 211                                tbl[j].rule_type = RTE_IPSEC_SAD_SPI_DIP;
 212                                config.nb_rules_64++;
 213                        } else if (strcmp(in[CB_RULE_LEN], "SPI") == 0) {
 214                                tbl[j].rule_type = RTE_IPSEC_SAD_SPI_ONLY;
 215                                config.nb_rules_32++;
 216                        } else {
 217                                return -EINVAL;
 218                        }
 219                }
 220                j++;
 221        }
 222        return 0;
 223}
 224
 225static uint64_t
 226get_rnd_rng(uint64_t l, uint64_t u)
 227{
 228        if (l == u)
 229                return l;
 230        else
 231                return (rte_rand() % (u - l) + l);
 232}
 233
 234static void
 235get_random_rules(struct rule *tbl, uint32_t nb_rules, int rule_tbl)
 236{
 237        unsigned int i, j, rnd;
 238        int rule_type;
 239        double edge = 0;
 240        double step;
 241
 242        step = (double)UINT32_MAX / nb_rules;
 243        for (i = 0; i < nb_rules; i++, edge += step) {
 244                rnd = rte_rand() % 100;
 245                if (rule_tbl) {
 246                        tbl[i].tuple.v4.spi = get_rnd_rng((uint64_t)edge,
 247                                                (uint64_t)(edge + step));
 248                        if (config.ipv6) {
 249                                for (j = 0; j < 16; j++) {
 250                                        tbl[i].tuple.v6.dip[j] = rte_rand();
 251                                        tbl[i].tuple.v6.sip[j] = rte_rand();
 252                                }
 253                        } else {
 254                                tbl[i].tuple.v4.dip = rte_rand();
 255                                tbl[i].tuple.v4.sip = rte_rand();
 256                        }
 257                        if (rnd >= (100UL - config.fract_32)) {
 258                                rule_type = RTE_IPSEC_SAD_SPI_ONLY;
 259                                config.nb_rules_32++;
 260                        } else if (rnd >= (100UL - (config.fract_32 +
 261                                        config.fract_64))) {
 262                                rule_type = RTE_IPSEC_SAD_SPI_DIP;
 263                                config.nb_rules_64++;
 264                        } else {
 265                                rule_type = RTE_IPSEC_SAD_SPI_DIP_SIP;
 266                                config.nb_rules_96++;
 267                        }
 268                        tbl[i].rule_type = rule_type;
 269                } else {
 270                        if (rnd >= 100UL - config.fract_rnd_tuples) {
 271                                tbl[i].tuple.v4.spi =
 272                                        get_rnd_rng((uint64_t)edge,
 273                                        (uint64_t)(edge + step));
 274                                if (config.ipv6) {
 275                                        for (j = 0; j < 16; j++) {
 276                                                tbl[i].tuple.v6.dip[j] =
 277                                                                rte_rand();
 278                                                tbl[i].tuple.v6.sip[j] =
 279                                                                rte_rand();
 280                                        }
 281                                } else {
 282                                        tbl[i].tuple.v4.dip = rte_rand();
 283                                        tbl[i].tuple.v4.sip = rte_rand();
 284                                }
 285                                config.nb_tuples_rnd++;
 286                        } else {
 287                                tbl[i].tuple.v4.spi = rules_tbl[i %
 288                                        config.nb_rules].tuple.v4.spi;
 289                                if (config.ipv6) {
 290                                        int r_idx = i % config.nb_rules;
 291                                        memcpy(tbl[i].tuple.v6.dip,
 292                                                rules_tbl[r_idx].tuple.v6.dip,
 293                                                sizeof(tbl[i].tuple.v6.dip));
 294                                        memcpy(tbl[i].tuple.v6.sip,
 295                                                rules_tbl[r_idx].tuple.v6.sip,
 296                                                sizeof(tbl[i].tuple.v6.sip));
 297                                } else {
 298                                        tbl[i].tuple.v4.dip = rules_tbl[i %
 299                                                config.nb_rules].tuple.v4.dip;
 300                                        tbl[i].tuple.v4.sip = rules_tbl[i %
 301                                                config.nb_rules].tuple.v4.sip;
 302                                }
 303                        }
 304                }
 305        }
 306}
 307
 308static void
 309tbl_init(struct rule **tbl, uint32_t *n_entries,
 310        const char *file_name, int rule_tbl)
 311{
 312        FILE *f = NULL;
 313        int ret;
 314        const char *rules = "rules";
 315        const char *tuples = "tuples";
 316
 317        if (file_name != NULL) {
 318                f = fopen(file_name, "r");
 319                if (f == NULL)
 320                        rte_exit(-EINVAL, "failed to open file: %s\n",
 321                                file_name);
 322        }
 323
 324        printf("init %s table...", (rule_tbl) ? rules : tuples);
 325        *n_entries = get_str_num(f, *n_entries);
 326        printf("%d entries\n", *n_entries);
 327        *tbl = rte_zmalloc(NULL, sizeof(struct rule) * *n_entries,
 328                RTE_CACHE_LINE_SIZE);
 329        if (*tbl == NULL)
 330                rte_exit(-ENOMEM, "failed to allocate tbl\n");
 331
 332        if (f != NULL) {
 333                printf("parse file %s\n", file_name);
 334                ret = parse_file(f, *tbl, rule_tbl);
 335                if (ret != 0)
 336                        rte_exit(-EINVAL, "failed to parse file %s\n"
 337                                "rules file must be: "
 338                                "<uint32_t: spi> <space> "
 339                                "<ip_addr: dip> <space> "
 340                                "<ip_addr: sip> <space> "
 341                                "<string: SPI|SPI_DIP|SIP_DIP_SIP>\n"
 342                                "tuples file must be: "
 343                                "<uint32_t: spi> <space> "
 344                                "<ip_addr: dip> <space> "
 345                                "<ip_addr: sip>\n",
 346                                file_name);
 347        } else {
 348                printf("generate random values in %s table\n",
 349                        (rule_tbl) ? rules : tuples);
 350                get_random_rules(*tbl, *n_entries, rule_tbl);
 351        }
 352        if (f != NULL)
 353                fclose(f);
 354}
 355
 356static void
 357parse_opts(int argc, char **argv)
 358{
 359        int opt, ret;
 360        char *endptr;
 361
 362        while ((opt = getopt(argc, argv, "f:t:n:d:l:r:6b:vpc")) != -1) {
 363                switch (opt) {
 364                case 'f':
 365                        config.rules_file = optarg;
 366                        break;
 367                case 't':
 368                        config.tuples_file = optarg;
 369                        break;
 370                case 'n':
 371                        errno = 0;
 372                        config.nb_rules = strtoul(optarg, &endptr, 10);
 373                        if ((errno != 0) || (config.nb_rules == 0) ||
 374                                        (endptr[0] != 0)) {
 375                                print_usage();
 376                                rte_exit(-EINVAL, "Invalid option -n\n");
 377                        }
 378                        break;
 379                case 'd':
 380                        ret = parse_distrib(optarg);
 381                        if (ret != 0) {
 382                                print_usage();
 383                                rte_exit(-EINVAL, "Invalid option -d\n");
 384                        }
 385                        break;
 386                case 'b':
 387                        errno = 0;
 388                        config.burst_sz = strtoul(optarg, &endptr, 10);
 389                        if ((errno != 0) || (config.burst_sz == 0) ||
 390                                        (config.burst_sz > BURST_SZ_MAX) ||
 391                                        (endptr[0] != 0)) {
 392                                print_usage();
 393                                rte_exit(-EINVAL, "Invalid option -b\n");
 394                        }
 395                        break;
 396                case 'l':
 397                        errno = 0;
 398                        config.nb_tuples = strtoul(optarg, &endptr, 10);
 399                        if ((errno != 0) || (config.nb_tuples == 0) ||
 400                                        (endptr[0] != 0)) {
 401                                print_usage();
 402                                rte_exit(-EINVAL, "Invalid option -l\n");
 403                        }
 404                        break;
 405                case 'r':
 406                        errno = 0;
 407                        config.fract_rnd_tuples = strtoul(optarg, &endptr, 10);
 408                        if ((errno != 0) || (config.fract_rnd_tuples == 0) ||
 409                                        (config.fract_rnd_tuples >= 100) ||
 410                                        (endptr[0] != 0)) {
 411                                print_usage();
 412                                rte_exit(-EINVAL, "Invalid option -r\n");
 413                        }
 414                        break;
 415                case '6':
 416                        config.ipv6 = 1;
 417                        break;
 418                case 'v':
 419                        config.verbose = 1;
 420                        break;
 421                case 'p':
 422                        config.parallel_lookup = 1;
 423                        break;
 424                case 'c':
 425                        config.concurrent_rw = 1;
 426                        break;
 427                default:
 428                        print_usage();
 429                        rte_exit(-EINVAL, "Invalid options\n");
 430                }
 431        }
 432}
 433
 434static void
 435print_addr(int af, const void *addr)
 436{
 437        char str[INET6_ADDRSTRLEN];
 438        const char *ret;
 439
 440        ret = inet_ntop(af, addr, str, sizeof(str));
 441        if (ret != NULL)
 442                printf("%s", str);
 443}
 444
 445static void
 446print_tuple(int af, uint32_t spi, const void *dip, const void *sip)
 447{
 448
 449        printf("<SPI: %u DIP: ", spi);
 450        print_addr(af, dip);
 451        printf(" SIP: ");
 452        print_addr(af, sip);
 453        printf(">");
 454}
 455
 456static void
 457print_result(const union rte_ipsec_sad_key *key, void *res)
 458{
 459        struct rule *rule = res;
 460        const struct rte_ipsec_sadv4_key *v4;
 461        const struct rte_ipsec_sadv6_key *v6;
 462        const char *spi_only = "SPI_ONLY";
 463        const char *spi_dip = "SPI_DIP";
 464        const char *spi_dip_sip = "SPI_DIP_SIP";
 465        const char *rule_type;
 466        const void *dip, *sip;
 467        uint32_t spi;
 468        int af;
 469
 470        af = (config.ipv6) ? AF_INET6 : AF_INET;
 471        v4 = &key->v4;
 472        v6 = &key->v6;
 473        spi = (config.ipv6 == 0) ? v4->spi : v6->spi;
 474        dip = (config.ipv6 == 0) ? &v4->dip : (const void *)v6->dip;
 475        sip = (config.ipv6 == 0) ? &v4->sip : (const void *)v6->sip;
 476
 477        if (res == NULL) {
 478                printf("TUPLE: ");
 479                print_tuple(af, spi, dip, sip);
 480                printf(" not found\n");
 481                return;
 482        }
 483
 484        switch (rule->rule_type) {
 485        case RTE_IPSEC_SAD_SPI_ONLY:
 486                rule_type = spi_only;
 487                break;
 488        case RTE_IPSEC_SAD_SPI_DIP:
 489                rule_type = spi_dip;
 490                break;
 491        case RTE_IPSEC_SAD_SPI_DIP_SIP:
 492                rule_type = spi_dip_sip;
 493                break;
 494        default:
 495                return;
 496        }
 497
 498        print_tuple(af, spi, dip, sip);
 499        v4 = &rule->tuple.v4;
 500        v6 = &rule->tuple.v6;
 501        spi = (config.ipv6 == 0) ? v4->spi : v6->spi;
 502        dip = (config.ipv6 == 0) ? &v4->dip : (const void *)v6->dip;
 503        sip = (config.ipv6 == 0) ? &v4->sip : (const void *)v6->sip;
 504        printf("\n\tpoints to RULE ID %zu ",
 505                RTE_PTR_DIFF(res, rules_tbl)/sizeof(struct rule));
 506        print_tuple(af, spi, dip, sip);
 507        printf(" %s\n", rule_type);
 508}
 509
 510static int
 511lookup(void *arg)
 512{
 513        int ret;
 514        unsigned int i, j;
 515        const union rte_ipsec_sad_key *keys[BURST_SZ_MAX];
 516        void *vals[BURST_SZ_MAX];
 517        uint64_t start, acc = 0;
 518        uint32_t burst_sz;
 519        struct rte_ipsec_sad *sad = arg;
 520
 521        if (config.nb_tuples == 0)
 522                return 0;
 523
 524        burst_sz = RTE_MIN(config.burst_sz, config.nb_tuples);
 525        for (i = 0; i < config.nb_tuples; i += burst_sz) {
 526                for (j = 0; j < burst_sz; j++)
 527                        keys[j] = (union rte_ipsec_sad_key *)
 528                                (&tuples_tbl[i + j].tuple);
 529                start = rte_rdtsc_precise();
 530                ret = rte_ipsec_sad_lookup(sad, keys, vals, burst_sz);
 531                acc += rte_rdtsc_precise() - start;
 532                if (ret < 0)
 533                        rte_exit(-EINVAL, "Lookup failed\n");
 534                if (config.verbose) {
 535                        for (j = 0; j < burst_sz; j++)
 536                                print_result(keys[j], vals[j]);
 537                }
 538        }
 539        acc = (acc == 0) ? UINT64_MAX : acc;
 540        printf("Average lookup cycles %.2Lf, lookups/sec: %.2Lf\n",
 541                (long double)acc / config.nb_tuples,
 542                (long double)config.nb_tuples * rte_get_tsc_hz() / acc);
 543
 544        return 0;
 545}
 546
 547static void
 548add_rules(struct rte_ipsec_sad *sad, uint32_t fract)
 549{
 550        int32_t ret;
 551        uint32_t i, j, f, fn, n;
 552        uint64_t start, tm[fract + 1];
 553        uint32_t nm[fract + 1];
 554
 555        f = (config.nb_rules > fract) ? config.nb_rules / fract : 1;
 556
 557        for (n = 0, j = 0; n != config.nb_rules; n = fn, j++) {
 558
 559                fn = n + f;
 560                fn = fn > config.nb_rules ? config.nb_rules : fn;
 561
 562                start = rte_rdtsc_precise();
 563                for (i = n; i != fn; i++) {
 564                        ret = rte_ipsec_sad_add(sad,
 565                                &rules_tbl[i].tuple,
 566                                rules_tbl[i].rule_type, &rules_tbl[i]);
 567                        if (ret != 0)
 568                                rte_exit(ret, "%s failed @ %u-th rule\n",
 569                                        __func__, i);
 570                }
 571                tm[j] = rte_rdtsc_precise() - start;
 572                nm[j] = fn - n;
 573        }
 574
 575        for (i = 0; i != j; i++)
 576                printf("ADD %u rules, %.2Lf cycles/rule, %.2Lf ADD/sec\n",
 577                        nm[i], (long double)tm[i] / nm[i],
 578                        (long double)nm[i] * rte_get_tsc_hz() / tm[i]);
 579}
 580
 581static void
 582del_rules(struct rte_ipsec_sad *sad, uint32_t fract)
 583{
 584        int32_t ret;
 585        uint32_t i, j, f, fn, n;
 586        uint64_t start, tm[fract + 1];
 587        uint32_t nm[fract + 1];
 588
 589        f = (config.nb_rules > fract) ? config.nb_rules / fract : 1;
 590
 591        for (n = 0, j = 0; n != config.nb_rules; n = fn, j++) {
 592
 593                fn = n + f;
 594                fn = fn > config.nb_rules ? config.nb_rules : fn;
 595
 596                start = rte_rdtsc_precise();
 597                for (i = n; i != fn; i++) {
 598                        ret = rte_ipsec_sad_del(sad,
 599                                &rules_tbl[i].tuple,
 600                                rules_tbl[i].rule_type);
 601                        if (ret != 0 && ret != -ENOENT)
 602                                rte_exit(ret, "%s failed @ %u-th rule\n",
 603                                        __func__, i);
 604                }
 605                tm[j] = rte_rdtsc_precise() - start;
 606                nm[j] = fn - n;
 607        }
 608
 609        for (i = 0; i != j; i++)
 610                printf("DEL %u rules, %.2Lf cycles/rule, %.2Lf DEL/sec\n",
 611                        nm[i], (long double)tm[i] / nm[i],
 612                        (long double)nm[i] * rte_get_tsc_hz() / tm[i]);
 613}
 614
 615int
 616main(int argc, char **argv)
 617{
 618        int ret;
 619        struct rte_ipsec_sad *sad;
 620        struct rte_ipsec_sad_conf conf = {0};
 621        unsigned int lcore_id;
 622
 623        ret = rte_eal_init(argc, argv);
 624        if (ret < 0)
 625                rte_panic("Cannot init EAL\n");
 626
 627        argc -= ret;
 628        argv += ret;
 629
 630        config.prgname = argv[0];
 631
 632        parse_opts(argc, argv);
 633        tbl_init(&rules_tbl, &config.nb_rules, config.rules_file, 1);
 634        tbl_init(&tuples_tbl, &config.nb_tuples, config.tuples_file, 0);
 635        if (config.rules_file != NULL) {
 636                config.fract_32 = (100 * config.nb_rules_32) / config.nb_rules;
 637                config.fract_64 = (100 * config.nb_rules_64) / config.nb_rules;
 638                config.fract_96 = (100 * config.nb_rules_96) / config.nb_rules;
 639        }
 640        if (config.tuples_file != NULL) {
 641                config.fract_rnd_tuples = 0;
 642                config.nb_tuples_rnd = 0;
 643        }
 644        conf.socket_id = -1;
 645        conf.max_sa[RTE_IPSEC_SAD_SPI_ONLY] = config.nb_rules_32 * 5 / 4;
 646        conf.max_sa[RTE_IPSEC_SAD_SPI_DIP] = config.nb_rules_64 * 5 / 4;
 647        conf.max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP] = config.nb_rules_96 * 5 / 4;
 648        if (config.ipv6)
 649                conf.flags |= RTE_IPSEC_SAD_FLAG_IPV6;
 650        if (config.concurrent_rw)
 651                conf.flags |= RTE_IPSEC_SAD_FLAG_RW_CONCURRENCY;
 652        sad = rte_ipsec_sad_create("test", &conf);
 653        if (sad == NULL)
 654                rte_exit(-rte_errno, "can not allocate SAD table\n");
 655
 656        print_config();
 657
 658        add_rules(sad, 10);
 659        if (config.parallel_lookup)
 660                rte_eal_mp_remote_launch(lookup, sad, SKIP_MAIN);
 661
 662        lookup(sad);
 663        if (config.parallel_lookup)
 664                RTE_LCORE_FOREACH_WORKER(lcore_id)
 665                        if (rte_eal_wait_lcore(lcore_id) < 0)
 666                                return -1;
 667
 668        del_rules(sad, 10);
 669
 670        return 0;
 671}
 672