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