Add test coverage for the multi-VRF IPv4 FIB API.

The app/test-fib functional harness exercises VRF-aware routes
with nexthop encoding, bulk VRF lookup, and nexthop validation
across multiple VRFs (enabled with the -V option).

The app/test unit tests cover VRF table creation, per-VRF
route add and delete, lookup correctness, inter-VRF isolation,
and all supported nexthop sizes.

Signed-off-by: Vladimir Medvedkin <[email protected]>
---
 app/test-fib/main.c | 167 +++++++++++++++++++++++--
 app/test/test_fib.c | 298 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 454 insertions(+), 11 deletions(-)

diff --git a/app/test-fib/main.c b/app/test-fib/main.c
index dd1a6d7297..5593fdd47e 100644
--- a/app/test-fib/main.c
+++ b/app/test-fib/main.c
@@ -82,6 +82,7 @@ static struct {
        uint32_t        nb_routes_per_depth[128 + 1];
        uint32_t        flags;
        uint32_t        tbl8;
+       uint32_t        nb_vrfs;
        uint8_t         ent_sz;
        uint8_t         rnd_lookup_ips_ratio;
        uint8_t         print_fract;
@@ -95,6 +96,7 @@ static struct {
        .nb_routes_per_depth = {0},
        .flags = FIB_V4_DIR_TYPE,
        .tbl8 = DEFAULT_LPM_TBL8,
+       .nb_vrfs = 1,
        .ent_sz = 4,
        .rnd_lookup_ips_ratio = 0,
        .print_fract = 10,
@@ -136,6 +138,45 @@ get_max_nh(uint8_t nh_sz)
                        (1ULL << 21) - 1);
 }
 
+/* Get number of bits needed to encode VRF IDs */
+static __rte_always_inline __rte_pure uint8_t
+get_vrf_bits(uint32_t nb_vrfs)
+{
+       uint8_t bits = 0;
+       uint32_t vrfs = nb_vrfs > 1 ? nb_vrfs : 2;  /* At least 1 bit */
+
+       /* Round up to next power of 2 */
+       vrfs--;
+       while (vrfs > 0) {
+               bits++;
+               vrfs >>= 1;
+       }
+       return bits;
+}
+
+/* Encode VRF ID into nexthop (high bits) */
+static __rte_always_inline uint64_t
+encode_vrf_nh(uint16_t vrf_id, uint64_t nh, uint8_t nh_sz)
+{
+       uint8_t vrf_bits = get_vrf_bits(config.nb_vrfs);
+       /* +1 to account for ext bit in nexthop */
+       uint8_t vrf_shift = bits_in_nh(nh_sz) - (vrf_bits + 1);
+       uint64_t nh_mask = (1ULL << vrf_shift) - 1;
+
+       return (nh & nh_mask) | ((uint64_t)vrf_id << vrf_shift);
+}
+
+/* Decode VRF ID from nexthop (high bits) */
+static __rte_always_inline uint16_t
+decode_vrf_nh(uint64_t nh, uint8_t nh_sz)
+{
+       uint8_t vrf_bits = get_vrf_bits(config.nb_vrfs);
+       /* +1 to account for ext bit in nexthop */
+       uint8_t vrf_shift = bits_in_nh(nh_sz) - (vrf_bits + 1);
+
+       return (uint16_t)(nh >> vrf_shift);
+}
+
 static int
 get_fib_type(void)
 {
@@ -629,7 +670,8 @@ print_usage(void)
                "[-v <type of lookup function:"
                "\ts1, s2, s3 (3 types of scalar), v (vector) -"
                " for DIR24_8 based FIB\n"
-               "\ts, v - for TRIE based ipv6 FIB>]\n",
+               "\ts, v - for TRIE based ipv6 FIB>]\n"
+               "[-V <number of VRFs (default 1)>]\n",
                config.prgname);
 }
 
@@ -652,6 +694,11 @@ check_config(void)
                return -1;
        }
 
