Observability
Statistics๐
By default, Tempesta Manager daemon (tempesta_mgr in process list) exposes an HTTP /metrics
endpoint on localhost:9090 that return available statistics in text-based
Prometheus exposition format.
The listen port and address for the statistics endpoint can be configured as the
daemon command-line arguments in the xfw.conf file:
{
"daemon_args": "--listen 127.0.0.1 --http-port 9090",
...
}
All statistics entries, both byte and packet counters, are of counter type.
Therefore, they are prefixed with the corresponding TYPE and HELP metadata
and look as follows:
# HELP xfw_passed_egress_bytes Total Passed egress bytes.
# TYPE xfw_passed_egress_bytes counter
xfw_passed_egress_bytes 0
All counters are prefixed with xfw_. Byte-related metrics are suffixed with _bytes,
and packet-related metrics are suffixed with _packets.
The simplest way to retrieve the statistics is by using curl:
$ curl http://127.0.0.1:9090/metrics
# HELP xfw_syn_cookies_packets Total SYN cookies packets.
# TYPE xfw_syn_cookies_packets counter
xfw_syn_cookies_packets 0
# HELP xfw_syn_cookies_bytes Total SYN cookies bytes.
# TYPE xfw_syn_cookies_bytes counter
xfw_syn_cookies_bytes 0
...
Events Logging๐
Tempesta Escudo uses the open-source tfw_logger daemon with an additional plug-in for
logging Tempesta xFW security events into a ClickHouse database. Refer to the
Tempesta FW Access Log Analytics
page for more information about the tfw_logger daemon.
Tempesta xFW event logging is configured using the xfw_events section in the
tfw_logger configuration file. A configuration example can be found at
/opt/tempesta/examples/xfw_logger.json.
Events log schema๐
The Tempesta xFW plug-in for tfw_logger creates the following ClickHouse table:
CREATE TABLE IF NOT EXISTS xfw_events (
timestamp DateTime64(3, 'UTC'),
addr IPv6,
reason UInt64,
packets UInt64,
bytes UInt64,
dropped_events UInt64
) ENGINE = MergeTree()
ORDER BY timestamp;
Field descriptions๐
| Field | Type | Description |
|---|---|---|
timestamp |
DateTime64(3) | Event timestamp with millisecond precision (UTC) |
addr |
IPv6 | Client IP address (IPv4 addresses are mapped to IPv6) |
reason |
UInt64 | Bit field representing blocking reasons |
packets |
UInt64 | Number of packets aggregated into the blocking event |
bytes |
UInt64 | Number of bytes aggregated into the blocking event |
dropped_events |
UInt64 | Number of dropped events |
A single IP address may generate multiple packets that Tempesta xFW blocks for the same reason. Such packets, along with their total size, may be aggregated into a single event. The dropped events count is useful to track the number of events that did not make it into the statistics.
Example of the event log table:
:) SELECT timestamp, addr, bitPositionsToArray(reason), packets, bytes
FROM xfw_events ORDER BY timestamp DESC LIMIT 10;
โโโโโโโโโโโโโโโโtimestampโโฌโaddrโโโโโโโโโโโโโโโโโโฌโbits(reason)โโฌโpacketsโโฌโbytesโโฌโdropped_eventsโโ
โ 2026-01-15 21:32:13.979 โ ::ffff:192.168.100.1 โ [8] โ 1 โ 70 โ 20 โ
โ 2026-01-13 15:26:22.618 โ ::ffff:192.168.100.1 โ [8] โ 1 โ 54 โ 18 โ
โ 2026-01-13 15:26:21.608 โ ::ffff:192.168.100.1 โ [8] โ 1 โ 54 โ 17 โ
โ 2026-01-13 15:26:19.596 โ ::ffff:192.168.100.1 โ [8] โ 1 โ 54 โ 15 โ
โ 2026-01-13 15:26:18.589 โ ::ffff:192.168.100.1 โ [8] โ 1 โ 54 โ 14 โ
โ 2026-01-13 14:00:55.076 โ ::ffff:192.168.100.1 โ [8] โ 1 โ 54 โ 12 โ
โ 2026-01-13 14:00:54.061 โ ::ffff:192.168.100.1 โ [2] โ 5 โ 270 โ 10 โ
โ 2026-01-13 13:44:05.385 โ ::ffff:192.168.100.1 โ [2] โ 6 โ 324 โ 7 โ
โ 2026-01-13 13:43:59.344 โ ::ffff:192.168.100.1 โ [2] โ 2 โ 108 โ 3 โ
โ 2026-01-13 13:43:58.337 โ ::ffff:192.168.100.1 โ [2,3] โ 5 โ 270 โ 0 โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโดโโโโโโโโโโดโโโโโโโโดโโโโโโโโโโโโโโโโโ
Bits constituting the reason field:
| Bit | Reason |
|---|---|
| 0 | Blocked by the icmp: block rule |
| 1 | Blocked by the tcp_flags syn: ratelimit rule |
| 2 | Blocked by the tcp_flags rst: ratelimit rule |
| 3 | Blocked by the icmp: ratelimit rule |
| 4 | Blocked by the defaults/icmp: block rule |
| 5 | Blocked by the defaults/icmp: ratelimit rule |
| 6 | Blocked by the dst: block rule |
| 7 | Rate limited by the dst: ratelimit rule |
| 8 | Blocked by the src_port: block rule |
| 9 | Rate limited by the src_port: ratelimit rule |
| 10 | Blocked by the defaults/src_port: block rule |
| 11 | Rate limited by the defaults/src_port: ratelimit rule |
| 12 | Blocked by the src_ip: block rule |
| 13 | Rate limited by the src_ip: ratelimit rule |
| 14 | Blocked by the defaults/src_ip: block rule |
| 15 | Rate limited by the defaults/src_ip: ratelimit rule |
| 16 | Blocked by TCP anomaly: invalid flags |
| 17 | Blocked by TCP anomaly: invalid SYN sequence number |
| 18 | Blocked by TCP anomaly: SYN without TCP options |
| 19 | Blocked by TCP anomaly: SYN packet with payload |
| 20 | Blocked by TCP anomaly: zero source or destination port |
| 21 | Blocked by UDP anomaly: zero source or destination port |
| 22 | Blocked during parsing: unknown EtherType |
| 23 | Blocked during parsing: malformed Ethernet header |
| 24 | Blocked during parsing: malformed IPv4 header |
| 25 | Blocked during parsing: fragmented IPv4 packet |
| 26 | Blocked during parsing: malformed IPv6 header |
| 27 | Blocked during parsing: fragmented IPv6 packet |
| 28 | Blocked during parsing: malformed TCP header |
| 29 | Blocked during parsing: malformed UDP header |
| 30 | Blocked during parsing: malformed ICMP header |
| 31 | Blocked during parsing: unsupported L4 protocol |
| 32 | Blocked by tcp_auth_filter: unknown connection |
| 33 | Blocked by tcp_auth_filter: expired connection |
| 34 | Blocked by the tcp_syncookies rule: invalid SYN cookie |
| 35 | Blocked during parsing: malformed DNS header |
| 36 | Blocked by DNS anomaly: non-zero RCODE in DNS query |
| 37 | Blocked during parsing: malformed DNS question |
| 38 | Blocked by DNS anomaly: more than one question in DNS packet |
| 39 | Blocked by DNS anomaly: answers or authority sections present in DNS query |
| 40 | Blocked by DNS anomaly: invalid IXFR query |
| 41 | Blocked by DNS anomaly: more than two additional sections in DNS query |
| 42 | Blocked by DNS anomaly: response received without a prior query |
| 43 | Blocked by DNS anomaly: DNS UDP response packet is too large |
| 44 | Blocked by DNS anomaly: DNS response contains too many answers |
| 45 | Blocked during parsing: malformed DNS resource record |
| 46 | Blocked by DNS anomaly: invalid TTL in DNS answer |
Dropped events (dropped_events) counter โ the total number of dropped events across all CPUs since system startup. The counter is global and is not reset during normal operation. (Since the table is sorted by timestamp in descending order (newest events are shown first), the dropped_events value increases from bottom to top. Older records contain lower counter values, while newer records contain higher values, reflecting the cumulative number of dropped events over time.)
Packets without an Ethernet header cannot be reliably associated with a source IP address in the statistics. Such packets are not reported as separate drop events with a specific source IP address; instead, they contribute only to the global dropped_events counter.
For example, mDNS traffic generated by the Avahi daemon may reach the XDP program without an L2 header when the program is running in SKB mode. In this case, the packet contains only the network-layer header (for example, IPv6), while the original Ethernet header is no longer available. As a result, the source IP address cannot be reliably processed by the L2 parser, and the packet is accounted for only in the global dropped_events counter.