dpdk/app/test/test_fib6.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright(c) 2018 Vladimir Medvedkin <medvedkinv@gmail.com>
   3 * Copyright(c) 2019 Intel Corporation
   4 */
   5
   6#include <stdio.h>
   7#include <stdint.h>
   8#include <stdlib.h>
   9
  10#include <rte_memory.h>
  11#include <rte_log.h>
  12
  13#include "test.h"
  14
  15#ifdef RTE_EXEC_ENV_WINDOWS
  16static int
  17test_fib6(void)
  18{
  19        printf("fib not supported on Windows, skipping test\n");
  20        return TEST_SKIPPED;
  21}
  22
  23static int
  24test_slow_fib6(void)
  25{
  26        printf("slow_fib not supported on Windows, skipping test\n");
  27        return TEST_SKIPPED;
  28}
  29
  30#else
  31
  32#include <rte_rib6.h>
  33#include <rte_fib6.h>
  34
  35typedef int32_t (*rte_fib6_test)(void);
  36
  37static int32_t test_create_invalid(void);
  38static int32_t test_multiple_create(void);
  39static int32_t test_free_null(void);
  40static int32_t test_add_del_invalid(void);
  41static int32_t test_get_invalid(void);
  42static int32_t test_lookup(void);
  43
  44#define MAX_ROUTES      (1 << 16)
  45/** Maximum number of tbl8 for 2-byte entries */
  46#define MAX_TBL8        (1 << 15)
  47
  48/*
  49 * Check that rte_fib6_create fails gracefully for incorrect user input
  50 * arguments
  51 */
  52int32_t
  53test_create_invalid(void)
  54{
  55        struct rte_fib6 *fib = NULL;
  56        struct rte_fib6_conf config;
  57
  58        config.max_routes = MAX_ROUTES;
  59        config.rib_ext_sz = 0;
  60        config.default_nh = 0;
  61        config.type = RTE_FIB6_DUMMY;
  62
  63        /* rte_fib6_create: fib name == NULL */
  64        fib = rte_fib6_create(NULL, SOCKET_ID_ANY, &config);
  65        RTE_TEST_ASSERT(fib == NULL,
  66                "Call succeeded with invalid parameters\n");
  67
  68        /* rte_fib6_create: config == NULL */
  69        fib = rte_fib6_create(__func__, SOCKET_ID_ANY, NULL);
  70        RTE_TEST_ASSERT(fib == NULL,
  71                "Call succeeded with invalid parameters\n");
  72
  73        /* socket_id < -1 is invalid */
  74        fib = rte_fib6_create(__func__, -2, &config);
  75        RTE_TEST_ASSERT(fib == NULL,
  76                "Call succeeded with invalid parameters\n");
  77
  78        /* rte_fib6_create: max_routes = 0 */
  79        config.max_routes = 0;
  80        fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
  81        RTE_TEST_ASSERT(fib == NULL,
  82                "Call succeeded with invalid parameters\n");
  83        config.max_routes = MAX_ROUTES;
  84
  85        config.type = RTE_FIB6_TRIE + 1;
  86        fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
  87        RTE_TEST_ASSERT(fib == NULL,
  88                "Call succeeded with invalid parameters\n");
  89
  90        config.type = RTE_FIB6_TRIE;
  91        config.trie.num_tbl8 = MAX_TBL8;
  92
  93        config.trie.nh_sz = RTE_FIB6_TRIE_8B + 1;
  94        fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
  95        RTE_TEST_ASSERT(fib == NULL,
  96                "Call succeeded with invalid parameters\n");
  97        config.trie.nh_sz = RTE_FIB6_TRIE_8B;
  98
  99        config.trie.num_tbl8 = 0;
 100        fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
 101        RTE_TEST_ASSERT(fib == NULL,
 102                "Call succeeded with invalid parameters\n");
 103
 104        return TEST_SUCCESS;
 105}
 106
 107/*
 108 * Create fib table then delete fib table 10 times
 109 * Use a slightly different rules size each time
 110 */
 111int32_t
 112test_multiple_create(void)
 113{
 114        struct rte_fib6 *fib = NULL;
 115        struct rte_fib6_conf config;
 116        int32_t i;
 117
 118        config.rib_ext_sz = 0;
 119        config.default_nh = 0;
 120        config.type = RTE_FIB6_DUMMY;
 121
 122        for (i = 0; i < 100; i++) {
 123                config.max_routes = MAX_ROUTES - i;
 124                fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
 125                RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n");
 126                rte_fib6_free(fib);
 127        }
 128        /* Can not test free so return success */
 129        return TEST_SUCCESS;
 130}
 131
 132/*
 133 * Call rte_fib6_free for NULL pointer user input. Note: free has no return and
 134 * therefore it is impossible to check for failure but this test is added to
 135 * increase function coverage metrics and to validate that freeing null does
 136 * not crash.
 137 */
 138int32_t
 139test_free_null(void)
 140{
 141        struct rte_fib6 *fib = NULL;
 142        struct rte_fib6_conf config;
 143
 144        config.max_routes = MAX_ROUTES;
 145        config.rib_ext_sz = 0;
 146        config.default_nh = 0;
 147        config.type = RTE_FIB6_DUMMY;
 148
 149        fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
 150        RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n");
 151
 152        rte_fib6_free(fib);
 153        rte_fib6_free(NULL);
 154
 155        return TEST_SUCCESS;
 156}
 157
 158/*
 159 * Check that rte_fib6_add and rte_fib6_delete fails gracefully
 160 * for incorrect user input arguments
 161 */
 162int32_t
 163test_add_del_invalid(void)
 164{
 165        struct rte_fib6 *fib = NULL;
 166        struct rte_fib6_conf config;
 167        uint64_t nh = 100;
 168        uint8_t ip[RTE_FIB6_IPV6_ADDR_SIZE] = {0};
 169        int ret;
 170        uint8_t depth = 24;
 171
 172        config.max_routes = MAX_ROUTES;
 173        config.rib_ext_sz = 0;
 174        config.default_nh = 0;
 175        config.type = RTE_FIB6_DUMMY;
 176
 177        /* rte_fib6_add: fib == NULL */
 178        ret = rte_fib6_add(NULL, ip, depth, nh);
 179        RTE_TEST_ASSERT(ret < 0,
 180                "Call succeeded with invalid parameters\n");
 181
 182        /* rte_fib6_delete: fib == NULL */
 183        ret = rte_fib6_delete(NULL, ip, depth);
 184        RTE_TEST_ASSERT(ret < 0,
 185                "Call succeeded with invalid parameters\n");
 186
 187        /*Create valid fib to use in rest of test. */
 188        fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
 189        RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n");
 190
 191        /* rte_fib6_add: depth > RTE_FIB6_MAXDEPTH */
 192        ret = rte_fib6_add(fib, ip, RTE_FIB6_MAXDEPTH + 1, nh);
 193        RTE_TEST_ASSERT(ret < 0,
 194                "Call succeeded with invalid parameters\n");
 195
 196        /* rte_fib6_delete: depth > RTE_FIB6_MAXDEPTH */
 197        ret = rte_fib6_delete(fib, ip, RTE_FIB6_MAXDEPTH + 1);
 198        RTE_TEST_ASSERT(ret < 0,
 199                "Call succeeded with invalid parameters\n");
 200
 201        rte_fib6_free(fib);
 202
 203        return TEST_SUCCESS;
 204}
 205
 206/*
 207 * Check that rte_fib6_get_dp and rte_fib6_get_rib fails gracefully
 208 * for incorrect user input arguments
 209 */
 210int32_t
 211test_get_invalid(void)
 212{
 213        void *p;
 214
 215        p = rte_fib6_get_dp(NULL);
 216        RTE_TEST_ASSERT(p == NULL,
 217                "Call succeeded with invalid parameters\n");
 218
 219        p = rte_fib6_get_rib(NULL);
 220        RTE_TEST_ASSERT(p == NULL,
 221                "Call succeeded with invalid parameters\n");
 222
 223        return TEST_SUCCESS;
 224}
 225
 226/*
 227 * Add routes for one supernet with all possible depths and do lookup
 228 * on each step
 229 * After delete routes with doing lookup on each step
 230 */
 231static int
 232lookup_and_check_asc(struct rte_fib6 *fib,
 233        uint8_t ip_arr[RTE_FIB6_MAXDEPTH][RTE_FIB6_IPV6_ADDR_SIZE],
 234        uint8_t ip_missing[][RTE_FIB6_IPV6_ADDR_SIZE], uint64_t def_nh,
 235        uint32_t n)
 236{
 237        uint64_t nh_arr[RTE_FIB6_MAXDEPTH];
 238        int ret;
 239        uint32_t i = 0;
 240
 241        ret = rte_fib6_lookup_bulk(fib, ip_arr, nh_arr, RTE_FIB6_MAXDEPTH);
 242        RTE_TEST_ASSERT(ret == 0, "Failed to lookup\n");
 243
 244        for (; i <= RTE_FIB6_MAXDEPTH - n; i++)
 245                RTE_TEST_ASSERT(nh_arr[i] == n,
 246                        "Failed to get proper nexthop\n");
 247
 248        for (; i < RTE_FIB6_MAXDEPTH; i++)
 249                RTE_TEST_ASSERT(nh_arr[i] == --n,
 250                        "Failed to get proper nexthop\n");
 251
 252        ret = rte_fib6_lookup_bulk(fib, ip_missing, nh_arr, 1);
 253        RTE_TEST_ASSERT((ret == 0) && (nh_arr[0] == def_nh),
 254                "Failed to get proper nexthop\n");
 255
 256        return TEST_SUCCESS;
 257}
 258
 259static int
 260lookup_and_check_desc(struct rte_fib6 *fib,
 261        uint8_t ip_arr[RTE_FIB6_MAXDEPTH][RTE_FIB6_IPV6_ADDR_SIZE],
 262        uint8_t ip_missing[][RTE_FIB6_IPV6_ADDR_SIZE], uint64_t def_nh,
 263        uint32_t n)
 264{
 265        uint64_t nh_arr[RTE_FIB6_MAXDEPTH];
 266        int ret;
 267        uint32_t i = 0;
 268
 269        ret = rte_fib6_lookup_bulk(fib, ip_arr, nh_arr, RTE_FIB6_MAXDEPTH);
 270        RTE_TEST_ASSERT(ret == 0, "Failed to lookup\n");
 271
 272        for (; i < n; i++)
 273                RTE_TEST_ASSERT(nh_arr[i] == RTE_FIB6_MAXDEPTH - i,
 274                        "Failed to get proper nexthop\n");
 275
 276        for (; i < RTE_FIB6_MAXDEPTH; i++)
 277                RTE_TEST_ASSERT(nh_arr[i] == def_nh,
 278                        "Failed to get proper nexthop\n");
 279
 280        ret = rte_fib6_lookup_bulk(fib, ip_missing, nh_arr, 1);
 281        RTE_TEST_ASSERT((ret == 0) && (nh_arr[0] == def_nh),
 282                "Failed to get proper nexthop\n");
 283
 284        return TEST_SUCCESS;
 285}
 286
 287static int
 288check_fib(struct rte_fib6 *fib)
 289{
 290        uint64_t def_nh = 100;
 291        uint8_t ip_arr[RTE_FIB6_MAXDEPTH][RTE_FIB6_IPV6_ADDR_SIZE];
 292        uint8_t ip_add[RTE_FIB6_IPV6_ADDR_SIZE] = {0};
 293        uint8_t ip_missing[1][RTE_FIB6_IPV6_ADDR_SIZE] = { {255} };
 294        uint32_t i, j;
 295        int ret;
 296
 297        ip_add[0] = 128;
 298        ip_missing[0][0] = 127;
 299        for (i = 0; i < RTE_FIB6_MAXDEPTH; i++) {
 300                for (j = 0; j < RTE_FIB6_IPV6_ADDR_SIZE; j++) {
 301                        ip_arr[i][j] = ip_add[j] |
 302                                ~get_msk_part(RTE_FIB6_MAXDEPTH - i, j);
 303                }
 304        }
 305
 306        ret = lookup_and_check_desc(fib, ip_arr, ip_missing, def_nh, 0);
 307        RTE_TEST_ASSERT(ret == TEST_SUCCESS, "Lookup and check fails\n");
 308
 309        for (i = 1; i <= RTE_FIB6_MAXDEPTH; i++) {
 310                ret = rte_fib6_add(fib, ip_add, i, i);
 311                RTE_TEST_ASSERT(ret == 0, "Failed to add a route\n");
 312                ret = lookup_and_check_asc(fib, ip_arr, ip_missing, def_nh, i);
 313                RTE_TEST_ASSERT(ret == TEST_SUCCESS,
 314                        "Lookup and check fails\n");
 315        }
 316
 317        for (i = RTE_FIB6_MAXDEPTH; i > 1; i--) {
 318                ret = rte_fib6_delete(fib, ip_add, i);
 319                RTE_TEST_ASSERT(ret == 0, "Failed to delete a route\n");
 320                ret = lookup_and_check_asc(fib, ip_arr, ip_missing,
 321                        def_nh, i - 1);
 322
 323                RTE_TEST_ASSERT(ret == TEST_SUCCESS,
 324                        "Lookup and check fails\n");
 325        }
 326        ret = rte_fib6_delete(fib, ip_add, i);
 327        RTE_TEST_ASSERT(ret == 0, "Failed to delete a route\n");
 328        ret = lookup_and_check_desc(fib, ip_arr, ip_missing, def_nh, 0);
 329        RTE_TEST_ASSERT(ret == TEST_SUCCESS,
 330                "Lookup and check fails\n");
 331
 332        for (i = 0; i < RTE_FIB6_MAXDEPTH; i++) {
 333                ret = rte_fib6_add(fib, ip_add, RTE_FIB6_MAXDEPTH - i,
 334                        RTE_FIB6_MAXDEPTH - i);
 335                RTE_TEST_ASSERT(ret == 0, "Failed to add a route\n");
 336                ret = lookup_and_check_desc(fib, ip_arr, ip_missing,
 337                        def_nh, i + 1);
 338                RTE_TEST_ASSERT(ret == TEST_SUCCESS,
 339                        "Lookup and check fails\n");
 340        }
 341
 342        for (i = 1; i <= RTE_FIB6_MAXDEPTH; i++) {
 343                ret = rte_fib6_delete(fib, ip_add, i);
 344                RTE_TEST_ASSERT(ret == 0, "Failed to delete a route\n");
 345                ret = lookup_and_check_desc(fib, ip_arr, ip_missing, def_nh,
 346                        RTE_FIB6_MAXDEPTH - i);
 347                RTE_TEST_ASSERT(ret == TEST_SUCCESS,
 348                        "Lookup and check fails\n");
 349        }
 350
 351        return TEST_SUCCESS;
 352}
 353
 354int32_t
 355test_lookup(void)
 356{
 357        struct rte_fib6 *fib = NULL;
 358        struct rte_fib6_conf config;
 359        uint64_t def_nh = 100;
 360        int ret;
 361
 362        config.max_routes = MAX_ROUTES;
 363        config.rib_ext_sz = 0;
 364        config.default_nh = def_nh;
 365        config.type = RTE_FIB6_DUMMY;
 366
 367        fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
 368        RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n");
 369        ret = check_fib(fib);
 370        RTE_TEST_ASSERT(ret == TEST_SUCCESS,
 371                "Check_fib fails for DUMMY type\n");
 372        rte_fib6_free(fib);
 373
 374        config.type = RTE_FIB6_TRIE;
 375
 376        config.trie.nh_sz = RTE_FIB6_TRIE_2B;
 377        config.trie.num_tbl8 = MAX_TBL8 - 1;
 378        fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
 379        RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n");
 380        ret = check_fib(fib);
 381        RTE_TEST_ASSERT(ret == TEST_SUCCESS,
 382                "Check_fib fails for TRIE_2B type\n");
 383        rte_fib6_free(fib);
 384
 385        config.trie.nh_sz = RTE_FIB6_TRIE_4B;
 386        config.trie.num_tbl8 = MAX_TBL8;
 387        fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
 388        RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n");
 389        ret = check_fib(fib);
 390        RTE_TEST_ASSERT(ret == TEST_SUCCESS,
 391                "Check_fib fails for TRIE_4B type\n");
 392        rte_fib6_free(fib);
 393
 394        config.trie.nh_sz = RTE_FIB6_TRIE_8B;
 395        config.trie.num_tbl8 = MAX_TBL8;
 396        fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
 397        RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n");
 398        ret = check_fib(fib);
 399        RTE_TEST_ASSERT(ret == TEST_SUCCESS,
 400                "Check_fib fails for TRIE_8B type\n");
 401        rte_fib6_free(fib);
 402
 403        return TEST_SUCCESS;
 404}
 405
 406static struct unit_test_suite fib6_fast_tests = {
 407        .suite_name = "fib6 autotest",
 408        .setup = NULL,
 409        .teardown = NULL,
 410        .unit_test_cases = {
 411        TEST_CASE(test_create_invalid),
 412        TEST_CASE(test_free_null),
 413        TEST_CASE(test_add_del_invalid),
 414        TEST_CASE(test_get_invalid),
 415        TEST_CASE(test_lookup),
 416        TEST_CASES_END()
 417        }
 418};
 419
 420static struct unit_test_suite fib6_slow_tests = {
 421        .suite_name = "fib6 slow autotest",
 422        .setup = NULL,
 423        .teardown = NULL,
 424        .unit_test_cases = {
 425        TEST_CASE(test_multiple_create),
 426        TEST_CASES_END()
 427        }
 428};
 429
 430/*
 431 * Do all unit tests.
 432 */
 433static int
 434test_fib6(void)
 435{
 436        return unit_test_suite_runner(&fib6_fast_tests);
 437}
 438
 439static int
 440test_slow_fib6(void)
 441{
 442        return unit_test_suite_runner(&fib6_slow_tests);
 443}
 444
 445#endif /* !RTE_EXEC_ENV_WINDOWS */
 446
 447REGISTER_TEST_COMMAND(fib6_autotest, test_fib6);
 448REGISTER_TEST_COMMAND(fib6_slow_autotest, test_slow_fib6);
 449