+       if ((config.flags & CMP_FLAG) && (config.nb_vrfs > 1)) {
+               printf("-c option can not be used with -V > 1\n");
+               return -1;
+       }
+
        if (!((config.ent_sz == 1) || (config.ent_sz == 2) ||
                        (config.ent_sz == 4) || (config.ent_sz == 8))) {
                printf("wrong -e option %d, can be 1 or 2 or 4 or 8\n",
@@ -663,6 +710,24 @@ check_config(void)
                printf("-e 1 is valid only for ipv4\n");
                return -1;
        }
+
+       /*
+        * For multi-VRF mode, VRF IDs are packed into the high bits of the
+        * nexthop for validation. Ensure there are enough bits:
+        * get_vrf_bits(nb_vrfs) must be strictly less than
+        * the total nexthop width.
+        */
+       if ((config.nb_vrfs > 1) && !(config.flags & IPV6_FLAG)) {
+               uint8_t nh_sz = rte_ctz32(config.ent_sz);
+               uint8_t vrf_bits = get_vrf_bits(config.nb_vrfs);
+               /* - 2 to leave at least 1 bit for nexthop and 1 bit for 
ext_ent flag */
+               if (vrf_bits >= bits_in_nh(nh_sz) - 2) {
+                       printf("%u VRFs cannot be encoded in a %u-byte nexthop; 
"
+                               "use a wider -e entry size\n",
+                               config.nb_vrfs, config.ent_sz);
+                       return -1;
+               }
+       }
        return 0;
 }
 
@@ -672,7 +737,7 @@ parse_opts(int argc, char **argv)
        int opt;
        char *endptr;
 
