Connection Tracking and NAT

A connection is more than one packet, so how does NAT remember the backend it picked? The first packet matches no entry and walks the NAT rules, and conntrack stores it as one entry with an original and a reply tuple. Every later packet is translated straight off that entry, no rule read, and the reply is what flips it to ESTABLISHED. That is why a flow sticks to one backend while the entry lives, and why a busy Node can exhaust its conntrack table.

Play the animation 5 steps, animated, best on a wide screen

Connection Tracking and NAT, Kubernetes diagram

Connection Tracking and NAT, step by step

  1. The client dials a Service address that no host owns, and the first packet of the flow reaches netfilter. There is no conntrack entry matching this packet, so nothing about this connection has been decided yet.

    Play from step 1
  2. With no entry to match, the NAT rules have to be walked. The chain is read top to bottom until a rule claims the destination and a backend is chosen for this connection. Every first packet of every new flow pays this walk, and no later packet of it pays again while the entry lives.

    Play from step 2
  3. The flow is now recorded by conntrack as one entry holding two tuples: the original direction the client sent, and the reply direction it expects back. The destination is rewritten to the chosen backend and the packet is delivered, with the mapping stored for the life of the connection.

    Play from step 3
  4. The backend answers from its own address, and the packet matches the reply tuple of the stored entry. That match alone is enough to undo the translation, so the client sees an answer from the Service address it dialed, and the entry moves to ESTABLISHED. Not one NAT rule is read on the way back.

    Play from step 4
  5. Every later packet of this flow matches the original tuple and is translated straight off the entry, with the rule ladder left untouched. That is why a flow stays on one backend for as long as its entry lives, and why a Node opening huge numbers of short connections can fill its conntrack table and start dropping new ones.

    Play from step 5

Sources