Here is a combined overview of IPv4 and IPv6 lookup data structures, focusing on Fixed-Stride, Level-Compressed (LC), and Multi-Bit Tries.
This guide prioritizes L3 cache efficiency and Memory Mapping (mmap) capabilities in Rust.
To choose the right structure, you must understand the discrepancy between IPv4 and IPv6:
-
IPv4 (32-bit): The address space is small (
$2^{32}$ ) and dense. You can afford "wasteful" pre-allocation (like a 16MB array) to gain raw speed. -
IPv6 (128-bit): The address space is massive (
$2^{128}$ ) and sparse. You cannot pre-allocate large fixed strides without compression. You must use a structure that compresses empty branches (via Bitmaps or Level Compression) to fit in the CPU cache.
Best for: IPv4 (Production Routing)
This is the standard for high-performance software routers (DPDK, VPP). It minimizes memory accesses (usually 1 or 2) at the cost of memory usage.
-
Mechanism:
-
Table 1 (DIR-24): A flat array of
$2^{24}$ (16 million) entries covering the first 24 bits of the IP. - Table 2 (DIR-8): Tiny secondary tables for the remaining 8 bits.
-
Table 1 (DIR-24): A flat array of
- Cache: The main table (16-32MB) fits in L3 cache on modern server CPUs (which often have >40MB L3).
-
IPv6 Suitability: Impossible. A
$2^{24}$ stride is fine, but you'd need millions of subsequent tables. -
Rust Implementation:
-
dpdk-rswrappers (binding to C) are common. -
Manual
Vec: In Rust, this is trivial to implement as aVec<u16>(holding indices) for the 24-bit table.
-
Best for: IPv4 & IPv6 (Balanced)
This algorithm mimics hardware routers. It is a Fixed-Stride Trie but with Bitmap Compression. It is the most robust all-rounder for Rust implementations.
- Mechanism:
- It uses a fixed stride (e.g., 4 bits per node).
- Instead of an array of 16 pointers (which bloats memory), it uses a 16-bit bitmap.
- Children are stored contiguously in a single
Vec.
- L3 Cache: Excellent. Nodes are tiny (bitmap + index), so many fit in a cache line.
- Mmap: High. Because it uses a single backing
Vec(arena style), it can be serialized directly to disk and mapped back without pointer fixups. - Rust Recommendation:
- Crate:
ip_network_table - Details: Uses the Tree-Bitmap algorithm. It handles both IPv4 and IPv6 elegantly by changing the stride logic internally.
- Crate:
Best for: IPv6 (Extreme Read Speed)
Poptrie (Population Count Trie) is the evolution of the LC-Trie. It uses the CPU's popcnt instruction to compress variable strides into dense arrays.
- Mechanism:
- It analyzes the tree and creates nodes with large strides (e.g., 6 bits = 64 children).
- It uses a 64-bit bitmap to mark which children exist.
- The index is calculated:
index = popcnt(bitmap & mask).
- L3 Cache: Supreme. It achieves the highest density of any structure here. It fits massive routing tables (Full Internet BGP) into L2/L3 cache.
- Mmap: Native. Poptrie is designed to be built into a contiguous array of
u64s. - Rust Recommendation:
- Crate:
oxidecomputer/poptrie - Details: Developed for the Helios emulator. It is read-optimized and extremely compact.
- Crate:
| Feature | DIR-24-8 | Tree-Bitmap | Poptrie / LC-Trie | Standard Radix |
|---|---|---|---|---|
| Primary Use | IPv4 High-Speed | IPv4/IPv6 General | IPv6 High-Speed | Generic Maps |
| Lookup Speed | π Fastest (1-2 accesses) | β‘ Fast (Unrolled loops) | β‘ Fast (Popcnt math) | π’ Slower (Pointer chase) |
| Memory Footprint | π High (Pre-allocated) | π¦ Compact | π Tiny | π Medium (Pointers) |
| IPv6 Capable? | β No | β Yes | β Yes | β Yes |
| L3 Cache Fit | β Good | β Excellent | β Poor | |
| Mmap Friendly? | β Yes (Flat Arrays) | β Yes (Contiguous Vec) | β Yes (Bit Arrays) | β No (Heap Pointers) |
If you need a crate that "just works" for both IPv4 and IPv6, supports Longest Prefix Match (LPM), and is memory efficient.
- Algo: Tree-Bitmap (Compressed Fixed-Stride).
- Link:
crates.io/crates/ip_network_table
If you are building a read-heavy system (like a firewall or packet filter) where you build the table once and query it billions of times.
- Algo: Popcount Compressed Trie.
- Link:
github.com/oxidecomputer/poptrie
If your data is static (e.g., a GeoIP database) and you want to mmap it from disk with zero parsing overhead.
- Algo: Finite State Transducer (effectively a highly compressed, shared-suffix trie).
- Note: You map IP bytes to values. It is immutable.
- Link:
crates.io/crates/fst
If you specifically need the raw speed of DIR-24-8 for IPv4, there isn't a dominant "pure Rust" general-purpose crate because the logic is so simple most engines write it manually.
- Implementation Sketch:
// A simple DIR-24-8 structure struct Ipv4Table<T> { // Covers first 24 bits. // Value: Some(T) or Index into `small_tables` main_table: Vec<Entry<T>>, // Covers last 8 bits. // Allocated only when needed. small_tables: Vec<[Entry<T>; 256]>, }