From: Stephen Hemminger <stephen@networkplumber.org>
To: Vladimir Medvedkin <vladimir.medvedkin@intel.com>
Cc: dev@dpdk.org, rjarry@redhat.com, mb@smartsharesystems.com,
maxime@leroys.fr, konstantin.ananyev@huawei.com
Subject: Re: [RFC PATCH v2 0/7] VRF support in FIB library
Date: Fri, 16 Oct 2026 15:54:35 -0700 [thread overview]
Message-ID: <20261016155435.17225ba7@phoenix.local> (raw)
In-Reply-To: <20261014183921.495158-1-vladimir.medvedkin@intel.com>
On Wed, 14 Oct 2026 18:39:14 +0000
Vladimir Medvedkin <vladimir.medvedkin@intel.com> wrote:
> This series adds multi-VRF support to the IPv4 FIB, allowing a single FIB
> instance to host multiple isolated routing tables.
>
> Today a FIB instance is a single routing table, so an application serving
> several VRFs needs one FIB per VRF. In a burst oriented datapath packets of
> one burst can belong to different VRFs, and the application either does
> per-packet lookups in different FIBs or regroups the burst by VRF before
> the lookup. Both are expensive. With this series all the VRFs live in one
> FIB, the bulk lookup takes a VRF ID per address, and the existing API
> operates on VRF 0.
>
> v1 replicated the 16M entry tbl24 per VRF. That kept the lookup on par with
> the single VRF case, but memory grew linearly with the number of VRFs,
> which was the main concern raised on v1. v2 resolves the issue by adding
> of two dataplane algorithms with different memory/lookup trade-offs.
>
> DIR8-16-8 is a new three level variant of DIR-24-8 with 8, 16 and 8 bit
> strides. Only the 256 entry root table (2 KB) is replicated per VRF; the
> tbl16 and tbl8 groups come from pools shared by all the VRFs, so memory
> follows the routes actually installed rather than the number of VRFs. The
> cost is an extra memory access for prefixes longer than /8.
>
> DIR-24-8 gets multi-VRF support by resolving the VRF after the longest
> prefix match, along the lines Konstantin suggested on v1. Instead of a
> vector of next hops per prefix, a single tbl24_8 shared by all the VRFs
> returns an internal prefix ID, and a hash table keyed by {VRF, prefix ID}
> returns the next hop, a miss meaning the VRF default next hop. The aim is
> to resolve the VRF with a single memory access, so buckets hold 8 records
> and there is no probing beyond the bucket.
>
> Such a table only works if the control path can keep buckets from
> overflowing while the hash stays cheap on the datapath. Since the prefix
> ID is internal, the library can pick it so that the records of a prefix
> land in buckets with free room. Collisions are chosen deliberately, so they
> are not a security concern, but finding them has to be cheap. Toeplitz was
> the first candidate: its structure is well studied and the thash library
> already knows how to find collisions, but it is only fast with GFNI. CRC
> has the same linear properties, is trivially inverted and is hardware
> accelerated on x86 and Arm, so CRC32C is used. Linearity also places the
> buckets of one prefix in different VRFs at fixed XOR offsets from each
> other, so a candidate prefix ID is checked for all the VRFs referencing
> the prefix at once, and these records never share a bucket. If a bucket
> fills up anyway, a prefix already in it is renumbered to make room.
>
> The price of the shared table is paid on the control path: a route in one
> VRF needs a record for every more specific prefix installed below it by
> other VRFs. Default routes are excluded, they map onto the per-VRF default
> next hop.
>
> The two algorithms target different deployments. DIR8-16-8 fits a limited
> number of VRFs (tens to hundreds) carrying large tables, up to a BGP full
> view each. The hash based DIR-24-8 fits one large VRF alongside hundreds
> or thousands of small ones.
>
> test-fib gets a VRF mode, including a profile with a full view in VRF 0 and
> smaller VRFs made of random subsets of it. The first three patches are fixes
> found along the way and are independent of the rest.
>
> Not done yet:
> - IPv6. The VRF bookkeeping of the hash based scheme is address family
> agnostic and is meant to be reused by TRIE.
> - RCU support for multi-VRF DIR-24-8.
>
> Vladimir Medvedkin (7):
> fib: fix return value of a nexthop update
> app/test-fib: fix lookup of the last burst
> app/test-fib: fix size of the tables for large counts
> fib: add DIR8-16-8 algorithm
> fib: add multi-VRF support
> fib: split DIR24-8 table update from the FIB wrapper
> fib: add hash based VRF support for DIR24-8
>
> app/test-fib/main.c | 673 ++++++++++---
> app/test/test_fib.c | 1001 ++++++++++++++++++-
> app/test/test_fib_perf.c | 440 +++------
> app/test/test_fib_routes.h | 282 ++++++
> doc/guides/prog_guide/fib_lib.rst | 66 ++
> doc/guides/rel_notes/release_26_11.rst | 21 +
> lib/fib/dir24_8.c | 34 +-
> lib/fib/dir24_8.h | 43 +-
> lib/fib/dir24_8_avx512.c | 18 +-
> lib/fib/dir24_8_avx512.h | 32 +-
> lib/fib/dir24_8_rvv.c | 3 +-
> lib/fib/dir24_8_rvv.h | 16 +-
> lib/fib/dir24_8_vrf.c | 290 ++++++
> lib/fib/dir24_8_vrf.h | 60 ++
> lib/fib/dir8_16_8.c | 665 +++++++++++++
> lib/fib/dir8_16_8.h | 192 ++++
> lib/fib/dir8_16_8_avx512.c | 183 ++++
> lib/fib/dir8_16_8_avx512.h | 24 +
> lib/fib/fib_vrf.c | 1256 ++++++++++++++++++++++++
> lib/fib/fib_vrf.h | 277 ++++++
> lib/fib/fib_vrf_avx512.c | 142 +++
> lib/fib/meson.build | 22 +-
> lib/fib/rte_fib.c | 249 ++++-
> lib/fib/rte_fib.h | 127 ++-
> 24 files changed, 5593 insertions(+), 523 deletions(-)
> create mode 100644 app/test/test_fib_routes.h
> create mode 100644 lib/fib/dir24_8_vrf.c
> create mode 100644 lib/fib/dir24_8_vrf.h
> create mode 100644 lib/fib/dir8_16_8.c
> create mode 100644 lib/fib/dir8_16_8.h
> create mode 100644 lib/fib/dir8_16_8_avx512.c
> create mode 100644 lib/fib/dir8_16_8_avx512.h
> create mode 100644 lib/fib/fib_vrf.c
> create mode 100644 lib/fib/fib_vrf.h
> create mode 100644 lib/fib/fib_vrf_avx512.c
>
The AI review feedback was interesting - not sure I agree.
On Wed, 14 Oct 2026 18:39 +0000
Vladimir Medvedkin <vladimir.medvedkin@intel.com> wrote:
Patches 1-3 are independent fixes and can go in ahead of the rest.
The VRF API is reasonable, but the series does not show a memory
saving over what applications do today, which is one rte_fib per VRF.
Pools and RIBs are still preallocated per VRF at worst case size.
Please include memory and lookup cycle numbers against N independent
DIR8_16_8 and 4B DIR24_8 FIBs for a realistic mix (one full view plus
many small VRFs, which --vrfconf already generates).
The hash based DIR24_8 (patch 7) is not safe with concurrent readers
and has no RCU support. Suggest dropping patches 6-7 from the next
version and going in with DIR8_16_8 VRF support first.
Series
------
Warning: per-VRF RIBs are sized for the whole FIB.
fib_create_ribs() creates every VRF RIB with max_nodes = 2 * max_routes
and the rib mempool is preallocated. With a full table max_routes this
dominates memory use and scales linearly with max_vrfs. Needs a
per-VRF route limit in rte_fib_conf, or RIB nodes from a shared pool.
[4/7] fib: add DIR8-16-8 algorithm
----------------------------------
Warning: memory cost is set by tbl16 group size, not the root table.
A tbl16 group is 65536 * 8 = 512 KB and a VRF consumes one for every
/8 it has a longer prefix in. A full view touches ~220 /8s, about
110 MB, same order as DIR24_8 with 8B next hops. The fib_lib.rst claim
that this suits a large number of VRFs only holds for VRFs touching
few /8s; say so in the guide.
Info: only 8 byte next hops are supported. A 4 byte entry variant
would halve the tbl16 cost.
Info: tbl_group_recycle() on a tbl16 group compares up to 65536
entries after every partial install. Sparse groups, the common VRF
case, rarely exit early.
[5/7] fib: add multi-VRF support
--------------------------------
Warning: the test-fib dump_lookup() IPv6 change
(&tbl6[i * 16] -> &tbl6[i]) fixes an out of bounds read unrelated to
VRF. Send it as a separate patch with Fixes: and Cc: stable@dpdk.org.
Warning: rte_fib_create() now allocates the dataplane and RIBs before
the duplicate name check. A duplicate fails in rte_rib_create() and
logs "Can not allocate RIBs". Keep the original order: take the tailq
lock, check the name, then allocate.
Info: new API should take const input:
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);
Info: an out of range vrf_id reads past tbl0 (DIR8_16_8) or def_nh
(hash path). Fine not to check in the fast path, but add a debug
assert in the lookup functions:
RTE_ASSERT(vrf_ids == NULL || vrf_ids[i] < dp->num_vrfs);
Info: in test-fib run_v4() the lpm_vrf_lookup_burst() branch of the
timed LPM loop leaves ret stale. Set ret = 0 on that branch.
Info: patch 7 reorders the rte_fib_create() error path and removes
comments added here. Settle both in this patch.
Info: "%p-v%u" RIB names and the "keep the name short" comment in
test_fib_perf.c work around the 32 byte memzone name limit, which
goes to 64 in 26.11. Derive readable names from the FIB name once
that lands.
[7/7] fib: add hash based VRF support for DIR24-8
-------------------------------------------------
Error: a lookup racing with an update can return another prefix's
next hop. ht_upsert() and ht_delete() reuse bucket slots in place.
A reader that matched key K in slot j can read val[j] after the
writer freed the slot and republished it for key K' (val then key),
returning K' next hop for a different VRF or prefix. ht_delete()
clears key then val, so the same window returns 0.
Error: node_move() switches the prefix ID in tbl24 and deletes the
old ID records immediately. A reader holding the old ID misses in the
hash and gets the VRF default. Relocation is driven by ordinary adds
(node_relocate_if_polarized(), record_upsert() eviction), so adding a
route can blackhole an unrelated prefix. remove_node() has the same
issue: a stale ID resolves to the default, not the covering route.
Both need deferred reclaim. rte_fib_rcu_qsbr_add() returns -ENOTSUP
in this mode; freed slots and retired prefix IDs need to go through
an rte_rcu_qsbr_dq and be reused only after a grace period.
Warning: the hash table is sized for the worst case,
max_routes * max_vrfs * 2 records at 16 bytes, i.e. 32 bytes per
route per VRF. At max_routes = 2M that is 64 MB per VRF, the same as
replicating a 4B DIR24_8 per VRF, so the shared tbl24 saves nothing.
Past the 2^24 bucket cap (2 GB) adds fail with -ENOSPC and nothing
warns at create time. Make the record count configurable and reject
values above the cap in rte_fib_create():
struct {
enum rte_fib_dir24_8_nh_sz nh_sz;
uint32_t num_tbl8;
uint32_t num_vrf_records; /* 0: derive from max_routes */
} dir24_8;
Warning: inherited records are not bounded by a VRF's own routes.
A VRF holding a covering /8 gets one record for every prefix any other
VRF has below it. Document this next to the sizing parameter.
Info: pid_alloc() for single VRF prefixes always scans from bucket 0,
so adds slow down as the low buckets fill.
Info: -mvpclmulqdq is added to cflags_avx512 for every AVX512 source
in lib/fib; only fib_vrf_avx512.c needs it.
Info: fib_vrf.c is ~1250 lines of CRC inversion placement, polarized
bucket tracking and eviction. That maintenance cost needs the numbers
above to justify it.
prev parent reply other threads:[~2026-10-16 22:54 UTC|newest]
Thread overview: 46+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-22 15:42 [RFC PATCH 0/4] VRF support in FIB library Vladimir Medvedkin
2026-03-22 15:42 ` [RFC PATCH 1/4] fib: add multi-VRF support Vladimir Medvedkin
2026-03-23 15:48 ` Konstantin Ananyev
2026-03-23 19:06 ` Medvedkin, Vladimir
2026-03-23 22:22 ` Konstantin Ananyev
2026-03-25 14:09 ` Medvedkin, Vladimir
2026-03-26 10:13 ` Konstantin Ananyev
2026-03-27 18:32 ` Medvedkin, Vladimir
2026-03-22 15:42 ` [RFC PATCH 2/4] fib: add VRF functional and unit tests Vladimir Medvedkin
2026-03-22 16:40 ` Stephen Hemminger
2026-03-22 16:41 ` Stephen Hemminger
2026-03-22 15:42 ` [RFC PATCH 3/4] fib6: add multi-VRF support Vladimir Medvedkin
2026-03-22 15:42 ` [RFC PATCH 4/4] fib6: add VRF functional and unit tests Vladimir Medvedkin
2026-03-22 16:45 ` Stephen Hemminger
2026-03-22 16:43 ` [RFC PATCH 0/4] VRF support in FIB library Stephen Hemminger
2026-03-23 9:01 ` Morten Brørup
2026-03-23 11:32 ` Medvedkin, Vladimir
2026-03-23 11:16 ` Medvedkin, Vladimir
2026-03-23 9:54 ` Robin Jarry
2026-03-23 11:34 ` Medvedkin, Vladimir
2026-03-23 11:27 ` Maxime Leroy
2026-03-23 12:49 ` Medvedkin, Vladimir
2026-03-23 14:53 ` Maxime Leroy
2026-03-23 15:08 ` Robin Jarry
2026-03-23 15:27 ` Morten Brørup
2026-03-23 18:52 ` Medvedkin, Vladimir
2026-03-23 18:42 ` Medvedkin, Vladimir
2026-03-24 9:19 ` Maxime Leroy
2026-03-25 15:56 ` Medvedkin, Vladimir
2026-03-25 21:43 ` Maxime Leroy
2026-03-27 18:27 ` Medvedkin, Vladimir
2026-04-02 16:51 ` Maxime Leroy
2026-03-23 19:05 ` Stephen Hemminger
2026-10-14 18:39 ` [RFC PATCH v2 0/7] " Vladimir Medvedkin
2026-10-14 18:39 ` [RFC PATCH v2 1/7] fib: fix return value of a nexthop update Vladimir Medvedkin
2026-10-14 18:39 ` [RFC PATCH v2 2/7] app/test-fib: fix lookup of the last burst Vladimir Medvedkin
2026-10-14 18:39 ` [RFC PATCH v2 3/7] app/test-fib: fix size of the tables for large counts Vladimir Medvedkin
2026-10-14 22:52 ` Stephen Hemminger
2026-10-15 14:21 ` Medvedkin, Vladimir
2026-10-14 18:39 ` [RFC PATCH v2 4/7] fib: add DIR8-16-8 algorithm Vladimir Medvedkin
2026-10-14 18:39 ` [RFC PATCH v2 5/7] fib: add multi-VRF support Vladimir Medvedkin
2026-10-14 18:39 ` [RFC PATCH v2 6/7] fib: split DIR24-8 table update from the FIB wrapper Vladimir Medvedkin
2026-10-14 18:39 ` [RFC PATCH v2 7/7] fib: add hash based VRF support for DIR24-8 Vladimir Medvedkin
2026-10-14 22:55 ` [RFC PATCH v2 0/7] VRF support in FIB library Stephen Hemminger
2026-10-15 14:17 ` Medvedkin, Vladimir
2026-10-16 22:54 ` Stephen Hemminger [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261016155435.17225ba7@phoenix.local \
--to=stephen@networkplumber.org \
--cc=dev@dpdk.org \
--cc=konstantin.ananyev@huawei.com \
--cc=maxime@leroys.fr \
--cc=mb@smartsharesystems.com \
--cc=rjarry@redhat.com \
--cc=vladimir.medvedkin@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox