fixeria has uploaded this change for review. ( https://gerrit.osmocom.org/c/pysim/+/42375?usp=email )
Change subject: global_platform: fix store_data() returning last chunk only
......................................................................
global_platform: fix store_data() returning last chunk only
The loop builds up `response` across multiple STORE DATA blocks,
but the function returns only `data` - the response from the
*last* block. It should return the accumulated response instead.
Change-Id: I3e15c8004d1e366e8c3896e559656622f48bb1a2
---
M pySim/global_platform/__init__.py
1 file changed, 1 insertion(+), 1 deletion(-)
git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/75/42375/1
diff --git a/pySim/global_platform/__init__.py b/pySim/global_platform/__init__.py
index 232c383..a836134 100644
--- a/pySim/global_platform/__init__.py
+++ b/pySim/global_platform/__init__.py
@@ -585,7 +585,7 @@
data, _sw = self._cmd.lchan.scc.send_apdu_checksw(hdr + b2h(chunk) + "00")
block_nr += 1
response += data
- return data
+ return bytes.fromhex(response)
put_key_parser = argparse.ArgumentParser()
put_key_parser.add_argument('--old-key-version-nr', type=auto_uint8, default=0, help='Old Key Version Number')
--
To view, visit https://gerrit.osmocom.org/c/pysim/+/42375?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: newchange
Gerrit-Project: pysim
Gerrit-Branch: master
Gerrit-Change-Id: I3e15c8004d1e366e8c3896e559656622f48bb1a2
Gerrit-Change-Number: 42375
Gerrit-PatchSet: 1
Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de>
fixeria has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/42372?usp=email )
Change subject: s1gw: add README.md
......................................................................
s1gw: add README.md
Change-Id: Ib5c1326c4260bf552b561a42f7ff9d3f28f89579
---
A s1gw/README.md
1 file changed, 154 insertions(+), 0 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-ttcn3-hacks refs/changes/72/42372/1
diff --git a/s1gw/README.md b/s1gw/README.md
new file mode 100644
index 0000000..8bdeeca
--- /dev/null
+++ b/s1gw/README.md
@@ -0,0 +1,154 @@
+# What is this?
+
+This is a TTCN-3 testsuite for osmo-s1gw.
+
+## What is osmo-s1gw?
+
+**OsmoS1GW** is an S1AP gateway (proxy) between eNBs and an MME.
+It terminates S1AP SCTP connections from eNBs on one side, forwards
+S1AP to/from the MMEs on the other, and coordinates user-plane bearer
+setup with a UPF via PFCP. It is implemented in Erlang.
+
+```
+eNB --[S1AP/SCTP]--> S1GW --[S1AP/SCTP]--> MME
+ |
+ [PFCP/UDP]
+ |
+ UPF
+```
+
+Network address layout in tests:
+- eNB-facing: S1GW=127.0.1.1, eNB(s)=127.0.1.10+
+- MME-facing: S1GW=127.0.2.1, MME=127.0.2.10+
+- UPF-facing: S1GW=127.0.3.1, UPF=127.0.3.10
+- StatsD: 127.0.4.10:8125, REST: 127.0.0.1:8080
+
+## Running the testsuite
+
+```bash
+# From repo root:
+./testenv.py run s1gw
+
+# Build only:
+make s1gw
+
+# Run manually (osmo-s1gw must already be running):
+cd s1gw
+../start-testsuite.sh s1gw/S1GW_Tests S1GW_Tests.cfg
+
+# Single test case:
+../start-testsuite.sh s1gw/S1GW_Tests S1GW_Tests.cfg S1GW_Tests.TC_e_rab_setup
+```
+
+## Module Overview
+
+| File | Purpose |
+|---|---|
+| `S1GW_Tests.ttcn` | Top-level test cases, `f_init_*`, control block |
+| `S1GW_ConnHdlr.ttcn` | Per-eNB connection handler; all protocol helper functions |
+| `S1AP_Server.ttcn` | MME emulator; routes S1AP PDUs to ConnHdlr subscribers |
+| `S1GW_UEMux.ttcn` | UE multiplexer for multi-UE tests (128 concurrent UEs, by default) |
+| `S1GW_REST_Types.ttcn` | JSON/REST data types for management API |
+| `S1GW_REST_Functions.ttcn` | REST helper functions (metrics, PFCP, MME/E-RAB mgmt) |
+
+## Architecture & Key Patterns
+
+### Component Hierarchy
+
+```
+test_CT (extends StatsD_Checker_CT, http_CT)
+ ├── S1AP_Server_CT (MME emulator, one instance)
+ ├── PFCP_Emulation_CT (UPF emulator, one instance)
+ └── ConnHdlr [0..N] (one per emulated eNB)
+ └── UEMux_CT / UEMuxUE_CT (only in TC_uemux_* tests)
+```
+
+`test_CT` starts in `f_init()`, which brings up the REST interface,
+S1AP server, PFCP emulation, and StatsD checker before spawning any
+ConnHdlr instances.
+
+### ConnHdlr Lifecycle
+
+Every test case follows this lifecycle via `f_TC_exec()`:
+
+```
+f_ConnHdlr_spawn()
+ → f_ConnHdlr_s1ap_connect() # TCP/SCTP connect to S1GW eNB-facing port
+ → f_ConnHdlr_s1ap_register() # register with S1AP_Server
+ → f_ConnHdlr_s1ap_setup() # S1AP SetupRequest/Response exchange
+ → [test body runs]
+ → f_ConnHdlr_s1ap_disconnect()
+ → f_ConnHdlr_s1ap_unregister()
+```
+
+Multi-eNB tests spawn N ConnHdlr instances, run them in parallel
+via `interleave`, then join.
+
+### E-RAB Parameter Tracking (`ERab` / `ERabList`)
+
+Each bearer is tracked with transport endpoints for all four forwarding
+directions (access↔core in both send/receive), plus UPF PFCP SEIDs and
+TEID/IP combos. These are populated during setup and then asserted
+during modification/release to verify S1GW correctly translates addresses.
+
+```ttcn
+type record ERab {
+ ERabParams u2c, -- UPF→Core side (what S1GW programs into UPF)
+ ERabParams c2u, -- Core→UPF side
+ ERabParams a2u, -- Access→UPF side
+ ERabParams u2a, -- UPF→Access side
+ ERabParams u2cm, -- modified variant
+ ERabParams u2am, -- modified variant
+ OCT8 pfcp_loc_seid,
+ OCT8 pfcp_rem_seid
+}
+```
+
+### PFCP Session Mutex
+
+`f_ConnHdlr_erab_setup_req()` acquires a mutex before establishing the
+PFCP session. This serialises concurrent E-RAB setups across eNBs
+because the initial PFCP trigger uses SEID=0, which cannot be
+unambiguously routed without locking.
+
+### Bidirectional PDU Helpers
+
+All S1AP send/receive functions come in two directional variants:
+
+- `f_ConnHdlr_tx_s1ap_from_enb()` / `f_ConnHdlr_rx_s1ap_from_enb()` — eNB -> S1GW -> MME direction
+- `f_ConnHdlr_tx_s1ap_from_mme()` / `f_ConnHdlr_rx_s1ap_from_mme()` — MME -> S1GW -> eNB direction
+
+Similarly for PFCP: `f_ConnHdlr_pfcp_expect()`, `f_ConnHdlr_pfcp_reply()`.
+
+### Test Case Parameterisation
+
+Test bodies are passed as function references to `f_TC_exec()`, which handles ConnHdlr
+spawn/teardown. This lets the same test body run with varying eNB count or E-RAB count
+just by changing parameters — e.g. `TC_e_rab_setup` and `TC_e_rab_setup_multi` share
+`f_TC_e_rab_setup`.
+
+### StatsD Validation
+
+Many tests call `f_statsd_expect()` at the end to assert S1GW exported the right metrics
+(connection counts, forwarded packet counters, PFCP association state). These expectations
+are declared with `StatsDExpect` records before the test body runs and checked after.
+
+### REST Interface
+
+`S1GW_REST_Functions.ttcn` wraps HTTP GET/POST calls for inspecting and controlling live
+S1GW state (PFCP association, MME pool, E-RAB list). Used both for supplementary assertions
+(e.g. verifying StatsD metrics are consistent with REST state) and as the primary mechanism
+in REST-focused test cases.
+
+## Test Case Groups
+
+| Group | What's Covered |
+|---|---|
+| Connection | eNB connect/disconnect, MME-initiated teardown, MME unavailable |
+| E-RAB | Bearer setup/release/modify in both directions, PFCP rejection |
+| Initial Context | Attach bearer setup, UE context lifecycle |
+| UE Mux | Concurrent multi-UE operation (128 UEs) via UEMux |
+| Handover | X2/S1 handover preparation, resource allocation, partial failure |
+| PFCP | UPF heartbeat exchange |
+| MME Pool | MME fallback on rejection/timeout, impatient eNB disconnect during pool selection |
+| REST | MME pool listing, runtime add/delete, fallback after runtime delete |
--
To view, visit https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/42372?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: newchange
Gerrit-Project: osmo-ttcn3-hacks
Gerrit-Branch: master
Gerrit-Change-Id: Ib5c1326c4260bf552b561a42f7ff9d3f28f89579
Gerrit-Change-Number: 42372
Gerrit-PatchSet: 1
Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de>
fixeria has uploaded this change for review. ( https://gerrit.osmocom.org/c/erlang/osmo-s1gw/+/42366?usp=email )
Change subject: doc/manuals: document GTP-U KPI monitoring
......................................................................
doc/manuals: document GTP-U KPI monitoring
Change-Id: I2709cd545bfd6c8f6e34358caf9d372c02dd5c3e
Related: OS#6671
---
M doc/manuals/chapters/configuration.adoc
A doc/manuals/chapters/gtpu_kpi.adoc
M doc/manuals/osmo-s1gw-usermanual.adoc
3 files changed, 113 insertions(+), 2 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/erlang/osmo-s1gw refs/changes/66/42366/1
diff --git a/doc/manuals/chapters/configuration.adoc b/doc/manuals/chapters/configuration.adoc
index 8bd7eea..dc738a4 100644
--- a/doc/manuals/chapters/configuration.adoc
+++ b/doc/manuals/chapters/configuration.adoc
@@ -161,8 +161,8 @@
=== GTP-U KPI Reporting (Optional)
OsmoS1GW can optionally poll nftables counters to derive per-eNB GTP-U
-traffic statistics and report them as exometer metrics. This feature
-requires a matching nftables ruleset.
+traffic statistics and report them as exometer metrics (see <<gtpu_kpi>>).
+This feature requires a matching nftables ruleset.
----
%% {gtpu_kpi_enable, true},
diff --git a/doc/manuals/chapters/gtpu_kpi.adoc b/doc/manuals/chapters/gtpu_kpi.adoc
new file mode 100644
index 0000000..ed43cd1
--- /dev/null
+++ b/doc/manuals/chapters/gtpu_kpi.adoc
@@ -0,0 +1,109 @@
+[[gtpu_kpi]]
+== GTP-U KPI Monitoring
+
+OsmoS1GW includes an optional GTP-U KPI monitoring module that tracks
+per-eNB GTP-U traffic volume. Because OsmoS1GW does not carry GTP-U
+traffic itself (see <<architecture>>), it cannot count packets and bytes
+from the data path directly. Instead, it leverages the Linux
+https://netfilter.org/projects/nftables/[nftables] framework: when an
+eNB connects and its GTP-U transport address becomes known, OsmoS1GW
+dynamically installs nftables rules with named counters to measure the
+traffic for that eNB. The counters are polled at a configurable interval
+and the results are exposed as exometer metrics.
+
+This feature is disabled by default. See <<config_gtpu_kpi>> for the
+configuration parameters.
+
+[[gtpu_kpi_requirements]]
+=== Requirements
+
+* Linux kernel 5.2 or later with nftables support.
+* The `CAP_NET_ADMIN` capability is required to manipulate nftables
+ rules. This is already granted by the installed systemd unit (see
+ <<running_systemd>>).
+
+[[gtpu_kpi_how_it_works]]
+=== How It Works
+
+[[gtpu_kpi_nftables_setup]]
+==== nftables Table and Chains
+
+At startup, the GTP-U KPI module creates a dedicated nftables table (an
+`inet` family table named `osmo-s1gw` by default, configurable via
+`gtpu_kpi_table_name`). The table is marked as process-owned, so the
+kernel automatically removes it if OsmoS1GW terminates unexpectedly. If
+a table with the same name already exists from a previous run, it is
+flushed first.
+
+Inside this table the module creates two base chains:
+
+`gtpu-ul` (hook: `prerouting`)::
+ Counts uplink GTP-U traffic — packets whose source address matches a
+ registered eNB's GTP-U address.
+
+`gtpu-dl` (hook: `postrouting`)::
+ Counts downlink GTP-U traffic — packets whose destination address
+ matches a registered eNB's GTP-U address.
+
+Both chains prepend two rules that fast-skip non-GTP-U packets (i.e.
+anything that is not UDP or whose destination port is not 2152).
+
+[[gtpu_kpi_address_learning]]
+==== GTP-U Address Learning
+
+GTP-U transport addresses are not explicitly configured; they are learned
+at run time from the S1AP signalling exchanged during E-RAB establishment.
+The source of the address used for nftables rule matching is controlled by
+the `gtpu_kpi_ul_addr` and `gtpu_kpi_dl_addr` configuration parameters:
+
+`s1ap` (default)::
+ The GTP-U address is taken from the F-TEID IEs carried in S1AP PDUs
+ (E-RAB Setup, Initial Context Setup, etc.).
+
+`sctp`::
+ The GTP-U address is assumed to be the same as the eNB's SCTP source
+ address. Useful when the GTP-U and S1AP addresses are always the same.
+
+[[gtpu_kpi_per_enb_rules]]
+==== Per-eNB Counter Rules
+
+Once an eNB's GTP-U address is known, the module adds:
+
+* A named nftables counter (`ul-{GlobalENBId}` for uplink,
+ `dl-{GlobalENBId}` for downlink).
+* A rule in the appropriate chain that matches packets by source (UL) or
+ destination (DL) IP address and updates the corresponding counter.
+
+When an eNB disconnects, the matching nftables rule is removed, but the
+counter object is intentionally left in place. This means counters
+accumulate across reconnections of the same eNB and do not reset to zero
+if the eNB briefly drops and re-establishes its connection.
+
+[[gtpu_kpi_polling]]
+==== Counter Polling and Metric Reporting
+
+A periodic timer (interval configurable via `gtpu_kpi_interval`, default
+3000 ms) fires and reads all named counters from the nftables table. For
+each registered eNB the difference since the last poll is computed and
+added to the corresponding exometer counters.
+
+Three metrics are maintained per eNB per direction (see also
+<<metrics_per_enb_counters>>):
+
+`enb.{id}.gtpu.packets.{ul|dl}`::
+ Total number of GTP-U packets seen for this eNB.
+
+`enb.{id}.gtpu.bytes.total.{ul|dl}`::
+ Total bytes seen for this eNB, including the outer IP, UDP, and GTP-U
+ headers (i.e. what nftables reports).
+
+`enb.{id}.gtpu.bytes.ue.{ul|dl}`::
+ Estimated UE payload bytes — total bytes minus the fixed overhead of
+ the outer IP header (20 bytes), UDP header (8 bytes), and GTP-U header
+ (8 bytes), i.e. 36 bytes per packet.
+
+NOTE: The UE payload byte estimate assumes a fixed 20-byte IP header.
+ IPv6 or IP options would result in a slight overcount in the
+ overhead subtraction.
+
+// vim:set ts=4 sw=4 et:
diff --git a/doc/manuals/osmo-s1gw-usermanual.adoc b/doc/manuals/osmo-s1gw-usermanual.adoc
index 7c97192..2427d31 100644
--- a/doc/manuals/osmo-s1gw-usermanual.adoc
+++ b/doc/manuals/osmo-s1gw-usermanual.adoc
@@ -17,6 +17,8 @@
include::{srcdir}/chapters/metrics.adoc[]
+include::{srcdir}/chapters/gtpu_kpi.adoc[]
+
include::{commondir}/chapters/glossary.adoc[]
include::{commondir}/chapters/bibliography.adoc[]
--
To view, visit https://gerrit.osmocom.org/c/erlang/osmo-s1gw/+/42366?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: newchange
Gerrit-Project: erlang/osmo-s1gw
Gerrit-Branch: master
Gerrit-Change-Id: I2709cd545bfd6c8f6e34358caf9d372c02dd5c3e
Gerrit-Change-Number: 42366
Gerrit-PatchSet: 1
Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de>
fixeria has uploaded this change for review. ( https://gerrit.osmocom.org/c/erlang/osmo-s1gw/+/42365?usp=email )
Change subject: doc/manuals: document the metrics
......................................................................
doc/manuals: document the metrics
Change-Id: Iacfefd387d0cd26eebbbeba0cd37efa78f90bb46
Related: OS#6671
---
M doc/manuals/chapters/configuration.adoc
A doc/manuals/chapters/metrics.adoc
M doc/manuals/osmo-s1gw-usermanual.adoc
3 files changed, 190 insertions(+), 3 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/erlang/osmo-s1gw refs/changes/65/42365/1
diff --git a/doc/manuals/chapters/configuration.adoc b/doc/manuals/chapters/configuration.adoc
index 53e23e5..8bd7eea 100644
--- a/doc/manuals/chapters/configuration.adoc
+++ b/doc/manuals/chapters/configuration.adoc
@@ -256,9 +256,10 @@
=== `exometer_core` — Metrics and StatsD Reporting
OsmoS1GW uses the https://github.com/Feuerlabs/exometer_core[exometer_core]
-library for internal metrics (counters and gauges). The `exometer_core`
-section configures reporters — processes that periodically push metric
-values to an external destination.
+library for internal metrics (counters and gauges); see <<metrics>> for the
+full list of available metrics. The `exometer_core` section configures
+reporters — processes that periodically push metric values to an external
+destination.
The default configuration reports all counters and gauges to a StatsD
server:
diff --git a/doc/manuals/chapters/metrics.adoc b/doc/manuals/chapters/metrics.adoc
new file mode 100644
index 0000000..5b81227
--- /dev/null
+++ b/doc/manuals/chapters/metrics.adoc
@@ -0,0 +1,184 @@
+[[metrics]]
+== Metrics
+
+OsmoS1GW exposes internal metrics using the
+https://github.com/Feuerlabs/exometer_core[exometer_core] library. Two
+metric types are used:
+
+Counter:: A monotonically increasing integer, incremented each time a
+ specific event occurs. Counters never decrease.
+
+Gauge:: An integer that reflects a current quantity (e.g. the number of
+ active connections). Gauges can go up and down.
+
+[[metrics_naming]]
+=== Metric Names
+
+Internally, each metric is identified by an Erlang list such as
+`[ctr, pfcp, heartbeat_req, tx]`. When reported externally — via StatsD
+(see <<config_exometer>>) or the REST API (see <<rest_metrics>>) — the
+list elements are joined with dots and the leading type element (`ctr` or
+`gauge`) is dropped. For example:
+
+* `[ctr, pfcp, heartbeat_req, tx]` → `pfcp.heartbeat_req.tx`
+* `[gauge, pfcp, associated]` → `pfcp.associated`
+
+When StatsD reporting is enabled, all metric names are further prefixed
+with the configured `prefix` string (default: `s1gw`), giving e.g.
+`s1gw.pfcp.heartbeat_req.tx`.
+
+[[metrics_global_counters]]
+=== Global Counters
+
+The following counters are registered at startup and count events across
+all connections.
+
+[[metrics_pfcp_counters]]
+==== PFCP Counters
+
+[options="header",cols="45,55"]
+|===
+| Metric name | Description
+| `pfcp.heartbeat_req.tx` | PFCP Heartbeat Requests sent to the UPF
+| `pfcp.heartbeat_req.rx` | PFCP Heartbeat Requests received from the UPF
+| `pfcp.heartbeat_req.timeout` | PFCP Heartbeat Requests that timed out
+| `pfcp.heartbeat_resp.tx` | PFCP Heartbeat Responses sent to the UPF
+| `pfcp.heartbeat_resp.rx` | PFCP Heartbeat Responses received from the UPF
+| `pfcp.assoc_setup_req.tx` | PFCP Association Setup Requests sent
+| `pfcp.assoc_setup_req.timeout` | PFCP Association Setup Requests that timed out
+| `pfcp.assoc_setup_resp.rx` | PFCP Association Setup Responses received
+| `pfcp.assoc_setup_resp.rx_ack` | PFCP Association Setup Responses with success cause
+| `pfcp.assoc_setup_resp.rx_nack` | PFCP Association Setup Responses with failure cause
+| `pfcp.unexpected_pdu` | Unexpected or unrecognised PFCP PDUs received
+|===
+
+[[metrics_s1ap_counters]]
+==== S1AP Counters
+
+[options="header",cols="55,45"]
+|===
+| Metric name | Description
+| `s1ap.enb.all.rx` | S1AP PDUs received from any eNB
+| `s1ap.enb.all.rx_unknown_enb` | S1AP PDUs received from an unregistered eNB
+| `s1ap.proxy.exception` | Exceptions raised during S1AP PDU processing
+| `s1ap.proxy.in_pkt.all` | S1AP PDUs entering the proxy (all directions)
+| `s1ap.proxy.in_pkt.drop.all` | S1AP PDUs dropped by the proxy
+| `s1ap.proxy.in_pkt.decode_error` | S1AP PDUs that failed to decode
+| `s1ap.proxy.in_pkt.proc_error` | S1AP PDUs that failed to process
+| `s1ap.proxy.in_pkt.erab_setup_req` | E-RAB SETUP REQUEST PDUs
+| `s1ap.proxy.in_pkt.erab_setup_rsp` | E-RAB SETUP RESPONSE PDUs
+| `s1ap.proxy.in_pkt.erab_modify_req` | E-RAB MODIFY REQUEST PDUs
+| `s1ap.proxy.in_pkt.erab_modify_rsp` | E-RAB MODIFY RESPONSE PDUs
+| `s1ap.proxy.in_pkt.erab_release_cmd` | E-RAB RELEASE COMMAND PDUs
+| `s1ap.proxy.in_pkt.erab_release_rsp` | E-RAB RELEASE RESPONSE PDUs
+| `s1ap.proxy.in_pkt.erab_release_ind` | E-RAB RELEASE INDICATION PDUs
+| `s1ap.proxy.in_pkt.erab_mod_ind` | E-RAB MODIFICATION INDICATION PDUs
+| `s1ap.proxy.in_pkt.erab_mod_cnf` | E-RAB MODIFICATION CONFIRM PDUs
+| `s1ap.proxy.in_pkt.init_ctx_req` | INITIAL CONTEXT SETUP REQUEST PDUs
+| `s1ap.proxy.in_pkt.init_ctx_rsp` | INITIAL CONTEXT SETUP RESPONSE PDUs
+| `s1ap.proxy.in_pkt.release_ctx_req` | UE CONTEXT RELEASE REQUEST PDUs
+| `s1ap.proxy.in_pkt.release_ctx_cmd` | UE CONTEXT RELEASE COMMAND PDUs
+| `s1ap.proxy.in_pkt.release_ctx_compl` | UE CONTEXT RELEASE COMPLETE PDUs
+| `s1ap.proxy.in_pkt.handover_cmd` | HANDOVER COMMAND PDUs
+| `s1ap.proxy.in_pkt.handover_req` | HANDOVER REQUEST PDUs
+| `s1ap.proxy.in_pkt.handover_req_ack` | HANDOVER REQUEST ACKNOWLEDGE PDUs
+| `s1ap.proxy.out_pkt.forward.all` | S1AP PDUs forwarded (total)
+| `s1ap.proxy.out_pkt.forward.proc` | S1AP PDUs forwarded after processing (with IE rewriting)
+| `s1ap.proxy.out_pkt.forward.unmodified` | S1AP PDUs forwarded without modification
+| `s1ap.proxy.out_pkt.reply.all` | S1AP PDUs generated locally by the proxy (total)
+| `s1ap.proxy.out_pkt.reply.erab_setup_rsp` | E-RAB SETUP RESPONSE PDUs generated locally
+|===
+
+[[metrics_enb_proxy_counters]]
+==== eNB Proxy Counters
+
+[options="header",cols="45,55"]
+|===
+| Metric name | Description
+| `enb_proxy.s1setup.req` | S1 SETUP REQUEST PDUs received from eNBs
+| `enb_proxy.s1setup.rsp` | S1 SETUP RESPONSE PDUs received from the MME and forwarded
+| `enb_proxy.s1setup.failure` | S1 SETUP FAILURE PDUs received from an MME (triggers retry)
+| `enb_proxy.s1setup.req.timeout` | Timeouts waiting for S1 SETUP REQUEST from an eNB
+| `enb_proxy.s1setup.rsp.timeout` | Timeouts waiting for S1 SETUP RESPONSE from an MME
+| `enb_proxy.conn_est.timeout` | MME SCTP connection establishment timeouts
+| `enb_proxy.conn_est.failure` | MME SCTP connection establishment failures
+| `enb_proxy.unexpected_pdu` | Unexpected PDUs received from an eNB or MME
+| `enb_proxy.malformed_pdu` | Malformed PDUs received from an eNB or MME
+| `enb_proxy.mme_select.ok` | Successful MME selections from the pool
+| `enb_proxy.mme_select.error` | Failed MME selections (pool exhausted)
+|===
+
+[[metrics_sctp_counters]]
+==== SCTP Error Counters
+
+[options="header",cols="40,60"]
+|===
+| Metric name | Description
+| `sctp.error.all` | Total number of SCTP errors
+| `sctp.error.send_failed` | SCTP send operation failures
+| `sctp.error.pdapi_event` | SCTP partial delivery API failures
+| `sctp.error.remote_error` | SCTP remote error notifications
+|===
+
+[[metrics_per_enb_counters]]
+=== Per-eNB Counters
+
+When an eNB connects and its Global-eNB-ID becomes known (after the S1
+Setup procedure), OsmoS1GW dynamically creates a set of per-eNB counters
+scoped to that eNB. These counters mirror the global eNB proxy counters
+but are broken down per connected base station.
+
+The naming scheme for per-eNB counters is
+`enb.{Global-eNB-ID}.{suffix}`, where `{Global-eNB-ID}` is the
+MCC-MNC-eNBId string (e.g. `001-01-1337`).
+
+In addition to the mirrored proxy counters, the following per-eNB
+counters are also registered:
+
+[options="header",cols="50,50"]
+|===
+| Metric name | Description
+| `enb.{id}.uptime` | Time (in seconds) since the eNB connected
+| `enb.{id}.gtpu.packets.ul` | GTP-U uplink packets (requires GTP-U KPI)
+| `enb.{id}.gtpu.packets.dl` | GTP-U downlink packets (requires GTP-U KPI)
+| `enb.{id}.gtpu.bytes.ue.ul` | GTP-U uplink bytes (UE side, requires GTP-U KPI)
+| `enb.{id}.gtpu.bytes.ue.dl` | GTP-U downlink bytes (UE side, requires GTP-U KPI)
+| `enb.{id}.gtpu.bytes.total.ul` | GTP-U uplink bytes (total, requires GTP-U KPI)
+| `enb.{id}.gtpu.bytes.total.dl` | GTP-U downlink bytes (total, requires GTP-U KPI)
+|===
+
+GTP-U counters are only populated when the GTP-U KPI module is enabled
+(see <<config_gtpu_kpi>>).
+
+[[metrics_per_mme_counters]]
+=== Per-MME Counters
+
+When an MME is registered in the pool — either at startup from the
+configuration file (see <<config_mme_pool>>) or dynamically via the REST
+API — OsmoS1GW creates a set of per-MME counters scoped to that MME entry.
+
+The naming scheme is `mme.{name}.{suffix}`, where `{name}` is the MME's
+configured name (e.g. `mme0`).
+
+[options="header",cols="45,55"]
+|===
+| Metric name | Description
+| `mme.{name}.selected` | Number of times this MME was selected for a connection attempt
+| `mme.{name}.conn_est.timeout` | Connection establishment timeouts to this MME
+| `mme.{name}.conn_est.failure` | Connection establishment failures to this MME
+| `mme.{name}.s1setup.rsp` | Successful S1 Setup procedures completed via this MME
+| `mme.{name}.s1setup.failure` | S1 SETUP FAILURE responses received from this MME
+| `mme.{name}.s1setup.rsp.timeout` | Timeouts waiting for S1 SETUP RESPONSE from this MME
+|===
+
+[[metrics_gauges]]
+=== Gauges
+
+[options="header",cols="45,55"]
+|===
+| Metric name | Description
+| `pfcp.associated` | `1` if the PFCP association with the UPF is currently established, `0` otherwise
+| `s1ap.enb.num_sctp_connections` | Current number of active eNB SCTP connections
+|===
+
+// vim:set ts=4 sw=4 et:
diff --git a/doc/manuals/osmo-s1gw-usermanual.adoc b/doc/manuals/osmo-s1gw-usermanual.adoc
index 13dcd4b..7c97192 100644
--- a/doc/manuals/osmo-s1gw-usermanual.adoc
+++ b/doc/manuals/osmo-s1gw-usermanual.adoc
@@ -15,6 +15,8 @@
include::{srcdir}/chapters/configuration.adoc[]
+include::{srcdir}/chapters/metrics.adoc[]
+
include::{commondir}/chapters/glossary.adoc[]
include::{commondir}/chapters/bibliography.adoc[]
--
To view, visit https://gerrit.osmocom.org/c/erlang/osmo-s1gw/+/42365?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: newchange
Gerrit-Project: erlang/osmo-s1gw
Gerrit-Branch: master
Gerrit-Change-Id: Iacfefd387d0cd26eebbbeba0cd37efa78f90bb46
Gerrit-Change-Number: 42365
Gerrit-PatchSet: 1
Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de>