> Add VRF (Virtual Routing and Forwarding) support to the IPv4
> FIB library, allowing multiple independent routing tables
> within a single FIB instance.
> 
> Introduce max_vrfs and vrf_default_nh fields in rte_fib_conf
> to configure the number of VRFs and per-VRF default nexthops.

Thanks Vladimir, allowing multiple VRFs per same LPM table will
definitely be a useful thing to have.
Though, I have the same concern as Maxime:
memory requirements are just overwhelming.
Stupid q - why just not to store a pointer to a vector of next-hops
within the table entry?
And we can provide to the user with ability to specify custom
alloc/free function for these vectors.
That would help to avoid allocating huge chunks of memory at startup.
I understand that it will be one extra memory dereference,
but probably it will be not that critical in terms of performance .
Again for bulk function  we might be able to pipeline lookups and
de-references and hide that extra load latency.  

> Add four new experimental APIs:
> - rte_fib_vrf_add() and rte_fib_vrf_delete() to manage routes
>   per VRF
> - rte_fib_vrf_lookup_bulk() for multi-VRF bulk lookups
> - rte_fib_vrf_get_rib() to retrieve a per-VRF RIB handle
> 
> Signed-off-by: Vladimir Medvedkin <[email protected]>
> ---
>  lib/fib/dir24_8.c        | 241 ++++++++++++++++------
>  lib/fib/dir24_8.h        | 255 ++++++++++++++++--------
>  lib/fib/dir24_8_avx512.c | 420 +++++++++++++++++++++++++++++++--------
>  lib/fib/dir24_8_avx512.h |  80 +++++++-
>  lib/fib/rte_fib.c        | 158 ++++++++++++---
>  lib/fib/rte_fib.h        |  94 ++++++++-
>  6 files changed, 988 insertions(+), 260 deletions(-)
> 
> diff --git a/lib/fib/dir24_8.c b/lib/fib/dir24_8.c
> index 489d2ef427..ad295c5f16 100644
> --- a/lib/fib/dir24_8.c
> +++ b/lib/fib/dir24_8.c
> @@ -32,41 +32,80 @@
>  #define ROUNDUP(x, y)         RTE_ALIGN_CEIL(x, (1 << (32 - y)))
> 
>  static inline rte_fib_lookup_fn_t
> -get_scalar_fn(enum rte_fib_dir24_8_nh_sz nh_sz, bool be_addr)
> +get_scalar_fn(const struct dir24_8_tbl *dp, enum rte_fib_dir24_8_nh_sz nh_sz,
> +     bool be_addr)
>  {
> +     bool single_vrf = dp->num_vrfs <= 1;
> +
>       switch (nh_sz) {
>       case RTE_FIB_DIR24_8_1B:
> -             return be_addr ? dir24_8_lookup_bulk_1b_be :
> dir24_8_lookup_bulk_1b;
> +             if (single_vrf)
> +                     return be_addr ? dir24_8_lookup_bulk_1b_be :
> +                             dir24_8_lookup_bulk_1b;
> +             return be_addr ? dir24_8_lookup_bulk_vrf_1b_be :
> +                     dir24_8_lookup_bulk_vrf_1b;
>       case RTE_FIB_DIR24_8_2B:
> -             return be_addr ? dir24_8_lookup_bulk_2b_be :
> dir24_8_lookup_bulk_2b;
> +             if (single_vrf)
> +                     return be_addr ? dir24_8_lookup_bulk_2b_be :
> +                             dir24_8_lookup_bulk_2b;
> +             return be_addr ? dir24_8_lookup_bulk_vrf_2b_be :
> +                     dir24_8_lookup_bulk_vrf_2b;
>       case RTE_FIB_DIR24_8_4B:
> -             return be_addr ? dir24_8_lookup_bulk_4b_be :
> dir24_8_lookup_bulk_4b;
> +             if (single_vrf)
> +                     return be_addr ? dir24_8_lookup_bulk_4b_be :
> +                             dir24_8_lookup_bulk_4b;
> +             return be_addr ? dir24_8_lookup_bulk_vrf_4b_be :
> +                     dir24_8_lookup_bulk_vrf_4b;
>       case RTE_FIB_DIR24_8_8B:
> -             return be_addr ? dir24_8_lookup_bulk_8b_be :
> dir24_8_lookup_bulk_8b;
> +             if (single_vrf)
> +                     return be_addr ? dir24_8_lookup_bulk_8b_be :
> +                             dir24_8_lookup_bulk_8b;
> +             return be_addr ? dir24_8_lookup_bulk_vrf_8b_be :
> +                     dir24_8_lookup_bulk_vrf_8b;
>       default:
>               return NULL;
>       }
>  }
> 
>  static inline rte_fib_lookup_fn_t
> -get_scalar_fn_inlined(enum rte_fib_dir24_8_nh_sz nh_sz, bool be_addr)
> +get_scalar_fn_inlined(const struct dir24_8_tbl *dp,
> +     enum rte_fib_dir24_8_nh_sz nh_sz, bool be_addr)
>  {
> +     bool single_vrf = dp->num_vrfs <= 1;
> +
>       switch (nh_sz) {
>       case RTE_FIB_DIR24_8_1B:
> -             return be_addr ? dir24_8_lookup_bulk_0_be :
> dir24_8_lookup_bulk_0;
> +             if (single_vrf)
> +                     return be_addr ? dir24_8_lookup_bulk_0_be :
> +                             dir24_8_lookup_bulk_0;
> +             return be_addr ? dir24_8_lookup_bulk_vrf_0_be :
> +                     dir24_8_lookup_bulk_vrf_0;
>       case RTE_FIB_DIR24_8_2B:
> -             return be_addr ? dir24_8_lookup_bulk_1_be :
> dir24_8_lookup_bulk_1;
> +             if (single_vrf)
> +                     return be_addr ? dir24_8_lookup_bulk_1_be :
> +                             dir24_8_lookup_bulk_1;
> +             return be_addr ? dir24_8_lookup_bulk_vrf_1_be :
> +                     dir24_8_lookup_bulk_vrf_1;
>       case RTE_FIB_DIR24_8_4B:
> -             return be_addr ? dir24_8_lookup_bulk_2_be :
> dir24_8_lookup_bulk_2;
> +             if (single_vrf)
> +                     return be_addr ? dir24_8_lookup_bulk_2_be :
> +                             dir24_8_lookup_bulk_2;
> +             return be_addr ? dir24_8_lookup_bulk_vrf_2_be :
> +                     dir24_8_lookup_bulk_vrf_2;
>       case RTE_FIB_DIR24_8_8B:
> -             return be_addr ? dir24_8_lookup_bulk_3_be :
> dir24_8_lookup_bulk_3;
> +             if (single_vrf)
> +                     return be_addr ? dir24_8_lookup_bulk_3_be :
> +                             dir24_8_lookup_bulk_3;
> +             return be_addr ? dir24_8_lookup_bulk_vrf_3_be :
> +                     dir24_8_lookup_bulk_vrf_3;
>       default:
>               return NULL;
>       }
>  }
> 
>  static inline rte_fib_lookup_fn_t
> -get_vector_fn(enum rte_fib_dir24_8_nh_sz nh_sz, bool be_addr)
> +get_vector_fn(const struct dir24_8_tbl *dp, enum rte_fib_dir24_8_nh_sz nh_sz,
> +     bool be_addr)
>  {
>  #ifdef CC_AVX512_SUPPORT
>       if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX512F) <= 0 ||
> @@ -77,24 +116,63 @@ get_vector_fn(enum rte_fib_dir24_8_nh_sz nh_sz, bool
> be_addr)
>       if (be_addr && rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX512BW) <=
> 0)
>               return NULL;
> 
> +     if (dp->num_vrfs <= 1) {
> +             switch (nh_sz) {
> +             case RTE_FIB_DIR24_8_1B:
> +                     return be_addr ? rte_dir24_8_vec_lookup_bulk_1b_be :
> +                             rte_dir24_8_vec_lookup_bulk_1b;
> +             case RTE_FIB_DIR24_8_2B:
> +                     return be_addr ? rte_dir24_8_vec_lookup_bulk_2b_be :
> +                             rte_dir24_8_vec_lookup_bulk_2b;
> +             case RTE_FIB_DIR24_8_4B:
> +                     return be_addr ? rte_dir24_8_vec_lookup_bulk_4b_be :
> +                             rte_dir24_8_vec_lookup_bulk_4b;
> +             case RTE_FIB_DIR24_8_8B:
> +                     return be_addr ? rte_dir24_8_vec_lookup_bulk_8b_be :
> +                             rte_dir24_8_vec_lookup_bulk_8b;
> +             default:
> +                     return NULL;
> +             }
> +     }
> +
> +     if (dp->num_vrfs >= 256) {
> +             switch (nh_sz) {
> +             case RTE_FIB_DIR24_8_1B:
> +                     return be_addr ?
> rte_dir24_8_vec_lookup_bulk_vrf_1b_be_large :
> +                             rte_dir24_8_vec_lookup_bulk_vrf_1b_large;
> +             case RTE_FIB_DIR24_8_2B:
> +                     return be_addr ?
> rte_dir24_8_vec_lookup_bulk_vrf_2b_be_large :
> +                             rte_dir24_8_vec_lookup_bulk_vrf_2b_large;
> +             case RTE_FIB_DIR24_8_4B:
> +                     return be_addr ?
> rte_dir24_8_vec_lookup_bulk_vrf_4b_be_large :
> +                             rte_dir24_8_vec_lookup_bulk_vrf_4b_large;
> +             case RTE_FIB_DIR24_8_8B:
> +                     return be_addr ?
> rte_dir24_8_vec_lookup_bulk_vrf_8b_be_large :
> +                             rte_dir24_8_vec_lookup_bulk_vrf_8b_large;
> +             default:
> +                     return NULL;
> +             }
> +     }
> +
>       switch (nh_sz) {
>       case RTE_FIB_DIR24_8_1B:
> -             return be_addr ? rte_dir24_8_vec_lookup_bulk_1b_be :
> -                     rte_dir24_8_vec_lookup_bulk_1b;
> +             return be_addr ? rte_dir24_8_vec_lookup_bulk_vrf_1b_be :
> +                     rte_dir24_8_vec_lookup_bulk_vrf_1b;
>       case RTE_FIB_DIR24_8_2B:
> -             return be_addr ? rte_dir24_8_vec_lookup_bulk_2b_be :
> -                     rte_dir24_8_vec_lookup_bulk_2b;
> +             return be_addr ? rte_dir24_8_vec_lookup_bulk_vrf_2b_be :
> +                     rte_dir24_8_vec_lookup_bulk_vrf_2b;
>       case RTE_FIB_DIR24_8_4B:
> -             return be_addr ? rte_dir24_8_vec_lookup_bulk_4b_be :
> -                     rte_dir24_8_vec_lookup_bulk_4b;
> +             return be_addr ? rte_dir24_8_vec_lookup_bulk_vrf_4b_be :
> +                     rte_dir24_8_vec_lookup_bulk_vrf_4b;
>       case RTE_FIB_DIR24_8_8B:
> -             return be_addr ? rte_dir24_8_vec_lookup_bulk_8b_be :
> -                     rte_dir24_8_vec_lookup_bulk_8b;
> +             return be_addr ? rte_dir24_8_vec_lookup_bulk_vrf_8b_be :
> +                     rte_dir24_8_vec_lookup_bulk_vrf_8b;
>       default:
>               return NULL;
>       }
>  #elif defined(RTE_RISCV_FEATURE_V)
>       RTE_SET_USED(be_addr);
> +     RTE_SET_USED(dp);
>       if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_RISCV_ISA_V) <= 0)
>               return NULL;
>       switch (nh_sz) {
> @@ -130,16 +208,17 @@ dir24_8_get_lookup_fn(void *p, enum
> rte_fib_lookup_type type, bool be_addr)
> 
>       switch (type) {
>       case RTE_FIB_LOOKUP_DIR24_8_SCALAR_MACRO:
> -             return get_scalar_fn(nh_sz, be_addr);
> +             return get_scalar_fn(dp, nh_sz, be_addr);
>       case RTE_FIB_LOOKUP_DIR24_8_SCALAR_INLINE:
> -             return get_scalar_fn_inlined(nh_sz, be_addr);
> +             return get_scalar_fn_inlined(dp, nh_sz, be_addr);
>       case RTE_FIB_LOOKUP_DIR24_8_SCALAR_UNI:
> -             return be_addr ? dir24_8_lookup_bulk_uni_be :
> dir24_8_lookup_bulk_uni;
> +             return be_addr ? dir24_8_lookup_bulk_uni_be :
> +                     dir24_8_lookup_bulk_uni;
>       case RTE_FIB_LOOKUP_DIR24_8_VECTOR_AVX512:
> -             return get_vector_fn(nh_sz, be_addr);
> +             return get_vector_fn(dp, nh_sz, be_addr);
>       case RTE_FIB_LOOKUP_DEFAULT:
> -             ret_fn = get_vector_fn(nh_sz, be_addr);
> -             return ret_fn != NULL ? ret_fn : get_scalar_fn(nh_sz, be_addr);
> +             ret_fn = get_vector_fn(dp, nh_sz, be_addr);
> +             return ret_fn != NULL ? ret_fn : get_scalar_fn(dp, nh_sz,
> be_addr);
>       default:
>               return NULL;
>       }
> @@ -246,15 +325,18 @@ __rcu_qsbr_free_resource(void *p, void *data,
> unsigned int n __rte_unused)
>  }
> 
>  static void
> -tbl8_recycle(struct dir24_8_tbl *dp, uint32_t ip, uint64_t tbl8_idx)
> +tbl8_recycle(struct dir24_8_tbl *dp, uint16_t vrf_id, uint32_t ip, uint64_t
> tbl8_idx)
>  {
>       uint32_t i;
>       uint64_t nh;
> +     uint64_t tbl24_idx;
>       uint8_t *ptr8;
>       uint16_t *ptr16;
>       uint32_t *ptr32;
>       uint64_t *ptr64;
> 
> +     tbl24_idx = get_tbl24_idx(vrf_id, ip);
> +
>       switch (dp->nh_sz) {
>       case RTE_FIB_DIR24_8_1B:
>               ptr8 = &((uint8_t *)dp->tbl8)[tbl8_idx *
> @@ -264,7 +346,7 @@ tbl8_recycle(struct dir24_8_tbl *dp, uint32_t ip, uint64_t
> tbl8_idx)
>                       if (nh != ptr8[i])
>                               return;
>               }
> -             ((uint8_t *)dp->tbl24)[ip >> 8] =
> +             ((uint8_t *)dp->tbl24)[tbl24_idx] =
>                       nh & ~DIR24_8_EXT_ENT;
>               break;
>       case RTE_FIB_DIR24_8_2B:
> @@ -275,7 +357,7 @@ tbl8_recycle(struct dir24_8_tbl *dp, uint32_t ip, uint64_t
> tbl8_idx)
>                       if (nh != ptr16[i])
>                               return;
>               }
> -             ((uint16_t *)dp->tbl24)[ip >> 8] =
> +             ((uint16_t *)dp->tbl24)[tbl24_idx] =
>                       nh & ~DIR24_8_EXT_ENT;
>               break;
>       case RTE_FIB_DIR24_8_4B:
> @@ -286,7 +368,7 @@ tbl8_recycle(struct dir24_8_tbl *dp, uint32_t ip, uint64_t
> tbl8_idx)
>                       if (nh != ptr32[i])
>                               return;
>               }
> -             ((uint32_t *)dp->tbl24)[ip >> 8] =
> +             ((uint32_t *)dp->tbl24)[tbl24_idx] =
>                       nh & ~DIR24_8_EXT_ENT;
>               break;
>       case RTE_FIB_DIR24_8_8B:
> @@ -297,7 +379,7 @@ tbl8_recycle(struct dir24_8_tbl *dp, uint32_t ip, uint64_t
> tbl8_idx)
>                       if (nh != ptr64[i])
>                               return;
>               }
> -             ((uint64_t *)dp->tbl24)[ip >> 8] =
> +             ((uint64_t *)dp->tbl24)[tbl24_idx] =
>                       nh & ~DIR24_8_EXT_ENT;
>               break;
>       }
> @@ -314,7 +396,7 @@ tbl8_recycle(struct dir24_8_tbl *dp, uint32_t ip, uint64_t
> tbl8_idx)
>  }
> 
>  static int
> -install_to_fib(struct dir24_8_tbl *dp, uint32_t ledge, uint32_t redge,
> +install_to_fib(struct dir24_8_tbl *dp, uint16_t vrf_id, uint32_t ledge, 
> uint32_t
> redge,
>       uint64_t next_hop)
>  {
>       uint64_t        tbl24_tmp;
> @@ -328,7 +410,7 @@ install_to_fib(struct dir24_8_tbl *dp, uint32_t ledge,
> uint32_t redge,
> 
>       if (((ledge >> 8) != (redge >> 8)) || (len == 1 << 24)) {
>               if ((ROUNDUP(ledge, 24) - ledge) != 0) {
> -                     tbl24_tmp = get_tbl24(dp, ledge, dp->nh_sz);
> +                     tbl24_tmp = get_tbl24(dp, vrf_id, ledge, dp->nh_sz);
>                       if ((tbl24_tmp & DIR24_8_EXT_ENT) !=
>                                       DIR24_8_EXT_ENT) {
>                               /**
> @@ -346,7 +428,7 @@ install_to_fib(struct dir24_8_tbl *dp, uint32_t ledge,
> uint32_t redge,
>                               }
>                               tbl8_free_idx(dp, tmp_tbl8_idx);
>                               /*update dir24 entry with tbl8 index*/
> -                             write_to_fib(get_tbl24_p(dp, ledge,
> +                             write_to_fib(get_tbl24_p(dp, vrf_id, ledge,
>                                       dp->nh_sz), (tbl8_idx << 1)|
>                                       DIR24_8_EXT_ENT,
>                                       dp->nh_sz, 1);
> @@ -360,19 +442,19 @@ install_to_fib(struct dir24_8_tbl *dp, uint32_t ledge,
> uint32_t redge,
>                       write_to_fib((void *)tbl8_ptr, (next_hop << 1)|
>                               DIR24_8_EXT_ENT,
>                               dp->nh_sz, ROUNDUP(ledge, 24) - ledge);
> -                     tbl8_recycle(dp, ledge, tbl8_idx);
> +                     tbl8_recycle(dp, vrf_id, ledge, tbl8_idx);
>               }
> -             write_to_fib(get_tbl24_p(dp, ROUNDUP(ledge, 24), dp->nh_sz),
> +             write_to_fib(get_tbl24_p(dp, vrf_id, ROUNDUP(ledge, 24), dp-
> >nh_sz),
>                       next_hop << 1, dp->nh_sz, len);
>               if (redge & ~DIR24_8_TBL24_MASK) {
> -                     tbl24_tmp = get_tbl24(dp, redge, dp->nh_sz);
> +                     tbl24_tmp = get_tbl24(dp, vrf_id, redge, dp->nh_sz);
>                       if ((tbl24_tmp & DIR24_8_EXT_ENT) !=
>                                       DIR24_8_EXT_ENT) {
>                               tbl8_idx = tbl8_alloc(dp, tbl24_tmp);
>                               if (tbl8_idx < 0)
>                                       return -ENOSPC;
>                               /*update dir24 entry with tbl8 index*/
> -                             write_to_fib(get_tbl24_p(dp, redge,
> +                             write_to_fib(get_tbl24_p(dp, vrf_id, redge,
>                                       dp->nh_sz), (tbl8_idx << 1)|
>                                       DIR24_8_EXT_ENT,
>                                       dp->nh_sz, 1);
> @@ -385,17 +467,17 @@ install_to_fib(struct dir24_8_tbl *dp, uint32_t ledge,
> uint32_t redge,
>                       write_to_fib((void *)tbl8_ptr, (next_hop << 1)|
>                               DIR24_8_EXT_ENT,
>                               dp->nh_sz, redge & ~DIR24_8_TBL24_MASK);
> -                     tbl8_recycle(dp, redge, tbl8_idx);
> +                     tbl8_recycle(dp, vrf_id, redge, tbl8_idx);
>               }
>       } else if ((redge - ledge) != 0) {
> -             tbl24_tmp = get_tbl24(dp, ledge, dp->nh_sz);
> +             tbl24_tmp = get_tbl24(dp, vrf_id, ledge, dp->nh_sz);
>               if ((tbl24_tmp & DIR24_8_EXT_ENT) !=
>                               DIR24_8_EXT_ENT) {
>                       tbl8_idx = tbl8_alloc(dp, tbl24_tmp);
>                       if (tbl8_idx < 0)
>                               return -ENOSPC;
>                       /*update dir24 entry with tbl8 index*/
> -                     write_to_fib(get_tbl24_p(dp, ledge, dp->nh_sz),
> +                     write_to_fib(get_tbl24_p(dp, vrf_id, ledge, dp->nh_sz),
>                               (tbl8_idx << 1)|
>                               DIR24_8_EXT_ENT,
>                               dp->nh_sz, 1);
> @@ -409,13 +491,13 @@ install_to_fib(struct dir24_8_tbl *dp, uint32_t ledge,
> uint32_t redge,
>               write_to_fib((void *)tbl8_ptr, (next_hop << 1)|
>                       DIR24_8_EXT_ENT,
>                       dp->nh_sz, redge - ledge);
> -             tbl8_recycle(dp, ledge, tbl8_idx);
> +             tbl8_recycle(dp, vrf_id, ledge, tbl8_idx);
>       }
>       return 0;
>  }
> 
>  static int
> -modify_fib(struct dir24_8_tbl *dp, struct rte_rib *rib, uint32_t ip,
> +modify_fib(struct dir24_8_tbl *dp, struct rte_rib *rib, uint16_t vrf_id, 
> uint32_t
> ip,
>       uint8_t depth, uint64_t next_hop)
>  {
>       struct rte_rib_node *tmp = NULL;
> @@ -438,7 +520,7 @@ modify_fib(struct dir24_8_tbl *dp, struct rte_rib *rib,
> uint32_t ip,
>                                       (uint32_t)(1ULL << (32 - tmp_depth));
>                               continue;
>                       }
> -                     ret = install_to_fib(dp, ledge, redge,
> +                     ret = install_to_fib(dp, vrf_id, ledge, redge,
>                               next_hop);
>                       if (ret != 0)
>                               return ret;
> @@ -454,7 +536,7 @@ modify_fib(struct dir24_8_tbl *dp, struct rte_rib *rib,
> uint32_t ip,
>                       redge = ip + (uint32_t)(1ULL << (32 - depth));
>                       if (ledge == redge && ledge != 0)
>                               break;
> -                     ret = install_to_fib(dp, ledge, redge,
> +                     ret = install_to_fib(dp, vrf_id, ledge, redge,
>                               next_hop);
>                       if (ret != 0)
>                               return ret;
> @@ -465,7 +547,7 @@ modify_fib(struct dir24_8_tbl *dp, struct rte_rib *rib,
> uint32_t ip,
>  }
> 
>  int
> -dir24_8_modify(struct rte_fib *fib, uint32_t ip, uint8_t depth,
> +dir24_8_modify(struct rte_fib *fib, uint16_t vrf_id, uint32_t ip, uint8_t 
> depth,
>       uint64_t next_hop, int op)
>  {
>       struct dir24_8_tbl *dp;
> @@ -480,8 +562,13 @@ dir24_8_modify(struct rte_fib *fib, uint32_t ip, uint8_t
> depth,
>               return -EINVAL;
> 
>       dp = rte_fib_get_dp(fib);
> -     rib = rte_fib_get_rib(fib);
> -     RTE_ASSERT((dp != NULL) && (rib != NULL));
> +     RTE_ASSERT(dp != NULL);
> +
> +     if (vrf_id >= dp->num_vrfs)
> +             return -EINVAL;
> +
> +     rib = rte_fib_vrf_get_rib(fib, vrf_id);
> +     RTE_ASSERT(rib != NULL);
> 
>       if (next_hop > get_max_nh(dp->nh_sz))
>               return -EINVAL;
> @@ -495,7 +582,7 @@ dir24_8_modify(struct rte_fib *fib, uint32_t ip, uint8_t
> depth,
>                       rte_rib_get_nh(node, &node_nh);
>                       if (node_nh == next_hop)
>                               return 0;
> -                     ret = modify_fib(dp, rib, ip, depth, next_hop);
> +                     ret = modify_fib(dp, rib, vrf_id, ip, depth, next_hop);
>                       if (ret == 0)
>                               rte_rib_set_nh(node, next_hop);
>                       return 0;
> @@ -518,7 +605,7 @@ dir24_8_modify(struct rte_fib *fib, uint32_t ip, uint8_t
> depth,
>                       if (par_nh == next_hop)
>                               goto successfully_added;
>               }
> -             ret = modify_fib(dp, rib, ip, depth, next_hop);
> +             ret = modify_fib(dp, rib, vrf_id, ip, depth, next_hop);
>               if (ret != 0) {
>                       rte_rib_remove(rib, ip, depth);
>                       return ret;
> @@ -536,9 +623,9 @@ dir24_8_modify(struct rte_fib *fib, uint32_t ip, uint8_t
> depth,
>                       rte_rib_get_nh(parent, &par_nh);
>                       rte_rib_get_nh(node, &node_nh);
>                       if (par_nh != node_nh)
> -                             ret = modify_fib(dp, rib, ip, depth, par_nh);
> +                             ret = modify_fib(dp, rib, vrf_id, ip, depth,
> par_nh);
>               } else
> -                     ret = modify_fib(dp, rib, ip, depth, dp->def_nh);
> +                     ret = modify_fib(dp, rib, vrf_id, ip, depth, dp-
> >def_nh[vrf_id]);
>               if (ret == 0) {
>                       rte_rib_remove(rib, ip, depth);
>                       if (depth > 24) {
> @@ -562,7 +649,10 @@ dir24_8_create(const char *name, int socket_id, struct
> rte_fib_conf *fib_conf)
>       struct dir24_8_tbl *dp;
>       uint64_t        def_nh;
>       uint32_t        num_tbl8;
> +     uint16_t        num_vrfs;
>       enum rte_fib_dir24_8_nh_sz      nh_sz;
> +     uint64_t        tbl24_sz;
> +     uint16_t        vrf;
> 
>       if ((name == NULL) || (fib_conf == NULL) ||
>                       (fib_conf->dir24_8.nh_sz < RTE_FIB_DIR24_8_1B) ||
> @@ -580,19 +670,56 @@ dir24_8_create(const char *name, int socket_id, struct
> rte_fib_conf *fib_conf)
>       nh_sz = fib_conf->dir24_8.nh_sz;
>       num_tbl8 = RTE_ALIGN_CEIL(fib_conf->dir24_8.num_tbl8,
>                       BITMAP_SLAB_BIT_SIZE);
> +     num_vrfs = (fib_conf->max_vrfs == 0) ? 1 : fib_conf->max_vrfs;
> +
> +     /* Validate per-VRF default nexthops if provided */
> +     if (fib_conf->vrf_default_nh != NULL) {
> +             for (vrf = 0; vrf < num_vrfs; vrf++) {
> +                     if (fib_conf->vrf_default_nh[vrf] > get_max_nh(nh_sz)) {
> +                             rte_errno = EINVAL;
> +                             return NULL;
> +                     }
> +             }
> +     }
> +
> +     tbl24_sz = (uint64_t)num_vrfs * DIR24_8_TBL24_NUM_ENT * (1 <<
> nh_sz);
> 
>       snprintf(mem_name, sizeof(mem_name), "DP_%s", name);
>       dp = rte_zmalloc_socket(name, sizeof(struct dir24_8_tbl) +
> -             DIR24_8_TBL24_NUM_ENT * (1 << nh_sz) + sizeof(uint32_t),
> +             tbl24_sz + sizeof(uint32_t),
>               RTE_CACHE_LINE_SIZE, socket_id);
>       if (dp == NULL) {
>               rte_errno = ENOMEM;
>               return NULL;
>       }
> 
> -     /* Init table with default value */
> -     write_to_fib(dp->tbl24, (def_nh << 1), nh_sz, 1 << 24);
> +     dp->num_vrfs = num_vrfs;
> +     dp->nh_sz = nh_sz;
> +     dp->number_tbl8s = num_tbl8;
> +
> +     /* Allocate per-VRF default nexthop array */
> +     snprintf(mem_name, sizeof(mem_name), "DEFNH_%p", dp);
> +     dp->def_nh = rte_zmalloc_socket(mem_name, num_vrfs *
> sizeof(uint64_t),
> +                     RTE_CACHE_LINE_SIZE, socket_id);
> +     if (dp->def_nh == NULL) {
> +             rte_errno = ENOMEM;
> +             rte_free(dp);
> +             return NULL;
> +     }
> +
> +     /* Initialize all VRFs with default nexthop */
> +     for (vrf = 0; vrf < num_vrfs; vrf++) {
> +             uint64_t vrf_def_nh = (fib_conf->vrf_default_nh != NULL) ?
> +                     fib_conf->vrf_default_nh[vrf] : def_nh;
> +             dp->def_nh[vrf] = vrf_def_nh;
> 
> +             /* Init TBL24 for this VRF with default value */
> +             uint64_t vrf_offset = (uint64_t)vrf * DIR24_8_TBL24_NUM_ENT;
> +             void *vrf_tbl24 = (void *)&((uint8_t *)dp->tbl24)[vrf_offset <<
> nh_sz];
> +             write_to_fib(vrf_tbl24, (vrf_def_nh << 1), nh_sz, 1 << 24);
> +     }
> +
> +     /* Allocate shared TBL8 for all VRFs */
>       snprintf(mem_name, sizeof(mem_name), "TBL8_%p", dp);
>       uint64_t tbl8_sz = DIR24_8_TBL8_GRP_NUM_ENT * (1ULL << nh_sz) *
>                       (num_tbl8 + 1);
> @@ -600,12 +727,10 @@ dir24_8_create(const char *name, int socket_id, struct
> rte_fib_conf *fib_conf)
>                       RTE_CACHE_LINE_SIZE, socket_id);
>       if (dp->tbl8 == NULL) {
>               rte_errno = ENOMEM;
> +             rte_free(dp->def_nh);
>               rte_free(dp);
>               return NULL;
>       }
> -     dp->def_nh = def_nh;
> -     dp->nh_sz = nh_sz;
> -     dp->number_tbl8s = num_tbl8;
> 
>       snprintf(mem_name, sizeof(mem_name), "TBL8_idxes_%p", dp);
>       dp->tbl8_idxes = rte_zmalloc_socket(mem_name,
> @@ -614,6 +739,7 @@ dir24_8_create(const char *name, int socket_id, struct
> rte_fib_conf *fib_conf)
>       if (dp->tbl8_idxes == NULL) {
>               rte_errno = ENOMEM;
>               rte_free(dp->tbl8);
> +             rte_free(dp->def_nh);
>               rte_free(dp);
>               return NULL;
>       }
> @@ -629,6 +755,7 @@ dir24_8_free(void *p)
>       rte_rcu_qsbr_dq_delete(dp->dq);
>       rte_free(dp->tbl8_idxes);
>       rte_free(dp->tbl8);
> +     rte_free(dp->def_nh);
>       rte_free(dp);
>  }
> 
> diff --git a/lib/fib/dir24_8.h b/lib/fib/dir24_8.h
> index b343b5d686..37a73a3cc2 100644
> --- a/lib/fib/dir24_8.h
> +++ b/lib/fib/dir24_8.h
> @@ -12,6 +12,7 @@
>  #include <rte_byteorder.h>
>  #include <rte_prefetch.h>
>  #include <rte_branch_prediction.h>
> +#include <rte_debug.h>
>  #include <rte_rcu_qsbr.h>
> 
>  /**
> @@ -32,24 +33,19 @@ struct dir24_8_tbl {
>       uint32_t        number_tbl8s;   /**< Total number of tbl8s */
>       uint32_t        rsvd_tbl8s;     /**< Number of reserved tbl8s */
>       uint32_t        cur_tbl8s;      /**< Current number of tbl8s */
> +     uint16_t        num_vrfs;       /**< Number of VRFs */
>       enum rte_fib_dir24_8_nh_sz      nh_sz;  /**< Size of nexthop entry */
>       /* RCU config. */
>       enum rte_fib_qsbr_mode rcu_mode;/* Blocking, defer queue. */
>       struct rte_rcu_qsbr *v;         /* RCU QSBR variable. */
>       struct rte_rcu_qsbr_dq *dq;     /* RCU QSBR defer queue. */
> -     uint64_t        def_nh;         /**< Default next hop */
> +     uint64_t        *def_nh;        /**< Per-VRF default next hop array */
>       uint64_t        *tbl8;          /**< tbl8 table. */
>       uint64_t        *tbl8_idxes;    /**< bitmap containing free tbl8 idxes*/
>       /* tbl24 table. */
>       alignas(RTE_CACHE_LINE_SIZE) uint64_t   tbl24[];
>  };
> 
> -static inline void *
> -get_tbl24_p(struct dir24_8_tbl *dp, uint32_t ip, uint8_t nh_sz)
> -{
> -     return (void *)&((uint8_t *)dp->tbl24)[(ip &
> -             DIR24_8_TBL24_MASK) >> (8 - nh_sz)];
> -}
> 
>  static inline  uint8_t
>  bits_in_nh(uint8_t nh_sz)
> @@ -63,14 +59,21 @@ get_max_nh(uint8_t nh_sz)
>       return ((1ULL << (bits_in_nh(nh_sz) - 1)) - 1);
>  }
> 
> -static  inline uint32_t
> -get_tbl24_idx(uint32_t ip)
> +static  inline uint64_t
> +get_tbl24_idx(uint16_t vrf_id, uint32_t ip)
> +{
> +     return ((uint64_t)vrf_id << 24) + (ip >> 8);
> +}
> +
> +static inline void *
> +get_tbl24_p(struct dir24_8_tbl *dp, uint16_t vrf_id, uint32_t ip, uint8_t 
> nh_sz)
>  {
> -     return ip >> 8;
> +     uint64_t idx = get_tbl24_idx(vrf_id, ip);
> +     return (void *)&((uint8_t *)dp->tbl24)[idx << nh_sz];
>  }
> 
> -static  inline uint32_t
> -get_tbl8_idx(uint32_t res, uint32_t ip)
> +static  inline uint64_t
> +get_tbl8_idx(uint64_t res, uint32_t ip)
>  {
>       return (res >> 1) * DIR24_8_TBL8_GRP_NUM_ENT + (uint8_t)ip;
>  }
> @@ -87,17 +90,18 @@ get_psd_idx(uint32_t val, uint8_t nh_sz)
>       return val & ((1 << (3 - nh_sz)) - 1);
>  }
> 
> -static inline uint32_t
> -get_tbl_idx(uint32_t val, uint8_t nh_sz)
> +static inline uint64_t
> +get_tbl_idx(uint64_t val, uint8_t nh_sz)
>  {
>       return val >> (3 - nh_sz);
>  }
> 
>  static inline uint64_t
> -get_tbl24(struct dir24_8_tbl *dp, uint32_t ip, uint8_t nh_sz)
> +get_tbl24(struct dir24_8_tbl *dp, uint16_t vrf_id, uint32_t ip, uint8_t 
> nh_sz)
>  {
> -     return ((dp->tbl24[get_tbl_idx(get_tbl24_idx(ip), nh_sz)] >>
> -             (get_psd_idx(get_tbl24_idx(ip), nh_sz) *
> +     uint64_t idx = get_tbl24_idx(vrf_id, ip);
> +     return ((dp->tbl24[get_tbl_idx(idx, nh_sz)] >>
> +             (get_psd_idx(idx, nh_sz) *
>               bits_in_nh(nh_sz))) & lookup_msk(nh_sz));
>  }
> 
> @@ -115,62 +119,92 @@ is_entry_extended(uint64_t ent)
>       return (ent & DIR24_8_EXT_ENT) == DIR24_8_EXT_ENT;
>  }
> 
> -#define LOOKUP_FUNC(suffix, type, bulk_prefetch, nh_sz)                      
> \
> -static inline void dir24_8_lookup_bulk_##suffix(void *p, const uint32_t 
> *ips, \
> -     uint64_t *next_hops, const unsigned int n)                      \
> -{                                                                    \
> -     struct dir24_8_tbl *dp = (struct dir24_8_tbl *)p;               \
> -     uint64_t tmp;                                                   \
> -     uint32_t i;                                                     \
> -     uint32_t prefetch_offset =                                      \
> -             RTE_MIN((unsigned int)bulk_prefetch, n);                \
> -                                                                     \
> -     for (i = 0; i < prefetch_offset; i++)                           \
> -             rte_prefetch0(get_tbl24_p(dp, ips[i], nh_sz));          \
> -     for (i = 0; i < (n - prefetch_offset); i++) {                   \
> -             rte_prefetch0(get_tbl24_p(dp,                           \
> -                     ips[i + prefetch_offset], nh_sz));              \
> -             tmp = ((type *)dp->tbl24)[ips[i] >> 8];                 \
> -             if (unlikely(is_entry_extended(tmp)))                   \
> -                     tmp = ((type *)dp->tbl8)[(uint8_t)ips[i] +      \
> -                             ((tmp >> 1) * DIR24_8_TBL8_GRP_NUM_ENT)]; \
> -             next_hops[i] = tmp >> 1;                                \
> -     }                                                               \
> -     for (; i < n; i++) {                                            \
> -             tmp = ((type *)dp->tbl24)[ips[i] >> 8];                 \
> -             if (unlikely(is_entry_extended(tmp)))                   \
> -                     tmp = ((type *)dp->tbl8)[(uint8_t)ips[i] +      \
> -                             ((tmp >> 1) * DIR24_8_TBL8_GRP_NUM_ENT)]; \
> -             next_hops[i] = tmp >> 1;                                \
> -     }                                                               \
> -}                                                                    \
> -
> -LOOKUP_FUNC(1b, uint8_t, 5, 0)
> -LOOKUP_FUNC(2b, uint16_t, 6, 1)
> -LOOKUP_FUNC(4b, uint32_t, 15, 2)
> -LOOKUP_FUNC(8b, uint64_t, 12, 3)
> +
> +#define LOOKUP_FUNC(suffix, type, bulk_prefetch, nh_sz, is_vrf)
>       \
> +static inline void dir24_8_lookup_bulk_##suffix(void *p,                     
> \
> +     const uint16_t *vrf_ids, const uint32_t *ips,                           
> \
> +     uint64_t *next_hops, const unsigned int n)                              
> \
> +{                                                                            
> \
> +     struct dir24_8_tbl *dp = (struct dir24_8_tbl *)p;                       
> \
> +     uint64_t tmp;                                                           
> \
> +     uint32_t i;                                                             
> \
> +     uint32_t prefetch_offset = RTE_MIN((unsigned int)bulk_prefetch, n);     
> \
> +                                                                             
> \
> +     if (!is_vrf)                                                            
> \
> +             RTE_SET_USED(vrf_ids);
>       \
> +                                                                             
> \
> +     for (i = 0; i < prefetch_offset; i++) {                                 
> \
> +             uint16_t vid = is_vrf ? vrf_ids[i] : 0;                         
> \
> +             RTE_ASSERT(vid < dp->num_vrfs);
>       \
> +             rte_prefetch0(get_tbl24_p(dp, vid, ips[i], nh_sz));             
> \
> +     }                                                                       
> \
> +     for (i = 0; i < (n - prefetch_offset); i++) {                           
> \
> +             uint16_t vid = is_vrf ? vrf_ids[i] : 0;                         
> \
> +             uint16_t vid_next = is_vrf ? vrf_ids[i + prefetch_offset] : 0;  
> \
> +             RTE_ASSERT(vid < dp->num_vrfs);
>       \
> +             RTE_ASSERT(vid_next < dp->num_vrfs);
>       \
> +             rte_prefetch0(get_tbl24_p(dp, vid_next,
>       \
> +                     ips[i + prefetch_offset], nh_sz));                      
> \
> +             tmp = ((type *)dp->tbl24)[get_tbl24_idx(vid, ips[i])];          
> \
> +             if (unlikely(is_entry_extended(tmp)))                           
> \
> +                     tmp = ((type *)dp->tbl8)[(uint8_t)ips[i] +              
> \
> +                             ((tmp >> 1) * DIR24_8_TBL8_GRP_NUM_ENT)];       
> \
> +             next_hops[i] = tmp >> 1;                                        
> \
> +     }                                                                       
> \
> +     for (; i < n; i++) {                                                    
> \
> +             uint16_t vid = is_vrf ? vrf_ids[i] : 0;                         
> \
> +             RTE_ASSERT(vid < dp->num_vrfs);                         \
> +             tmp = ((type *)dp->tbl24)[get_tbl24_idx(vid, ips[i])];          
> \
> +             if (unlikely(is_entry_extended(tmp)))                           
> \
> +                     tmp = ((type *)dp->tbl8)[(uint8_t)ips[i] +              
> \
> +                             ((tmp >> 1) * DIR24_8_TBL8_GRP_NUM_ENT)];       
> \
> +             next_hops[i] = tmp >> 1;                                        
> \
> +     }                                                                       
> \
> +}
> +
> +LOOKUP_FUNC(1b, uint8_t, 5, 0, false)
> +LOOKUP_FUNC(2b, uint16_t, 6, 1, false)
> +LOOKUP_FUNC(4b, uint32_t, 15, 2, false)
> +LOOKUP_FUNC(8b, uint64_t, 12, 3, false)
> +LOOKUP_FUNC(vrf_1b, uint8_t, 5, 0, true)
> +LOOKUP_FUNC(vrf_2b, uint16_t, 6, 1, true)
> +LOOKUP_FUNC(vrf_4b, uint32_t, 15, 2, true)
> +LOOKUP_FUNC(vrf_8b, uint64_t, 12, 3, true)
> 
>  static inline void
> -dir24_8_lookup_bulk(struct dir24_8_tbl *dp, const uint32_t *ips,
> -     uint64_t *next_hops, const unsigned int n, uint8_t nh_sz)
> +__dir24_8_lookup_bulk(struct dir24_8_tbl *dp, const uint16_t *vrf_ids,
> +     const uint32_t *ips, uint64_t *next_hops, const unsigned int n,
> +     uint8_t nh_sz, bool is_vrf)
>  {
>       uint64_t tmp;
>       uint32_t i;
>       uint32_t prefetch_offset = RTE_MIN(15U, n);
> 
> -     for (i = 0; i < prefetch_offset; i++)
> -             rte_prefetch0(get_tbl24_p(dp, ips[i], nh_sz));
> +     if (!is_vrf)
> +             RTE_SET_USED(vrf_ids);
> +
> +     for (i = 0; i < prefetch_offset; i++) {
> +             uint16_t vid = is_vrf ? vrf_ids[i] : 0;
> +             RTE_ASSERT(vid < dp->num_vrfs);
> +             rte_prefetch0(get_tbl24_p(dp, vid, ips[i], nh_sz));
> +     }
>       for (i = 0; i < (n - prefetch_offset); i++) {
> -             rte_prefetch0(get_tbl24_p(dp, ips[i + prefetch_offset],
> -                     nh_sz));
> -             tmp = get_tbl24(dp, ips[i], nh_sz);
> +             uint16_t vid = is_vrf ? vrf_ids[i] : 0;
> +             uint16_t vid_next = is_vrf ? vrf_ids[i + prefetch_offset] : 0;
> +             RTE_ASSERT(vid < dp->num_vrfs);
> +             RTE_ASSERT(vid_next < dp->num_vrfs);
> +             rte_prefetch0(get_tbl24_p(dp, vid_next,
> +                     ips[i + prefetch_offset], nh_sz));
> +             tmp = get_tbl24(dp, vid, ips[i], nh_sz);
>               if (unlikely(is_entry_extended(tmp)))
>                       tmp = get_tbl8(dp, tmp, ips[i], nh_sz);
> 
>               next_hops[i] = tmp >> 1;
>       }
>       for (; i < n; i++) {
> -             tmp = get_tbl24(dp, ips[i], nh_sz);
> +             uint16_t vid = is_vrf ? vrf_ids[i] : 0;
> +             RTE_ASSERT(vid < dp->num_vrfs);
> +             tmp = get_tbl24(dp, vid, ips[i], nh_sz);
>               if (unlikely(is_entry_extended(tmp)))
>                       tmp = get_tbl8(dp, tmp, ips[i], nh_sz);
> 
> @@ -179,43 +213,79 @@ dir24_8_lookup_bulk(struct dir24_8_tbl *dp, const
> uint32_t *ips,
>  }
> 
>  static inline void
> -dir24_8_lookup_bulk_0(void *p, const uint32_t *ips,
> +dir24_8_lookup_bulk_0(void *p, const uint16_t *vrf_ids, const uint32_t *ips,
>       uint64_t *next_hops, const unsigned int n)
>  {
>       struct dir24_8_tbl *dp = (struct dir24_8_tbl *)p;
> 
> -     dir24_8_lookup_bulk(dp, ips, next_hops, n, 0);
> +     __dir24_8_lookup_bulk(dp, vrf_ids, ips, next_hops, n, 0, false);
> +}
> +
> +static inline void
> +dir24_8_lookup_bulk_vrf_0(void *p, const uint16_t *vrf_ids,
> +     const uint32_t *ips, uint64_t *next_hops, const unsigned int n)
> +{
> +     struct dir24_8_tbl *dp = (struct dir24_8_tbl *)p;
> +
> +     __dir24_8_lookup_bulk(dp, vrf_ids, ips, next_hops, n, 0, true);
>  }
> 
>  static inline void
> -dir24_8_lookup_bulk_1(void *p, const uint32_t *ips,
> +dir24_8_lookup_bulk_1(void *p, const uint16_t *vrf_ids, const uint32_t *ips,
>       uint64_t *next_hops, const unsigned int n)
>  {
>       struct dir24_8_tbl *dp = (struct dir24_8_tbl *)p;
> 
> -     dir24_8_lookup_bulk(dp, ips, next_hops, n, 1);
> +     __dir24_8_lookup_bulk(dp, vrf_ids, ips, next_hops, n, 1, false);
>  }
> 
>  static inline void
> -dir24_8_lookup_bulk_2(void *p, const uint32_t *ips,
> +dir24_8_lookup_bulk_vrf_1(void *p, const uint16_t *vrf_ids,
> +     const uint32_t *ips, uint64_t *next_hops, const unsigned int n)
> +{
> +     struct dir24_8_tbl *dp = (struct dir24_8_tbl *)p;
> +
> +     __dir24_8_lookup_bulk(dp, vrf_ids, ips, next_hops, n, 1, true);
> +}
> +
> +static inline void
> +dir24_8_lookup_bulk_2(void *p, const uint16_t *vrf_ids, const uint32_t *ips,
>       uint64_t *next_hops, const unsigned int n)
>  {
>       struct dir24_8_tbl *dp = (struct dir24_8_tbl *)p;
> 
> -     dir24_8_lookup_bulk(dp, ips, next_hops, n, 2);
> +     __dir24_8_lookup_bulk(dp, vrf_ids, ips, next_hops, n, 2, false);
>  }
> 
>  static inline void
> -dir24_8_lookup_bulk_3(void *p, const uint32_t *ips,
> +dir24_8_lookup_bulk_vrf_2(void *p, const uint16_t *vrf_ids,
> +     const uint32_t *ips, uint64_t *next_hops, const unsigned int n)
> +{
> +     struct dir24_8_tbl *dp = (struct dir24_8_tbl *)p;
> +
> +     __dir24_8_lookup_bulk(dp, vrf_ids, ips, next_hops, n, 2, true);
> +}
> +
> +static inline void
> +dir24_8_lookup_bulk_3(void *p, const uint16_t *vrf_ids, const uint32_t *ips,
>       uint64_t *next_hops, const unsigned int n)
>  {
>       struct dir24_8_tbl *dp = (struct dir24_8_tbl *)p;
> 
> -     dir24_8_lookup_bulk(dp, ips, next_hops, n, 3);
> +     __dir24_8_lookup_bulk(dp, vrf_ids, ips, next_hops, n, 3, false);
>  }
> 
>  static inline void
> -dir24_8_lookup_bulk_uni(void *p, const uint32_t *ips,
> +dir24_8_lookup_bulk_vrf_3(void *p, const uint16_t *vrf_ids,
> +     const uint32_t *ips, uint64_t *next_hops, const unsigned int n)
> +{
> +     struct dir24_8_tbl *dp = (struct dir24_8_tbl *)p;
> +
> +     __dir24_8_lookup_bulk(dp, vrf_ids, ips, next_hops, n, 3, true);
> +}
> +
> +static inline void
> +dir24_8_lookup_bulk_uni(void *p, const uint16_t *vrf_ids, const uint32_t 
> *ips,
>       uint64_t *next_hops, const unsigned int n)
>  {
>       struct dir24_8_tbl *dp = (struct dir24_8_tbl *)p;
> @@ -224,66 +294,83 @@ dir24_8_lookup_bulk_uni(void *p, const uint32_t *ips,
>       uint32_t prefetch_offset = RTE_MIN(15U, n);
>       uint8_t nh_sz = dp->nh_sz;
> 
> -     for (i = 0; i < prefetch_offset; i++)
> -             rte_prefetch0(get_tbl24_p(dp, ips[i], nh_sz));
> +     for (i = 0; i < prefetch_offset; i++) {
> +             uint16_t vid = vrf_ids[i];
> +             RTE_ASSERT(vid < dp->num_vrfs);
> +             rte_prefetch0(get_tbl24_p(dp, vid, ips[i], nh_sz));
> +     }
>       for (i = 0; i < (n - prefetch_offset); i++) {
> -             rte_prefetch0(get_tbl24_p(dp, ips[i + prefetch_offset],
> -                     nh_sz));
> -             tmp = get_tbl24(dp, ips[i], nh_sz);
> +             uint16_t vid = vrf_ids[i];
> +             uint16_t vid_next = vrf_ids[i + prefetch_offset];
> +             RTE_ASSERT(vid < dp->num_vrfs);
> +             RTE_ASSERT(vid_next < dp->num_vrfs);
> +             rte_prefetch0(get_tbl24_p(dp, vid_next,
> +                     ips[i + prefetch_offset], nh_sz));
> +             tmp = get_tbl24(dp, vid, ips[i], nh_sz);
>               if (unlikely(is_entry_extended(tmp)))
>                       tmp = get_tbl8(dp, tmp, ips[i], nh_sz);
> 
>               next_hops[i] = tmp >> 1;
>       }
>       for (; i < n; i++) {
> -             tmp = get_tbl24(dp, ips[i], nh_sz);
> +             uint16_t vid = vrf_ids[i];
> +             RTE_ASSERT(vid < dp->num_vrfs);
> +             tmp = get_tbl24(dp, vid, ips[i], nh_sz);
>               if (unlikely(is_entry_extended(tmp)))
>                       tmp = get_tbl8(dp, tmp, ips[i], nh_sz);
> 
>               next_hops[i] = tmp >> 1;
>       }
>  }
> -
>  #define BSWAP_MAX_LENGTH     64
> 
> -typedef void (*dir24_8_lookup_bulk_be_cb)(void *p, const uint32_t *ips,
> uint64_t *next_hops,
> -     const unsigned int n);
> +typedef void (*dir24_8_lookup_bulk_be_cb)(void *p, const uint16_t *vrf_ids,
> +     const uint32_t *ips, uint64_t *next_hops, const unsigned int n);
> 
>  static inline void
> -dir24_8_lookup_bulk_be(void *p, const uint32_t *ips, uint64_t *next_hops,
> const unsigned int n,
> -     dir24_8_lookup_bulk_be_cb cb)
> +dir24_8_lookup_bulk_be(void *p, const uint16_t *vrf_ids, const uint32_t *ips,
> +     uint64_t *next_hops, const unsigned int n, dir24_8_lookup_bulk_be_cb
> cb)
>  {
>       uint32_t le_ips[BSWAP_MAX_LENGTH];
>       unsigned int i;
> 
>  #if RTE_BYTE_ORDER == RTE_BIG_ENDIAN
> -     cb(p, ips, next_hops, n);
> +     cb(p, vrf_ids, ips, next_hops, n);
>  #else
>       for (i = 0; i < n; i += BSWAP_MAX_LENGTH) {
>               int j;
>               for (j = 0; j < BSWAP_MAX_LENGTH && i + j < n; j++)
>                       le_ips[j] = rte_be_to_cpu_32(ips[i + j]);
> 
> -             cb(p, le_ips, next_hops + i, j);
> +             cb(p, vrf_ids + i, le_ips, next_hops + i, j);
>       }
>  #endif
>  }
> 
>  #define DECLARE_BE_LOOKUP_FN(name) \
>  static inline void \
> -name##_be(void *p, const uint32_t *ips, uint64_t *next_hops, const unsigned
> int n) \
> +name##_be(void *p, const uint16_t *vrf_ids, const uint32_t *ips, \
> +     uint64_t *next_hops, const unsigned int n) \
>  { \
> -     dir24_8_lookup_bulk_be(p, ips, next_hops, n, name); \
> +     dir24_8_lookup_bulk_be(p, vrf_ids, ips, next_hops, n, name); \
>  }
> 
>  DECLARE_BE_LOOKUP_FN(dir24_8_lookup_bulk_1b)
>  DECLARE_BE_LOOKUP_FN(dir24_8_lookup_bulk_2b)
>  DECLARE_BE_LOOKUP_FN(dir24_8_lookup_bulk_4b)
>  DECLARE_BE_LOOKUP_FN(dir24_8_lookup_bulk_8b)
> +DECLARE_BE_LOOKUP_FN(dir24_8_lookup_bulk_vrf_1b)
> +DECLARE_BE_LOOKUP_FN(dir24_8_lookup_bulk_vrf_2b)
> +DECLARE_BE_LOOKUP_FN(dir24_8_lookup_bulk_vrf_4b)
> +DECLARE_BE_LOOKUP_FN(dir24_8_lookup_bulk_vrf_8b)
>  DECLARE_BE_LOOKUP_FN(dir24_8_lookup_bulk_0)
>  DECLARE_BE_LOOKUP_FN(dir24_8_lookup_bulk_1)
>  DECLARE_BE_LOOKUP_FN(dir24_8_lookup_bulk_2)
>  DECLARE_BE_LOOKUP_FN(dir24_8_lookup_bulk_3)
> +DECLARE_BE_LOOKUP_FN(dir24_8_lookup_bulk_vrf_0)
> +DECLARE_BE_LOOKUP_FN(dir24_8_lookup_bulk_vrf_1)
> +DECLARE_BE_LOOKUP_FN(dir24_8_lookup_bulk_vrf_2)
> +DECLARE_BE_LOOKUP_FN(dir24_8_lookup_bulk_vrf_3)
>  DECLARE_BE_LOOKUP_FN(dir24_8_lookup_bulk_uni)
> 
>  void *
> @@ -296,7 +383,7 @@ rte_fib_lookup_fn_t
>  dir24_8_get_lookup_fn(void *p, enum rte_fib_lookup_type type, bool be_addr);
> 
>  int
> -dir24_8_modify(struct rte_fib *fib, uint32_t ip, uint8_t depth,
> +dir24_8_modify(struct rte_fib *fib, uint16_t vrf_id, uint32_t ip, uint8_t 
> depth,
>       uint64_t next_hop, int op);
> 
>  int
> diff --git a/lib/fib/dir24_8_avx512.c b/lib/fib/dir24_8_avx512.c
> index 89b43583c7..3e576e410e 100644
> --- a/lib/fib/dir24_8_avx512.c
> +++ b/lib/fib/dir24_8_avx512.c
> @@ -4,75 +4,132 @@
> 
>  #include <rte_vect.h>
>  #include <rte_fib.h>
> +#include <rte_debug.h>
> 
>  #include "dir24_8.h"
>  #include "dir24_8_avx512.h"
> 
> +enum vrf_scale {
> +     VRF_SCALE_SINGLE = 0,
> +     VRF_SCALE_SMALL = 1,
> +     VRF_SCALE_LARGE = 2,
> +};
> +
>  static __rte_always_inline void
> -dir24_8_vec_lookup_x16(void *p, const uint32_t *ips,
> -     uint64_t *next_hops, int size, bool be_addr)
> +dir24_8_vec_lookup_x8_64b_path(struct dir24_8_tbl *dp, __m256i ip_vec_256,
> +     __m256i vrf32_256, uint64_t *next_hops, int size)
>  {
> -     struct dir24_8_tbl *dp = (struct dir24_8_tbl *)p;
> -     __mmask16 msk_ext;
> -     __mmask16 exp_msk = 0x5555;
> -     __m512i ip_vec, idxes, res, bytes;
> -     const __m512i zero = _mm512_set1_epi32(0);
> -     const __m512i lsb = _mm512_set1_epi32(1);
> -     const __m512i lsbyte_msk = _mm512_set1_epi32(0xff);
> -     __m512i tmp1, tmp2, res_msk;
> -     __m256i tmp256;
> -     /* used to mask gather values if size is 1/2 (8/16 bit next hops) */
> +     const __m512i zero_64 = _mm512_set1_epi64(0);
> +     const __m512i lsb_64 = _mm512_set1_epi64(1);
> +     const __m512i lsbyte_msk_64 = _mm512_set1_epi64(0xff);
> +     __m512i res_msk_64, vrf64, idxes_64, res, bytes_64;
> +     __mmask8 msk_ext_64;
> +
>       if (size == sizeof(uint8_t))
> -             res_msk = _mm512_set1_epi32(UINT8_MAX);
> +             res_msk_64 = _mm512_set1_epi64(UINT8_MAX);
>       else if (size == sizeof(uint16_t))
> -             res_msk = _mm512_set1_epi32(UINT16_MAX);
> +             res_msk_64 = _mm512_set1_epi64(UINT16_MAX);
> +     else if (size == sizeof(uint32_t))
> +             res_msk_64 = _mm512_set1_epi64(UINT32_MAX);
> 
> -     ip_vec = _mm512_loadu_si512(ips);
> -     if (be_addr) {
> -             const __m512i bswap32 = _mm512_set_epi32(
> -                     0x0c0d0e0f, 0x08090a0b, 0x04050607, 0x00010203,
> -                     0x0c0d0e0f, 0x08090a0b, 0x04050607, 0x00010203,
> -                     0x0c0d0e0f, 0x08090a0b, 0x04050607, 0x00010203,
> -                     0x0c0d0e0f, 0x08090a0b, 0x04050607, 0x00010203
> -             );
> -             ip_vec = _mm512_shuffle_epi8(ip_vec, bswap32);
> +     vrf64 = _mm512_cvtepu32_epi64(vrf32_256);
> +
> +     /* Compute index: (vrf_id << 24) + (ip >> 8) using 64-bit shift */
> +     idxes_64 = _mm512_slli_epi64(vrf64, 24);
> +     idxes_64 = _mm512_add_epi64(idxes_64, _mm512_cvtepu32_epi64(
> +             _mm256_srli_epi32(ip_vec_256, 8)));
> +
> +     /* lookup in tbl24 */
> +     if (size == sizeof(uint8_t)) {
> +             res = _mm512_i64gather_epi64(idxes_64, (const void *)dp-
> >tbl24, 1);
> +             res = _mm512_and_epi64(res, res_msk_64);
> +     } else if (size == sizeof(uint16_t)) {
> +             res = _mm512_i64gather_epi64(idxes_64, (const void *)dp-
> >tbl24, 2);
> +             res = _mm512_and_epi64(res, res_msk_64);
> +     } else {
> +             res = _mm512_i64gather_epi64(idxes_64, (const void *)dp-
> >tbl24, 4);
> +             res = _mm512_and_epi64(res, res_msk_64);
> +     }
> +
> +     /* get extended entries indexes */
> +     msk_ext_64 = _mm512_test_epi64_mask(res, lsb_64);
> +
> +     if (msk_ext_64 != 0) {
> +             bytes_64 = _mm512_cvtepu32_epi64(ip_vec_256);
> +             idxes_64 = _mm512_srli_epi64(res, 1);
> +             idxes_64 = _mm512_slli_epi64(idxes_64, 8);
> +             bytes_64 = _mm512_and_epi64(bytes_64, lsbyte_msk_64);
> +             idxes_64 = _mm512_maskz_add_epi64(msk_ext_64, idxes_64,
> bytes_64);
> +
> +             if (size == sizeof(uint8_t))
> +                     idxes_64 = _mm512_mask_i64gather_epi64(zero_64,
> msk_ext_64,
> +                             idxes_64, (const void *)dp->tbl8, 1);
> +             else if (size == sizeof(uint16_t))
> +                     idxes_64 = _mm512_mask_i64gather_epi64(zero_64,
> msk_ext_64,
> +                             idxes_64, (const void *)dp->tbl8, 2);
> +             else
> +                     idxes_64 = _mm512_mask_i64gather_epi64(zero_64,
> msk_ext_64,
> +                             idxes_64, (const void *)dp->tbl8, 4);
> +
> +             res = _mm512_mask_blend_epi64(msk_ext_64, res, idxes_64);
>       }
> 
> -     /* mask 24 most significant bits */
> -     idxes = _mm512_srli_epi32(ip_vec, 8);
> +     res = _mm512_srli_epi64(res, 1);
> +     _mm512_storeu_si512(next_hops, res);
> +}
> +
> +static __rte_always_inline void
> +dir24_8_vec_lookup_x16_32b_path(struct dir24_8_tbl *dp, __m512i ip_vec,
> +     __m512i idxes, uint64_t *next_hops, int size)
> +{
> +     __mmask16 msk_ext;
> +     const __mmask16 exp_msk = 0x5555;
> +     const __m512i zero_32 = _mm512_set1_epi32(0);
> +     const __m512i lsb_32 = _mm512_set1_epi32(1);
> +     const __m512i lsbyte_msk_32 = _mm512_set1_epi32(0xff);
> +     __m512i res, bytes, tmp1, tmp2;
> +     __m256i tmp256;
> +     __m512i res_msk_32;
> +
> +     if (size == sizeof(uint8_t))
> +             res_msk_32 = _mm512_set1_epi32(UINT8_MAX);
> +     else if (size == sizeof(uint16_t))
> +             res_msk_32 = _mm512_set1_epi32(UINT16_MAX);
> 
> -     /**
> +     /*
>        * lookup in tbl24
>        * Put it inside branch to make compiler happy with -O0
>        */
>       if (size == sizeof(uint8_t)) {
>               res = _mm512_i32gather_epi32(idxes, (const int *)dp->tbl24, 1);
> -             res = _mm512_and_epi32(res, res_msk);
> +             res = _mm512_and_epi32(res, res_msk_32);
>       } else if (size == sizeof(uint16_t)) {
>               res = _mm512_i32gather_epi32(idxes, (const int *)dp->tbl24, 2);
> -             res = _mm512_and_epi32(res, res_msk);
> -     } else
> +             res = _mm512_and_epi32(res, res_msk_32);
> +     } else {
>               res = _mm512_i32gather_epi32(idxes, (const int *)dp->tbl24, 4);
> +     }
> 
>       /* get extended entries indexes */
> -     msk_ext = _mm512_test_epi32_mask(res, lsb);
> +     msk_ext = _mm512_test_epi32_mask(res, lsb_32);
> 
>       if (msk_ext != 0) {
>               idxes = _mm512_srli_epi32(res, 1);
>               idxes = _mm512_slli_epi32(idxes, 8);
> -             bytes = _mm512_and_epi32(ip_vec, lsbyte_msk);
> +             bytes = _mm512_and_epi32(ip_vec, lsbyte_msk_32);
>               idxes = _mm512_maskz_add_epi32(msk_ext, idxes, bytes);
>               if (size == sizeof(uint8_t)) {
> -                     idxes = _mm512_mask_i32gather_epi32(zero, msk_ext,
> +                     idxes = _mm512_mask_i32gather_epi32(zero_32,
> msk_ext,
>                               idxes, (const int *)dp->tbl8, 1);
> -                     idxes = _mm512_and_epi32(idxes, res_msk);
> +                     idxes = _mm512_and_epi32(idxes, res_msk_32);
>               } else if (size == sizeof(uint16_t)) {
> -                     idxes = _mm512_mask_i32gather_epi32(zero, msk_ext,
> +                     idxes = _mm512_mask_i32gather_epi32(zero_32,
> msk_ext,
>                               idxes, (const int *)dp->tbl8, 2);
> -                     idxes = _mm512_and_epi32(idxes, res_msk);
> -             } else
> -                     idxes = _mm512_mask_i32gather_epi32(zero, msk_ext,
> +                     idxes = _mm512_and_epi32(idxes, res_msk_32);
> +             } else {
> +                     idxes = _mm512_mask_i32gather_epi32(zero_32,
> msk_ext,
>                               idxes, (const int *)dp->tbl8, 4);
> +             }
> 
>               res = _mm512_mask_blend_epi32(msk_ext, res, idxes);
>       }
> @@ -86,16 +143,74 @@ dir24_8_vec_lookup_x16(void *p, const uint32_t *ips,
>       _mm512_storeu_si512(next_hops + 8, tmp2);
>  }
> 
> +/* Unified function with vrf_scale parameter similar to be_addr */
> +static __rte_always_inline void
> +dir24_8_vec_lookup_x16(void *p, const uint16_t *vrf_ids, const uint32_t *ips,
> +     uint64_t *next_hops, int size, bool be_addr, enum vrf_scale vrf_scale)
> +{
> +     struct dir24_8_tbl *dp = (struct dir24_8_tbl *)p;
> +     __m512i ip_vec, idxes;
> +     __m256i ip_vec_256, vrf32_256;
> +
> +     ip_vec = _mm512_loadu_si512(ips);
> +     if (be_addr) {
> +             const __m512i bswap32 = _mm512_set_epi32(
> +                     0x0c0d0e0f, 0x08090a0b, 0x04050607, 0x00010203,
> +                     0x0c0d0e0f, 0x08090a0b, 0x04050607, 0x00010203,
> +                     0x0c0d0e0f, 0x08090a0b, 0x04050607, 0x00010203,
> +                     0x0c0d0e0f, 0x08090a0b, 0x04050607, 0x00010203
> +             );
> +             ip_vec = _mm512_shuffle_epi8(ip_vec, bswap32);
> +     }
> +
> +     if (vrf_scale == VRF_SCALE_SINGLE) {
> +             /* mask 24 most significant bits */
> +             idxes = _mm512_srli_epi32(ip_vec, 8);
> +             dir24_8_vec_lookup_x16_32b_path(dp, ip_vec, idxes, next_hops,
> size);
> +     } else if (vrf_scale == VRF_SCALE_SMALL) {
> +             /* For < 256 VRFs: use 32-bit indices with 32-bit shift */
> +             __m512i vrf32;
> +             uint32_t i;
> +
> +             for (i = 0; i < 16; i++)
> +                     RTE_ASSERT(vrf_ids[i] < dp->num_vrfs);
> +
> +             vrf32 = _mm512_cvtepu16_epi32(_mm256_loadu_si256((const
> void *)vrf_ids));
> +
> +             /* mask 24 most significant bits */
> +             idxes = _mm512_srli_epi32(ip_vec, 8);
> +             idxes = _mm512_add_epi32(idxes, _mm512_slli_epi32(vrf32,
> 24));
> +             dir24_8_vec_lookup_x16_32b_path(dp, ip_vec, idxes, next_hops,
> size);
> +     } else {
> +             /* For >= 256 VRFs: use 64-bit indices to avoid overflow */
> +             uint32_t i;
> +
> +             for (i = 0; i < 16; i++)
> +                     RTE_ASSERT(vrf_ids[i] < dp->num_vrfs);
> +
> +             /* Extract first 8 IPs and VRF IDs */
> +             ip_vec_256 = _mm512_castsi512_si256(ip_vec);
> +             vrf32_256 = _mm256_cvtepu16_epi32(_mm_loadu_si128((const
> void *)vrf_ids));
> +             dir24_8_vec_lookup_x8_64b_path(dp, ip_vec_256, vrf32_256,
> next_hops, size);
> +
> +             /* Process next 8 IPs from the second half of the vector */
> +             ip_vec_256 = _mm512_extracti32x8_epi32(ip_vec, 1);
> +             vrf32_256 = _mm256_cvtepu16_epi32(_mm_loadu_si128((const
> void *)(vrf_ids + 8)));
> +             dir24_8_vec_lookup_x8_64b_path(dp, ip_vec_256, vrf32_256,
> next_hops + 8, size);
> +     }
> +}
> +
> +/* Unified function with vrf_scale parameter */
>  static __rte_always_inline void
> -dir24_8_vec_lookup_x8_8b(void *p, const uint32_t *ips,
> -     uint64_t *next_hops, bool be_addr)
> +dir24_8_vec_lookup_x8_8b(void *p, const uint16_t *vrf_ids,
> +     const uint32_t *ips, uint64_t *next_hops, bool be_addr, enum vrf_scale
> vrf_scale)
>  {
>       struct dir24_8_tbl *dp = (struct dir24_8_tbl *)p;
> -     const __m512i zero = _mm512_set1_epi32(0);
> -     const __m512i lsbyte_msk = _mm512_set1_epi64(0xff);
> -     const __m512i lsb = _mm512_set1_epi64(1);
> +     const __m512i zero_64 = _mm512_set1_epi64(0);
> +     const __m512i lsbyte_msk_64 = _mm512_set1_epi64(0xff);
> +     const __m512i lsb_64 = _mm512_set1_epi64(1);
>       __m512i res, idxes, bytes;
> -     __m256i idxes_256, ip_vec;
> +     __m256i ip_vec, vrf32_256;
>       __mmask8 msk_ext;
> 
>       ip_vec = _mm256_loadu_si256((const void *)ips);
> @@ -106,66 +221,207 @@ dir24_8_vec_lookup_x8_8b(void *p, const uint32_t
> *ips,
>               );
>               ip_vec = _mm256_shuffle_epi8(ip_vec, bswap32);
>       }
> -     /* mask 24 most significant bits */
> -     idxes_256 = _mm256_srli_epi32(ip_vec, 8);
> 
> -     /* lookup in tbl24 */
> -     res = _mm512_i32gather_epi64(idxes_256, (const void *)dp->tbl24, 8);
> +     if (vrf_scale == VRF_SCALE_SINGLE) {
> +             /* For single VRF: use 32-bit indices without vrf_ids */
> +             __m256i idxes_256;
> 
> -     /* get extended entries indexes */
> -     msk_ext = _mm512_test_epi64_mask(res, lsb);
> +             /* mask 24 most significant bits */
> +             idxes_256 = _mm256_srli_epi32(ip_vec, 8);
> 
> -     if (msk_ext != 0) {
> -             bytes = _mm512_cvtepi32_epi64(ip_vec);
> -             idxes = _mm512_srli_epi64(res, 1);
> -             idxes = _mm512_slli_epi64(idxes, 8);
> -             bytes = _mm512_and_epi64(bytes, lsbyte_msk);
> -             idxes = _mm512_maskz_add_epi64(msk_ext, idxes, bytes);
> -             idxes = _mm512_mask_i64gather_epi64(zero, msk_ext, idxes,
> -                     (const void *)dp->tbl8, 8);
> -
> -             res = _mm512_mask_blend_epi64(msk_ext, res, idxes);
> -     }
> +             /* lookup in tbl24 */
> +             res = _mm512_i32gather_epi64(idxes_256, (const void *)dp-
> >tbl24, 8);
> 
> -     res = _mm512_srli_epi64(res, 1);
> -     _mm512_storeu_si512(next_hops, res);
> +             /* get extended entries indexes */
> +             msk_ext = _mm512_test_epi64_mask(res, lsb_64);
> +
> +             if (msk_ext != 0) {
> +                     bytes = _mm512_cvtepu32_epi64(ip_vec);
> +                     idxes = _mm512_srli_epi64(res, 1);
> +                     idxes = _mm512_slli_epi64(idxes, 8);
> +                     bytes = _mm512_and_epi64(bytes, lsbyte_msk_64);
> +                     idxes = _mm512_maskz_add_epi64(msk_ext, idxes,
> bytes);
> +                     idxes = _mm512_mask_i64gather_epi64(zero_64,
> msk_ext, idxes,
> +                             (const void *)dp->tbl8, 8);
> +
> +                     res = _mm512_mask_blend_epi64(msk_ext, res, idxes);
> +             }
> +
> +             res = _mm512_srli_epi64(res, 1);
> +             _mm512_storeu_si512(next_hops, res);
> +     } else if (vrf_scale == VRF_SCALE_SMALL) {
> +             /* For < 256 VRFs: use 32-bit indices with 32-bit shift */
> +             __m256i idxes_256;
> +             uint32_t i;
> +
> +             for (i = 0; i < 8; i++)
> +                     RTE_ASSERT(vrf_ids[i] < dp->num_vrfs);
> +
> +             /* mask 24 most significant bits */
> +             idxes_256 = _mm256_srli_epi32(ip_vec, 8);
> +             vrf32_256 = _mm256_cvtepu16_epi32(_mm_loadu_si128((const
> void *)vrf_ids));
> +             idxes_256 = _mm256_add_epi32(idxes_256,
> _mm256_slli_epi32(vrf32_256, 24));
> +
> +             /* lookup in tbl24 */
> +             res = _mm512_i32gather_epi64(idxes_256, (const void *)dp-
> >tbl24, 8);
> +
> +             /* get extended entries indexes */
> +             msk_ext = _mm512_test_epi64_mask(res, lsb_64);
> +
> +             if (msk_ext != 0) {
> +                     bytes = _mm512_cvtepu32_epi64(ip_vec);
> +                     idxes = _mm512_srli_epi64(res, 1);
> +                     idxes = _mm512_slli_epi64(idxes, 8);
> +                     bytes = _mm512_and_epi64(bytes, lsbyte_msk_64);
> +                     idxes = _mm512_maskz_add_epi64(msk_ext, idxes,
> bytes);
> +                     idxes = _mm512_mask_i64gather_epi64(zero_64,
> msk_ext, idxes,
> +                             (const void *)dp->tbl8, 8);
> +
> +                     res = _mm512_mask_blend_epi64(msk_ext, res, idxes);
> +             }
> +
> +             res = _mm512_srli_epi64(res, 1);
> +             _mm512_storeu_si512(next_hops, res);
> +     } else {
> +             /* For >= 256 VRFs: use 64-bit indices to avoid overflow */
> +             uint32_t i;
> +
> +             for (i = 0; i < 8; i++)
> +                     RTE_ASSERT(vrf_ids[i] < dp->num_vrfs);
> +
> +             vrf32_256 = _mm256_cvtepu16_epi32(_mm_loadu_si128((const
> void *)vrf_ids));
> +             __m512i vrf64 = _mm512_cvtepu32_epi64(vrf32_256);
> +
> +             /* Compute index: (vrf_id << 24) + (ip >> 8) using 64-bit
> arithmetic */
> +             idxes = _mm512_slli_epi64(vrf64, 24);
> +             idxes = _mm512_add_epi64(idxes, _mm512_cvtepu32_epi64(
> +                     _mm256_srli_epi32(ip_vec, 8)));
> +
> +             /* lookup in tbl24 with 64-bit gather */
> +             res = _mm512_i64gather_epi64(idxes, (const void *)dp->tbl24, 8);
> +
> +             /* get extended entries indexes */
> +             msk_ext = _mm512_test_epi64_mask(res, lsb_64);
> +
> +             if (msk_ext != 0) {
> +                     bytes = _mm512_cvtepu32_epi64(ip_vec);
> +                     idxes = _mm512_srli_epi64(res, 1);
> +                     idxes = _mm512_slli_epi64(idxes, 8);
> +                     bytes = _mm512_and_epi64(bytes, lsbyte_msk_64);
> +                     idxes = _mm512_maskz_add_epi64(msk_ext, idxes,
> bytes);
> +                     idxes = _mm512_mask_i64gather_epi64(zero_64,
> msk_ext, idxes,
> +                             (const void *)dp->tbl8, 8);
> +
> +                     res = _mm512_mask_blend_epi64(msk_ext, res, idxes);
> +             }
> +
> +             res = _mm512_srli_epi64(res, 1);
> +             _mm512_storeu_si512(next_hops, res);
> +     }
>  }
> 
> -#define DECLARE_VECTOR_FN(suffix, nh_type, be_addr) \
> +#define DECLARE_VECTOR_FN(suffix, scalar_suffix, nh_type, be_addr, vrf_scale)
> \
>  void \
> -rte_dir24_8_vec_lookup_bulk_##suffix(void *p, const uint32_t *ips, uint64_t
> *next_hops, \
> -     const unsigned int n) \
> +rte_dir24_8_vec_lookup_bulk_##suffix(void *p, const uint16_t *vrf_ids, \
> +     const uint32_t *ips, uint64_t *next_hops, const unsigned int n) \
>  { \
>       uint32_t i; \
>       for (i = 0; i < (n / 16); i++) \
> -             dir24_8_vec_lookup_x16(p, ips + i * 16, next_hops + i * 16,
> sizeof(nh_type), \
> -                     be_addr); \
> -     dir24_8_lookup_bulk_##suffix(p, ips + i * 16, next_hops + i * 16, n - i 
> *
> 16); \
> +             dir24_8_vec_lookup_x16(p, vrf_ids + i * 16, ips + i * 16, \
> +                     next_hops + i * 16, sizeof(nh_type), be_addr, 
> vrf_scale); \
> +     dir24_8_lookup_bulk_##scalar_suffix(p, vrf_ids + i * 16, ips + i * 16, \
> +             next_hops + i * 16, n - i * 16); \
> +}
> +
> +DECLARE_VECTOR_FN(1b, 1b, uint8_t, false, VRF_SCALE_SINGLE)
> +DECLARE_VECTOR_FN(1b_be, 1b_be, uint8_t, true, VRF_SCALE_SINGLE)
> +DECLARE_VECTOR_FN(2b, 2b, uint16_t, false, VRF_SCALE_SINGLE)
> +DECLARE_VECTOR_FN(2b_be, 2b_be, uint16_t, true, VRF_SCALE_SINGLE)
> +DECLARE_VECTOR_FN(4b, 4b, uint32_t, false, VRF_SCALE_SINGLE)
> +DECLARE_VECTOR_FN(4b_be, 4b_be, uint32_t, true, VRF_SCALE_SINGLE)
> +
> +DECLARE_VECTOR_FN(vrf_1b, vrf_1b, uint8_t, false, VRF_SCALE_SMALL)
> +DECLARE_VECTOR_FN(vrf_1b_be, vrf_1b_be, uint8_t, true, VRF_SCALE_SMALL)
> +DECLARE_VECTOR_FN(vrf_2b, vrf_2b, uint16_t, false, VRF_SCALE_SMALL)
> +DECLARE_VECTOR_FN(vrf_2b_be, vrf_2b_be, uint16_t, true, VRF_SCALE_SMALL)
> +DECLARE_VECTOR_FN(vrf_4b, vrf_4b, uint32_t, false, VRF_SCALE_SMALL)
> +DECLARE_VECTOR_FN(vrf_4b_be, vrf_4b_be, uint32_t, true, VRF_SCALE_SMALL)
> +
> +DECLARE_VECTOR_FN(vrf_1b_large, vrf_1b, uint8_t, false, VRF_SCALE_LARGE)
> +DECLARE_VECTOR_FN(vrf_1b_be_large, vrf_1b_be, uint8_t, true,
> VRF_SCALE_LARGE)
> +DECLARE_VECTOR_FN(vrf_2b_large, vrf_2b, uint16_t, false, VRF_SCALE_LARGE)
> +DECLARE_VECTOR_FN(vrf_2b_be_large, vrf_2b_be, uint16_t, true,
> VRF_SCALE_LARGE)
> +DECLARE_VECTOR_FN(vrf_4b_large, vrf_4b, uint32_t, false, VRF_SCALE_LARGE)
> +DECLARE_VECTOR_FN(vrf_4b_be_large, vrf_4b_be, uint32_t, true,
> VRF_SCALE_LARGE)
> +
> +void
> +rte_dir24_8_vec_lookup_bulk_8b(void *p, const uint16_t *vrf_ids,
> +     const uint32_t *ips, uint64_t *next_hops, const unsigned int n)
> +{
> +     uint32_t i;
> +     for (i = 0; i < (n / 8); i++)
> +             dir24_8_vec_lookup_x8_8b(p, vrf_ids + i * 8, ips + i * 8,
> +                     next_hops + i * 8, false, VRF_SCALE_SINGLE);
> +     dir24_8_lookup_bulk_8b(p, vrf_ids + i * 8, ips + i * 8,
> +             next_hops + i * 8, n - i * 8);
> +}
> +
> +void
> +rte_dir24_8_vec_lookup_bulk_8b_be(void *p, const uint16_t *vrf_ids,
> +     const uint32_t *ips, uint64_t *next_hops, const unsigned int n)
> +{
> +     uint32_t i;
> +     for (i = 0; i < (n / 8); i++)
> +             dir24_8_vec_lookup_x8_8b(p, vrf_ids + i * 8, ips + i * 8,
> +                     next_hops + i * 8, true, VRF_SCALE_SINGLE);
> +     dir24_8_lookup_bulk_8b_be(p, vrf_ids + i * 8, ips + i * 8,
> +             next_hops + i * 8, n - i * 8);
> +}
> +
> +void
> +rte_dir24_8_vec_lookup_bulk_vrf_8b(void *p, const uint16_t *vrf_ids,
> +     const uint32_t *ips, uint64_t *next_hops, const unsigned int n)
> +{
> +     uint32_t i;
> +     for (i = 0; i < (n / 8); i++)
> +             dir24_8_vec_lookup_x8_8b(p, vrf_ids + i * 8, ips + i * 8,
> +                     next_hops + i * 8, false, VRF_SCALE_SMALL);
> +     dir24_8_lookup_bulk_vrf_8b(p, vrf_ids + i * 8, ips + i * 8,
> +             next_hops + i * 8, n - i * 8);
>  }
> 
> -DECLARE_VECTOR_FN(1b, uint8_t, false)
> -DECLARE_VECTOR_FN(1b_be, uint8_t, true)
> -DECLARE_VECTOR_FN(2b, uint16_t, false)
> -DECLARE_VECTOR_FN(2b_be, uint16_t, true)
> -DECLARE_VECTOR_FN(4b, uint32_t, false)
> -DECLARE_VECTOR_FN(4b_be, uint32_t, true)
> +void
> +rte_dir24_8_vec_lookup_bulk_vrf_8b_be(void *p, const uint16_t *vrf_ids,
> +     const uint32_t *ips, uint64_t *next_hops, const unsigned int n)
> +{
> +     uint32_t i;
> +     for (i = 0; i < (n / 8); i++)
> +             dir24_8_vec_lookup_x8_8b(p, vrf_ids + i * 8, ips + i * 8,
> +                     next_hops + i * 8, true, VRF_SCALE_SMALL);
> +     dir24_8_lookup_bulk_vrf_8b_be(p, vrf_ids + i * 8, ips + i * 8,
> +             next_hops + i * 8, n - i * 8);
> +}
> 
>  void
> -rte_dir24_8_vec_lookup_bulk_8b(void *p, const uint32_t *ips,
> -     uint64_t *next_hops, const unsigned int n)
> +rte_dir24_8_vec_lookup_bulk_vrf_8b_large(void *p, const uint16_t *vrf_ids,
> +     const uint32_t *ips, uint64_t *next_hops, const unsigned int n)
>  {
>       uint32_t i;
>       for (i = 0; i < (n / 8); i++)
> -             dir24_8_vec_lookup_x8_8b(p, ips + i * 8, next_hops + i * 8, 
> false);
> -     dir24_8_lookup_bulk_8b(p, ips + i * 8, next_hops + i * 8, n - i * 8);
> +             dir24_8_vec_lookup_x8_8b(p, vrf_ids + i * 8, ips + i * 8,
> +                     next_hops + i * 8, false, VRF_SCALE_LARGE);
> +     dir24_8_lookup_bulk_vrf_8b(p, vrf_ids + i * 8, ips + i * 8,
> +             next_hops + i * 8, n - i * 8);
>  }
> 
>  void
> -rte_dir24_8_vec_lookup_bulk_8b_be(void *p, const uint32_t *ips,
> -     uint64_t *next_hops, const unsigned int n)
> +rte_dir24_8_vec_lookup_bulk_vrf_8b_be_large(void *p, const uint16_t *vrf_ids,
> +     const uint32_t *ips, uint64_t *next_hops, const unsigned int n)
>  {
>       uint32_t i;
>       for (i = 0; i < (n / 8); i++)
> -             dir24_8_vec_lookup_x8_8b(p, ips + i * 8, next_hops + i * 8, 
> true);
> -     dir24_8_lookup_bulk_8b_be(p, ips + i * 8, next_hops + i * 8, n - i * 8);
> +             dir24_8_vec_lookup_x8_8b(p, vrf_ids + i * 8, ips + i * 8,
> +                     next_hops + i * 8, true, VRF_SCALE_LARGE);
> +     dir24_8_lookup_bulk_vrf_8b_be(p, vrf_ids + i * 8, ips + i * 8,
> +             next_hops + i * 8, n - i * 8);
>  }
> diff --git a/lib/fib/dir24_8_avx512.h b/lib/fib/dir24_8_avx512.h
> index 3e2bbc2490..d42ef1d17f 100644
> --- a/lib/fib/dir24_8_avx512.h
> +++ b/lib/fib/dir24_8_avx512.h
> @@ -6,35 +6,99 @@
>  #define _DIR248_AVX512_H_
> 
>  void
> -rte_dir24_8_vec_lookup_bulk_1b(void *p, const uint32_t *ips,
> +rte_dir24_8_vec_lookup_bulk_1b(void *p, const uint16_t *vrf_ids,
> +     const uint32_t *ips, uint64_t *next_hops, const unsigned int n);
> +
> +void
> +rte_dir24_8_vec_lookup_bulk_1b_be(void *p, const uint16_t *vrf_ids,
> +     const uint32_t *ips, uint64_t *next_hops, const unsigned int n);
> +
> +void
> +rte_dir24_8_vec_lookup_bulk_vrf_1b(void *p, const uint16_t *vrf_ids, const
> uint32_t *ips,
>       uint64_t *next_hops, const unsigned int n);
> 
>  void
> -rte_dir24_8_vec_lookup_bulk_2b(void *p, const uint32_t *ips,
> +rte_dir24_8_vec_lookup_bulk_vrf_1b_be(void *p, const uint16_t *vrf_ids, const
> uint32_t *ips,
>       uint64_t *next_hops, const unsigned int n);
> 
>  void
> -rte_dir24_8_vec_lookup_bulk_4b(void *p, const uint32_t *ips,
> +rte_dir24_8_vec_lookup_bulk_vrf_1b_large(void *p, const uint16_t *vrf_ids,
> +     const uint32_t *ips, uint64_t *next_hops, const unsigned int n);
> +
> +void
> +rte_dir24_8_vec_lookup_bulk_vrf_1b_be_large(void *p, const uint16_t *vrf_ids,
> +     const uint32_t *ips, uint64_t *next_hops, const unsigned int n);
> +
> +void
> +rte_dir24_8_vec_lookup_bulk_2b(void *p, const uint16_t *vrf_ids,
> +     const uint32_t *ips, uint64_t *next_hops, const unsigned int n);
> +
> +void
> +rte_dir24_8_vec_lookup_bulk_2b_be(void *p, const uint16_t *vrf_ids,
> +     const uint32_t *ips, uint64_t *next_hops, const unsigned int n);
> +
> +void
> +rte_dir24_8_vec_lookup_bulk_vrf_2b(void *p, const uint16_t *vrf_ids, const
> uint32_t *ips,
>       uint64_t *next_hops, const unsigned int n);
> 
>  void
> -rte_dir24_8_vec_lookup_bulk_8b(void *p, const uint32_t *ips,
> +rte_dir24_8_vec_lookup_bulk_vrf_2b_be(void *p, const uint16_t *vrf_ids, const
> uint32_t *ips,
>       uint64_t *next_hops, const unsigned int n);
> 
>  void
> -rte_dir24_8_vec_lookup_bulk_1b_be(void *p, const uint32_t *ips,
> +rte_dir24_8_vec_lookup_bulk_vrf_2b_large(void *p, const uint16_t *vrf_ids,
> +     const uint32_t *ips, uint64_t *next_hops, const unsigned int n);
> +
> +void
> +rte_dir24_8_vec_lookup_bulk_vrf_2b_be_large(void *p, const uint16_t *vrf_ids,
> +     const uint32_t *ips, uint64_t *next_hops, const unsigned int n);
> +
> +void
> +rte_dir24_8_vec_lookup_bulk_4b(void *p, const uint16_t *vrf_ids,
> +     const uint32_t *ips, uint64_t *next_hops, const unsigned int n);
> +
> +void
> +rte_dir24_8_vec_lookup_bulk_4b_be(void *p, const uint16_t *vrf_ids,
> +     const uint32_t *ips, uint64_t *next_hops, const unsigned int n);
> +
> +void
> +rte_dir24_8_vec_lookup_bulk_vrf_4b(void *p, const uint16_t *vrf_ids, const
> uint32_t *ips,
>       uint64_t *next_hops, const unsigned int n);
> 
>  void
> -rte_dir24_8_vec_lookup_bulk_2b_be(void *p, const uint32_t *ips,
> +rte_dir24_8_vec_lookup_bulk_vrf_4b_be(void *p, const uint16_t *vrf_ids, const
> uint32_t *ips,
>       uint64_t *next_hops, const unsigned int n);
> 
>  void
> -rte_dir24_8_vec_lookup_bulk_4b_be(void *p, const uint32_t *ips,
> +rte_dir24_8_vec_lookup_bulk_vrf_4b_large(void *p, const uint16_t *vrf_ids,
> +     const uint32_t *ips, uint64_t *next_hops, const unsigned int n);
> +
> +void
> +rte_dir24_8_vec_lookup_bulk_vrf_4b_be_large(void *p, const uint16_t *vrf_ids,
> +     const uint32_t *ips, uint64_t *next_hops, const unsigned int n);
> +
> +void
> +rte_dir24_8_vec_lookup_bulk_8b(void *p, const uint16_t *vrf_ids,
> +     const uint32_t *ips, uint64_t *next_hops, const unsigned int n);
> +
> +void
> +rte_dir24_8_vec_lookup_bulk_8b_be(void *p, const uint16_t *vrf_ids,
> +     const uint32_t *ips, uint64_t *next_hops, const unsigned int n);
> +
> +void
> +rte_dir24_8_vec_lookup_bulk_vrf_8b(void *p, const uint16_t *vrf_ids, const
> uint32_t *ips,
>       uint64_t *next_hops, const unsigned int n);
> 
>  void
> -rte_dir24_8_vec_lookup_bulk_8b_be(void *p, const uint32_t *ips,
> +rte_dir24_8_vec_lookup_bulk_vrf_8b_be(void *p, const uint16_t *vrf_ids, const
> uint32_t *ips,
>       uint64_t *next_hops, const unsigned int n);
> 
> +void
> +rte_dir24_8_vec_lookup_bulk_vrf_8b_large(void *p, const uint16_t *vrf_ids,
> +     const uint32_t *ips, uint64_t *next_hops, const unsigned int n);
> +
> +void
> +rte_dir24_8_vec_lookup_bulk_vrf_8b_be_large(void *p, const uint16_t *vrf_ids,
> +     const uint32_t *ips, uint64_t *next_hops, const unsigned int n);
> +
>  #endif /* _DIR248_AVX512_H_ */
> diff --git a/lib/fib/rte_fib.c b/lib/fib/rte_fib.c
> index 184210f380..efc0595a7f 100644
> --- a/lib/fib/rte_fib.c
> +++ b/lib/fib/rte_fib.c
> @@ -14,12 +14,15 @@
>  #include <rte_string_fns.h>
>  #include <rte_tailq.h>
> 
> +#include <rte_debug.h>
>  #include <rte_rib.h>
>  #include <rte_fib.h>
> 
>  #include "dir24_8.h"
>  #include "fib_log.h"
> 
> +#define FIB_MAX_LOOKUP_BULK 64U
> +
>  RTE_LOG_REGISTER_DEFAULT(fib_logtype, INFO);
> 
>  TAILQ_HEAD(rte_fib_list, rte_tailq_entry);
> @@ -40,52 +43,61 @@ EAL_REGISTER_TAILQ(rte_fib_tailq)
>  struct rte_fib {
>       char                    name[RTE_FIB_NAMESIZE];
>       enum rte_fib_type       type;   /**< Type of FIB struct */
> -     unsigned int flags;             /**< Flags */
> -     struct rte_rib          *rib;   /**< RIB helper datastructure */
> +     uint16_t flags;                 /**< Flags */
> +     uint16_t                num_vrfs;/**< Number of VRFs */
> +     struct rte_rib          **ribs; /**< RIB helper datastructures per VRF 
> */
>       void                    *dp;    /**< pointer to the dataplane struct*/
>       rte_fib_lookup_fn_t     lookup; /**< FIB lookup function */
>       rte_fib_modify_fn_t     modify; /**< modify FIB datastructure */
> -     uint64_t                def_nh;
> +     uint64_t                *def_nh;/**< Per-VRF default next hop array */
>  };
> 
>  static void
> -dummy_lookup(void *fib_p, const uint32_t *ips, uint64_t *next_hops,
> -     const unsigned int n)
> +dummy_lookup(void *fib_p, const uint16_t *vrf_ids,
> +     const uint32_t *ips, uint64_t *next_hops, const unsigned int n)
>  {
>       unsigned int i;
>       struct rte_fib *fib = fib_p;
>       struct rte_rib_node *node;
> +     struct rte_rib *rib;
> 
>       for (i = 0; i < n; i++) {
> -             node = rte_rib_lookup(fib->rib, ips[i]);
> +             RTE_ASSERT(vrf_ids[i] < fib->num_vrfs);
> +             rib = rte_fib_vrf_get_rib(fib, vrf_ids[i]);
> +             node = rte_rib_lookup(rib, ips[i]);
>               if (node != NULL)
>                       rte_rib_get_nh(node, &next_hops[i]);
>               else
> -                     next_hops[i] = fib->def_nh;
> +                     next_hops[i] = fib->def_nh[vrf_ids[i]];
>       }
>  }
> 
>  static int
> -dummy_modify(struct rte_fib *fib, uint32_t ip, uint8_t depth,
> -     uint64_t next_hop, int op)
> +dummy_modify(struct rte_fib *fib, uint16_t vrf_id, uint32_t ip,
> +     uint8_t depth, uint64_t next_hop, int op)
>  {
>       struct rte_rib_node *node;
> +     struct rte_rib *rib;
>       if ((fib == NULL) || (depth > RTE_FIB_MAXDEPTH))
>               return -EINVAL;
> 
> -     node = rte_rib_lookup_exact(fib->rib, ip, depth);
> +     rib = rte_fib_vrf_get_rib(fib, vrf_id);
> +     if (rib == NULL)
> +             return -EINVAL;
> +
> +     node = rte_rib_lookup_exact(rib, ip, depth);
> 
>       switch (op) {
>       case RTE_FIB_ADD:
>               if (node == NULL)
> -                     node = rte_rib_insert(fib->rib, ip, depth);
> +                     node = rte_rib_insert(rib, ip, depth);
>               if (node == NULL)
>                       return -rte_errno;
>               return rte_rib_set_nh(node, next_hop);
>       case RTE_FIB_DEL:
>               if (node == NULL)
>                       return -ENOENT;
> -             rte_rib_remove(fib->rib, ip, depth);
> +             rte_rib_remove(rib, ip, depth);
>               return 0;
>       }
>       return -EINVAL;
> @@ -125,7 +137,7 @@ rte_fib_add(struct rte_fib *fib, uint32_t ip, uint8_t 
> depth,
> uint64_t next_hop)
>       if ((fib == NULL) || (fib->modify == NULL) ||
>                       (depth > RTE_FIB_MAXDEPTH))
>               return -EINVAL;
> -     return fib->modify(fib, ip, depth, next_hop, RTE_FIB_ADD);
> +     return fib->modify(fib, 0, ip, depth, next_hop, RTE_FIB_ADD);
>  }
> 
>  RTE_EXPORT_SYMBOL(rte_fib_delete)
> @@ -135,7 +147,7 @@ rte_fib_delete(struct rte_fib *fib, uint32_t ip, uint8_t
> depth)
>       if ((fib == NULL) || (fib->modify == NULL) ||
>                       (depth > RTE_FIB_MAXDEPTH))
>               return -EINVAL;
> -     return fib->modify(fib, ip, depth, 0, RTE_FIB_DEL);
> +     return fib->modify(fib, 0, ip, depth, 0, RTE_FIB_DEL);
>  }
> 
>  RTE_EXPORT_SYMBOL(rte_fib_lookup_bulk)
> @@ -143,24 +155,73 @@ int
>  rte_fib_lookup_bulk(struct rte_fib *fib, uint32_t *ips,
>       uint64_t *next_hops, int n)
>  {
> +     static const uint16_t zero_vrf_ids[FIB_MAX_LOOKUP_BULK];
> +     unsigned int off = 0;
> +     unsigned int total = (unsigned int)n;
> +
>       FIB_RETURN_IF_TRUE(((fib == NULL) || (ips == NULL) ||
>               (next_hops == NULL) || (fib->lookup == NULL)), -EINVAL);
> 
> -     fib->lookup(fib->dp, ips, next_hops, n);
> +     while (off < total) {
> +             unsigned int chunk = RTE_MIN(total - off,
> +                     FIB_MAX_LOOKUP_BULK);
> +             fib->lookup(fib->dp, zero_vrf_ids, ips + off,
> +                     next_hops + off, chunk);
> +             off += chunk;
> +     }
> +
> +     return 0;
> +}
> +
> +RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_fib_vrf_lookup_bulk, 26.07)
> +int
> +rte_fib_vrf_lookup_bulk(struct rte_fib *fib, const uint16_t *vrf_ids,
> +     const uint32_t *ips, uint64_t *next_hops, int n)
> +{
> +     FIB_RETURN_IF_TRUE(((fib == NULL) || (vrf_ids == NULL) ||
> +             (ips == NULL) || (next_hops == NULL) ||
> +             (fib->lookup == NULL)), -EINVAL);
> +
> +     fib->lookup(fib->dp, vrf_ids, ips, next_hops, (unsigned int)n);
>       return 0;
>  }
> 
> +RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_fib_vrf_add, 26.07)
> +int
> +rte_fib_vrf_add(struct rte_fib *fib, uint16_t vrf_id, uint32_t ip,
> +     uint8_t depth, uint64_t next_hop)
> +{
> +     if ((fib == NULL) || (fib->modify == NULL) ||
> +                     (depth > RTE_FIB_MAXDEPTH))
> +             return -EINVAL;
> +     return fib->modify(fib, vrf_id, ip, depth, next_hop, RTE_FIB_ADD);
> +}
> +
> +RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_fib_vrf_delete, 26.07)
> +int
> +rte_fib_vrf_delete(struct rte_fib *fib, uint16_t vrf_id, uint32_t ip,
> +     uint8_t depth)
> +{
> +     if ((fib == NULL) || (fib->modify == NULL) ||
> +                     (depth > RTE_FIB_MAXDEPTH))
> +             return -EINVAL;
> +     return fib->modify(fib, vrf_id, ip, depth, 0, RTE_FIB_DEL);
> +}
> +
>  RTE_EXPORT_SYMBOL(rte_fib_create)
>  struct rte_fib *
>  rte_fib_create(const char *name, int socket_id, struct rte_fib_conf *conf)
>  {
>       char mem_name[RTE_FIB_NAMESIZE];
> +     char rib_name[RTE_FIB_NAMESIZE];
>       int ret;
>       struct rte_fib *fib = NULL;
>       struct rte_rib *rib = NULL;
>       struct rte_tailq_entry *te;
>       struct rte_fib_list *fib_list;
>       struct rte_rib_conf rib_conf;
> +     uint16_t num_vrfs;
> +     uint16_t vrf;
> 
>       /* Check user arguments. */
>       if ((name == NULL) || (conf == NULL) || (conf->max_routes < 0) ||
> @@ -170,16 +231,42 @@ rte_fib_create(const char *name, int socket_id, struct
> rte_fib_conf *conf)
>               return NULL;
>       }
> 
> +     num_vrfs = (conf->max_vrfs == 0) ? 1 : conf->max_vrfs;
>       rib_conf.ext_sz = conf->rib_ext_sz;
>       rib_conf.max_nodes = conf->max_routes * 2;
> 
> -     rib = rte_rib_create(name, socket_id, &rib_conf);
> -     if (rib == NULL) {
> -             FIB_LOG(ERR,
> -                     "Can not allocate RIB %s", name);
> +     struct rte_rib **ribs = rte_zmalloc_socket("FIB_RIBS",
> +             num_vrfs * sizeof(*fib->ribs), RTE_CACHE_LINE_SIZE, socket_id);
> +     if (ribs == NULL) {
> +             FIB_LOG(ERR, "FIB %s RIB array allocation failed", name);
> +             rte_errno = ENOMEM;
>               return NULL;
>       }
> 
> +     uint64_t *def_nh = rte_zmalloc_socket("FIB_DEF_NH",
> +             num_vrfs * sizeof(*def_nh), RTE_CACHE_LINE_SIZE, socket_id);
> +     if (def_nh == NULL) {
> +             FIB_LOG(ERR, "FIB %s default nexthop array allocation failed",
> name);
> +             rte_errno = ENOMEM;
> +             rte_free(ribs);
> +             return NULL;
> +     }
> +
> +     for (vrf = 0; vrf < num_vrfs; vrf++) {
> +             if (num_vrfs == 1)
> +                     snprintf(rib_name, sizeof(rib_name), "%s", name);
> +             else
> +                     snprintf(rib_name, sizeof(rib_name), "%s_vrf%u", name,
> vrf);
> +             rib = rte_rib_create(rib_name, socket_id, &rib_conf);
> +             if (rib == NULL) {
> +                     FIB_LOG(ERR, "Can not allocate RIB %s", rib_name);
> +                     goto free_ribs;
> +             }
> +             ribs[vrf] = rib;
> +             def_nh[vrf] = (conf->vrf_default_nh != NULL) ?
> +                     conf->vrf_default_nh[vrf] : conf->default_nh;
> +     }
> +
>       snprintf(mem_name, sizeof(mem_name), "FIB_%s", name);
>       fib_list = RTE_TAILQ_CAST(rte_fib_tailq.head, rte_fib_list);
> 
> @@ -215,11 +302,13 @@ rte_fib_create(const char *name, int socket_id, struct
> rte_fib_conf *conf)
>               goto free_te;
>       }
> 
> +     fib->num_vrfs = num_vrfs;
> +     fib->ribs = ribs;
> +     fib->def_nh = def_nh;
> +
>       rte_strlcpy(fib->name, name, sizeof(fib->name));
> -     fib->rib = rib;
>       fib->type = conf->type;
>       fib->flags = conf->flags;
> -     fib->def_nh = conf->default_nh;
>       ret = init_dataplane(fib, socket_id, conf);
>       if (ret < 0) {
>               FIB_LOG(ERR,
> @@ -242,8 +331,12 @@ rte_fib_create(const char *name, int socket_id, struct
> rte_fib_conf *conf)
>       rte_free(te);
>  exit:
>       rte_mcfg_tailq_write_unlock();
> -     rte_rib_free(rib);
> +free_ribs:
> +     for (vrf = 0; vrf < num_vrfs; vrf++)
> +             rte_rib_free(ribs[vrf]);
> 
> +     rte_free(def_nh);
> +     rte_free(ribs);
>       return NULL;
>  }
> 
> @@ -311,7 +404,13 @@ rte_fib_free(struct rte_fib *fib)
>       rte_mcfg_tailq_write_unlock();
> 
>       free_dataplane(fib);
> -     rte_rib_free(fib->rib);
> +     if (fib->ribs != NULL) {
> +             uint16_t vrf;
> +             for (vrf = 0; vrf < fib->num_vrfs; vrf++)
> +                     rte_rib_free(fib->ribs[vrf]);
> +     }
> +     rte_free(fib->ribs);
> +     rte_free(fib->def_nh);
>       rte_free(fib);
>       rte_free(te);
>  }
> @@ -327,7 +426,18 @@ RTE_EXPORT_SYMBOL(rte_fib_get_rib)
>  struct rte_rib *
>  rte_fib_get_rib(struct rte_fib *fib)
>  {
> -     return (fib == NULL) ? NULL : fib->rib;
> +     return (fib == NULL || fib->ribs == NULL) ? NULL : fib->ribs[0];
> +}
> +
> +RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_fib_vrf_get_rib, 26.07)
> +struct rte_rib *
> +rte_fib_vrf_get_rib(struct rte_fib *fib, uint16_t vrf_id)
> +{
> +     if (fib == NULL || fib->ribs == NULL)
> +             return NULL;
> +     if (vrf_id >= fib->num_vrfs)
> +             return NULL;
> +     return fib->ribs[vrf_id];
>  }
> 
>  RTE_EXPORT_SYMBOL(rte_fib_select_lookup)
> diff --git a/lib/fib/rte_fib.h b/lib/fib/rte_fib.h
> index b16a653535..883195c7d6 100644
> --- a/lib/fib/rte_fib.h
> +++ b/lib/fib/rte_fib.h
> @@ -53,11 +53,11 @@ enum rte_fib_type {
>  };
> 
>  /** Modify FIB function */
> -typedef int (*rte_fib_modify_fn_t)(struct rte_fib *fib, uint32_t ip,
> -     uint8_t depth, uint64_t next_hop, int op);
> +typedef int (*rte_fib_modify_fn_t)(struct rte_fib *fib, uint16_t vrf_id,
> +     uint32_t ip, uint8_t depth, uint64_t next_hop, int op);
>  /** FIB bulk lookup function */
> -typedef void (*rte_fib_lookup_fn_t)(void *fib, const uint32_t *ips,
> -     uint64_t *next_hops, const unsigned int n);
> +typedef void (*rte_fib_lookup_fn_t)(void *fib, const uint16_t *vrf_ids,
> +     const uint32_t *ips, uint64_t *next_hops, const unsigned int n);
> 
>  enum rte_fib_op {
>       RTE_FIB_ADD,
> @@ -110,6 +110,10 @@ struct rte_fib_conf {
>               } dir24_8;
>       };
>       unsigned int flags; /**< Optional feature flags from RTE_FIB_F_* */
> +     /** Number of VRFs to support (0 or 1 = single VRF for backward compat)
> */
> +     uint16_t max_vrfs;
> +     /** Per-VRF default nexthops (NULL = use default_nh for all) */
> +     uint64_t *vrf_default_nh;
>  };
> 
>  /** FIB RCU QSBR configuration structure. */
> @@ -224,6 +228,71 @@ rte_fib_delete(struct rte_fib *fib, uint32_t ip, uint8_t
> depth);
>  int
>  rte_fib_lookup_bulk(struct rte_fib *fib, uint32_t *ips,
>               uint64_t *next_hops, int n);
> +
> +/**
> + * Add a route to the FIB with VRF ID.
> + *
> + * @param fib
> + *   FIB object handle
> + * @param vrf_id
> + *   VRF ID (0 to max_vrfs-1)
> + * @param ip
> + *   IPv4 prefix address to be added to the FIB
> + * @param depth
> + *   Prefix length
> + * @param next_hop
> + *   Next hop to be added to the FIB
> + * @return
> + *   0 on success, negative value otherwise
> + */
> +__rte_experimental
> +int
> +rte_fib_vrf_add(struct rte_fib *fib, uint16_t vrf_id, uint32_t ip,
> +     uint8_t depth, uint64_t next_hop);
> +
> +/**
> + * Delete a rule from the FIB with VRF ID.
> + *
> + * @param fib
> + *   FIB object handle
> + * @param vrf_id
> + *   VRF ID (0 to max_vrfs-1)
> + * @param ip
> + *   IPv4 prefix address to be deleted from the FIB
> + * @param depth
> + *   Prefix length
> + * @return
> + *   0 on success, negative value otherwise
> + */
> +__rte_experimental
> +int
> +rte_fib_vrf_delete(struct rte_fib *fib, uint16_t vrf_id, uint32_t ip,
> +     uint8_t depth);
> +
> +/**
> + * Lookup multiple IP addresses in the FIB with per-packet VRF IDs.
> + *
> + * @param fib
> + *   FIB object handle
> + * @param vrf_ids
> + *   Array of VRF IDs
> + * @param ips
> + *   Array of IPs to be looked up in the FIB
> + * @param next_hops
> + *   Next hop of the most specific rule found for IP in the corresponding 
> VRF.
> + *   This is an array of eight byte values.
> + *   If the lookup for the given IP failed, then corresponding element would
> + *   contain default nexthop value configured for that VRF.
> + * @param n
> + *   Number of elements in vrf_ids, ips (and next_hops) arrays to lookup.
> + * @return
> + *   -EINVAL for incorrect arguments, otherwise 0
> + */
> +__rte_experimental
> +int
> +rte_fib_vrf_lookup_bulk(struct rte_fib *fib, const uint16_t *vrf_ids,
> +     const uint32_t *ips, uint64_t *next_hops, int n);
> +
>  /**
>   * Get pointer to the dataplane specific struct
>   *
> @@ -237,7 +306,7 @@ void *
>  rte_fib_get_dp(struct rte_fib *fib);
> 
>  /**
> - * Get pointer to the RIB
> + * Get pointer to the RIB for VRF 0
>   *
>   * @param fib
>   *   FIB object handle
> @@ -248,6 +317,21 @@ rte_fib_get_dp(struct rte_fib *fib);
>  struct rte_rib *
>  rte_fib_get_rib(struct rte_fib *fib);
> 
> +/**
> + * Get pointer to the RIB for a specific VRF
> + *
> + * @param fib
> + *   FIB object handle
> + * @param vrf_id
> + *   VRF ID (0 to max_vrfs-1)
> + * @return
> + *   Pointer on the RIB on success
> + *   NULL otherwise
> + */
> +__rte_experimental
> +struct rte_rib *
> +rte_fib_vrf_get_rib(struct rte_fib *fib, uint16_t vrf_id);
> +
>  /**
>   * Set lookup function based on type
>   *
> --
> 2.43.0

Reply via email to