Skip to content

feat(gateway): add egress masquerade datapath to edgenat.c - #381

Open
privateip wants to merge 1 commit into
feat/865-egress-phase-afrom
feat/865-egress-phase-b
Open

feat(gateway): add egress masquerade datapath to edgenat.c#381
privateip wants to merge 1 commit into
feat/865-egress-phase-afrom
feat/865-egress-phase-b

Conversation

@privateip

Copy link
Copy Markdown
Contributor

Summary

Phase B of #865, per docs/plans/865-edge-gateway-nat66-egress.md §3.
Stacked on #380 (Phase A).

  • egress_config_table, egress_conn_table, handle_egress_forward,
    handle_egress_return, updated 4-way dispatch in edge_nat().
  • tenant_arg (egress_sid's uFMT Argument bits) keys the forward row,
    so two tenants with colliding ULA backend addresses never collide in
    egress_conn_table.
  • New drop reasons, plumbed through dropreason.go.

Flagged for review

  • backend_usid (needed to route replies back to the originating
    worker node) has no per-tenant policy table in Phase B. Resolved by
    reading it off the wire -- the egress-forward packet's own outer
    SRv6 source address, captured before the outer header is stripped.
    Assumes RouteEgressAdd's SEG6 encap route always stamps the
    originating node's own uSID as that outer source, consistent with
    every other cross-node SRv6 packet in this codebase -- not
    independently verified here. Marked in the code; worth confirming
    before Phase D's e2e proof depends on it.
  • handle_egress_return drops any non-TCP/UDP protocol addressed to
    masq_addr (e.g. ICMPv6) rather than passing it to the kernel
    stack -- same fail-closed convention gw_addr's own return branch
    uses for claimed addresses, but a real cost for an internet-facing
    address that gw_addr's internal-only precedent didn't have to
    weigh.

Testing

  • New root-required tests in edgenat_egress_test.go: both branches
    end-to-end (SNAT/DNAT, checksum, real FIB-resolved L2), non-SYN/no-conn
    drops, PAT exhaustion, and the tenant-isolation scenario §6 calls out
    explicitly (colliding backend/dest tuple, distinct tenant_arg ->
    two independent rows and masq_port allocations).
  • go build ./..., go vet ./..., task lint (0 issues) -- clean.
  • Full edgenat suite passes under root + -race.
  • Broader task test:unit: one pre-existing, unrelated failure in
    internal/cni/tap (environment-specific -- confirmed on the
    unmodified branch too).

🤖 Generated with Claude Code

@privateip
privateip requested a review from a team as a code owner August 13, 2026 19:29
@privateip
privateip requested review from drewr and removed request for a team August 13, 2026 19:29
@privateip

Copy link
Copy Markdown
Contributor Author

The test failures are expected. Need to merge datum-cloud/network#15 first.

Phase B of #865, per docs/plans/865-edge-gateway-nat66-egress.md §3.

Adds egress_config_table, egress_conn_table, handle_egress_forward,
handle_egress_return, and the updated 4-way top-level dispatch in
edge_nat(). tenant_arg (the egress_sid locator's uFMT Argument bits)
keys the forward row so two tenants with colliding ULA backend
addresses never collide in egress_conn_table.

backend_usid (needed to route replies back to the originating worker
node) is captured directly from the egress-forward packet's own outer
SRv6 source address, since Phase B proposes no per-tenant policy table
to look it up from. This assumes RouteEgressAdd's SEG6 encap route
always stamps the originating node's own uSID as that outer source,
consistent with every other cross-node SRv6 packet in this codebase,
but that has not been independently verified here -- flagged in the
code and worth confirming before Phase D's e2e proof relies on it.

handle_egress_return drops any non-TCP/UDP protocol addressed to
masq_addr (e.g. ICMPv6) rather than passing it to the kernel stack,
the same fail-closed convention gw_addr's own return branch already
uses for claimed addresses -- a real cost for an internet-facing
address that gw_addr's internal-only precedent didn't have to weigh.

Tests cover both new branches end-to-end (SNAT/DNAT, checksum, real
FIB-resolved L2), non-SYN/no-conn drops, PAT exhaustion, and the
tenant-isolation scenario the plan's §6 calls out explicitly: two
tenants presenting the same colliding backend_addr:port->dest_addr:port
tuple via distinct tenant_arg values resolve to two independent
egress_conn_table rows and masq_port allocations.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Design: edge XDP egress (masquerade) datapath (865 Phase B)

2 participants