Skip to content

Stateless NAT: Simplify TrieValue, improve error handling in IpList #663

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

qmonnet
Copy link
Member

@qmonnet qmonnet commented Jul 2, 2025

  • fix(nat): Fix TrieValue building and address mapping
  • feat(nat): Simplify struct TrieValue
  • feat(nat): Add proper error handling for IpList (stateless NAT)

The main motivation of this PR is to reduce the memory footpring and the complexity of the address mapping for stateless NAT, by reducing the amount of information stored in struct TrieValue.

Please refer to individual commit descriptions for details.

qmonnet added 3 commits July 1, 2025 23:30
Functions get_public_trie_value() and get_private_trie_value() are
identical but shouldn't be. It makes more sense to have them distinct,
and then consistently assign the original and target ranges to the
variables with similar names when retrieving the values on the NAT
processor's side.

Signed-off-by: Quentin Monnet <[email protected]>
Instead of holding the full BTreeSet<Prefix> for the original prefixes
for the mapping, just store the prefix in use with its offset in the
list. This is more efficient in terms of memory usage, and saves us from
recomputing the offset of this prefix at runtime when computing the IP
address mapping.

Signed-off-by: Quentin Monnet <[email protected]>
We have a few calls to unreachable!() in the IpList logics, where we
compute and map the offsets from and to IP addresses within lists of
prefixes for stateless NAT.

Those unreachable!() have been reached in the past.

We also have assumptions that the offsets or IP addresses that we pass
to the functions are always contained within the lists or prefixes that
we process, which is only true as far as we don't have any bug in the
logics.

Instead of these, let's introduce proper error handling for the module.
When something's wrong, we raise it to the caller. This should avoid
crashing the whole dataplane (you never know) and should help debug in
case of bugs.

The errors propagate to the NAT translation functions, where we stop
translating the address when we fail to compute the mapping. We need to
improve error handling in there as well, and to drop the packet when we
face issues with the logics of the processing during NAT, but this is
not covered by this commit.

Signed-off-by: Quentin Monnet <[email protected]>
@qmonnet qmonnet added this to the GW R2 milestone Jul 2, 2025
@qmonnet qmonnet requested a review from mvachhar July 2, 2025 00:03
@qmonnet qmonnet self-assigned this Jul 2, 2025
@qmonnet qmonnet requested a review from a team as a code owner July 2, 2025 00:03
@qmonnet qmonnet added the area/nat Related to Network Address Translation (NAT) label Jul 2, 2025
@qmonnet qmonnet enabled auto-merge July 2, 2025 00:37

// We should probably return an error in this case, but at the moment we don't
let offset = ipls.addr_offset_in_prefix(&addr_v4("1.2.0.0"));
assert_eq!(offset.offset, 65536);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No V6 tests?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also suggest a fuzzer where we generate a prefix as a u128 or u32 and mask off the low bits. Then the fuzzer generates a random u32 or u128 and we | in the lower bits with the prefix. This forms our address. We know the offset is the |'ed in lower bits. So then we can call the addr_offset_in_prefix and compare to the known offset. Let me know if you want some help writing this.

offset: 3 * 65536 + 256 * (128 + 72) + 1,
ip_version: IpVersion::V4
}),
addr_v4("2.5.72.1")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, no V6? Also, can we write a fuzzer easily for this as well? I'm less certain of the exact logic for the prefix offset. The addr offset is super clear.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/nat Related to Network Address Translation (NAT)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants