dpdk/app/test-fib/main.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright(c) 2019 Intel Corporation
   3 */
   4
   5#include <getopt.h>
   6#include <string.h>
   7#include <arpa/inet.h>
   8#include <sys/socket.h>
   9
  10#include <rte_cycles.h>
  11#include <rte_errno.h>
  12#include <rte_ip.h>
  13#include <rte_random.h>
  14#include <rte_malloc.h>
  15#include <rte_lpm.h>
  16#include <rte_lpm6.h>
  17#include <rte_fib.h>
  18#include <rte_fib6.h>
  19
  20#define PRINT_USAGE_START       "%s [EAL options] --\n"
  21
  22#define GET_CB_FIELD(in, fd, base, lim, dlm)    do {            \
  23        unsigned long val;                                      \
  24        char *end_fld;                                          \
  25        errno = 0;                                              \
  26        val = strtoul((in), &end_fld, (base));                  \
  27        if (errno != 0 || end_fld[0] != (dlm) || val > (lim))   \
  28                return -EINVAL;                                 \
  29        (fd) = (typeof(fd))val;                                 \
  30        (in) = end_fld + 1;                                     \
  31} while (0)
  32
  33#define DEF_ROUTES_NUM          0x10000
  34#define DEF_LOOKUP_IPS_NUM      0x100000
  35#define BURST_SZ                64
  36#define DEFAULT_LPM_TBL8        100000U
  37
  38#define CMP_FLAG                (1 << 0)
  39#define CMP_ALL_FLAG            (1 << 1)
  40#define IPV6_FLAG               (1 << 2)
  41#define FIB_RIB_TYPE            (1 << 3)
  42#define FIB_V4_DIR_TYPE         (1 << 4)
  43#define FIB_V6_TRIE_TYPE        (1 << 4)
  44#define FIB_TYPE_MASK           (FIB_RIB_TYPE|FIB_V4_DIR_TYPE|FIB_V6_TRIE_TYPE)
  45#define SHUFFLE_FLAG            (1 << 7)
  46#define DRY_RUN_FLAG            (1 << 8)
  47
  48static char *distrib_string;
  49static char line[LINE_MAX];
  50
  51enum {
  52        RT_PREFIX,
  53        RT_NEXTHOP,
  54        RT_NUM
  55};
  56
  57#ifndef NIPQUAD
  58#define NIPQUAD_FMT "%u.%u.%u.%u"
  59#define NIPQUAD(addr)                           \
  60        (unsigned)((unsigned char *)&addr)[3],  \
  61        (unsigned)((unsigned char *)&addr)[2],  \
  62        (unsigned)((unsigned char *)&addr)[1],  \
  63        (unsigned)((unsigned char *)&addr)[0]
  64
  65#define NIPQUAD6_FMT "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x"
  66#define NIPQUAD6(addr)                          \
  67        ((uint8_t *)addr)[0] << 8 |     \
  68        ((uint8_t *)addr)[1],           \
  69        ((uint8_t *)addr)[2] << 8 |     \
  70        ((uint8_t *)addr)[3],           \
  71        ((uint8_t *)addr)[4] << 8 |     \
  72        ((uint8_t *)addr)[5],           \
  73        ((uint8_t *)addr)[6] << 8 |     \
  74        ((uint8_t *)addr)[7],           \
  75        ((uint8_t *)addr)[8] << 8 |     \
  76        ((uint8_t *)addr)[9],           \
  77        ((uint8_t *)addr)[10] << 8 |    \
  78        ((uint8_t *)addr)[11],          \
  79        ((uint8_t *)addr)[12] << 8 |    \
  80        ((uint8_t *)addr)[13],          \
  81        ((uint8_t *)addr)[14] << 8 |    \
  82        ((uint8_t *)addr)[15]
  83#endif
  84
  85static struct {
  86        const char      *prgname;
  87        const char      *routes_file;
  88        const char      *lookup_ips_file;
  89        const char      *routes_file_s;
  90        const char      *lookup_ips_file_s;
  91        void            *rt;
  92        void            *lookup_tbl;
  93        uint32_t        nb_routes;
  94        uint32_t        nb_lookup_ips;
  95        uint32_t        nb_lookup_ips_rnd;
  96        uint32_t        nb_routes_per_depth[128 + 1];
  97        uint32_t        flags;
  98        uint32_t        tbl8;
  99        uint8_t         ent_sz;
 100        uint8_t         rnd_lookup_ips_ratio;
 101        uint8_t         print_fract;
 102        uint8_t         lookup_fn;
 103} config = {
 104        .routes_file = NULL,
 105        .lookup_ips_file = NULL,
 106        .nb_routes = DEF_ROUTES_NUM,
 107        .nb_lookup_ips = DEF_LOOKUP_IPS_NUM,
 108        .nb_lookup_ips_rnd = 0,
 109        .nb_routes_per_depth = {0},
 110        .flags = FIB_V4_DIR_TYPE,
 111        .tbl8 = DEFAULT_LPM_TBL8,
 112        .ent_sz = 4,
 113        .rnd_lookup_ips_ratio = 0,
 114        .print_fract = 10,
 115        .lookup_fn = 0
 116};
 117
 118struct rt_rule_4 {
 119        uint32_t        addr;
 120        uint8_t         depth;
 121        uint64_t        nh;
 122};
 123
 124struct rt_rule_6 {
 125        uint8_t         addr[16];
 126        uint8_t         depth;
 127        uint64_t        nh;
 128};
 129
 130static uint64_t
 131get_rnd_rng(uint64_t l, uint64_t u)
 132{
 133        if (l == u)
 134                return l;
 135        else
 136                return (rte_rand() % (u - l) + l);
 137}
 138
 139static __rte_always_inline __attribute__((pure)) uint8_t
 140bits_in_nh(uint8_t nh_sz)
 141{
 142        return 8 * (1 << nh_sz);
 143}
 144
 145static  __rte_always_inline __attribute__((pure)) uint64_t
 146get_max_nh(uint8_t nh_sz)
 147{
 148        /* min between fib and lpm6 which is 21 bits */
 149        return RTE_MIN(((1ULL << (bits_in_nh(nh_sz) - 1)) - 1),
 150                        (1ULL << 21) - 1);
 151}
 152
 153static int
 154get_fib_type(void)
 155{
 156        if (config.flags & IPV6_FLAG) {
 157                if ((config.flags & FIB_TYPE_MASK) == FIB_V6_TRIE_TYPE)
 158                        return RTE_FIB6_TRIE;
 159                else
 160                        return RTE_FIB6_DUMMY;
 161        } else {
 162                if ((config.flags & FIB_TYPE_MASK) == FIB_V4_DIR_TYPE)
 163                        return RTE_FIB_DIR24_8;
 164                if ((config.flags & FIB_TYPE_MASK) == FIB_RIB_TYPE)
 165                        return RTE_FIB_DUMMY;
 166        }
 167        return -1;
 168}
 169
 170static int
 171complete_distrib(uint8_t depth_lim, const uint32_t n, uint8_t rpd[],
 172        uint32_t nrpd[])
 173{
 174        uint8_t depth;
 175        uint32_t nr = 0;
 176        uint8_t m = 0;
 177
 178        /*
 179         * complete number of routes for every depth
 180         * that was configured with ratio
 181         */
 182        for (depth = 0; depth <= depth_lim; depth++) {
 183                if (rpd[depth] != 0) {
 184                        if (rpd[depth] == UINT8_MAX)
 185                                config.nb_routes_per_depth[depth] =
 186                                        nrpd[depth];
 187                        else
 188                                config.nb_routes_per_depth[depth] =
 189                                        (n * rpd[depth]) / 100;
 190
 191                        nr += config.nb_routes_per_depth[depth];
 192                        m++;
 193                }
 194        }
 195
 196        if (nr > n) {
 197                printf("Too much configured routes\n");
 198                return -1;
 199        }
 200
 201        /*complete number of routes for every unspecified depths*/
 202        for (depth = 0; depth <= depth_lim; depth++) {
 203                if (rpd[depth] == 0) {
 204                        /*we don't need more than two /1 routes*/
 205                        uint64_t max_routes_per_depth =
 206                                1ULL << RTE_MIN(depth, 63);
 207                        uint32_t avg_routes_left = (n - nr) /
 208                                (depth_lim + 1 - m++);
 209                        config.nb_routes_per_depth[depth] =
 210                                RTE_MIN(max_routes_per_depth, avg_routes_left);
 211                        nr += config.nb_routes_per_depth[depth];
 212                }
 213        }
 214
 215        return 0;
 216}
 217
 218static int
 219parse_distrib(uint8_t depth_lim, const uint32_t n)
 220{
 221        uint8_t rpd[128 + 1] = {0}; /*routes ratios per depth including /0 */
 222        uint32_t nrpd[128 + 1] = {0}; /* number of routes per depth */
 223        uint32_t n_routes;
 224        uint8_t depth, ratio, ratio_acc = 0;
 225        char *in;
 226
 227        in = strtok(distrib_string, ",");
 228
 229        /*parse configures routes percentage ratios*/
 230        while (in != NULL) {
 231                GET_CB_FIELD(in, depth, 0, UINT8_MAX, ':');
 232                if (in[strlen(in) - 1] == '%') {
 233                        in[strlen(in) - 1] = 0;
 234                        GET_CB_FIELD(in, ratio, 0, UINT8_MAX, '\0');
 235                        if (depth > depth_lim) {
 236                                printf("Depth /%d is bigger than maximum "
 237                                        "allowed depth /%d for this AF\n",
 238                                        depth, depth_lim);
 239                                return -EINVAL;
 240                        }
 241                        if (ratio > 100) {
 242                                printf("Ratio for depth /%d is bigger "
 243                                        "than 100%%\n", depth);
 244                                return -EINVAL;
 245                        }
 246                        if ((depth < 64) && ((n * ratio) / 100) >
 247                                        (1ULL << depth)) {
 248                                printf("Configured ratio %d%% for depth /%d "
 249                                        "has %d different routes, but maximum "
 250                                        "is %lu\n", ratio, depth,
 251                                        ((n * ratio) / 100), (1UL << depth));
 252                                return -EINVAL;
 253                        }
 254                        rpd[depth] = ratio;
 255                        /*configured zero routes for a given depth*/
 256                        if (ratio == 0)
 257                                rpd[depth] = UINT8_MAX;
 258                        /*sum of all percentage ratios*/
 259                        ratio_acc += ratio;
 260                } else {
 261                        GET_CB_FIELD(in, n_routes, 0, UINT32_MAX, '\0');
 262                        rpd[depth] = UINT8_MAX;
 263                        nrpd[depth] = n_routes;
 264                }
 265
 266                /*number of configured depths in*/
 267                in = strtok(NULL, ",");
 268        }
 269
 270        if (ratio_acc > 100) {
 271                printf("Total ratio's sum is bigger than 100%%\n");
 272                return -EINVAL;
 273        }
 274
 275        return complete_distrib(depth_lim, n, rpd, nrpd);
 276}
 277
 278static void
 279shuffle_rt_4(struct rt_rule_4 *rt, int n)
 280{
 281        struct rt_rule_4 tmp;
 282        int i, j;
 283
 284        for (i = 0; i < n; i++) {
 285                j = rte_rand() % n;
 286                tmp.addr = rt[i].addr;
 287                tmp.depth = rt[i].depth;
 288                tmp.nh = rt[i].nh;
 289
 290                rt[i].addr = rt[j].addr;
 291                rt[i].depth = rt[j].depth;
 292                rt[i].nh = rt[j].nh;
 293
 294                rt[j].addr = tmp.addr;
 295                rt[j].depth = tmp.depth;
 296                rt[j].nh = tmp.nh;
 297        }
 298}
 299
 300static void
 301shuffle_rt_6(struct rt_rule_6 *rt, int n)
 302{
 303        struct rt_rule_6 tmp;
 304        int i, j;
 305
 306        for (i = 0; i < n; i++) {
 307                j = rte_rand() % n;
 308                memcpy(tmp.addr, rt[i].addr, 16);
 309                tmp.depth = rt[i].depth;
 310                tmp.nh = rt[i].nh;
 311
 312                memcpy(rt[i].addr, rt[j].addr, 16);
 313                rt[i].depth = rt[j].depth;
 314                rt[i].nh = rt[j].nh;
 315
 316                memcpy(rt[j].addr, tmp.addr, 16);
 317                rt[j].depth = tmp.depth;
 318                rt[j].nh = tmp.nh;
 319        }
 320}
 321
 322static void
 323gen_random_rt_4(struct rt_rule_4 *rt, int nh_sz)
 324{
 325        uint32_t i, j, k = 0;
 326
 327        if (config.nb_routes_per_depth[0] != 0) {
 328                rt[k].addr = 0;
 329                rt[k].depth = 0;
 330                rt[k++].nh = rte_rand() & get_max_nh(nh_sz);
 331        }
 332
 333        for (i = 1; i <= 32; i++) {
 334                double edge = 0;
 335                double step;
 336                step = (double)(1ULL << i) / config.nb_routes_per_depth[i];
 337                for (j = 0; j < config.nb_routes_per_depth[i];
 338                                j++, k++, edge += step) {
 339                        uint64_t rnd_val = get_rnd_rng((uint64_t)edge,
 340                                (uint64_t)(edge + step));
 341                        rt[k].addr = rnd_val << (32 - i);
 342                        rt[k].depth = i;
 343                        rt[k].nh = rte_rand() & get_max_nh(nh_sz);
 344                }
 345        }
 346}
 347
 348static void
 349complete_v6_addr(uint32_t *addr, uint32_t rnd, int n)
 350{
 351        int i;
 352
 353        for (i = 0; i < n; i++)
 354                addr[i] = rte_rand();
 355        addr[i++] = rnd;
 356        for (; i < 4; i++)
 357                addr[i] = 0;
 358}
 359
 360static void
 361gen_random_rt_6(struct rt_rule_6 *rt, int nh_sz)
 362{
 363        uint32_t a, i, j, k = 0;
 364
 365        if (config.nb_routes_per_depth[0] != 0) {
 366                memset(rt[k].addr, 0, 16);
 367                rt[k].depth = 0;
 368                rt[k++].nh = rte_rand() & get_max_nh(nh_sz);
 369        }
 370
 371        for (a = 0; a < 4; a++) {
 372                for (i = 1; i <= 32; i++) {
 373                        uint32_t rnd;
 374                        double edge = 0;
 375                        double step = (double)(1ULL << i) /
 376                                config.nb_routes_per_depth[(a * 32) + i];
 377                        for (j = 0; j < config.nb_routes_per_depth[a * 32 + i];
 378                                        j++, k++, edge += step) {
 379                                uint64_t rnd_val = get_rnd_rng((uint64_t)edge,
 380                                        (uint64_t)(edge + step));
 381                                rnd = rte_cpu_to_be_32(rnd_val << (32 - i));
 382                                complete_v6_addr((uint32_t *)rt[k].addr,
 383                                        rnd, a);
 384                                rt[k].depth = (a * 32) + i;
 385                                rt[k].nh = rte_rand() & get_max_nh(nh_sz);
 386                        }
 387                }
 388        }
 389}
 390
 391static inline void
 392set_rnd_ipv6(uint8_t *addr, uint8_t *route, int depth)
 393{
 394        int i;
 395
 396        for (i = 0; i < 16; i++)
 397                addr[i] = rte_rand();
 398
 399        for (i = 0; i < 16; i++) {
 400                if (depth >= 8)
 401                        addr[i] = route[i];
 402                else if (depth > 0) {
 403                        addr[i] &= (uint16_t)UINT8_MAX >> depth;
 404                        addr[i] |= route[i] & UINT8_MAX << (8 - depth);
 405                } else
 406                        return;
 407                depth -= 8;
 408        }
 409}
 410
 411static void
 412gen_rnd_lookup_tbl(int af)
 413{
 414        uint32_t *tbl4 = config.lookup_tbl;
 415        uint8_t *tbl6 = config.lookup_tbl;
 416        struct rt_rule_4 *rt4 = (struct rt_rule_4 *)config.rt;
 417        struct rt_rule_6 *rt6 = (struct rt_rule_6 *)config.rt;
 418        uint32_t i, j;
 419
 420        if (af == AF_INET) {
 421                for (i = 0, j = 0; i < config.nb_lookup_ips;
 422                                i++, j = (j + 1) % config.nb_routes) {
 423                        if ((rte_rand() % 100) < config.rnd_lookup_ips_ratio) {
 424                                tbl4[i] = rte_rand();
 425                                config.nb_lookup_ips_rnd++;
 426                        } else
 427                                tbl4[i] = rt4[j].addr | (rte_rand() &
 428                                        ((1ULL << (32 - rt4[j].depth)) - 1));
 429                }
 430        } else {
 431                for (i = 0, j = 0; i < config.nb_lookup_ips;
 432                                i++, j = (j + 1) % config.nb_routes) {
 433                        if ((rte_rand() % 100) < config.rnd_lookup_ips_ratio) {
 434                                set_rnd_ipv6(&tbl6[i * 16], rt6[j].addr, 0);
 435                                config.nb_lookup_ips_rnd++;
 436                        } else {
 437                                set_rnd_ipv6(&tbl6[i * 16], rt6[j].addr,
 438                                        rt6[j].depth);
 439                        }
 440                }
 441        }
 442}
 443
 444static int
 445_inet_net_pton(int af, char *prefix, void *addr)
 446{
 447        const char *dlm = "/";
 448        char *s, *sp;
 449        int ret, depth;
 450        unsigned int max_depth;
 451
 452        if ((prefix == NULL) || (addr == NULL))
 453                return -EINVAL;
 454
 455        s = strtok_r(prefix, dlm, &sp);
 456        if (s == NULL)
 457                return -EINVAL;
 458
 459        ret = inet_pton(af, s, addr);
 460        if (ret != 1)
 461                return -errno;
 462
 463        s = strtok_r(NULL, dlm, &sp);
 464        max_depth = (af == AF_INET) ? 32 : 128;
 465        GET_CB_FIELD(s, depth, 0, max_depth, 0);
 466
 467        return depth;
 468}
 469
 470static int
 471parse_rt_4(FILE *f)
 472{
 473        int ret, i, j = 0;
 474        char *s, *sp, *in[RT_NUM];
 475        static const char *dlm = " \t\n";
 476        int string_tok_nb = RTE_DIM(in);
 477        struct rt_rule_4 *rt;
 478
 479        rt = (struct rt_rule_4 *)config.rt;
 480
 481        while (fgets(line, sizeof(line), f) != NULL) {
 482                s = line;
 483                for (i = 0; i != string_tok_nb; i++) {
 484                        in[i] = strtok_r(s, dlm, &sp);
 485                        if (in[i] == NULL)
 486                                return -EINVAL;
 487                        s = NULL;
 488                }
 489
 490                ret = _inet_net_pton(AF_INET, in[RT_PREFIX], &rt[j].addr);
 491                if (ret == -1)
 492                        return -errno;
 493
 494                rt[j].addr = rte_be_to_cpu_32(rt[j].addr);
 495                rt[j].depth = ret;
 496                config.nb_routes_per_depth[ret]++;
 497                GET_CB_FIELD(in[RT_NEXTHOP], rt[j].nh, 0,
 498                                UINT32_MAX, 0);
 499                j++;
 500        }
 501        return 0;
 502}
 503
 504static int
 505parse_rt_6(FILE *f)
 506{
 507        int ret, i, j = 0;
 508        char *s, *sp, *in[RT_NUM];
 509        static const char *dlm = " \t\n";
 510        int string_tok_nb = RTE_DIM(in);
 511        struct rt_rule_6 *rt;
 512
 513        rt = (struct rt_rule_6 *)config.rt;
 514
 515        while (fgets(line, sizeof(line), f) != NULL) {
 516                s = line;
 517                for (i = 0; i != string_tok_nb; i++) {
 518                        in[i] = strtok_r(s, dlm, &sp);
 519                        if (in[i] == NULL)
 520                                return -EINVAL;
 521                        s = NULL;
 522                }
 523
 524                ret = _inet_net_pton(AF_INET6, in[RT_PREFIX], rt[j].addr);
 525                if (ret < 0)
 526                        return ret;
 527
 528                rt[j].depth = ret;
 529                config.nb_routes_per_depth[ret]++;
 530                GET_CB_FIELD(in[RT_NEXTHOP], rt[j].nh, 0,
 531                                UINT32_MAX, 0);
 532                j++;
 533        }
 534
 535        return 0;
 536}
 537
 538static int
 539parse_lookup(FILE *f, int af)
 540{
 541        int ret, i = 0;
 542        uint8_t *tbl = (uint8_t *)config.lookup_tbl;
 543        int step = (af == AF_INET) ? 4 : 16;
 544        char *s;
 545
 546        while (fgets(line, sizeof(line), f) != NULL) {
 547                s = strtok(line, " \t\n");
 548                if (s == NULL)
 549                        return -EINVAL;
 550                ret = inet_pton(af, s, &tbl[i]);
 551                if (ret != 1)
 552                        return -EINVAL;
 553                i += step;
 554        }
 555        return 0;
 556}
 557
 558static int
 559dump_lookup(int af)
 560{
 561        FILE *f;
 562        uint32_t *tbl4 = config.lookup_tbl;
 563        uint8_t *tbl6 = config.lookup_tbl;
 564        uint32_t i;
 565
 566        f = fopen(config.lookup_ips_file_s, "w");
 567        if (f == NULL) {
 568                printf("Can not open file %s\n", config.lookup_ips_file_s);
 569                return -1;
 570        }
 571
 572        if (af == AF_INET) {
 573                for (i = 0; i < config.nb_lookup_ips; i++)
 574                        fprintf(f, NIPQUAD_FMT"\n", NIPQUAD(tbl4[i]));
 575        } else {
 576                for (i = 0; i < config.nb_lookup_ips; i++)
 577                        fprintf(f, NIPQUAD6_FMT"\n", NIPQUAD6(&tbl6[i * 16]));
 578        }
 579        fclose(f);
 580        return 0;
 581}
 582
 583static void
 584print_config(void)
 585{
 586        uint8_t depth_lim;
 587        char dlm;
 588        int i;
 589
 590        depth_lim = ((config.flags & IPV6_FLAG) == IPV6_FLAG) ? 128 : 32;
 591
 592        fprintf(stdout,
 593                "Routes total: %u\n"
 594                "Routes distribution:\n", config.nb_routes);
 595
 596        for (i = 1; i <= depth_lim; i++) {
 597                fprintf(stdout,
 598                        "depth /%d:%u", i, config.nb_routes_per_depth[i]);
 599                if (i % 4 == 0)
 600                        dlm = '\n';
 601                else
 602                        dlm = '\t';
 603                fprintf(stdout, "%c", dlm);
 604        }
 605
 606        fprintf(stdout,
 607                "Lookup tuples: %u\n"
 608                "Configured ratios of random ips for lookup: %u\n"
 609                "Random lookup ips: %u\n",
 610                config.nb_lookup_ips, config.rnd_lookup_ips_ratio,
 611                config.nb_lookup_ips_rnd);
 612}
 613
 614static void
 615print_usage(void)
 616{
 617        fprintf(stdout,
 618                PRINT_USAGE_START
 619                "[-f <routes file>]\n"
 620                "[-t <ip's file for lookup>]\n"
 621                "[-n <number of routes (if -f is not specified)>]\n"
 622                "[-l <number of ip's for lookup (if -t is not specified)>]\n"
 623                "[-d <\",\" separated \"depth:n%%\"routes depth distribution"
 624                "(if -f is not specified)>]\n"
 625                "[-r <percentage ratio of random ip's to lookup"
 626                "(if -t is not specified)>]\n"
 627                "[-c <do comarison with LPM library>]\n"
 628                "[-6 <do tests with ipv6 (default ipv4)>]\n"
 629                "[-s <shuffle randomly generated routes>]\n"
 630                "[-a <check nexthops for all ipv4 address space"
 631                "(only valid with -c)>]\n"
 632                "[-b <fib algorithm>]\n\tavailable options for ipv4\n"
 633                "\t\trib - RIB based FIB\n"
 634                "\t\tdir - DIR24_8 based FIB\n"
 635                "\tavailable options for ipv6:\n"
 636                "\t\trib - RIB based FIB\n"
 637                "\t\ttrie - TRIE based FIB\n"
 638                "defaults are: dir for ipv4 and trie for ipv6\n"
 639                "[-e <entry size (valid only for dir and trie fib types): "
 640                "1/2/4/8 (default 4)>]\n"
 641                "[-g <number of tbl8's for dir24_8 or trie FIBs>]\n"
 642                "[-w <path to the file to dump routing table>]\n"
 643                "[-u <path to the file to dump ip's for lookup>]\n"
 644                "[-v <type of loookup function:"
 645                "\ts1, s2, s3 (3 types of scalar), v (vector) -"
 646                " for DIR24_8 based FIB\n"
 647                "\ts, v - for TRIE based ipv6 FIB>]\n",
 648                config.prgname);
 649}
 650
 651static int
 652check_config(void)
 653{
 654        if ((config.routes_file == NULL) && (config.lookup_ips_file != NULL)) {
 655                printf("-t option only valid with -f option\n");
 656                return -1;
 657        }
 658
 659        if ((config.flags & CMP_ALL_FLAG) && (config.flags & IPV6_FLAG)) {
 660                printf("-a flag is only valid for ipv4\n");
 661                return -1;
 662        }
 663
 664        if ((config.flags & CMP_ALL_FLAG) &&
 665                        ((config.flags & CMP_FLAG) != CMP_FLAG)) {
 666                printf("-a flag is valid only with -c flag\n");
 667                return -1;
 668        }
 669
 670        if (!((config.ent_sz == 1) || (config.ent_sz == 2) ||
 671                        (config.ent_sz == 4) || (config.ent_sz == 8))) {
 672                printf("wrong -e option %d, can be 1 or 2 or 4 or 8\n",
 673                        config.ent_sz);
 674                return -1;
 675        }
 676
 677        if ((config.ent_sz == 1) && (config.flags & IPV6_FLAG)) {
 678                printf("-e 1 is valid only for ipv4\n");
 679                return -1;
 680        }
 681        return 0;
 682}
 683
 684static void
 685parse_opts(int argc, char **argv)
 686{
 687        int opt;
 688        char *endptr;
 689
 690        while ((opt = getopt(argc, argv, "f:t:n:d:l:r:c6ab:e:g:w:u:sv:")) !=
 691                        -1) {
 692                switch (opt) {
 693                case 'f':
 694                        config.routes_file = optarg;
 695                        break;
 696                case 't':
 697                        config.lookup_ips_file = optarg;
 698                        break;
 699                case 'w':
 700                        config.routes_file_s = optarg;
 701                        config.flags |= DRY_RUN_FLAG;
 702                        break;
 703                case 'u':
 704                        config.lookup_ips_file_s = optarg;
 705                        config.flags |= DRY_RUN_FLAG;
 706                        break;
 707                case 'n':
 708                        errno = 0;
 709                        config.nb_routes = strtoul(optarg, &endptr, 10);
 710                        if ((errno != 0) || (config.nb_routes == 0)) {
 711                                print_usage();
 712                                rte_exit(-EINVAL, "Invalid option -n\n");
 713                        }
 714                        break;
 715                case 'd':
 716                        distrib_string = optarg;
 717                        break;
 718                case 'l':
 719                        errno = 0;
 720                        config.nb_lookup_ips = strtoul(optarg, &endptr, 10);
 721                        if ((errno != 0) || (config.nb_lookup_ips == 0)) {
 722                                print_usage();
 723                                rte_exit(-EINVAL, "Invalid option -l\n");
 724                        }
 725                        break;
 726                case 'r':
 727                        errno = 0;
 728                        config.rnd_lookup_ips_ratio =
 729                                strtoul(optarg, &endptr, 10);
 730                        if ((errno != 0) ||
 731                                        (config.rnd_lookup_ips_ratio == 0) ||
 732                                        (config.rnd_lookup_ips_ratio >= 100)) {
 733                                print_usage();
 734                                rte_exit(-EINVAL, "Invalid option -r\n");
 735                        }
 736                        break;
 737                case 's':
 738                        config.flags |= SHUFFLE_FLAG;
 739                        break;
 740                case 'c':
 741                        config.flags |= CMP_FLAG;
 742                        break;
 743                case '6':
 744                        config.flags |= IPV6_FLAG;
 745                        break;
 746                case 'a':
 747                        config.flags |= CMP_ALL_FLAG;
 748                        break;
 749                case 'b':
 750                        if (strcmp(optarg, "rib") == 0) {
 751                                config.flags &= ~FIB_TYPE_MASK;
 752                                config.flags |= FIB_RIB_TYPE;
 753                        } else if (strcmp(optarg, "dir") == 0) {
 754                                config.flags &= ~FIB_TYPE_MASK;
 755                                config.flags |= FIB_V4_DIR_TYPE;
 756                        } else if (strcmp(optarg, "trie") == 0) {
 757                                config.flags &= ~FIB_TYPE_MASK;
 758                                config.flags |= FIB_V6_TRIE_TYPE;
 759                        } else
 760                                rte_exit(-EINVAL, "Invalid option -b\n");
 761                        break;
 762                case 'e':
 763                        errno = 0;
 764                        config.ent_sz = strtoul(optarg, &endptr, 10);
 765                        if (errno != 0) {
 766                                print_usage();
 767                                rte_exit(-EINVAL, "Invalid option -e\n");
 768                        }
 769                        break;
 770                case 'g':
 771                        errno = 0;
 772                        config.tbl8 = strtoul(optarg, &endptr, 10);
 773                        if ((errno != 0) || (config.tbl8 == 0)) {
 774                                print_usage();
 775                                rte_exit(-EINVAL, "Invalid option -g\n");
 776                        }
 777                        break;
 778                case 'v':
 779                        if ((strcmp(optarg, "s1") == 0) ||
 780                                        (strcmp(optarg, "s") == 0)) {
 781                                config.lookup_fn = 1;
 782                                break;
 783                        } else if (strcmp(optarg, "v") == 0) {
 784                                config.lookup_fn = 2;
 785                                break;
 786                        } else if (strcmp(optarg, "s2") == 0) {
 787                                config.lookup_fn = 3;
 788                                break;
 789                        } else if (strcmp(optarg, "s3") == 0) {
 790                                config.lookup_fn = 4;
 791                                break;
 792                        }
 793                        print_usage();
 794                        rte_exit(-EINVAL, "Invalid option -v %s\n", optarg);
 795                default:
 796                        print_usage();
 797                        rte_exit(-EINVAL, "Invalid options\n");
 798                }
 799        }
 800}
 801
 802static int
 803dump_rt_4(struct rt_rule_4 *rt)
 804{
 805        FILE *f;
 806        uint32_t i;
 807
 808        f = fopen(config.routes_file_s, "w");
 809        if (f == NULL) {
 810                printf("Can not open file %s\n", config.routes_file_s);
 811                return -1;
 812        }
 813
 814        for (i = 0; i < config.nb_routes; i++)
 815                fprintf(f, NIPQUAD_FMT"/%d %"PRIu64"\n", NIPQUAD(rt[i].addr),
 816                        rt[i].depth, rt[i].nh);
 817
 818        fclose(f);
 819        return 0;
 820}
 821
 822static inline void
 823print_depth_err(void)
 824{
 825        printf("LPM does not support /0 prefix length (default route), use "
 826                "-d 0:0 option or remove /0 prefix from routes file\n");
 827}
 828
 829static int
 830run_v4(void)
 831{
 832        uint64_t start, acc;
 833        uint64_t def_nh = 0;
 834        struct rte_fib *fib;
 835        struct rte_fib_conf conf = {0};
 836        struct rt_rule_4 *rt;
 837        uint32_t i, j, k;
 838        int ret = 0;
 839        struct rte_lpm  *lpm = NULL;
 840        struct rte_lpm_config lpm_conf;
 841        uint32_t *tbl4 = config.lookup_tbl;
 842        uint64_t fib_nh[BURST_SZ];
 843        uint32_t lpm_nh[BURST_SZ];
 844
 845        rt = (struct rt_rule_4 *)config.rt;
 846
 847        if (config.flags & DRY_RUN_FLAG) {
 848                if (config.routes_file_s != NULL)
 849                        ret = dump_rt_4(rt);
 850                if (ret != 0)
 851                        return ret;
 852                if (config.lookup_ips_file_s != NULL)
 853                        ret = dump_lookup(AF_INET);
 854                return ret;
 855        }
 856
 857        conf.type = get_fib_type();
 858        conf.default_nh = def_nh;
 859        conf.max_routes = config.nb_routes * 2;
 860        if (conf.type == RTE_FIB_DIR24_8) {
 861                conf.dir24_8.nh_sz = __builtin_ctz(config.ent_sz);
 862                conf.dir24_8.num_tbl8 = RTE_MIN(config.tbl8,
 863                        get_max_nh(conf.dir24_8.nh_sz));
 864        }
 865
 866        fib = rte_fib_create("test", -1, &conf);
 867        if (fib == NULL) {
 868                printf("Can not alloc FIB, err %d\n", rte_errno);
 869                return -rte_errno;
 870        }
 871
 872        if (config.lookup_fn != 0) {
 873                if (config.lookup_fn == 1)
 874                        ret = rte_fib_select_lookup(fib,
 875                                RTE_FIB_LOOKUP_DIR24_8_SCALAR_MACRO);
 876                else if (config.lookup_fn == 2)
 877                        ret = rte_fib_select_lookup(fib,
 878                                RTE_FIB_LOOKUP_DIR24_8_VECTOR_AVX512);
 879                else if (config.lookup_fn == 3)
 880                        ret = rte_fib_select_lookup(fib,
 881                                RTE_FIB_LOOKUP_DIR24_8_SCALAR_INLINE);
 882                else if (config.lookup_fn == 4)
 883                        ret = rte_fib_select_lookup(fib,
 884                                RTE_FIB_LOOKUP_DIR24_8_SCALAR_UNI);
 885                else
 886                        ret = -EINVAL;
 887                if (ret != 0) {
 888                        printf("Can not init lookup function\n");
 889                        return ret;
 890                }
 891        }
 892
 893        for (k = config.print_fract, i = 0; k > 0; k--) {
 894                start = rte_rdtsc_precise();
 895                for (j = 0; j < (config.nb_routes - i) / k; j++) {
 896                        ret = rte_fib_add(fib, rt[i + j].addr, rt[i + j].depth,
 897                                rt[i + j].nh);
 898                        if (unlikely(ret != 0)) {
 899                                printf("Can not add a route to FIB, err %d\n",
 900                                        ret);
 901                                return -ret;
 902                        }
 903                }
 904                printf("AVG FIB add %"PRIu64"\n",
 905                        (rte_rdtsc_precise() - start) / j);
 906                i += j;
 907        }
 908
 909        if (config.flags & CMP_FLAG) {
 910                lpm_conf.max_rules = config.nb_routes * 2;
 911                lpm_conf.number_tbl8s = RTE_MAX(conf.dir24_8.num_tbl8,
 912                        config.tbl8);
 913
 914                lpm = rte_lpm_create("test_lpm", -1, &lpm_conf);
 915                if (lpm == NULL) {
 916                        printf("Can not alloc LPM, err %d\n", rte_errno);
 917                        return -rte_errno;
 918                }
 919                for (k = config.print_fract, i = 0; k > 0; k--) {
 920                        start = rte_rdtsc_precise();
 921                        for (j = 0; j < (config.nb_routes - i) / k; j++) {
 922                                ret = rte_lpm_add(lpm, rt[i + j].addr,
 923                                        rt[i + j].depth, rt[i + j].nh);
 924                                if (ret != 0) {
 925                                        if (rt[i + j].depth == 0)
 926                                                print_depth_err();
 927                                        printf("Can not add a route to LPM, "
 928                                                "err %d\n", ret);
 929                                        return -ret;
 930                                }
 931                        }
 932                        printf("AVG LPM add %"PRIu64"\n",
 933                                (rte_rdtsc_precise() - start) / j);
 934                        i += j;
 935                }
 936        }
 937
 938        acc = 0;
 939        for (i = 0; i < config.nb_lookup_ips; i += BURST_SZ) {
 940                start = rte_rdtsc_precise();
 941                ret = rte_fib_lookup_bulk(fib, tbl4 + i, fib_nh, BURST_SZ);
 942                acc += rte_rdtsc_precise() - start;
 943                if (ret != 0) {
 944                        printf("FIB lookup fails, err %d\n", ret);
 945                        return -ret;
 946                }
 947        }
 948        printf("AVG FIB lookup %.1f\n", (double)acc / (double)i);
 949
 950        if (config.flags & CMP_FLAG) {
 951                acc = 0;
 952                for (i = 0; i < config.nb_lookup_ips; i += BURST_SZ) {
 953                        start = rte_rdtsc_precise();
 954                        ret = rte_lpm_lookup_bulk(lpm, tbl4 + i, lpm_nh,
 955                                BURST_SZ);
 956                        acc += rte_rdtsc_precise() - start;
 957                        if (ret != 0) {
 958                                printf("LPM lookup fails, err %d\n", ret);
 959                                return -ret;
 960                        }
 961                }
 962                printf("AVG LPM lookup %.1f\n", (double)acc / (double)i);
 963
 964                for (i = 0; i < config.nb_lookup_ips; i += BURST_SZ) {
 965                        rte_fib_lookup_bulk(fib, tbl4 + i, fib_nh, BURST_SZ);
 966                        rte_lpm_lookup_bulk(lpm, tbl4 + i, lpm_nh, BURST_SZ);
 967                        for (j = 0; j < BURST_SZ; j++) {
 968                                struct rte_lpm_tbl_entry *tbl;
 969                                tbl = (struct rte_lpm_tbl_entry *)&lpm_nh[j];
 970                                if ((fib_nh[j] != tbl->next_hop) &&
 971                                                !((tbl->valid == 0) &&
 972                                                (fib_nh[j] == def_nh))) {
 973                                        printf("FAIL\n");
 974                                        return -1;
 975                                }
 976                        }
 977                }
 978                printf("FIB and LPM lookup returns same values\n");
 979        }
 980
 981        for (k = config.print_fract, i = 0; k > 0; k--) {
 982                start = rte_rdtsc_precise();
 983                for (j = 0; j < (config.nb_routes - i) / k; j++)
 984                        rte_fib_delete(fib, rt[i + j].addr, rt[i + j].depth);
 985
 986                printf("AVG FIB delete %"PRIu64"\n",
 987                        (rte_rdtsc_precise() - start) / j);
 988                i += j;
 989        }
 990
 991        if (config.flags & CMP_FLAG) {
 992                for (k = config.print_fract, i = 0; k > 0; k--) {
 993                        start = rte_rdtsc_precise();
 994                        for (j = 0; j < (config.nb_routes - i) / k; j++)
 995                                rte_lpm_delete(lpm, rt[i + j].addr,
 996                                        rt[i + j].depth);
 997
 998                        printf("AVG LPM delete %"PRIu64"\n",
 999                                (rte_rdtsc_precise() - start) / j);
1000                        i += j;
1001                }
1002        }
1003
1004        return 0;
1005}
1006
1007static int
1008dump_rt_6(struct rt_rule_6 *rt)
1009{
1010        FILE *f;
1011        uint32_t i;
1012
1013        f = fopen(config.routes_file_s, "w");
1014        if (f == NULL) {
1015                printf("Can not open file %s\n", config.routes_file_s);
1016                return -1;
1017        }
1018
1019        for (i = 0; i < config.nb_routes; i++) {
1020                fprintf(f, NIPQUAD6_FMT"/%d %"PRIu64"\n", NIPQUAD6(rt[i].addr),
1021                        rt[i].depth, rt[i].nh);
1022
1023        }
1024        fclose(f);
1025        return 0;
1026}
1027
1028static int
1029run_v6(void)
1030{
1031        uint64_t start, acc;
1032        uint64_t def_nh = 0;
1033        struct rte_fib6 *fib;
1034        struct rte_fib6_conf conf = {0};
1035        struct rt_rule_6 *rt;
1036        uint32_t i, j, k;
1037        int ret = 0;
1038        struct rte_lpm6 *lpm = NULL;
1039        struct rte_lpm6_config lpm_conf;
1040        uint8_t *tbl6;
1041        uint64_t fib_nh[BURST_SZ];
1042        int32_t lpm_nh[BURST_SZ];
1043
1044        rt = (struct rt_rule_6 *)config.rt;
1045        tbl6 = config.lookup_tbl;
1046
1047        if (config.flags & DRY_RUN_FLAG) {
1048                if (config.routes_file_s != NULL)
1049                        ret =  dump_rt_6(rt);
1050                if (ret != 0)
1051                        return ret;
1052                if (config.lookup_ips_file_s != NULL)
1053                        ret = dump_lookup(AF_INET6);
1054                return ret;
1055        }
1056
1057        conf.type = get_fib_type();
1058        conf.default_nh = def_nh;
1059        conf.max_routes = config.nb_routes * 2;
1060        if (conf.type == RTE_FIB6_TRIE) {
1061                conf.trie.nh_sz = __builtin_ctz(config.ent_sz);
1062                conf.trie.num_tbl8 = RTE_MIN(config.tbl8,
1063                        get_max_nh(conf.trie.nh_sz));
1064        }
1065
1066        fib = rte_fib6_create("test", -1, &conf);
1067        if (fib == NULL) {
1068                printf("Can not alloc FIB, err %d\n", rte_errno);
1069                return -rte_errno;
1070        }
1071
1072        if (config.lookup_fn != 0) {
1073                if (config.lookup_fn == 1)
1074                        ret = rte_fib6_select_lookup(fib,
1075                                RTE_FIB6_LOOKUP_TRIE_SCALAR);
1076                else if (config.lookup_fn == 2)
1077                        ret = rte_fib6_select_lookup(fib,
1078                                RTE_FIB6_LOOKUP_TRIE_VECTOR_AVX512);
1079                else
1080                        ret = -EINVAL;
1081                if (ret != 0) {
1082                        printf("Can not init lookup function\n");
1083                        return ret;
1084                }
1085        }
1086
1087        for (k = config.print_fract, i = 0; k > 0; k--) {
1088                start = rte_rdtsc_precise();
1089                for (j = 0; j < (config.nb_routes - i) / k; j++) {
1090                        ret = rte_fib6_add(fib, rt[i + j].addr,
1091                                rt[i + j].depth, rt[i + j].nh);
1092                        if (unlikely(ret != 0)) {
1093                                printf("Can not add a route to FIB, err %d\n",
1094                                        ret);
1095                                return -ret;
1096                        }
1097                }
1098                printf("AVG FIB add %"PRIu64"\n",
1099                        (rte_rdtsc_precise() - start) / j);
1100                i += j;
1101        }
1102
1103        if (config.flags & CMP_FLAG) {
1104                lpm_conf.max_rules = config.nb_routes * 2;
1105                lpm_conf.number_tbl8s = RTE_MAX(conf.trie.num_tbl8,
1106                        config.tbl8);
1107
1108                lpm = rte_lpm6_create("test_lpm", -1, &lpm_conf);
1109                if (lpm == NULL) {
1110                        printf("Can not alloc LPM, err %d\n", rte_errno);
1111                        return -rte_errno;
1112                }
1113                for (k = config.print_fract, i = 0; k > 0; k--) {
1114                        start = rte_rdtsc_precise();
1115                        for (j = 0; j < (config.nb_routes - i) / k; j++) {
1116                                ret = rte_lpm6_add(lpm, rt[i + j].addr,
1117                                        rt[i + j].depth, rt[i + j].nh);
1118                                if (ret != 0) {
1119                                        if (rt[i + j].depth == 0)
1120                                                print_depth_err();
1121                                        printf("Can not add a route to LPM, "
1122                                                "err %d\n", ret);
1123                                        return -ret;
1124                                }
1125                        }
1126                        printf("AVG LPM add %"PRIu64"\n",
1127                                (rte_rdtsc_precise() - start) / j);
1128                        i += j;
1129                }
1130        }
1131
1132        acc = 0;
1133        for (i = 0; i < config.nb_lookup_ips; i += BURST_SZ) {
1134                start = rte_rdtsc_precise();
1135                ret = rte_fib6_lookup_bulk(fib, (uint8_t (*)[16])(tbl6 + i*16),
1136                        fib_nh, BURST_SZ);
1137                acc += rte_rdtsc_precise() - start;
1138                if (ret != 0) {
1139                        printf("FIB lookup fails, err %d\n", ret);
1140                        return -ret;
1141                }
1142        }
1143        printf("AVG FIB lookup %.1f\n", (double)acc / (double)i);
1144
1145        if (config.flags & CMP_FLAG) {
1146                acc = 0;
1147                for (i = 0; i < config.nb_lookup_ips; i += BURST_SZ) {
1148                        start = rte_rdtsc_precise();
1149                        ret = rte_lpm6_lookup_bulk_func(lpm,
1150                                (uint8_t (*)[16])(tbl6 + i*16),
1151                                lpm_nh, BURST_SZ);
1152                        acc += rte_rdtsc_precise() - start;
1153                        if (ret != 0) {
1154                                printf("LPM lookup fails, err %d\n", ret);
1155                                return -ret;
1156                        }
1157                }
1158                printf("AVG LPM lookup %.1f\n", (double)acc / (double)i);
1159
1160                for (i = 0; i < config.nb_lookup_ips; i += BURST_SZ) {
1161                        rte_fib6_lookup_bulk(fib,
1162                                (uint8_t (*)[16])(tbl6 + i*16),
1163                                fib_nh, BURST_SZ);
1164                        rte_lpm6_lookup_bulk_func(lpm,
1165                                (uint8_t (*)[16])(tbl6 + i*16),
1166                                lpm_nh, BURST_SZ);
1167                        for (j = 0; j < BURST_SZ; j++) {
1168                                if ((fib_nh[j] != (uint32_t)lpm_nh[j]) &&
1169                                                !((lpm_nh[j] == -1) &&
1170                                                (fib_nh[j] == def_nh))) {
1171                                        printf("FAIL\n");
1172                                        return -1;
1173                                }
1174                        }
1175                }
1176                printf("FIB and LPM lookup returns same values\n");
1177        }
1178
1179        for (k = config.print_fract, i = 0; k > 0; k--) {
1180                start = rte_rdtsc_precise();
1181                for (j = 0; j < (config.nb_routes - i) / k; j++)
1182                        rte_fib6_delete(fib, rt[i + j].addr, rt[i + j].depth);
1183
1184                printf("AVG FIB delete %"PRIu64"\n",
1185                        (rte_rdtsc_precise() - start) / j);
1186                i += j;
1187        }
1188
1189        if (config.flags & CMP_FLAG) {
1190                for (k = config.print_fract, i = 0; k > 0; k--) {
1191                        start = rte_rdtsc_precise();
1192                        for (j = 0; j < (config.nb_routes - i) / k; j++)
1193                                rte_lpm6_delete(lpm, rt[i + j].addr,
1194                                        rt[i + j].depth);
1195
1196                        printf("AVG LPM delete %"PRIu64"\n",
1197                                (rte_rdtsc_precise() - start) / j);
1198                        i += j;
1199                }
1200        }
1201        return 0;
1202}
1203
1204int
1205main(int argc, char **argv)
1206{
1207        int ret, af, rt_ent_sz, lookup_ent_sz;
1208        FILE *fr = NULL;
1209        FILE *fl = NULL;
1210        uint8_t depth_lim;
1211
1212        ret = rte_eal_init(argc, argv);
1213        if (ret < 0)
1214                rte_panic("Cannot init EAL\n");
1215
1216        argc -= ret;
1217        argv += ret;
1218
1219        config.prgname = argv[0];
1220
1221        parse_opts(argc, argv);
1222
1223        ret = check_config();
1224        if (ret != 0)
1225                rte_exit(-ret, "Bad configuration\n");
1226
1227        af = ((config.flags & IPV6_FLAG) == 0) ? AF_INET : AF_INET6;
1228        depth_lim = (af == AF_INET) ? 32 : 128;
1229        rt_ent_sz = (af == AF_INET) ? sizeof(struct rt_rule_4) :
1230                sizeof(struct rt_rule_6);
1231        lookup_ent_sz = (af == AF_INET) ? 4 : 16;
1232
1233        /* Count number of rules in file*/
1234        if (config.routes_file != NULL) {
1235                fr = fopen(config.routes_file, "r");
1236                if (fr == NULL)
1237                        rte_exit(-errno, "Can not open file with routes %s\n",
1238                                config.routes_file);
1239
1240                config.nb_routes = 0;
1241                while (fgets(line, sizeof(line), fr) != NULL)
1242                        config.nb_routes++;
1243                rewind(fr);
1244        }
1245
1246        /* Count number of ip's in file*/
1247        if (config.lookup_ips_file != NULL) {
1248                fl = fopen(config.lookup_ips_file, "r");
1249                if (fl == NULL)
1250                        rte_exit(-errno, "Can not open file with ip's %s\n",
1251                                config.lookup_ips_file);
1252
1253                config.nb_lookup_ips = 0;
1254                while (fgets(line, sizeof(line), fl) != NULL)
1255                        config.nb_lookup_ips++;
1256                rewind(fl);
1257        }
1258
1259        /* Alloc routes table*/
1260        config.rt  = rte_malloc(NULL, rt_ent_sz * config.nb_routes, 0);
1261        if (config.rt == NULL)
1262                rte_exit(-ENOMEM, "Can not alloc rt\n");
1263
1264        /* Alloc table with ip's for lookup*/
1265        config.lookup_tbl  = rte_malloc(NULL, lookup_ent_sz *
1266                config.nb_lookup_ips, 0);
1267        if (config.lookup_tbl == NULL)
1268                rte_exit(-ENOMEM, "Can not alloc lookup table\n");
1269
1270        /* Fill routes table */
1271        if (fr == NULL) {
1272                if (distrib_string != NULL)
1273                        ret = parse_distrib(depth_lim, config.nb_routes);
1274                else {
1275                        uint8_t rpd[129] = {0};
1276                        uint32_t nrpd[129] = {0};
1277                        ret = complete_distrib(depth_lim, config.nb_routes,
1278                                rpd, nrpd);
1279                }
1280                if (ret != 0)
1281                        rte_exit(-ret,
1282                                "Bad routes distribution configuration\n");
1283                if (af == AF_INET) {
1284                        gen_random_rt_4(config.rt,
1285                                __builtin_ctz(config.ent_sz));
1286                        if (config.flags & SHUFFLE_FLAG)
1287                                shuffle_rt_4(config.rt, config.nb_routes);
1288                } else {
1289                        gen_random_rt_6(config.rt,
1290                                __builtin_ctz(config.ent_sz));
1291                        if (config.flags & SHUFFLE_FLAG)
1292                                shuffle_rt_6(config.rt, config.nb_routes);
1293                }
1294        } else {
1295                if (af == AF_INET)
1296                        ret = parse_rt_4(fr);
1297                else
1298                        ret = parse_rt_6(fr);
1299
1300                if (ret != 0) {
1301                        rte_exit(-ret, "failed to parse routes file %s\n",
1302                                config.routes_file);
1303                }
1304        }
1305
1306        /* Fill lookup table with ip's*/
1307        if (fl == NULL)
1308                gen_rnd_lookup_tbl(af);
1309        else {
1310                ret = parse_lookup(fl, af);
1311                if (ret != 0)
1312                        rte_exit(-ret, "failed to parse lookup file\n");
1313        }
1314
1315        print_config();
1316
1317        if (af == AF_INET)
1318                ret = run_v4();
1319        else
1320                ret = run_v6();
1321
1322        return ret;
1323}
1324