Guides
Load balancing
NAT-based VIPs with health-checked backends, VRRP failover and BGP active-active.
SiHA load-balances with NATLBMapping: a VIP:port → backend set,
implemented on VPP’s nat44_ed stateful NAT. It supports twice-NAT (SNAT)
so the backend sees SiHA as the client, per-backend weights, session
affinity, and health-checked backends. It is the same dataplane that
serves the firewall’s NAT rules — one session table, one L4 mental model.
The active backend set is filtered through health checks run by probed.
You declare the health-check policy inline in the resource; probed
writes BackendHealthCheckStatus resources that the controller reads to
build the live backend list before each VPP API call.
Backend selection
There is no configurable scheduling algorithm — no Maglev, no
round-robin, no least-connections. Backend selection is VPP’s native
weighted probabilistic scheme in nat44_ed: each backend carries a
weight (1–255), and VPP picks a backend per session in proportion to
that weight. weight in the spec maps directly to this probability;
weights are relative, so 10/10 splits sessions evenly and 30/10
sends ~3× more to the first backend. The choice is made once per session
and then pinned by the NAT session table for the life of that flow.
The only tuning knob is the per-backend weight; the selection
policy itself is not configurable.
NATLBMapping
type: NATLBMappings.lb.siha
metadata:
namespace: lb
id: web
spec:
vipAddress: 203.0.113.10
vipPort: 443
protocol: tcp # name (tcp, udp) or a raw number
twiceNat: true # SNAT: backend sees SiHA's own interface IP as source
backends:
- name: backend-1
address: 10.0.1.11
port: 8443
weight: 10
- name: backend-2
address: 10.0.1.12
port: 8443
weight: 10
healthCheck:
type: HTTP
port: 8443
httpPath: /healthz
httpExpectedStatus: 200
intervalMs: 5000
timeoutMs: 2000
healthyThreshold: 2
unhealthyThreshold: 3
failOpen: false
The VIP answers ARP natively (the external address joins the NAT plugin’s owned-addresses set), so a VIP on the client subnet needs no extra routing or proxy-ARP configuration.
Twice-NAT (SNAT)
When twiceNat: true, VPP SNATs the source address of forwarded packets to
the SiHA interface IP before sending them to the backend. The backend sees
SiHA itself as the client; its replies route back to SiHA naturally without
any policy routing on the backend.
The SNAT source address is always the LB’s own outbound interface IP. VPP does not ARP for an arbitrary pool address in twice-NAT mode — if you point it at an address that isn’t already configured on the egress interface, return traffic will be lost. Make sure the interface that reaches your backends has the appropriate IP configured.
Affinity
affinityTimeoutSec enables per-source-IP session affinity (sticky
sessions). Set to 0 (default) to disable.
High availability
Two validated deployment shapes:
- Active/passive — two appliances share the VIP through VRRP; twice-NAT keeps the failover hitless for the backends (the standby takes over the VIP and the SNAT identity follows).
- Active/active — each appliance announces the VIP over BGP and the fabric spreads flows by ECMP.
Known limit of active/active: flow placement is a per-flow 5-tuple hash. When the ECMP topology changes (an appliance joins or leaves), the fabric re-hashes flows across the survivors, and a TCP session that lands on a different appliance mid-flight is reset — the NAT session state does not follow it. Plan for client retries on failover, or use active/passive VRRP where hitless failover matters more than horizontal scale.
Health checks
Three check types are available:
type | What probed tests |
|---|---|
DISABLED | No probing; all backends are always considered live |
TCP | Three-way handshake to address:port |
HTTP | Full HTTP request; status code compared against httpExpectedStatus |
failOpen: true means backends are considered healthy when probed cannot
reach them at all (useful for tolerating transient network partitions).
failOpen: false (the default) drains unreachable backends from the live
set immediately — the VIP stays programmed and drops new flows while every
backend is down.
Thresholds: a backend is declared healthy after healthyThreshold
consecutive successes, and unhealthy after unhealthyThreshold
consecutive failures.
Probes run through VPP’s host stack, so backends on VPP-owned subnets are
reachable — the appliance’s dataplane config must enable the session layer
(machine.dataplane.hostStack: true in the fleet config).
Operating
S="sihactl --sihaconfig ~/.siha/config --addr <node-ip>:6443"
$S get natlb # list all NATLBMappings
$S get natlb web -o yaml # full spec + status (programmed backends, health)
# Backend health detail
$S get bhcs # BackendHealthCheckStatuses for all mappings
$S get bhcs natlb:web -o yaml # health counters per backend
The status block reports:
programmedBackends— backends currently active in VPP (after health filtering).backendHealth— per-backendhealthy,consecutiveSuccesses,consecutiveFailures,lastProbeUnixSec,lastError, and cumulativefailedChecks/downCount/downtimeSec.lastError— last reconcile error from the controller.
Notes and limitations
Enum sentinel values
healthCheck.type has an _UNSPECIFIED sentinel at index 0. Omitting the
field or setting it to the zero value fails validation — always set an
explicit DISABLED, TCP, or HTTP.
Coexistence with NAT rules
NATLBMapping uses nat44_ed_lb_static_mapping. Regular NAT rules
(NATPool, NATStaticMapping, NATInterfaceMode) share the same VPP
session table and coexist on the same interface without conflict, provided
the VIP address itself is not also a NAT pool address.
Client-IP visibility
With twice-NAT the backend sees the appliance, not the client. Without twice-NAT the client address is preserved but the backend must route its replies back through the appliance. For PROXY-protocol-style client-IP preservation on backends that can’t do either, a proxy-based LB resource is on the roadmap.