Sharing connections with conntrackd
conntrackd watches the kernel's connection table and sends every change to the other router over the sync link. Debian's default configuration only collects statistics, so it needs a sync configuration on both routers.
Mode FTFW(fault-tolerant firewall): a reliable protocol on top of UDP, with acknowledgements and resends, so a lost update doesn't leave a hole in the other router's table.DisableExternalCache On: the other router's connections go straight into this router's kernel table. A backup router then always has every connection ready, and a failover needs no extra steps. (The alternative keeps them in conntrackd's own cache, and a keepalived notify script commits them into the kernel when the router becomes master.)UDP: this router's address on the sync link, the other router's address, and the port. The firewall allows that port, on that interface only.- The filter syncs TCP, UDP and ICMP, and ignores the sync link's own traffic and loopback.
With conntrackd restarted on both routers, the stream's connection appears in both kernel tables: on r1, where it really goes through, and on r2, put there by conntrackd. conntrackd -s on r2 counts the injected connections and the sync traffic.
The same failure, with sync
r1 is killed again, with a new stream running. The ping gap is about the same, 3.3 seconds, because it's VRRP's timing. But this time the stream paused for 3.5 seconds, then carried on from line 28, to the end of the test. r2 already knew the connection and its NAT translation, so the web server's packets matched, and TCP retransmitted the few that were lost. The person on the staff PC saw a short stall, not a broken connection.
# /etc/conntrackd/conntrackd.conf on r1: send our connection table to the other router, and
# put theirs straight into our kernel, so either router can carry on any connection.
Sync {
Mode FTFW {
DisableExternalCache On
}
UDP {
IPv4_address 10.99.0.1
IPv4_Destination_Address 10.99.0.2
Port 3780
Interface eth2
Checksum on
}
}
General {
HashSize 8192
HashLimit 65535
Syslog on
LockFile /var/lock/conntrackd.lock
UNIX {
Path /var/run/conntrackd.sock
}
Systemd on
Filter From Userspace {
Protocol Accept {
TCP
UDP
ICMP
}
Address Ignore {
IPv4_address 127.0.0.1
IPv4_address 10.99.0.0/30
}
}
}- Lines 4–6: FTFW, with the other router's connections put straight into the kernel.
- Lines 7–13: r1's sync address, r2's, and the port. On r2 the two addresses are swapped.
- Lines 25–35: Sync TCP, UDP and ICMP, but not loopback or the sync link itself.
root@r1:~# cp conntrackd.conf /etc/conntrackd/ && systemctl restart conntrackd
root@r2:~# cp conntrackd.conf /etc/conntrackd/ && systemctl restart conntrackd
root@r1:~# conntrack -L -p tcp --dport 9000 2>/dev/null
tcp 6 431999 ESTABLISHED src=10.10.10.20 dst=198.51.100.10 sport=44080 dport=9000 src=198.51.100.10 dst=203.0.113.4 sport=9000 dport=44080 [ASSURED] mark=0 use=1
root@r2:~# conntrack -L -p tcp --dport 9000 2>/dev/null
tcp 6 431994 ESTABLISHED src=10.10.10.20 dst=198.51.100.10 sport=44080 dport=9000 src=198.51.100.10 dst=203.0.113.4 sport=9000 dport=44080 [ASSURED] mark=0 use=1
root@r2:~# conntrackd -s | sed -n "/external inject/,/^$/p;/UDP traffic/,/^$/p"
external inject:
connections created: 2 failed: 0
connections updated: 5 failed: 0
connections destroyed: 0 failed: 0
UDP traffic (active device=eth2):
660 Bytes sent 636 Bytes recv
9 Pckts sent 10 Pckts recv
0 Error send 0 Error recv
root@staff:~# awk '/bytes from/{print $1}' /tmp/ping2.log | tr -d '[]' | awk 'NR>1 && $1-p>0.5 {printf "ping: no replies for %.1f s\n", $1-p} {p=$1}'; tail -2 /tmp/stream2.log; awk '{split($1,t,":"); s=t[1]*3600+t[2]*60+t[3]; if (NR>1 && s-p>0.5) printf "stream: nothing for %.1f s, then line %s\n", s-p, $2; p=s}' /tmp/stream2.log
ping: no replies for 3.3 s
22:48:29.898 126 22:48:29
22:48:30.101 127 22:48:30
stream: nothing for 3.5 s, then line 28- Lines 1–3: Both routers switch from statistics to sync.
- Lines 5–9: The stream's connection, on r1 and, put there by conntrackd, on r2.
- Lines 11–20: conntrackd on r2: connections injected into its kernel, and the sync traffic.
- Lines 23–27: After killing r1: ping back in 3.3 s, and the stream paused 3.5 s, then carried on from line 28 to the end of the test.
Check your understanding
Why doesn't connection sync shorten the 3.3-second gap?
- The gap is VRRP noticing r1 is gone (three missed advertisements); sync only decides whether open connections survive it.
- conntrackd is slow to copy connections.
- TCP has to reconnect.
- It does; without sync the gap was longer.