capsule-rs / capsule-rs/capsule

LPM (forwarding table) interface and underlying implemenation

Open
#93 0 comments 0 reactions 1 assignee Claimed by @zeeshanlakhani View on GitHub
enhancement
Dominant language
Rust
Stars
443
Forks
42
PR merge metrics
No merged PRs in 30d

Description

## Background

We want Capsule to offer a nice shim/API layer and implementation for LPM-based ([Longest prefix match](https://en.wikipedia.org/wiki/Longest_prefix_match)) forwarding table search, especially around setup, insertion, deletion, and lookups1.

Screen Shot 2020-05-06 at 3 24 57 PM

The LPM interface revolves around a key-value pair lookup where we give an IPv4/IPv6 address as a *key*, which gets matched to cidr essentially (e.g. `(prefix, length)`), and returns a corresponding value. The algorithm/implementation is mostly used in routing applications where the value represents the next-hop. An LPM table contains one or more rules, where each rule is a pair of an IP with prefix and a value. If the input *key* IP matches with more than one rules then the rule with the highest prefix will be used to determine the required value.

An LPM structure is usually designed around a [Trie](https://en.wikipedia.org/wiki/Trie) data structure. DPDK, for example, exposes an [LPM library](https://doc.dpdk.org/guides/prog_guide/lpm_lib.html), including a separate [LPM6](https://doc.dpdk.org/guides/prog_guide/lpm6_lib.html) one for IPv6 addresses, with an implementation using a variation of the [DIR-24-8 algorithm](http://14.139.13.47:8080/jspui/bitstream/10603/26971/7/07_chapter2.pdf), trading-off memory usage for improved LPM lookup speed. Of note, for the IPv4 library for example, the documentation goes into depth on how the algorithm allows for the lookup operation to be performed with typically a single memory read access. In the statistically rare case when the best match rule is having a depth bigger than 24, the lookup operation requires two memory read accesses. So, the performance of the LPM lookup operation is greatly influenced by whether the specific memory location is present in the processor cache or not. The IPv6 library/version of the data structure is more complicated, working across 14 levels instead of IPv4's 2. We, of course, would have to handle both kinds, IPv4 & IPv6, of structures.

## Describe alternatives you've considered?

There are many, [many approaches](https://pdfs.semanticscholar.org/563f/f3059cf0d0bf7d9bef0c0d17c890e47f5090.pdf) to handling IP lookup, and LPM particularly2. DPDK's libraries are well-optimized and [used](https://github.com/AltraMayor/gatekeeper/wiki/Functional-Block:-GK#lpm-table), but definitely have a [memory tradeoff](https://medium.com/@anubhavchoudhary/anatomy-of-dpdk-data-structure-314bb994617d). Calculation of the size of an IPV4 LPM table, for example, equates to `Size of LPM structure + Size of array of 8-bit table + Size of Rule table`.

Another LPM approach that's gained a ton of steam is that of a [Poptrie](https://conferences.sigcomm.org/sigcomm/2015/pdf/papers/p57.pdf), a data structure that it is sufficiently general to work on prefixes of arbitrary lengths3 and leverages the [population count instruction](https://dev.to/eugenebabichenko/how-to-force-rust-compiler-to-use-several-x86-instructions-popcount-etc-496f) on bit-vector indices for the descendant nodes to compress the data structure within the CPU cache. A Poptrie IP lookup table attempts to reduce the memory footprint of the data structure by way of laying out descendant internal and leaf nodes in a contiguous array, where the indirect index of smaller size is achieved. I have not found a memory footprint comparison between the Poptrie reference implementation and DPDK's libraries (DPDK's LPM6 is *newish* as well). The Poptrie paper purports better performance than another interesting alternative, the [Tree Bitmap](http://cseweb.ucsd.edu/~varghese/PAPERS/ccr2004.pdf)4.

Another interesting option is using something like a [Length Aware Cuckoo Filter](https://www.cs.rit.edu/usr/local/pub/GraduateProjects/2155/2155/vdp7159/Report.pdf) for IP lookup, which implemented is more like LACF + LPM trie (in the paper). Though probabilistic in [nature](https://www.cs.cmu.edu/~dga/papers/cuckoo-conext2014.pdf), i.e. can contain false positives, the research and [possible? performance benefits](https://www.cs.rit.edu/~jmk/papers/VPPsigcomm17.pdf) (e.g. for VPP) are intriguing; and, it handles dynamic deletion of entries.

## Possible Solution

After discussion w/ @capsule-rs/maintainers and @capsule-rs/collaborators, the best route would be to offer a nice, *somewhat tunable*, easy-to-use API/shim module over DPDK's lpm libraries. With a good shim, hopefully, we could easily replace the DPDK library at some other point for something like a Poptrie or offer the consumer/user a choice based on the possible tradeoffs.

#### Footnoes

1 [libmoon](https://github.com/libmoon/libmoon/blob/57beade301472e354cb03c79240f6fbdee96eee4/lua/lpm.lua) has the spirit of an API layer, just as an example.

2 Snabb has [various implementations](https://github.com/snabbco/snabb/tree/master/src/lib/lpm) for example.

3 Helpful implementations in [C](https://github.com/pixos/poptrie) (for reference) and [Lua](https://github.com/snabbco/snabb/blob/master/src/lib/poptrie.lua), along with a good [blog post](https://mr.gy/blog/poptrie-dynasm.html) on implementing a Poptrie lookup table for Snabb.

4 Here's an example of a [Rust Tree Bitmap implementation](https://github.com/hroi/treebitmap) of a IPv4/IPv6 lookup table.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.