LCOV - code coverage report
Current view: top level - app/test - test_fib6.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 242 257 94.2 %
Date: 2025-12-01 19:08:10 Functions: 14 16 87.5 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 94 162 58.0 %

           Branch data     Line data    Source code
       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                 :            : #include <rte_malloc.h>
      15                 :            : 
      16                 :            : #include "test.h"
      17                 :            : 
      18                 :            : typedef int32_t (*rte_fib6_test)(void);
      19                 :            : 
      20                 :            : static int32_t test_create_invalid(void);
      21                 :            : static int32_t test_multiple_create(void);
      22                 :            : static int32_t test_free_null(void);
      23                 :            : static int32_t test_add_del_invalid(void);
      24                 :            : static int32_t test_get_invalid(void);
      25                 :            : static int32_t test_lookup(void);
      26                 :            : static int32_t test_invalid_rcu(void);
      27                 :            : static int32_t test_fib_rcu_sync_rw(void);
      28                 :            : 
      29                 :            : #define MAX_ROUTES      (1 << 16)
      30                 :            : /** Maximum number of tbl8 for 2-byte entries */
      31                 :            : #define MAX_TBL8        (1 << 15)
      32                 :            : 
      33                 :            : /*
      34                 :            :  * Check that rte_fib6_create fails gracefully for incorrect user input
      35                 :            :  * arguments
      36                 :            :  */
      37                 :            : int32_t
      38                 :          1 : test_create_invalid(void)
      39                 :            : {
      40                 :            :         struct rte_fib6 *fib = NULL;
      41                 :            :         struct rte_fib6_conf config;
      42                 :            : 
      43                 :          1 :         config.max_routes = MAX_ROUTES;
      44                 :          1 :         config.rib_ext_sz = 0;
      45                 :          1 :         config.default_nh = 0;
      46                 :          1 :         config.type = RTE_FIB6_DUMMY;
      47                 :            : 
      48                 :            :         /* rte_fib6_create: fib name == NULL */
      49                 :          1 :         fib = rte_fib6_create(NULL, SOCKET_ID_ANY, &config);
      50         [ -  + ]:          1 :         RTE_TEST_ASSERT(fib == NULL,
      51                 :            :                 "Call succeeded with invalid parameters\n");
      52                 :            : 
      53                 :            :         /* rte_fib6_create: config == NULL */
      54                 :          1 :         fib = rte_fib6_create(__func__, SOCKET_ID_ANY, NULL);
      55         [ -  + ]:          1 :         RTE_TEST_ASSERT(fib == NULL,
      56                 :            :                 "Call succeeded with invalid parameters\n");
      57                 :            : 
      58                 :            :         /* socket_id < -1 is invalid */
      59                 :          1 :         fib = rte_fib6_create(__func__, -2, &config);
      60         [ -  + ]:          1 :         RTE_TEST_ASSERT(fib == NULL,
      61                 :            :                 "Call succeeded with invalid parameters\n");
      62                 :            : 
      63                 :            :         /* rte_fib6_create: max_routes = 0 */
      64                 :          1 :         config.max_routes = 0;
      65                 :          1 :         fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
      66         [ -  + ]:          1 :         RTE_TEST_ASSERT(fib == NULL,
      67                 :            :                 "Call succeeded with invalid parameters\n");
      68                 :          1 :         config.max_routes = MAX_ROUTES;
      69                 :            : 
      70                 :          1 :         config.type = RTE_FIB6_TRIE + 1;
      71                 :          1 :         fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
      72         [ -  + ]:          1 :         RTE_TEST_ASSERT(fib == NULL,
      73                 :            :                 "Call succeeded with invalid parameters\n");
      74                 :            : 
      75                 :          1 :         config.type = RTE_FIB6_TRIE;
      76                 :          1 :         config.trie.num_tbl8 = MAX_TBL8;
      77                 :            : 
      78                 :          1 :         config.trie.nh_sz = RTE_FIB6_TRIE_8B + 1;
      79                 :          1 :         fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
      80         [ -  + ]:          1 :         RTE_TEST_ASSERT(fib == NULL,
      81                 :            :                 "Call succeeded with invalid parameters\n");
      82                 :          1 :         config.trie.nh_sz = RTE_FIB6_TRIE_8B;
      83                 :            : 
      84                 :          1 :         config.trie.num_tbl8 = 0;
      85                 :          1 :         fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
      86         [ -  + ]:          1 :         RTE_TEST_ASSERT(fib == NULL,
      87                 :            :                 "Call succeeded with invalid parameters\n");
      88                 :            : 
      89                 :            :         return TEST_SUCCESS;
      90                 :            : }
      91                 :            : 
      92                 :            : /*
      93                 :            :  * Create fib table then delete fib table 10 times
      94                 :            :  * Use a slightly different rules size each time
      95                 :            :  */
      96                 :            : int32_t
      97                 :          0 : test_multiple_create(void)
      98                 :            : {
      99                 :            :         struct rte_fib6 *fib = NULL;
     100                 :            :         struct rte_fib6_conf config;
     101                 :            :         int32_t i;
     102                 :            : 
     103                 :          0 :         config.rib_ext_sz = 0;
     104                 :          0 :         config.default_nh = 0;
     105                 :          0 :         config.type = RTE_FIB6_DUMMY;
     106                 :            : 
     107         [ #  # ]:          0 :         for (i = 0; i < 100; i++) {
     108                 :          0 :                 config.max_routes = MAX_ROUTES - i;
     109                 :          0 :                 fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
     110         [ #  # ]:          0 :                 RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n");
     111                 :          0 :                 rte_fib6_free(fib);
     112                 :            :         }
     113                 :            :         /* Can not test free so return success */
     114                 :            :         return TEST_SUCCESS;
     115                 :            : }
     116                 :            : 
     117                 :            : /*
     118                 :            :  * Call rte_fib6_free for NULL pointer user input. Note: free has no return and
     119                 :            :  * therefore it is impossible to check for failure but this test is added to
     120                 :            :  * increase function coverage metrics and to validate that freeing null does
     121                 :            :  * not crash.
     122                 :            :  */
     123                 :            : int32_t
     124                 :          1 : test_free_null(void)
     125                 :            : {
     126                 :            :         struct rte_fib6 *fib = NULL;
     127                 :            :         struct rte_fib6_conf config;
     128                 :            : 
     129                 :          1 :         config.max_routes = MAX_ROUTES;
     130                 :          1 :         config.rib_ext_sz = 0;
     131                 :          1 :         config.default_nh = 0;
     132                 :          1 :         config.type = RTE_FIB6_DUMMY;
     133                 :            : 
     134                 :          1 :         fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
     135         [ -  + ]:          1 :         RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n");
     136                 :            : 
     137                 :          1 :         rte_fib6_free(fib);
     138                 :          1 :         rte_fib6_free(NULL);
     139                 :            : 
     140                 :          1 :         return TEST_SUCCESS;
     141                 :            : }
     142                 :            : 
     143                 :            : /*
     144                 :            :  * Check that rte_fib6_add and rte_fib6_delete fails gracefully
     145                 :            :  * for incorrect user input arguments
     146                 :            :  */
     147                 :            : int32_t
     148                 :          1 : test_add_del_invalid(void)
     149                 :            : {
     150                 :            :         struct rte_fib6 *fib = NULL;
     151                 :            :         struct rte_fib6_conf config;
     152                 :            :         uint64_t nh = 100;
     153                 :          1 :         struct rte_ipv6_addr ip = RTE_IPV6_ADDR_UNSPEC;
     154                 :            :         int ret;
     155                 :            :         uint8_t depth = 24;
     156                 :            : 
     157                 :          1 :         config.max_routes = MAX_ROUTES;
     158                 :          1 :         config.rib_ext_sz = 0;
     159                 :          1 :         config.default_nh = 0;
     160                 :          1 :         config.type = RTE_FIB6_DUMMY;
     161                 :            : 
     162                 :            :         /* rte_fib6_add: fib == NULL */
     163                 :          1 :         ret = rte_fib6_add(NULL, &ip, depth, nh);
     164         [ -  + ]:          1 :         RTE_TEST_ASSERT(ret < 0,
     165                 :            :                 "Call succeeded with invalid parameters\n");
     166                 :            : 
     167                 :            :         /* rte_fib6_delete: fib == NULL */
     168                 :          1 :         ret = rte_fib6_delete(NULL, &ip, depth);
     169         [ -  + ]:          1 :         RTE_TEST_ASSERT(ret < 0,
     170                 :            :                 "Call succeeded with invalid parameters\n");
     171                 :            : 
     172                 :            :         /*Create valid fib to use in rest of test. */
     173                 :          1 :         fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
     174         [ -  + ]:          1 :         RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n");
     175                 :            : 
     176                 :            :         /* rte_fib6_add: depth > RTE_IPV6_MAX_DEPTH */
     177                 :          1 :         ret = rte_fib6_add(fib, &ip, RTE_IPV6_MAX_DEPTH + 1, nh);
     178         [ -  + ]:          1 :         RTE_TEST_ASSERT(ret < 0,
     179                 :            :                 "Call succeeded with invalid parameters\n");
     180                 :            : 
     181                 :            :         /* rte_fib6_delete: depth > RTE_IPV6_MAX_DEPTH */
     182                 :          1 :         ret = rte_fib6_delete(fib, &ip, RTE_IPV6_MAX_DEPTH + 1);
     183         [ -  + ]:          1 :         RTE_TEST_ASSERT(ret < 0,
     184                 :            :                 "Call succeeded with invalid parameters\n");
     185                 :            : 
     186                 :          1 :         rte_fib6_free(fib);
     187                 :            : 
     188                 :          1 :         return TEST_SUCCESS;
     189                 :            : }
     190                 :            : 
     191                 :            : /*
     192                 :            :  * Check that rte_fib6_get_dp and rte_fib6_get_rib fails gracefully
     193                 :            :  * for incorrect user input arguments
     194                 :            :  */
     195                 :            : int32_t
     196                 :          1 : test_get_invalid(void)
     197                 :            : {
     198                 :            :         void *p;
     199                 :            : 
     200                 :          1 :         p = rte_fib6_get_dp(NULL);
     201         [ -  + ]:          1 :         RTE_TEST_ASSERT(p == NULL,
     202                 :            :                 "Call succeeded with invalid parameters\n");
     203                 :            : 
     204                 :          1 :         p = rte_fib6_get_rib(NULL);
     205         [ -  + ]:          1 :         RTE_TEST_ASSERT(p == NULL,
     206                 :            :                 "Call succeeded with invalid parameters\n");
     207                 :            : 
     208                 :            :         return TEST_SUCCESS;
     209                 :            : }
     210                 :            : 
     211                 :            : /*
     212                 :            :  * Add routes for one supernet with all possible depths and do lookup
     213                 :            :  * on each step
     214                 :            :  * After delete routes with doing lookup on each step
     215                 :            :  */
     216                 :            : static int
     217                 :       1020 : lookup_and_check_asc(struct rte_fib6 *fib,
     218                 :            :         struct rte_ipv6_addr *ip_arr,
     219                 :            :         struct rte_ipv6_addr *ip_missing, uint64_t def_nh,
     220                 :            :         uint32_t n)
     221                 :            : {
     222                 :            :         uint64_t nh_arr[RTE_IPV6_MAX_DEPTH];
     223                 :            :         int ret;
     224                 :            :         uint32_t i = 0;
     225                 :            : 
     226                 :       1020 :         ret = rte_fib6_lookup_bulk(fib, ip_arr, nh_arr, RTE_IPV6_MAX_DEPTH);
     227         [ -  + ]:       1020 :         RTE_TEST_ASSERT(ret == 0, "Failed to lookup\n");
     228                 :            : 
     229         [ +  + ]:      67064 :         for (; i <= RTE_IPV6_MAX_DEPTH - n; i++)
     230         [ -  + ]:      66044 :                 RTE_TEST_ASSERT(nh_arr[i] == n,
     231                 :            :                         "Failed to get proper nexthop\n");
     232                 :            : 
     233         [ +  + ]:      65536 :         for (; i < RTE_IPV6_MAX_DEPTH; i++)
     234         [ -  + ]:      64516 :                 RTE_TEST_ASSERT(nh_arr[i] == --n,
     235                 :            :                         "Failed to get proper nexthop\n");
     236                 :            : 
     237                 :       1020 :         ret = rte_fib6_lookup_bulk(fib, ip_missing, nh_arr, 1);
     238   [ +  -  -  + ]:       1020 :         RTE_TEST_ASSERT((ret == 0) && (nh_arr[0] == def_nh),
     239                 :            :                 "Failed to get proper nexthop\n");
     240                 :            : 
     241                 :            :         return TEST_SUCCESS;
     242                 :            : }
     243                 :            : 
     244                 :            : static int
     245                 :       1032 : lookup_and_check_desc(struct rte_fib6 *fib,
     246                 :            :         struct rte_ipv6_addr *ip_arr,
     247                 :            :         struct rte_ipv6_addr *ip_missing, uint64_t def_nh,
     248                 :            :         uint32_t n)
     249                 :            : {
     250                 :            :         uint64_t nh_arr[RTE_IPV6_MAX_DEPTH];
     251                 :            :         int ret;
     252                 :            :         uint32_t i = 0;
     253                 :            : 
     254                 :       1032 :         ret = rte_fib6_lookup_bulk(fib, ip_arr, nh_arr, RTE_IPV6_MAX_DEPTH);
     255         [ -  + ]:       1032 :         RTE_TEST_ASSERT(ret == 0, "Failed to lookup\n");
     256                 :            : 
     257         [ +  + ]:      66568 :         for (; i < n; i++)
     258         [ -  + ]:      65536 :                 RTE_TEST_ASSERT(nh_arr[i] == RTE_IPV6_MAX_DEPTH - i,
     259                 :            :                         "Failed to get proper nexthop\n");
     260                 :            : 
     261         [ +  + ]:      67592 :         for (; i < RTE_IPV6_MAX_DEPTH; i++)
     262         [ -  + ]:      66560 :                 RTE_TEST_ASSERT(nh_arr[i] == def_nh,
     263                 :            :                         "Failed to get proper nexthop\n");
     264                 :            : 
     265                 :       1032 :         ret = rte_fib6_lookup_bulk(fib, ip_missing, nh_arr, 1);
     266   [ +  -  -  + ]:       1032 :         RTE_TEST_ASSERT((ret == 0) && (nh_arr[0] == def_nh),
     267                 :            :                 "Failed to get proper nexthop\n");
     268                 :            : 
     269                 :            :         return TEST_SUCCESS;
     270                 :            : }
     271                 :            : 
     272                 :            : static int
     273                 :          4 : check_fib(struct rte_fib6 *fib)
     274                 :            : {
     275                 :            :         uint64_t def_nh = 100;
     276                 :            :         struct rte_ipv6_addr ip_arr[RTE_IPV6_MAX_DEPTH];
     277                 :          4 :         struct rte_ipv6_addr ip_add = RTE_IPV6(0x8000, 0, 0, 0, 0, 0, 0, 0);
     278                 :          4 :         struct rte_ipv6_addr ip_missing =
     279                 :            :                 RTE_IPV6(0x7fff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff);
     280                 :            :         uint32_t i, j;
     281                 :            :         int ret;
     282                 :            : 
     283         [ +  + ]:        516 :         for (i = 0; i < RTE_IPV6_MAX_DEPTH; i++) {
     284                 :        512 :                 ip_arr[i] = ip_add;
     285                 :        512 :                 j = (RTE_IPV6_MAX_DEPTH - i) / CHAR_BIT;
     286         [ +  + ]:        512 :                 if (j < RTE_IPV6_ADDR_SIZE) {
     287                 :        508 :                         ip_arr[i].a[j] |= UINT8_MAX >> ((RTE_IPV6_MAX_DEPTH - i) % CHAR_BIT);
     288         [ +  + ]:       4288 :                         for (j++; j < RTE_IPV6_ADDR_SIZE; j++)
     289                 :       3780 :                                 ip_arr[i].a[j] = 0xff;
     290                 :            :                 }
     291                 :            :         }
     292                 :            : 
     293                 :          4 :         ret = lookup_and_check_desc(fib, ip_arr, &ip_missing, def_nh, 0);
     294         [ -  + ]:          4 :         RTE_TEST_ASSERT(ret == TEST_SUCCESS, "Lookup and check fails\n");
     295                 :            : 
     296         [ +  + ]:        516 :         for (i = 1; i <= RTE_IPV6_MAX_DEPTH; i++) {
     297                 :        512 :                 ret = rte_fib6_add(fib, &ip_add, i, i);
     298         [ -  + ]:        512 :                 RTE_TEST_ASSERT(ret == 0, "Failed to add a route\n");
     299                 :        512 :                 ret = lookup_and_check_asc(fib, ip_arr, &ip_missing, def_nh, i);
     300         [ -  + ]:        512 :                 RTE_TEST_ASSERT(ret == TEST_SUCCESS,
     301                 :            :                         "Lookup and check fails\n");
     302                 :            :         }
     303                 :            : 
     304         [ +  + ]:        512 :         for (i = RTE_IPV6_MAX_DEPTH; i > 1; i--) {
     305                 :        508 :                 ret = rte_fib6_delete(fib, &ip_add, i);
     306         [ -  + ]:        508 :                 RTE_TEST_ASSERT(ret == 0, "Failed to delete a route\n");
     307                 :        508 :                 ret = lookup_and_check_asc(fib, ip_arr, &ip_missing,
     308                 :            :                         def_nh, i - 1);
     309                 :            : 
     310         [ -  + ]:        508 :                 RTE_TEST_ASSERT(ret == TEST_SUCCESS,
     311                 :            :                         "Lookup and check fails\n");
     312                 :            :         }
     313                 :          4 :         ret = rte_fib6_delete(fib, &ip_add, i);
     314         [ -  + ]:          4 :         RTE_TEST_ASSERT(ret == 0, "Failed to delete a route\n");
     315                 :          4 :         ret = lookup_and_check_desc(fib, ip_arr, &ip_missing, def_nh, 0);
     316         [ -  + ]:          4 :         RTE_TEST_ASSERT(ret == TEST_SUCCESS,
     317                 :            :                 "Lookup and check fails\n");
     318                 :            : 
     319         [ +  + ]:        516 :         for (i = 0; i < RTE_IPV6_MAX_DEPTH; i++) {
     320                 :        512 :                 ret = rte_fib6_add(fib, &ip_add, RTE_IPV6_MAX_DEPTH - i,
     321                 :        512 :                         RTE_IPV6_MAX_DEPTH - i);
     322         [ -  + ]:        512 :                 RTE_TEST_ASSERT(ret == 0, "Failed to add a route\n");
     323                 :        512 :                 ret = lookup_and_check_desc(fib, ip_arr, &ip_missing,
     324                 :            :                         def_nh, i + 1);
     325         [ -  + ]:        512 :                 RTE_TEST_ASSERT(ret == TEST_SUCCESS,
     326                 :            :                         "Lookup and check fails\n");
     327                 :            :         }
     328                 :            : 
     329         [ +  + ]:        516 :         for (i = 1; i <= RTE_IPV6_MAX_DEPTH; i++) {
     330                 :        512 :                 ret = rte_fib6_delete(fib, &ip_add, i);
     331         [ -  + ]:        512 :                 RTE_TEST_ASSERT(ret == 0, "Failed to delete a route\n");
     332                 :        512 :                 ret = lookup_and_check_desc(fib, ip_arr, &ip_missing, def_nh,
     333                 :            :                         RTE_IPV6_MAX_DEPTH - i);
     334         [ -  + ]:        512 :                 RTE_TEST_ASSERT(ret == TEST_SUCCESS,
     335                 :            :                         "Lookup and check fails\n");
     336                 :            :         }
     337                 :            : 
     338                 :            :         return TEST_SUCCESS;
     339                 :            : }
     340                 :            : 
     341                 :            : int32_t
     342                 :          1 : test_lookup(void)
     343                 :            : {
     344                 :            :         struct rte_fib6 *fib = NULL;
     345                 :            :         struct rte_fib6_conf config;
     346                 :            :         uint64_t def_nh = 100;
     347                 :            :         int ret;
     348                 :            : 
     349                 :          1 :         config.max_routes = MAX_ROUTES;
     350                 :          1 :         config.rib_ext_sz = 0;
     351                 :          1 :         config.default_nh = def_nh;
     352                 :          1 :         config.type = RTE_FIB6_DUMMY;
     353                 :            : 
     354                 :          1 :         fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
     355         [ -  + ]:          1 :         RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n");
     356                 :          1 :         ret = check_fib(fib);
     357         [ -  + ]:          1 :         RTE_TEST_ASSERT(ret == TEST_SUCCESS,
     358                 :            :                 "Check_fib fails for DUMMY type\n");
     359                 :          1 :         rte_fib6_free(fib);
     360                 :            : 
     361                 :          1 :         config.type = RTE_FIB6_TRIE;
     362                 :            : 
     363                 :          1 :         config.trie.nh_sz = RTE_FIB6_TRIE_2B;
     364                 :          1 :         config.trie.num_tbl8 = MAX_TBL8 - 1;
     365                 :          1 :         fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
     366         [ -  + ]:          1 :         RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n");
     367                 :          1 :         ret = check_fib(fib);
     368         [ -  + ]:          1 :         RTE_TEST_ASSERT(ret == TEST_SUCCESS,
     369                 :            :                 "Check_fib fails for TRIE_2B type\n");
     370                 :          1 :         rte_fib6_free(fib);
     371                 :            : 
     372                 :          1 :         config.trie.nh_sz = RTE_FIB6_TRIE_4B;
     373                 :          1 :         config.trie.num_tbl8 = MAX_TBL8;
     374                 :          1 :         fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
     375         [ -  + ]:          1 :         RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n");
     376                 :          1 :         ret = check_fib(fib);
     377         [ -  + ]:          1 :         RTE_TEST_ASSERT(ret == TEST_SUCCESS,
     378                 :            :                 "Check_fib fails for TRIE_4B type\n");
     379                 :          1 :         rte_fib6_free(fib);
     380                 :            : 
     381                 :          1 :         config.trie.nh_sz = RTE_FIB6_TRIE_8B;
     382                 :          1 :         config.trie.num_tbl8 = MAX_TBL8;
     383                 :          1 :         fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
     384         [ -  + ]:          1 :         RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n");
     385                 :          1 :         ret = check_fib(fib);
     386         [ -  + ]:          1 :         RTE_TEST_ASSERT(ret == TEST_SUCCESS,
     387                 :            :                 "Check_fib fails for TRIE_8B type\n");
     388                 :          1 :         rte_fib6_free(fib);
     389                 :            : 
     390                 :          1 :         return TEST_SUCCESS;
     391                 :            : }
     392                 :            : 
     393                 :            : /*
     394                 :            :  * rte_fib6_rcu_qsbr_add positive and negative tests.
     395                 :            :  *  - Add RCU QSBR variable to FIB
     396                 :            :  *  - Add another RCU QSBR variable to FIB
     397                 :            :  *  - Check returns
     398                 :            :  */
     399                 :            : int32_t
     400                 :          1 : test_invalid_rcu(void)
     401                 :            : {
     402                 :            :         struct rte_fib6 *fib = NULL;
     403                 :          1 :         struct rte_fib6_conf config = { 0 };
     404                 :            :         size_t sz;
     405                 :            :         struct rte_rcu_qsbr *qsv;
     406                 :            :         struct rte_rcu_qsbr *qsv2;
     407                 :            :         int32_t status;
     408                 :          1 :         struct rte_fib6_rcu_config rcu_cfg = {0};
     409                 :            :         uint64_t def_nh = 100;
     410                 :            : 
     411                 :          1 :         config.max_routes = MAX_ROUTES;
     412                 :            :         config.rib_ext_sz = 0;
     413                 :          1 :         config.default_nh = def_nh;
     414                 :            : 
     415                 :          1 :         fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
     416         [ -  + ]:          1 :         RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n");
     417                 :            : 
     418                 :            :         /* Create RCU QSBR variable */
     419                 :          1 :         sz = rte_rcu_qsbr_get_memsize(RTE_MAX_LCORE);
     420                 :          1 :         qsv = (struct rte_rcu_qsbr *)rte_zmalloc_socket(NULL, sz, RTE_CACHE_LINE_SIZE,
     421                 :            :                 SOCKET_ID_ANY);
     422         [ -  + ]:          1 :         RTE_TEST_ASSERT(qsv != NULL, "Can not allocate memory for RCU\n");
     423                 :            : 
     424                 :          1 :         status = rte_rcu_qsbr_init(qsv, RTE_MAX_LCORE);
     425         [ -  + ]:          1 :         RTE_TEST_ASSERT(status == 0, "Can not initialize RCU\n");
     426                 :            : 
     427                 :          1 :         rcu_cfg.v = qsv;
     428                 :            : 
     429                 :            :         /* adding rcu to RTE_FIB6_DUMMY FIB type */
     430                 :          1 :         config.type = RTE_FIB6_DUMMY;
     431                 :          1 :         rcu_cfg.mode = RTE_FIB6_QSBR_MODE_SYNC;
     432                 :          1 :         status = rte_fib6_rcu_qsbr_add(fib, &rcu_cfg);
     433         [ -  + ]:          1 :         RTE_TEST_ASSERT(status == -ENOTSUP,
     434                 :            :                 "rte_fib6_rcu_qsbr_add returned wrong error status when called with DUMMY type FIB\n");
     435                 :          1 :         rte_fib6_free(fib);
     436                 :            : 
     437                 :          1 :         config.type = RTE_FIB6_TRIE;
     438                 :          1 :         config.trie.nh_sz = RTE_FIB6_TRIE_4B;
     439                 :          1 :         config.trie.num_tbl8 = MAX_TBL8;
     440                 :          1 :         fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
     441         [ -  + ]:          1 :         RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n");
     442                 :            : 
     443                 :            :         /* Call rte_fib6_rcu_qsbr_add without fib or config */
     444                 :          1 :         status = rte_fib6_rcu_qsbr_add(NULL, &rcu_cfg);
     445         [ -  + ]:          1 :         RTE_TEST_ASSERT(status == -EINVAL, "RCU added without fib\n");
     446                 :          1 :         status = rte_fib6_rcu_qsbr_add(fib, NULL);
     447         [ -  + ]:          1 :         RTE_TEST_ASSERT(status == -EINVAL, "RCU added without config\n");
     448                 :            : 
     449                 :            :         /* Invalid QSBR mode */
     450                 :          1 :         rcu_cfg.mode = 2;
     451                 :          1 :         status = rte_fib6_rcu_qsbr_add(fib, &rcu_cfg);
     452         [ -  + ]:          1 :         RTE_TEST_ASSERT(status == -EINVAL, "RCU added with incorrect mode\n");
     453                 :            : 
     454                 :          1 :         rcu_cfg.mode = RTE_FIB6_QSBR_MODE_DQ;
     455                 :            : 
     456                 :            :         /* Attach RCU QSBR to FIB to check for double attach */
     457                 :          1 :         status = rte_fib6_rcu_qsbr_add(fib, &rcu_cfg);
     458         [ -  + ]:          1 :         RTE_TEST_ASSERT(status == 0, "Can not attach RCU to FIB\n");
     459                 :            : 
     460                 :            :         /* Create and attach another RCU QSBR to FIB table */
     461                 :          1 :         qsv2 = (struct rte_rcu_qsbr *)rte_zmalloc_socket(NULL, sz, RTE_CACHE_LINE_SIZE,
     462                 :            :                 SOCKET_ID_ANY);
     463         [ -  + ]:          1 :         RTE_TEST_ASSERT(qsv2 != NULL, "Can not allocate memory for RCU\n");
     464                 :            : 
     465                 :          1 :         rcu_cfg.v = qsv2;
     466                 :          1 :         rcu_cfg.mode = RTE_FIB6_QSBR_MODE_SYNC;
     467                 :          1 :         status = rte_fib6_rcu_qsbr_add(fib, &rcu_cfg);
     468         [ -  + ]:          1 :         RTE_TEST_ASSERT(status == -EEXIST, "Secondary RCU was mistakenly attached\n");
     469                 :            : 
     470                 :          1 :         rte_fib6_free(fib);
     471                 :          1 :         rte_free(qsv);
     472                 :          1 :         rte_free(qsv2);
     473                 :            : 
     474                 :          1 :         return TEST_SUCCESS;
     475                 :            : }
     476                 :            : 
     477                 :            : static struct rte_fib6 *g_fib;
     478                 :            : static struct rte_rcu_qsbr *g_v;
     479                 :            : static struct rte_ipv6_addr g_ip = RTE_IPV6(0x2001, 0xabcd, 0, 0, 0, 0, 0, 1);
     480                 :            : static volatile uint8_t writer_done;
     481                 :            : /* Report quiescent state interval every 1024 lookups. Larger critical
     482                 :            :  * sections in reader will result in writer polling multiple times.
     483                 :            :  */
     484                 :            : #define QSBR_REPORTING_INTERVAL 1024
     485                 :            : #define WRITER_ITERATIONS       512
     486                 :            : 
     487                 :            : /*
     488                 :            :  * Reader thread using rte_fib6 data structure with RCU.
     489                 :            :  */
     490                 :            : static int
     491                 :          1 : test_fib_rcu_qsbr_reader(void *arg)
     492                 :            : {
     493                 :            :         int i;
     494                 :          1 :         uint64_t next_hop_return = 0;
     495                 :            : 
     496                 :            :         RTE_SET_USED(arg);
     497                 :            :         /* Register this thread to report quiescent state */
     498                 :          1 :         rte_rcu_qsbr_thread_register(g_v, 0);
     499                 :          1 :         rte_rcu_qsbr_thread_online(g_v, 0);
     500                 :            : 
     501                 :            :         do {
     502         [ +  + ]:     526850 :                 for (i = 0; i < QSBR_REPORTING_INTERVAL; i++)
     503                 :     526336 :                         rte_fib6_lookup_bulk(g_fib, &g_ip, &next_hop_return, 1);
     504                 :            : 
     505                 :            :                 /* Update quiescent state */
     506         [ +  + ]:        514 :                 rte_rcu_qsbr_quiescent(g_v, 0);
     507         [ +  + ]:        514 :         } while (!writer_done);
     508                 :            : 
     509                 :          1 :         rte_rcu_qsbr_thread_offline(g_v, 0);
     510                 :          1 :         rte_rcu_qsbr_thread_unregister(g_v, 0);
     511                 :            : 
     512                 :          1 :         return 0;
     513                 :            : }
     514                 :            : 
     515                 :            : /*
     516                 :            :  * rte_fib6_rcu_qsbr_add sync mode functional test.
     517                 :            :  * 1 Reader and 1 writer. They cannot be in the same thread in this test.
     518                 :            :  *  - Create FIB which supports 1 tbl8 group at max
     519                 :            :  *  - Add RCU QSBR variable with sync mode to FIB
     520                 :            :  *  - Register a reader thread. Reader keeps looking up a specific rule.
     521                 :            :  *  - Writer keeps adding and deleting a specific rule with depth=28 (> 24)
     522                 :            :  */
     523                 :            : int32_t
     524                 :          1 : test_fib_rcu_sync_rw(void)
     525                 :            : {
     526                 :          1 :         struct rte_fib6_conf config = { 0 };
     527                 :            :         size_t sz;
     528                 :            :         int32_t status;
     529                 :            :         uint32_t i, next_hop;
     530                 :            :         uint8_t depth;
     531                 :          1 :         struct rte_fib6_rcu_config rcu_cfg = {0};
     532                 :            :         uint64_t def_nh = 100;
     533                 :            : 
     534         [ -  + ]:          1 :         if (rte_lcore_count() < 2) {
     535                 :            :                 printf("Not enough cores for %s, expecting at least 2\n", __func__);
     536                 :          0 :                 return TEST_SKIPPED;
     537                 :            :         }
     538                 :            : 
     539                 :          1 :         config.max_routes = MAX_ROUTES;
     540                 :          1 :         config.rib_ext_sz = 0;
     541                 :          1 :         config.default_nh = def_nh;
     542                 :          1 :         config.type = RTE_FIB6_TRIE;
     543                 :          1 :         config.trie.nh_sz = RTE_FIB6_TRIE_4B;
     544                 :          1 :         config.trie.num_tbl8 = 1;
     545                 :            : 
     546                 :          1 :         g_fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config);
     547         [ -  + ]:          1 :         RTE_TEST_ASSERT(g_fib != NULL, "Failed to create FIB\n");
     548                 :            : 
     549                 :            :         /* Create RCU QSBR variable */
     550                 :          1 :         sz = rte_rcu_qsbr_get_memsize(1);
     551                 :          1 :         g_v = (struct rte_rcu_qsbr *)rte_zmalloc_socket(NULL, sz, RTE_CACHE_LINE_SIZE,
     552                 :            :                 SOCKET_ID_ANY);
     553         [ -  + ]:          1 :         RTE_TEST_ASSERT(g_v != NULL, "Can not allocate memory for RCU\n");
     554                 :            : 
     555                 :          1 :         status = rte_rcu_qsbr_init(g_v, 1);
     556         [ -  + ]:          1 :         RTE_TEST_ASSERT(status == 0, "Can not initialize RCU\n");
     557                 :            : 
     558                 :          1 :         rcu_cfg.v = g_v;
     559                 :          1 :         rcu_cfg.mode = RTE_FIB6_QSBR_MODE_SYNC;
     560                 :            :         /* Attach RCU QSBR to FIB table */
     561                 :          1 :         status = rte_fib6_rcu_qsbr_add(g_fib, &rcu_cfg);
     562         [ -  + ]:          1 :         RTE_TEST_ASSERT(status == 0, "Can not attach RCU to FIB\n");
     563                 :            : 
     564                 :          1 :         writer_done = 0;
     565                 :            :         /* Launch reader thread */
     566                 :          1 :         rte_eal_remote_launch(test_fib_rcu_qsbr_reader, NULL, rte_get_next_lcore(-1, 1, 0));
     567                 :            : 
     568                 :            :         depth = 28;
     569                 :            :         next_hop = 1;
     570                 :          1 :         status = rte_fib6_add(g_fib, &g_ip, depth, next_hop);
     571         [ -  + ]:          1 :         if (status != 0) {
     572                 :            :                 printf("%s: Failed to add rule\n", __func__);
     573                 :          0 :                 goto error;
     574                 :            :         }
     575                 :            : 
     576                 :            :         /* Writer update */
     577         [ +  + ]:        513 :         for (i = 0; i < WRITER_ITERATIONS; i++) {
     578                 :        512 :                 status = rte_fib6_delete(g_fib, &g_ip, depth);
     579         [ -  + ]:        512 :                 if (status != 0) {
     580                 :            :                         printf("%s: Failed to delete rule at iteration %d\n", __func__, i);
     581                 :          0 :                         goto error;
     582                 :            :                 }
     583                 :            : 
     584                 :        512 :                 status = rte_fib6_add(g_fib, &g_ip, depth, next_hop);
     585         [ -  + ]:        512 :                 if (status != 0) {
     586                 :            :                         printf("%s: Failed to add rule at iteration %d\n", __func__, i);
     587                 :          0 :                         goto error;
     588                 :            :                 }
     589                 :            :         }
     590                 :            : 
     591                 :          1 : error:
     592                 :          1 :         writer_done = 1;
     593                 :            :         /* Wait until reader exited. */
     594                 :          1 :         rte_eal_mp_wait_lcore();
     595                 :            : 
     596                 :          1 :         rte_fib6_free(g_fib);
     597                 :          1 :         rte_free(g_v);
     598                 :            : 
     599         [ -  + ]:          1 :         return status == 0 ? TEST_SUCCESS : TEST_FAILED;
     600                 :            : }
     601                 :            : 
     602                 :            : static struct unit_test_suite fib6_fast_tests = {
     603                 :            :         .suite_name = "fib6 autotest",
     604                 :            :         .setup = NULL,
     605                 :            :         .teardown = NULL,
     606                 :            :         .unit_test_cases = {
     607                 :            :         TEST_CASE(test_create_invalid),
     608                 :            :         TEST_CASE(test_free_null),
     609                 :            :         TEST_CASE(test_add_del_invalid),
     610                 :            :         TEST_CASE(test_get_invalid),
     611                 :            :         TEST_CASE(test_lookup),
     612                 :            :         TEST_CASE(test_invalid_rcu),
     613                 :            :         TEST_CASE(test_fib_rcu_sync_rw),
     614                 :            :         TEST_CASES_END()
     615                 :            :         }
     616                 :            : };
     617                 :            : 
     618                 :            : static struct unit_test_suite fib6_slow_tests = {
     619                 :            :         .suite_name = "fib6 slow autotest",
     620                 :            :         .setup = NULL,
     621                 :            :         .teardown = NULL,
     622                 :            :         .unit_test_cases = {
     623                 :            :         TEST_CASE(test_multiple_create),
     624                 :            :         TEST_CASES_END()
     625                 :            :         }
     626                 :            : };
     627                 :            : 
     628                 :            : /*
     629                 :            :  * Do all unit tests.
     630                 :            :  */
     631                 :            : static int
     632                 :          1 : test_fib6(void)
     633                 :            : {
     634                 :          1 :         return unit_test_suite_runner(&fib6_fast_tests);
     635                 :            : }
     636                 :            : 
     637                 :            : static int
     638                 :          0 : test_slow_fib6(void)
     639                 :            : {
     640                 :          0 :         return unit_test_suite_runner(&fib6_slow_tests);
     641                 :            : }
     642                 :            : 
     643                 :        254 : REGISTER_FAST_TEST(fib6_autotest, true, true, test_fib6);
     644                 :        254 : REGISTER_PERF_TEST(fib6_slow_autotest, test_slow_fib6);

Generated by: LCOV version 1.14