Synopsis #
This chapter provides deterministic troubleshooting playbooks for common production faults: High Availability (HA) role flaps, asymmetric paths at multi-WAN edges, tunnel MTU black holes, IPv6 Neighbor Discovery (ND) and Router Advertisement (RA) problems, and practical Quality-of-Service (QoS) verification. Each playbook uses base tools only: packet filter policy in pf.conf(5) inspected with pfctl(8), interfaces via ifconfig(8), live captures with tcpdump(8), system controls with sysctl(8), reachability tests with ping(8) and ping6(8), path inspection with traceroute(8), IPv6 neighbor tools in ndp(8), and service-specific helpers such as ikectl(8) for IPsec or relayctl(8)
for relayd when relevant. Device-level features include carp(4), pfsync(4), wg(4), gif(4), and gre(4).
Design Considerations #
- Reproduce, then narrow. Reproduce the failure, capture once near the fault, and use counters and states to avoid guessing.
- Prefer egress perspective. At policy edges, states and NAT pin flows to egress. Inspect states before changing routes.
- One change at a time. Introduce a reversible change, observe, revert if inconclusive.
- Clocks and logs. Ensure accurate time (see ntpd(8)). Use
/var/log/messages
and PF rule counters to align observations. - Safety. During production incidents, demote a node or isolate a path rather than wholesale restarts. Keep a failsafe PF anchor for management access (see the Hardening chapter).
Configuration (Operator Toolbox) #
Prepare a minimal, reusable toolbox on each device.
# rcctl enable pflogd ; rcctl start pflogd
# Persist and start PF log capture to /var/log/pflog
# pfctl -sr | sed -n '1,40p'
# Snapshot of the active rule order for later correlation
# sysctl net.inet.carp
# Baseline CARP preempt/log/demotion values (on HA nodes)
# install -d -m 700 /root/ts ; date > /root/ts/incident.start
# Create a working scratch area with a start timestamp
Playbook 1 — HA Role Flaps (CARP/pfsync) #
Symptoms. Frequent MASTER↔BACKUP flips, brief outages, or state desynchronization.
Likely causes. Unstable SYNC link, VHID/password mismatch, asymmetric upstream reachability, or aggressive preemption.
Steps #
- Observe CARP status and demotion.
$ ifconfig carp0 carp1
# Expect one MASTER and one BACKUP per VIP
$ sysctl net.inet.carp.demotion
# Non-zero indicates a fault (e.g., interface down, pfsync issues)
$ tail -n 100 /var/log/messages | egrep -i 'carp|pfsync'
# Timeline of role changes and reasons
- Verify the SYNC domain and state replication.
$ ifconfig pfsync0
# Confirm syncdev and UP status
# tcpdump -ni pfsync0
# Observe steady updates under load; bursts during new flows/failover
$ pfctl -vvss | head
# States present with creators and counters on both nodes
- Check HA control-plane allowances and VHID/secret.
$ pfctl -sr | egrep 'proto (carp|pfsync)'
# Rules allowing carp and pfsync
$ grep -H carpdev /etc/hostname.carp*
# Same VHIDs and sharedsecret on both nodes?
- Stabilize now, investigate next.
# ifconfig carp0 advskew 240 ; ifconfig carp1 advskew 240
# Demote this node (prefer peer as MASTER)
# sysctl net.inet.carp.preempt=0
# Temporarily disable preemption to avoid ping-pong
- Common fixes. Replace or isolate the SYNC cable/VLAN, ensure
set skip on pfsync0
in PF, align rulesets and NAT, and only then re-enable preemption and restoreadvskew
.
Playbook 2 — Asymmetric Paths and Broken Inbound NAT #
Symptoms. Some destinations work; others time out. Inbound services connect but replies exit via the wrong WAN. Outbound policies appear ignored.
Likely causes. Missing reply-to
on WAN pass rules for NAT’d services, stale states, or rule ordering issues for route-to
.
Steps #
- Confirm rule matches and state egress.
$ pfctl -vvsr | egrep 'route-to|reply-to'
# Ensure per-WAN pinning rules exist and are ordered correctly
$ pfctl -vvss | egrep 'em0|em3|Gateway'
# Inspect states for selected egress interface/gateway
- Capture on both WANs while reproducing.
# tcpdump -ni em0 host <client-or-server> and port 443
# tcpdump -ni em3 host <client-or-server> and port 443
# Verify which interface carries SYN/ACK or replies
- Apply corrective actions.
# pfctl -K 10.10.10.50
# Kill states for a published server so new states pick up corrected policy
# pfctl -f /etc/pf.conf
# Reload after adding missing reply-to/route-to
$ route -n show -inet | head
# Remember: system default route affects firewall-originated traffic only
Playbook 3 — Tunnel MTU / Black-Hole Detection (IPsec, WireGuard, gif/gre) #
Symptoms. Small packets succeed; large transfers stall. TLS handshakes complete but large responses hang. ICMP “Too Big” not seen.
Likely causes. Encapsulation overhead exceeding underlay MTU; PMTUD blocked; excessive MSS.
Steps #
- Probe with increasing payload sizes.
$ ping -n -c 3 -s 1400 <remote-ipv4>
# Try large payload; decrease (e.g., 1380, 1360) until it works
$ ping6 -n -c 3 -s 1400 <remote-ipv6>
# IPv6 is more sensitive; adjust until success
- Inspect the tunnel and adjust MTU/MSS.
- IPsec (IKEv2):
$ ikectl show sa ; ikectl show flows
# Confirm SAs/flows up
# tcpdump -ni enc0 host <peer-inside>
# Plaintext post-decrypt traffic
Add a conservative scrub during mitigation, then refine:
## pf.conf excerpt — temporary MSS clamp
scrub in on egress max-mss 1452
- WireGuard:
$ ifconfig wg0
# Review wgpeer stats; note current MTU
# ifconfig wg0 mtu 1380
# Lower MTU to accommodate overhead
- gif/gre:
$ ifconfig gif0 ; ifconfig gre0
# Check configured MTU
# ifconfig gif0 mtu 1400
# Lower and re-test; adjust per path measurements
- Confirm ICMP visibility.
# tcpdump -ni egress icmp or icmp6
# Look for “Fragmentation needed” (v4) or “Packet Too Big” (v6)
Playbook 4 — IPv6 ND and RA Failures (Hosts Not Getting IPv6) #
Symptoms. Clients lack global IPv6, show only link-local, or lose default route. Duplicate Address Detection (DAD) failures appear.
Likely causes. RA not sent on the right interface, ICMPv6 blocked, multiple routers advertising, or stale ND cache.
Steps #
- Check the router side (RA sender).
# rcctl check rad
# RA daemon running?
$ ifconfig em1 | grep inet6
# Router has an on-link address for the /64
# tcpdump -ni em1 icmp6
# Observe Router Advertisements on the segment
- Allow mandatory ICMPv6 in PF and reload.
## pf.conf excerpt — ensure ICMPv6 is permitted
pass inet6 proto icmp6 keep state
# pfctl -f /etc/pf.conf
- Inspect from a host (client side).
$ ndp -an | head
# Router entries should appear with reachable MAC
# rcctl check slaacd
# Autoconf client running?
$ route -n show -inet6 | egrep '::/0|2001:'
# Default route via router; global address present
- Resolve duplicates or rogue RAs.
$ ndp -an | egrep -i 'incomplete|failed'
# Identify anomalies
# ndp -d <IPv6-or-mac>
# Clear a problematic cache entry (repopulates via ND)
If two routers advertise the same /64 unintentionally, disable RA on the retiring router first, then withdraw addresses.
Playbook 5 — QoS Verification (PF Queues) #
Symptoms. Interactive traffic suffers under load; queue counters do not move as expected.
Likely causes. Classification direction mismatch, incorrect queue names, or parents allowing unlimited borrowing.
Steps #
- Confirm the queue tree and counters.
$ pfctl -vvsq
# Tree, bandwidth/min/max, packets/bytes per queue
- Validate classification rules and hits.
$ pfctl -vvsr | egrep 'set queue|set prio'
# Verify intended rules exist and order is correct
# tcpdump -ni egress port 22 or port 443
# Generate traffic and correlate with queue counters
- Exercise under load and observe.
$ scp largefile user@remote:/dev/null &
# Create bulk load
$ ssh user@remote
# Verify keystroke latency while watching 'pfctl -vvsq'
- Adjust and re-test.
- Lower
bandwidth
or setmax
on default/bulk queues. - Use two-queue assignment, for example
set queue (web_bulk, web_prio)
, to prioritize ACKs.
Verification #
- Repeatable tests. Keep a short script that pings, curls a known endpoint, and emits a syslog marker before and after changes.
- Counters before/after. Record
pfctl -vvsr
,pfctl -vvsq
, andpfctl -s state | wc -l
before and after each step. - Packet captures. Save
tcpdump
traces with timestamps during failures; retain them alongside the PF snapshot for later analysis.
$ date && pfctl -vvsr | wc -l && pfctl -vvsq | wc -l
# Quick sanity of rule/queue counts with a timestamp
# tcpdump -ni egress -w /root/ts/egress.pcap host <peer> and port <svc>
# Capture for offline review
Troubleshooting #
- Changes did not take effect. Ensure you reloaded PF (
pfctl -f
) and killed stale states where path selection must change. - Data path differs from captures. Verify you are capturing on the correct interface (physical vs. VLAN vs. tunnel) and that
set skip on
is not hiding traffic from PF. - HA “works” but drops occur. Confirm identical rulesets and NAT on both nodes; states replicate, rules do not.
- MTU still inconsistent. Check intermediate links (PPPoE, VPNs, or VLAN stacks). If ICMP control is filtered upstream, keep MSS clamping in place.
See Also #
- Networking
- OpenBGBD
- Related: High Availability and State Replication
- Related: Multi-WAN and Policy-Based Routing
- Related: VPN and Cryptographic Tunneling
- Related: IPv6 at Scale
- Related: QoS and Traffic Shaping