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:

typeWhat probed tests
DISABLEDNo probing; all backends are always considered live
TCPThree-way handshake to address:port
HTTPFull 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-backend healthy, consecutiveSuccesses, consecutiveFailures, lastProbeUnixSec, lastError, and cumulative failedChecks / 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.