Metrics Reference
This document describes all Prometheus metrics exposed by OmniUPF on the /api/metrics endpoint (the HTTP API runs on api_port, default 8080). Note the /api prefix - every API route is served under it.
The metric names, types, and labels below reflect the metrics OmniUPF exposes.
Metric Categories
- PFCP metrics - control-plane message, association, session, and error counters
- Session lifecycle metrics - session create/delete/modify counters and establishment latency
- Userspace slow-path and buffering metrics - punt counters for downlink buffering, walled-garden, and unknown-TEID Error Indications
- Downlink Data Report (DLDR) metrics - PFCP Session Report Request notifications and FAR index tracking
- GTP-U metrics - echo responses and Error Indication counters
- URR metrics - usage-report counters and active URR timers
- eBPF map metrics - dataplane map entry gauges
- Dataplane throughput - per-direction (N3/N6)
_totalcounters, gated byexpose_xdp_metrics(#57); also on-demand via/api/v1/xdp_stats - Resource / routing metrics - TEID/FAR-ID pool and UE route gauges
- Walled Garden metrics - captive-portal interception, forwarding, and DNS spoofing counters
PFCP metrics
Control-plane protocol counters between the UPF and its PFCP peers (SMF / PGW-C / SGW-C).
| Metric Name | Type | Labels | Description |
|---|---|---|---|
upf_pfcp_associations | Gauge | none | Currently active PFCP associations (all peers) |
upf_pfcp_sessions | Gauge | none | Currently active PFCP sessions (all peers) |
upf_pfcp_peer_restarts_total | Counter | peer | Peer restart detections (Recovery Timestamp change) |
upf_pfcp_duplicate_requests_total | Counter | none | Duplicate PFCP requests detected and suppressed |
upf_orphaned_sessions_deleted_total | Counter | none | Sessions deleted as a result of a peer restart |
upf_pfcp_messages_rx_total | Counter | type, peer | PFCP messages received per message type and peer |
upf_pfcp_messages_tx_total | Counter | type, peer | PFCP messages sent per message type and peer |
upf_pfcp_errors_total | Counter | type | PFCP request rejections, labelled by the reject cause (e.g. session_context_not_found, mandatory_ie_missing) |
Session lifecycle metrics
| Metric Name | Type | Labels | Description |
|---|---|---|---|
upf_sessions_created_total | Counter | none | PFCP sessions established |
upf_sessions_deleted_total | Counter | none | PFCP sessions deleted |
upf_sessions_modified_total | Counter | none | PFCP sessions modified |
upf_session_establishment_duration_microseconds | Histogram | none | Session establishment processing time (microseconds). Buckets: 10, 25, 50, 100, 250, 500, 1000, 2500, 5000, 10000 |
Userspace slow-path and buffering metrics
The eBPF dataplane punts packets to the userspace slow path (UDP port 22152, default) for three distinct jobs: downlink buffering when a UE is idle (held until the UE is paged), walled-garden redirect, and answering unknown-TEID uplink G-PDUs with a GTP-U Error Indication. Only the buffered/flushed/current metrics below describe the buffer proper; walled-garden has its own upf_walled_garden_* metrics and unknown-TEID is counted as upf_gtpu_error_indications_sent_total.
| Metric Name | Type | Labels | Description |
|---|---|---|---|
upf_userspace_punt_received_total | Counter | none | All packets punted to the userspace slow path (buffering + walled-garden + unknown-TEID) |
upf_buffer_packets_buffered_total | Counter | none | Packets successfully added to the buffer |
upf_buffer_packets_flushed_total | Counter | none | Packets flushed from the buffer |
upf_buffer_packets_dropped_total | Counter | reason | Packets dropped from / not admitted to the buffer |
upf_buffer_packets_current | Gauge | none | Packets currently held in the buffer |
upf_buffer_flush_operations_total | Counter | none | Successful buffer flush operations (per FAR flush) |
upf_buffer_flush_packets_sent_total | Counter | none | Packets sent during flush operations |
upf_buffer_flush_errors_total | Counter | reason | Failed buffer flush operations |
upf_buffer_packets_dropped_total reason values (from buffer-add drops and buffer-listener errors):
global_limit- total buffer capacity (buffer_max_total) reachedfar_limit- per-FAR buffer limit (buffer_max_per_far) reachedexpired- TTL (buffer_ttl_ms) exceeded before flushread_error- error reading from the buffer sockettoo_small- packet too small for a GTP headerinvalid_gtp_type- non-G-PDU GTP message typenot_buffering_far- FAR does not have a BUFF actionerror_indication_failed- could not send the GTP-U Error Indication for an unknown-TEID uplink
Unknown-TEID uplink is not a buffer drop: it is answered with a GTP-U Error Indication and counted by
upf_gtpu_error_indications_sent_total(a correct slow-path response, not packet loss).
upf_buffer_flush_errors_total reason values:
far_lookup_failed- could not look up FAR info from the eBPF mapno_forw_action- FAR does not have a FORW action setconnection_failed- failed to open a UDP socket for flushing
Downlink Data Report (DLDR) metrics
Metrics for PFCP Session Report Request notifications sent to the control plane when downlink packets are buffered. These notifications trigger the SMF/PGW-C to page the UE.
| Metric Name | Type | Labels | Description |
|---|---|---|---|
upf_dldr_sent_total | Counter | peer | Downlink Data Reports sent, labelled by SMF/PGW-C address |
upf_dldr_errors_total | Counter | none | DLDR encoding / send errors |
upf_dldr_skipped_total | Counter | none | DLDRs skipped because the FAR was already notified |
upf_far_index_size | Gauge | none | FARs registered in the FarIndex for DLDR notification |
GTP-U metrics
GTP-U path-management and Error Indication counters. Error Indications are exchanged when a peer receives packets for an unknown TEID (typically after a restart).
| Metric Name | Type | Labels | Description |
|---|---|---|---|
upf_gtpu_echo_responses_tx_total | Counter | none | GTP-U Echo Responses sent |
upf_gtpu_error_indications_sent_total | Counter | none | GTP-U Error Indications sent (for unknown incoming TEIDs) |
upf_gtpu_error_indications_rx_total | Counter | none | GTP-U Error Indications received from peers |
upf_error_indication_sessions_deleted_total | Counter | none | Sessions deleted as a result of a received Error Indication |
When Error Indications are sent: the UPF receives a GTP-U packet for a TEID that does not exist (e.g. after a restart, or the session was already deleted), and informs the sender to stop.
When Error Indications are received: a downstream peer does not recognise a TEID the UPF forwarded to; the UPF deletes the affected session to stop forwarding to a dead tunnel.
URR (Usage Reporting Rule) metrics
| Metric Name | Type | Labels | Description |
|---|---|---|---|
upf_urr_reports_sent_total | Counter | trigger | URR usage reports sent, labelled by reporting trigger |
upf_urr_report_errors_total | Counter | none | URR report encoding / send errors |
upf_urr_active_timers | Gauge | none | Active URR timers (periodic / time-threshold / quota-validity) |
trigger reflects the URR reporting trigger that fired - e.g. periodic (PERIO), volume_threshold (VOLTH), time_threshold (TIMTH), quota_validity (QUVTI).
Per-URR byte counters are not exported as Prometheus metrics (to avoid high cardinality). Read individual URR statistics via the REST API at /api/v1/urr_map.
eBPF map metrics
Gauges for dataplane map utilisation, refreshed on each scrape.
| Metric Name | Type | Labels | Description |
|---|---|---|---|
upf_ebpf_far_entries | Gauge | none | FAR entries in the eBPF map |
upf_ebpf_pdr_uplink_entries | Gauge | none | Uplink PDR entries in the eBPF map (PDRs with a TEID) |
upf_ebpf_pdr_downlink_entries | Gauge | none | Downlink PDR entries in the eBPF map (PDRs keyed by UE IP) |
upf_ebpf_far_entries mirrors the allocated-FAR-id pool (upf_far_ids_allocated), since the far_map holds one entry per allocated FAR id. The PDR gauges are aggregated from live session state on each scrape (cost is O(total sessions)).
Dataplane throughput (N3/N6)
Per-direction packet and byte counters for user-plane traffic (N3 = GTP-U side towards the gNB/eNB; N6 = SGi side towards the data network) come from the eBPF upf_ext_stat percpu map.
| Metric Name | Type | Labels | Description |
|---|---|---|---|
upf_n3_rx_packets_total / upf_n3_tx_packets_total | Counter | none | N3 (GTP-U) packets in / out of the XDP datapath |
upf_n6_rx_packets_total / upf_n6_tx_packets_total | Counter | none | N6 (SGi) packets in / out of the XDP datapath |
upf_n3_rx_bytes_total / upf_n3_tx_bytes_total | Counter | none | N3 (GTP-U) bytes in / out |
upf_n6_rx_bytes_total / upf_n6_tx_bytes_total | Counter | none | N6 (SGi) bytes in / out |
Gated by expose_xdp_metrics (issue #57). Reading upf_ext_stat on the request path (per Prometheus scrape) was proven to trigger a virtio_net generic-XDP TX-ring wedge. Two mitigations apply: the read is done off the request path by the background Sampler (on a fixed interval, never on a scrape), and it is gated behind config :upf_ex, expose_xdp_metrics: true. When disabled, these counters are not declared or exported.
These are cumulative _total Counters. The underlying upf_ext_stat map is pinned, so it survives an omniupf restart but is zeroed on an eBPF .o redeploy; the collector translates its absolute value into monotonic counter increments so rate() stays correct across both. Do not read these as gauges. Use rate().
On-demand JSON: GET /api/v1/xdp_stats returns the same fields and only touches eBPF when you explicitly call it. Fields: rx_n3 / tx_n3 / rx_n6 / tx_n6 (packets) and rx_n3_bytes / tx_n3_bytes / rx_n6_bytes / tx_n6_bytes.
Resource / routing metrics
| Metric Name | Type | Labels | Description |
|---|---|---|---|
upf_routes_total | Gauge | none | UE IP routes currently tracked by the route manager |
upf_teid_allocated | Gauge | none | TEIDs currently allocated from the pool |
upf_far_ids_allocated | Gauge | none | FAR IDs currently allocated from the pool |
Walled Garden metrics
Counters for the out-of-credit / captive-portal walled garden. See the Walled Garden Guide for behaviour.
| Metric Name | Type | Labels | Description |
|---|---|---|---|
upf_walled_garden_active_redirects | Gauge | none | Active walled-garden redirect sessions |
upf_walled_garden_packets_intercepted_total | Counter | none | Packets intercepted by the walled garden |
upf_walled_garden_packets_dropped_total | Counter | none | Packets dropped by the walled garden |
upf_walled_garden_packets_forwarded_total | Counter | dst_ip | Whitelisted packets forwarded, per destination IP |
upf_walled_garden_bytes_forwarded_total | Counter | dst_ip | Whitelisted bytes forwarded, per destination IP |
upf_walled_garden_dns_spoofed_total | Counter | domain | DNS queries spoofed to the portal, per domain |
upf_walled_garden_dns_forwarded_total | Counter | domain | DNS queries forwarded (whitelisted domains), per domain |
Cardinality note. The
dst_ipanddomainlabels are unbounded. Keep the whitelist tight, and aggregate away these labels in recording rules if you scrape a busy walled garden.
Using Prometheus Metrics
Accessing Metrics
Metrics are exposed on the /api/metrics endpoint of the HTTP API server, which listens on api_port (default 8080). Note the /api prefix - every API route is served under it:
# View raw metrics
curl http://localhost:8080/api/metrics
# Example output
upf_pfcp_sessions 42
upf_pfcp_associations 2
upf_dldr_sent_total{peer="10.100.50.241"} 17
Prometheus Configuration
Add the OmniUPF target to your prometheus.yml:
scrape_configs:
- job_name: 'omniupf'
metrics_path: /api/metrics
static_configs:
- targets: ['localhost:8080']
Grafana Dashboards
Useful panels to build from these metrics:
- Session and association counts (
upf_pfcp_sessions,upf_pfcp_associations) - Per-direction N3/N6 throughput is available on demand via
/api/v1/xdp_stats(removed from the scrape, see #57) - Buffer pressure (
upf_buffer_packets_current, drop rate byreason) - DLDR / paging activity (
rate(upf_dldr_sent_total[5m])) - Error Indication and peer-restart rates for tunnel-health alerting
Related Documentation
- Monitoring Guide - Statistics monitoring, capacity planning, and alerting
- Configuration Guide - Configure
api_port, buffer tuning, and other UPF options - Web UI Guide - View metrics in the Statistics page
- Architecture Guide - eBPF datapath and performance optimization
- Rules Management Guide - Understanding PDR, FAR, QER, URR metrics
- Walled Garden Guide - Captive-portal redirect and whitelist behaviour
- Troubleshooting Guide - Using metrics for diagnostics