-       while ((opt = getopt(argc, argv, "f:t:n:d:l:r:c6ab:e:g:w:u:sv:")) !=
+       while ((opt = getopt(argc, argv, "f:t:n:d:l:r:c6ab:e:g:w:u:sv:V:")) !=
                        -1) {
                switch (opt) {
                case 'f':
@@ -781,6 +846,16 @@ parse_opts(int argc, char **argv)
                        }
                        print_usage();
                        rte_exit(-EINVAL, "Invalid option -v %s\n", optarg);
+               case 'V':
+                       errno = 0;
+                       config.nb_vrfs = strtoul(optarg, &endptr, 10);
+                       /* VRF IDs are uint16_t, max valid VRF is 65535 */
+                       if ((errno != 0) || (config.nb_vrfs == 0) ||
+                                       (config.nb_vrfs > UINT16_MAX)) {
+                               print_usage();
+                               rte_exit(-EINVAL, "Invalid option -V: must be 
1..65535\n");
+                       }
+                       break;
                default:
                        print_usage();
                        rte_exit(-EINVAL, "Invalid options\n");
@@ -820,6 +895,7 @@ run_v4(void)
 {
        uint64_t start, acc;
        uint64_t def_nh = 0;
+       uint8_t nh_sz = rte_ctz32(config.ent_sz);
        struct rte_fib *fib;
        struct rte_fib_conf conf = {0};
        struct rt_rule_4 *rt;
@@ -830,6 +906,7 @@ run_v4(void)
        uint32_t *tbl4 = config.lookup_tbl;
        uint64_t fib_nh[BURST_SZ];
        uint32_t lpm_nh[BURST_SZ];
+       uint16_t *vrf_ids = NULL;
 
        rt = (struct rt_rule_4 *)config.rt;
 
@@ -843,16 +920,38 @@ run_v4(void)
                return ret;
        }
 
+       /* Allocate VRF IDs array for lookups if using multiple VRFs */
+       if (config.nb_vrfs > 1) {
+               vrf_ids = rte_malloc(NULL, sizeof(uint16_t) * 
config.nb_lookup_ips, 0);
+               if (vrf_ids == NULL) {
+                       printf("Can not alloc VRF IDs array\n");
+                       return -ENOMEM;
+               }
+               /* Generate random VRF IDs for each lookup */
+               for (i = 0; i < config.nb_lookup_ips; i++)
+                       vrf_ids[i] = rte_rand() % config.nb_vrfs;
+       }
+
        conf.type = get_fib_type();
        conf.default_nh = def_nh;
        conf.max_routes = config.nb_routes * 2;
        conf.rib_ext_sz = 0;
+       conf.max_vrfs = config.nb_vrfs;
+       conf.vrf_default_nh = NULL;  /* Use global default for single VRF */
        if (conf.type == RTE_FIB_DIR24_8) {
                conf.dir24_8.nh_sz = rte_ctz32(config.ent_sz);
                conf.dir24_8.num_tbl8 = RTE_MIN(config.tbl8,
                        get_max_nh(conf.dir24_8.nh_sz));
        }
 
+       conf.vrf_default_nh = rte_malloc(NULL, conf.max_vrfs * 
sizeof(uint64_t), 0);
+       if (conf.vrf_default_nh == NULL) {
+               printf("Can not alloc VRF default nexthops array\n");
+               return -ENOMEM;
+       }
+       for (i = 0; i < conf.max_vrfs; i++)
+               conf.vrf_default_nh[i] = encode_vrf_nh(i, def_nh, nh_sz);
+
        fib = rte_fib_create("test", -1, &conf);
        if (fib == NULL) {
                printf("Can not alloc FIB, err %d\n", rte_errno);
@@ -883,12 +982,27 @@ run_v4(void)
        for (k = config.print_fract, i = 0; k > 0; k--) {
                start = rte_rdtsc_precise();
                for (j = 0; j < (config.nb_routes - i) / k; j++) {
-                       ret = rte_fib_add(fib, rt[i + j].addr, rt[i + j].depth,
-                               rt[i + j].nh);
-                       if (unlikely(ret != 0)) {
-                               printf("Can not add a route to FIB, err %d\n",
-                                       ret);
-                               return -ret;
+                       uint32_t idx = i + j;
+                       if (config.nb_vrfs > 1) {
+                               uint16_t vrf_id;
+                               for (vrf_id = 0; vrf_id < config.nb_vrfs; 
vrf_id++) {
+                                       uint64_t nh = encode_vrf_nh(vrf_id, 
rt[idx].nh, nh_sz);
+                                       ret = rte_fib_vrf_add(fib, vrf_id, 
rt[idx].addr,
+                                               rt[idx].depth, nh);
+                                       if (unlikely(ret != 0)) {
+                                               printf("Can not add a route to 
FIB, err %d\n",
+                                                       ret);
+                                               return -ret;
+                                       }
+                               }
+                       } else {
+                               ret = rte_fib_add(fib, rt[idx].addr, 
rt[idx].depth,
+                                       rt[idx].nh);
+                               if (unlikely(ret != 0)) {
+                                       printf("Can not add a route to FIB, err 
%d\n",
+                                               ret);
+                                       return -ret;
+                               }
                        }
                }
                printf("AVG FIB add %"PRIu64"\n",
@@ -928,14 +1042,33 @@ run_v4(void)
        acc = 0;
        for (i = 0; i < config.nb_lookup_ips; i += BURST_SZ) {
                start = rte_rdtsc_precise();
-               ret = rte_fib_lookup_bulk(fib, tbl4 + i, fib_nh, BURST_SZ);
+               if (config.nb_vrfs > 1)
+                       ret = rte_fib_vrf_lookup_bulk(fib, vrf_ids + i,
+                               tbl4 + i, fib_nh, BURST_SZ);
+               else
+                       ret = rte_fib_lookup_bulk(fib, tbl4 + i, fib_nh,
+                               BURST_SZ);
                acc += rte_rdtsc_precise() - start;
                if (ret != 0) {
                        printf("FIB lookup fails, err %d\n", ret);
                        return -ret;
                }
+               /* Validate VRF IDs in returned nexthops */
+               if (config.nb_vrfs > 1) {
+                       for (j = 0; j < BURST_SZ; j++) {
+                               uint16_t returned_vrf = 
decode_vrf_nh(fib_nh[j], nh_sz);
+                               if (returned_vrf != vrf_ids[i + j]) {
+                                       printf("VRF validation failed: "
+                                               "expected VRF %u, got %u\n",
+                                               vrf_ids[i + j], returned_vrf);
+                                       return -1;
+                               }
+                       }
+               }
        }
        printf("AVG FIB lookup %.1f\n", (double)acc / (double)i);
+       if (config.nb_vrfs > 1)
+               printf("VRF validation passed\n");
 
        if (config.flags & CMP_FLAG) {
                acc = 0;
@@ -970,8 +1103,17 @@ run_v4(void)
 
        for (k = config.print_fract, i = 0; k > 0; k--) {
                start = rte_rdtsc_precise();
-               for (j = 0; j < (config.nb_routes - i) / k; j++)
-                       rte_fib_delete(fib, rt[i + j].addr, rt[i + j].depth);
+               for (j = 0; j < (config.nb_routes - i) / k; j++) {
+                       uint32_t idx = i + j;
+                       if (config.nb_vrfs > 1) {
+                               uint16_t vrf_id;
+                               for (vrf_id = 0; vrf_id < config.nb_vrfs; 
vrf_id++)
+                                       rte_fib_vrf_delete(fib, vrf_id, 
rt[idx].addr,
+                                               rt[idx].depth);
+                       } else {
+                               rte_fib_delete(fib, rt[idx].addr, 
rt[idx].depth);
+                       }
+               }
 
                printf("AVG FIB delete %"PRIu64"\n",
                        (rte_rdtsc_precise() - start) / j);
@@ -991,6 +1133,9 @@ run_v4(void)
                }
        }
 
+       if (vrf_ids != NULL)
+               rte_free(vrf_ids);
+
        return 0;
 }
 
diff --git a/app/test/test_fib.c b/app/test/test_fib.c
index bd73399d56..6a5d9836de 100644
--- a/app/test/test_fib.c
+++ b/app/test/test_fib.c
@@ -24,6 +24,11 @@ static int32_t test_get_invalid(void);
 static int32_t test_lookup(void);
 static int32_t test_invalid_rcu(void);
 static int32_t test_fib_rcu_sync_rw(void);
+static int32_t test_create_vrf(void);
+static int32_t test_vrf_add_del(void);
+static int32_t test_vrf_lookup(void);
+static int32_t test_vrf_isolation(void);
+static int32_t test_vrf_all_nh_sizes(void);
 
 #define MAX_ROUTES     (1 << 16)
 #define MAX_TBL8       (1 << 15)
@@ -588,6 +593,294 @@ test_fib_rcu_sync_rw(void)
        return status == 0 ? TEST_SUCCESS : TEST_FAILED;
 }
 
+/*
+ * Test VRF creation and basic operations
+ */
+static int32_t
+test_create_vrf(void)
+{
+       struct rte_fib *fib = NULL;
+       struct rte_fib_conf config = { 0 };
+       uint64_t def_nh = 100;
+       uint64_t vrf_def_nh[4] = {100, 200, 300, 400};
+
+       config.max_routes = MAX_ROUTES;
+       config.rib_ext_sz = 0;
+       config.default_nh = def_nh;
+       config.type = RTE_FIB_DIR24_8;
+       config.dir24_8.nh_sz = RTE_FIB_DIR24_8_4B;
+       config.dir24_8.num_tbl8 = MAX_TBL8;
+
+       /* Test single VRF (backward compat) */
+       config.max_vrfs = 0;
+       config.vrf_default_nh = NULL;
+       fib = rte_fib_create(__func__, SOCKET_ID_ANY, &config);
+       RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB with max_vrfs=0\n");
+       rte_fib_free(fib);
+
+       /* Test single VRF explicitly */
+       config.max_vrfs = 1;
+       fib = rte_fib_create(__func__, SOCKET_ID_ANY, &config);
+       RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB with max_vrfs=1\n");
+       rte_fib_free(fib);
+
+       /* Test multi-VRF with per-VRF defaults */
+       config.max_vrfs = 4;
+       config.vrf_default_nh = vrf_def_nh;
+       fib = rte_fib_create(__func__, SOCKET_ID_ANY, &config);
+       RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB with max_vrfs=4\n");
+       rte_fib_free(fib);
+
+       return TEST_SUCCESS;
+}
+
+/*
+ * Test VRF route add/delete operations
+ */
+static int32_t
+test_vrf_add_del(void)
+{
+       struct rte_fib *fib = NULL;
+       struct rte_fib_conf config = { 0 };
+       uint64_t def_nh = 100;
+       uint64_t vrf_def_nh[4] = {100, 200, 300, 400};
+       uint32_t ip = RTE_IPV4(192, 168, 1, 0);
+       uint8_t depth = 24;
+       uint64_t nh = 1000;
+       int ret;
+
+       config.max_routes = MAX_ROUTES;
+       config.rib_ext_sz = 0;
+       config.default_nh = def_nh;
+       config.type = RTE_FIB_DIR24_8;
+       config.dir24_8.nh_sz = RTE_FIB_DIR24_8_4B;
+       config.dir24_8.num_tbl8 = MAX_TBL8;
+       config.max_vrfs = 4;
+       config.vrf_default_nh = vrf_def_nh;
+
+       fib = rte_fib_create(__func__, SOCKET_ID_ANY, &config);
+       RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n");
+
+       /* Add route to VRF 0 */
+       ret = rte_fib_vrf_add(fib, 0, ip, depth, nh);
+       RTE_TEST_ASSERT(ret == 0, "Failed to add route to VRF 0\n");
+
+       /* Add route to VRF 1 with different nexthop */
+       ret = rte_fib_vrf_add(fib, 1, ip, depth, nh + 1);
+       RTE_TEST_ASSERT(ret == 0, "Failed to add route to VRF 1\n");
+
+       /* Add route to VRF 2 */
+       ret = rte_fib_vrf_add(fib, 2, ip, depth, nh + 2);
+       RTE_TEST_ASSERT(ret == 0, "Failed to add route to VRF 2\n");
+
+       /* Test invalid VRF ID */
+       ret = rte_fib_vrf_add(fib, 10, ip, depth, nh);
+       RTE_TEST_ASSERT(ret != 0, "Should fail with invalid VRF ID\n");
+
+       /* Delete route from VRF 1 */
+       ret = rte_fib_vrf_delete(fib, 1, ip, depth);
+       RTE_TEST_ASSERT(ret == 0, "Failed to delete route from VRF 1\n");
+
+       /* Delete non-existent route - implementation may return error */
+       ret = rte_fib_vrf_delete(fib, 3, ip, depth);
+       (void)ret;  /* Accept any return value */
+
+       rte_fib_free(fib);
+       return TEST_SUCCESS;
+}
+
+/*
+ * Test VRF lookup functionality
+ */
+static int32_t
+test_vrf_lookup(void)
+{
+       struct rte_fib *fib = NULL;
+       struct rte_fib_conf config = { 0 };
+       uint64_t def_nh = 100;
+       uint64_t vrf_def_nh[4] = {1000, 2000, 3000, 4000};
+       uint32_t ip_base = RTE_IPV4(10, 0, 0, 0);
+       uint16_t vrf_ids[8];
+       uint32_t ips[8];
+       uint64_t next_hops[8];
+       int ret;
+       uint32_t i;
+
+       config.max_routes = MAX_ROUTES;
+       config.rib_ext_sz = 0;
+       config.default_nh = def_nh;
+       config.type = RTE_FIB_DIR24_8;
+       config.dir24_8.nh_sz = RTE_FIB_DIR24_8_4B;
+       config.dir24_8.num_tbl8 = MAX_TBL8;
+       config.max_vrfs = 4;
+       config.vrf_default_nh = vrf_def_nh;
+
+       fib = rte_fib_create(__func__, SOCKET_ID_ANY, &config);
+       RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n");
+
+       /* Add routes to different VRFs with VRF-specific nexthops */
+       for (i = 0; i < 4; i++) {
+               ret = rte_fib_vrf_add(fib, i, ip_base + (i << 16), 16, 100 + i);
+               RTE_TEST_ASSERT(ret == 0, "Failed to add route to VRF %u\n", i);
+       }
+
+       /* Prepare lookup: each IP should match its VRF-specific route */
+       for (i = 0; i < 4; i++) {
+               vrf_ids[i] = i;
+               ips[i] = ip_base + (i << 16) + 0x1234;  /* Within the /16 */
+       }
+
+       /* Lookup should return VRF-specific nexthops */
+       ret = rte_fib_vrf_lookup_bulk(fib, vrf_ids, ips, next_hops, 4);
+       RTE_TEST_ASSERT(ret == 0, "VRF lookup failed\n");
+
+       for (i = 0; i < 4; i++) {
+               RTE_TEST_ASSERT(next_hops[i] == 100 + i,
+                       "Wrong nexthop for VRF %u: expected %"PRIu64", got 
%"PRIu64"\n",
+                       i, (uint64_t)(100 + i), next_hops[i]);
+       }
+
+       /* Test default nexthops for unmatched IPs */
+       for (i = 0; i < 4; i++) {
+               vrf_ids[i] = i;
+               ips[i] = RTE_IPV4(192, 168, i, 1);  /* No route for these */
+       }
+
+       ret = rte_fib_vrf_lookup_bulk(fib, vrf_ids, ips, next_hops, 4);
+       RTE_TEST_ASSERT(ret == 0, "VRF lookup failed\n");
+
+       for (i = 0; i < 4; i++) {
+               RTE_TEST_ASSERT(next_hops[i] == vrf_def_nh[i],
+                       "Wrong default nexthop for VRF %u: expected %"PRIu64", 
got %"PRIu64"\n",
+                       i, vrf_def_nh[i], next_hops[i]);
+       }
+
+       rte_fib_free(fib);
+       return TEST_SUCCESS;
+}
+
+/*
+ * Test VRF isolation - routes in one VRF shouldn't affect others
+ */
+static int32_t
+test_vrf_isolation(void)
+{
+       struct rte_fib *fib = NULL;
+       struct rte_fib_conf config = { 0 };
+       uint64_t vrf_def_nh[3] = {100, 200, 300};
+       uint32_t ip = RTE_IPV4(10, 10, 10, 0);
+       uint16_t vrf_ids[3] = {0, 1, 2};
+       uint32_t ips[3];
+       uint64_t next_hops[3];
+       int ret;
+       uint32_t i;
+
+       config.max_routes = MAX_ROUTES;
+       config.rib_ext_sz = 0;
+       config.default_nh = 0;
+       config.type = RTE_FIB_DIR24_8;
+       config.dir24_8.nh_sz = RTE_FIB_DIR24_8_4B;
+       config.dir24_8.num_tbl8 = MAX_TBL8;
+       config.max_vrfs = 3;
+       config.vrf_default_nh = vrf_def_nh;
+
+       fib = rte_fib_create("test_vrfisol", SOCKET_ID_ANY, &config);
+       RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n");
+
+       /* Add route only to VRF 1 */
+       ret = rte_fib_vrf_add(fib, 1, ip, 24, 777);
+       RTE_TEST_ASSERT(ret == 0, "Failed to add route to VRF 1\n");
+
+       /* Lookup same IP in all three VRFs */
+       for (i = 0; i < 3; i++)
+               ips[i] = ip + 15;  /* Within /24 */
+
+       ret = rte_fib_vrf_lookup_bulk(fib, vrf_ids, ips, next_hops, 3);
+       RTE_TEST_ASSERT(ret == 0, "VRF lookup failed\n");
+
+       /* VRF 0 should get default */
+       RTE_TEST_ASSERT(next_hops[0] == vrf_def_nh[0],
+               "VRF 0 should return default nexthop\n");
+
+       /* VRF 1 should get the route */
+       RTE_TEST_ASSERT(next_hops[1] == 777,
+               "VRF 1 should return route nexthop 777, got %"PRIu64"\n", 
next_hops[1]);
+
+       /* VRF 2 should get default */
+       RTE_TEST_ASSERT(next_hops[2] == vrf_def_nh[2],
+               "VRF 2 should return default nexthop\n");
+
+       rte_fib_free(fib);
+       return TEST_SUCCESS;
+}
+
+/*
+ * Test multi-VRF with all nexthop sizes
+ */
+static int32_t
+test_vrf_all_nh_sizes(void)
+{
+       struct rte_fib *fib = NULL;
+       struct rte_fib_conf config = { 0 };
+       uint64_t vrf_def_nh[2] = {10, 20};
+       uint32_t ip = RTE_IPV4(172, 16, 0, 0);
+       uint16_t vrf_ids[2] = {0, 1};
+       uint32_t ips[2];
+       uint64_t next_hops[2];
+       int ret;
+       enum rte_fib_dir24_8_nh_sz nh_sizes[] = {
+               RTE_FIB_DIR24_8_1B,
+               RTE_FIB_DIR24_8_2B,
+               RTE_FIB_DIR24_8_4B,
+               RTE_FIB_DIR24_8_8B
+       };
+       uint64_t max_nhs[] = {127, 32767, 2147483647ULL, 
9223372036854775807ULL};
+       int i;
+
+       config.max_routes = MAX_ROUTES;
+       config.rib_ext_sz = 0;
+       config.default_nh = 0;
+       config.type = RTE_FIB_DIR24_8;
+       config.dir24_8.num_tbl8 = 127;
+       config.max_vrfs = 2;
+       config.vrf_default_nh = vrf_def_nh;
+
+       for (i = 0; i < (int)RTE_DIM(nh_sizes); i++) {
+               char name[32];
+               config.dir24_8.nh_sz = nh_sizes[i];
+               snprintf(name, sizeof(name), "vrf_nh%d", i);
+
+               fib = rte_fib_create(name, SOCKET_ID_ANY, &config);
+               RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n");
+
+               /* Add routes with max nexthop for this size */
+               ret = rte_fib_vrf_add(fib, 0, ip, 16, max_nhs[i]);
+               RTE_TEST_ASSERT(ret == 0,
+                       "Failed to add route to VRF 0 with nh_sz=%d\n", 
nh_sizes[i]);
+
+               ret = rte_fib_vrf_add(fib, 1, ip, 16, max_nhs[i] - 1);
+               RTE_TEST_ASSERT(ret == 0,
+                       "Failed to add route to VRF 1 with nh_sz=%d\n", 
nh_sizes[i]);
+
+               /* Lookup */
+               ips[0] = ip + 0x100;
+               ips[1] = ip + 0x200;
+
+               ret = rte_fib_vrf_lookup_bulk(fib, vrf_ids, ips, next_hops, 2);
+               RTE_TEST_ASSERT(ret == 0, "VRF lookup failed with nh_sz=%d\n", 
nh_sizes[i]);
+
+               RTE_TEST_ASSERT(next_hops[0] == max_nhs[i],
+                       "Wrong nexthop for VRF 0 with nh_sz=%d\n", nh_sizes[i]);
+               RTE_TEST_ASSERT(next_hops[1] == max_nhs[i] - 1,
+                       "Wrong nexthop for VRF 1 with nh_sz=%d\n", nh_sizes[i]);
+
+               rte_fib_free(fib);
+               fib = NULL;
+       }
+
+       return TEST_SUCCESS;
+}
+
 static struct unit_test_suite fib_fast_tests = {
        .suite_name = "fib autotest",
        .setup = NULL,
@@ -600,6 +893,11 @@ static struct unit_test_suite fib_fast_tests = {
        TEST_CASE(test_lookup),
        TEST_CASE(test_invalid_rcu),
        TEST_CASE(test_fib_rcu_sync_rw),
+       TEST_CASE(test_create_vrf),
+       TEST_CASE(test_vrf_add_del),
+       TEST_CASE(test_vrf_lookup),
+       TEST_CASE(test_vrf_isolation),
+       TEST_CASE(test_vrf_all_nh_sizes),
        TEST_CASES_END()
        }
 };
-- 
2.43.0

Reply via email to