Troubleshooting Guide
Log interpretation
All logs are structured JSON, one object per line:
journalctl -u flowwler -f
Escalation events
{"level":"info","msg":"escalation: Idle→Active",
"victim":"203.0.113.10","group":"datacenter-a","level":1,
"mitigation":"flowspec","bps":5200000000,"pps":620000,"discard_bps":0}
An attack has been detected. Level 1 mitigation (FlowSpec) has been activated. BPS is ~5.2 Gbps; the router is not yet discarding anything (discard_bps:0).
{"level":"info","msg":"escalation: level up",
"victim":"203.0.113.10","group":"datacenter-a",
"prev_level":1,"level":2,"mitigation":"subnet-blackhole",
"bps":12000000000,"pps":1400000,"discard_bps":0}
Attack exceeded the level 2 threshold after escalate_after elapsed. FlowSpec was withdrawn and a subnet-blackhole was announced.
{"level":"info","msg":"escalation: Active→HoldDown",
"victim":"203.0.113.10","group":"datacenter-a",
"bps":180000,"pps":210,"discard_bps":11980000000}
Traffic dropped below the level 2 threshold. Mitigation moved to HoldDown - it will remain active for hold_time (default 15 minutes) before being withdrawn. discard_bps near the original bps means the router is absorbing almost all remaining traffic via the BGP route.
{"level":"info","msg":"escalation: HoldDown→Idle (hold-down expired)",
"victim":"203.0.113.10","group":"datacenter-a","hold_time":"15m0s"}
Hold-down timer expired. The mitigation is withdrawn and the state machine returns to Idle.
BGP events
{"level":"info","msg":"bgp: blackhole announced",
"prefix":"203.0.113.10/32","next_hop":"192.0.2.1","community":"65535:666",
"victim":"203.0.113.10","group":"datacenter-a"}
{"level":"info","msg":"bgp: startup cleanup complete","withdrawn":3,"families":4}
Stale routes from a previous crash were removed on startup.
Decode warnings
{"level":"warn","msg":"flow decode error",
"router":"10.0.0.1","protocol":"netflow",
"error":"netflow: unsupported version 5 (want 9 or 10)"}
The router is sending NetFlow v5 on the v9 listener port. Configure the router to export v9 or IPFIX, or switch the router to the netflow5 listener if you want v5 support.
{"level":"debug","msg":"flow data set skipped: template not cached yet",
"router":"10.0.0.1","protocol":"netflow","domain_id":100,"template_id":256}
Normal at startup. Templates arrive every template-timeout seconds (typically 30–60 s). This message disappears once the first template set is received.
IRR / NetBox prefix resolution
{"level":"info","msg":"irr: resolving prefixes","group":"customers","as_set":"AS64500:AS-CUSTOMERS"}
{"level":"info","msg":"irr: resolved prefixes","group":"customers","asns":47,"routes_v4":312,"routes_v6":89,"duration":"4.2s"}
Normal resolution log. If routes_v4 and routes_v6 are both 0, the AS-SET may be empty or the WHOIS server may be unreachable.
{"level":"warn","msg":"irr: IPv6 route query failed","asn":"AS60735","error":"read tcp ... connection reset by peer"}
The WHOIS server rate-limited or dropped the connection for this ASN. The query is skipped and the process continues. If this is frequent, consider reducing concurrency in the irr: block.
Troubleshooting runbook
No flows being detected despite real traffic
-
Check Prometheus:
flowwler_router_bytes_decoded_total{protocol="netflow"}- is it counting?- No: packets are not reaching flowwler. Check UDP routing and firewall (
sudo ufw status). Confirm the router is sending to the correct IP and port. - Yes: packets are arriving, but no flow records. Likely a template timing issue.
- No: packets are not reaching flowwler. Check UDP routing and firewall (
-
Check for template cache misses:
flowwler_netflow_template_cache_misses_total- High and rising: data flowsets are arriving before templates. Enable debug logging and look for
"flow template stored"- if absent, the template refresh interval is very long or templates are being sent to a different collector.
- High and rising: data flowsets are arriving before templates. Enable debug logging and look for
-
Enable debug logging (
logging.level: debugin config, thensudo systemctl reload flowwler) and look for:"flow template stored"- template received"flow record dropped: no destination IP"- flows decoded but missing dst IP (template lacks key fields)"flow data set skipped"- data arriving before template
BPS readings are wrong
Too high (e.g., 10× actual rate):
FIRST_SWITCHED/LAST_SWITCHEDfields (21/22) are missing from the template - flow duration cannot be computed, so byte counts are not normalised to BPS correctly.- Enable debug logging and check the
"field_type_ids"log line - are21and22present? - If absent: configure the router flow template to export timing fields, or reduce
active-flow-timeoutto 1–2 seconds (forces shorter flow records, reducing the error).
Too low:
- NetFlow: check
flowwler_router_sampling_ratefor this router. If the metric is absent, no packets have been received yet. If it shows1when the router is sampling at 1:1000, the sampling rate has not been learned yet - flowwler learns it from Options Data records, which can take up to one template refresh interval (typically 1–10 minutes). If the router never exports sampling info via Options Templates, setnetflow.default_sampling_rateto the router's 1-in-N ratio as a static fallback. - sFlow: verify
default_sampling_ratein the sFlow config matches the router's actual sampling ratio. - Check that flows are being exported for all transit interfaces, not just one.
Mitigation activates but traffic does not drop
-
Check
flowwler_mitigation_effectiveness- is it rising?- Near 0 after 2–3 minutes: the BGP route was not accepted by the peer. Check the peer's import policy and community filtering.
- Near 1: traffic is being dropped at the router. The remaining traffic is background noise or new flows established after the route was applied.
-
Inspect BGP routes on the router peer (JunOS):
show route receive-protocol bgp 192.0.2.100 show route protocol bgp community 65535:666 -
Inspect flowwler's RIB via the REST API:
bash curl -s http://localhost:9731/api/v1/bgp/routes -
Check the BGP session is established:
bash curl -s http://localhost:9731/api/v1/bgp/peers curl -s http://localhost:9731/metrics | grep flowwler_bgp_peer_up
HoldDown never expires
The hold-down timer is defaults.hold_time (default 15 minutes), or a per-level hold_time override that applies to all mitigation types, not just FlowSpec. If the victim re-triggers before the timer expires, the hold-down is re-entered at the appropriate level. This is expected during an ongoing attack.
To shorten the recovery time for testing, temporarily set hold_time: 1m in config and send a SIGHUP.
Group subnets are not being matched
- Confirm the group is loaded:
curl -s http://localhost:9731/api/v1/groups - Confirm
flowwler_group_up{group="..."}is 1. - If using IRR or NetBox, check that resolution succeeded - look for
"irr: resolved prefixes"or"netbox: resolved prefixes"in the logs with a non-zeroroutes_v4/routes_v6count. - Check
flowwler_irr_last_refresh_timestamp_seconds/flowwler_netbox_last_refresh_timestamp_seconds- if these are absent or very old, the last resolution may have failed.
High CPU or memory
- A large
aggregation_windowwith many unique 5-tuple sources creates many smoothing state entries. These are pruned each tick for keys that leave the window, so memory is proportional to active unique flows × window depth. - High sFlow sampling rates (low
sample-rateon the router, e.g. 1-in-100) generate many flow records per second. Consider raising the sampling interval on the router. - For IRR resolution with large AS-SETs, reduce
irr.concurrencyto limit simultaneous WHOIS connections if the host's outbound connection rate is constrained.