fixeria has uploaded this change for review. ( https://gerrit.osmocom.org/c/erlang/osmo-s1gw/+/42367?usp=email )
Change subject: doc/manuals: document the REST interface
......................................................................
doc/manuals: document the REST interface
Change-Id: I8bc9183fff8f65db71554ee26369db9bdb61b78a
Related: OS#6671
---
M doc/manuals/chapters/metrics.adoc
M doc/manuals/chapters/overview.adoc
A doc/manuals/chapters/rest.adoc
M doc/manuals/osmo-s1gw-usermanual.adoc
4 files changed, 338 insertions(+), 3 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/erlang/osmo-s1gw refs/changes/67/42367/1
diff --git a/doc/manuals/chapters/metrics.adoc b/doc/manuals/chapters/metrics.adoc
index 5b81227..963e303 100644
--- a/doc/manuals/chapters/metrics.adoc
+++ b/doc/manuals/chapters/metrics.adoc
@@ -155,7 +155,8 @@
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.
+API (see <<rest_mme>>) — 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`).
diff --git a/doc/manuals/chapters/overview.adoc b/doc/manuals/chapters/overview.adoc
index d8248ca..d91b466 100644
--- a/doc/manuals/chapters/overview.adoc
+++ b/doc/manuals/chapters/overview.adoc
@@ -63,9 +63,9 @@
provisioned statically via the configuration file or dynamically via
the REST API.
* *`enb_registry`* — Tracks all active eNB connections and their state.
- Queryable via the REST API.
+ Queryable via the REST API (see <<rest_enb>>).
* *`rest_server`* — OpenAPI-based HTTP REST interface for monitoring and
- management.
+ management (see <<rest>>).
[[use_cases]]
=== Use Cases
diff --git a/doc/manuals/chapters/rest.adoc b/doc/manuals/chapters/rest.adoc
new file mode 100644
index 0000000..e1fb324
--- /dev/null
+++ b/doc/manuals/chapters/rest.adoc
@@ -0,0 +1,332 @@
+[[rest]]
+== REST Interface
+
+OsmoS1GW exposes an HTTP REST API for monitoring and management. The
+API follows the OpenAPI 3.0 specification; the full machine-readable spec
+is served at `GET /openapi.json`. A Swagger UI is available at
+`/swagger` when enabled (see <<config_rest>>).
+
+By default the REST server listens on port `8080`. No authentication is
+implemented; access control should be enforced at the network level if
+required.
+
+[[rest_identifiers]]
+=== Resource Identifiers
+
+Several endpoints accept a resource identifier in the URL path that can
+be expressed in multiple forms:
+
+[[rest_mme_id]]
+==== MME Identifier (`{MmeId}`)
+
+[options="header",cols="25,35,40"]
+|===
+| Form | Pattern | Example
+| Name | `name:<name>` | `name:mme0`
+| Address/port | `addr:<ip>-<port>` | `addr:192.168.1.1-36412`
+|===
+
+[[rest_enb_id]]
+==== eNB Identifier (`{EnbId}`)
+
+[options="header",cols="25,35,40"]
+|===
+| Form | Pattern | Example
+| Registry handle | `handle:<n>` | `handle:42`
+| Process ID | `pid:<x>.<y>.<z>` | `pid:0.33.1`
+| Global-eNB-ID | `genbid:<mcc>-<mnc>-<id>` | `genbid:999-70-1337`
+| eNB SCTP assoc ID | `enb-sctp-aid:<n>` | `enb-sctp-aid:42`
+| MME SCTP assoc ID | `mme-sctp-aid:<n>` | `mme-sctp-aid:42`
+| eNB connection addr | `enb-conn:<ip>-<port>` | `enb-conn:192.168.1.1-34650`
+|===
+
+[[rest_erab_id]]
+==== E-RAB Identifier (`{ErabId}`)
+
+[options="header",cols="25,35,40"]
+|===
+| Form | Pattern | Example
+| Process ID | `pid:<x>.<y>.<z>` | `pid:0.33.1`
+|===
+
+[[rest_metrics]]
+=== Metrics
+
+[[rest_metrics_list]]
+==== `GET /metrics-list` — List Metrics
+
+Returns a list of all matching metrics with their current values.
+
+Query parameters:
+
+`type`::
+ Filter by metric type. One of `all` (default), `counter`, or `gauge`.
+
+`path`::
+ Filter by metric name prefix (dot-separated). For example, `s1ap.proxy`
+ returns all metrics whose name starts with `s1ap.proxy`.
+
+Response (HTTP 200):
+
+----
+[
+ {"type": "counter", "name": "pfcp.heartbeat_req.tx", "value": 42},
+ {"type": "counter", "name": "pfcp.heartbeat_req.timeout", "value": 0},
+ {"type": "gauge", "name": "pfcp.associated", "value": 1}
+]
+----
+
+Returns HTTP 404 if no metrics match the given filter.
+
+See <<metrics>> for the full list of metric names.
+
+[[rest_pfcp]]
+=== PFCP
+
+[[rest_pfcp_assoc]]
+==== `GET /pfcp/assoc` — PFCP Association State
+
+Returns the current PFCP association state between OsmoS1GW and the UPF.
+
+Response (HTTP 200):
+
+----
+{
+ "state": "connected",
+ "laddr": "127.0.1.1",
+ "raddr": "127.0.1.2",
+ "lrts": 3967211233,
+ "rrts": 3965211123
+}
+----
+
+`state`:: Current association state: `connecting` or `connected`.
+`laddr`:: Local PFCP bind address.
+`raddr`:: Remote UPF address.
+`lrts`:: Local Recovery Timestamp.
+`rrts`:: Remote Recovery Timestamp (present only when associated).
+
+==== `POST /pfcp/assoc` — Initiate PFCP Association Setup
+
+Triggers an immediate PFCP Association Setup Request to the UPF.
+Returns an `OperationResult` object indicating success or failure.
+
+==== `DELETE /pfcp/assoc` — Release PFCP Association
+
+Initiates a PFCP Association Release procedure.
+Returns an `OperationResult` object.
+
+==== `POST /pfcp/heartbeat` — Send PFCP Heartbeat
+
+Sends a PFCP Heartbeat Request to the UPF and waits for the response.
+Returns an `OperationResult` object.
+
+[[rest_mme]]
+=== MME Pool
+
+[[rest_mme_list]]
+==== `GET /mme-list` — List MMEs
+
+Returns the current contents of the MME pool.
+
+Response (HTTP 200):
+
+----
+[
+ {"name": "mme0", "laddr": "::", "raddr": "192.168.2.10", "rport": 36412, "tac_list": []},
+ {"name": "mme1", "laddr": "::", "raddr": "192.168.2.20", "rport": 36412, "tac_list": [100, 101]}
+]
+----
+
+[[rest_mme_add]]
+==== `POST /mme-list` — Add MME
+
+Adds a new MME to the pool. The request body is a JSON object with the
+same fields as the entries returned by `GET /mme-list`:
+
+`name` (required):: Unique human-readable name.
+`raddr` (required):: Remote IP address of the MME.
+`laddr` (optional):: Local bind address. Default: `"::"` (any).
+`rport` (optional):: Remote SCTP port. Default: `36412`.
+`tac_list` (optional):: List of TACs this MME serves. Default: `[]` (all).
+
+Returns HTTP 201 on success, HTTP 409 if the name or address is already
+registered.
+
+[[rest_mme_info]]
+==== `GET /mme/{MmeId}` — MME Info
+
+Returns configuration details for a single MME. The response format is
+the same as a single element from `GET /mme-list`.
+
+Returns HTTP 404 if no matching MME is found.
+
+[[rest_mme_delete]]
+==== `DELETE /mme/{MmeId}` — Delete MME
+
+Removes an MME from the pool. Active connections to this MME are not
+affected; the change only prevents the MME from being selected for future
+connection attempts.
+
+Returns HTTP 200 on success, HTTP 404 if no matching MME is found.
+
+[[rest_enb]]
+=== eNB Connections
+
+[[rest_enb_list]]
+==== `GET /enb-list` — List eNB Connections
+
+Returns a list of all currently connected eNBs.
+
+Response (HTTP 200):
+
+----
+[
+ {
+ "handle": 0,
+ "pid": "<0.699.0>",
+ "genb_id": "001-01-0",
+ "state": "connected",
+ "enb_saddr": "192.168.1.10",
+ "enb_sport": 56767,
+ "enb_sctp_aid": 5706,
+ "mme_daddr": "192.168.2.10",
+ "mme_dport": 36412,
+ "mme_sport": 34500,
+ "mme_sctp_aid": 5707,
+ "uptime": 418,
+ "erab_count": 3
+ }
+]
+----
+
+`handle`:: Unique integer identifier within the eNB registry.
+`pid`:: Erlang process ID of the `enb_proxy` process.
+`genb_id`:: Global-eNB-ID in MCC-MNC-eNBId format. Present once the S1
+ Setup procedure has completed.
+`state`:: Current proxy state: `wait_s1setup_req`, `connecting`,
+ `wait_s1setup_rsp`, or `connected`.
+`enb_saddr` / `enb_sport`:: Source address and port of the eNB's SCTP connection.
+`enb_sctp_aid`:: SCTP association ID of the eNB-S1GW connection.
+`mme_daddr` / `mme_dport`:: Destination address and port of the MME.
+`mme_sport`:: Local source port of the S1GW-MME SCTP connection.
+`mme_sctp_aid`:: SCTP association ID of the S1GW-MME connection.
+`uptime`:: Seconds since the eNB connected.
+`erab_count`:: Number of currently active E-RABs for this eNB.
+
+==== `GET /enb/{EnbId}` — eNB Info
+
+Returns details for a single eNB. The response format is the same as a
+single element from `GET /enb-list`.
+
+Returns HTTP 404 if no matching eNB is found.
+
+==== `DELETE /enb/{EnbId}` — Force Disconnect eNB
+
+Forcibly terminates the SCTP connection to the specified eNB. This
+causes the eNB to reconnect and restart the S1 Setup procedure.
+
+Returns HTTP 200 on success, HTTP 404 if no matching eNB is found.
+
+[[rest_erab]]
+=== E-RAB Bearers
+
+==== `GET /erab-list` — List All E-RABs
+
+Returns a list of all active E-RABs across all connected eNBs.
+
+==== `GET /enb/{EnbId}/erab-list` — List E-RABs for an eNB
+
+Returns all active E-RABs for a specific eNB.
+
+Returns HTTP 404 if no matching eNB is found.
+
+The response for both list endpoints is an array of E-RAB objects (same
+format as `GET /erab/{ErabId}`).
+
+==== `GET /erab/{ErabId}` — E-RAB Info
+
+Returns details for a single E-RAB.
+
+Response (HTTP 200):
+
+----
+{
+ "pid": "<0.714.0>",
+ "mme_ue_id": 4242,
+ "erab_id": 1,
+ "state": "erab_setup",
+ "pfcp_lseid": 2,
+ "pfcp_rseid": 6076548759901618177,
+ "f_teid_u2c": {"teid": 65537, "tla": "127.0.0.1"},
+ "f_teid_c2u": {"teid": 16842753, "tla": "127.0.1.1"},
+ "f_teid_a2u": {"teid": 33686529, "tla": "127.0.2.2"},
+ "f_teid_u2a": {"teid": 131073, "tla": "127.0.0.2"}
+}
+----
+
+`pid`:: Erlang process ID of the `erab_fsm` process.
+`mme_ue_id`:: MME-UE-S1AP-ID.
+`erab_id`:: E-RAB-ID.
+`state`:: Current FSM state.
+`pfcp_lseid` / `pfcp_rseid`:: Local and remote PFCP SEIDs.
+`f_teid_u2c`:: GTP-U F-TEID for UPF → Core direction.
+`f_teid_c2u`:: GTP-U F-TEID for Core → UPF direction.
+`f_teid_a2u`:: GTP-U F-TEID for Access (eNB) → UPF direction.
+`f_teid_u2a`:: GTP-U F-TEID for UPF → Access (eNB) direction.
+
+Each F-TEID object has a `teid` (integer) and a `tla` (Transport Layer
+Address, dotted IP string).
+
+==== `DELETE /erab/{ErabId}` — Terminate E-RAB
+
+Forcibly terminates the `erab_fsm` process for the given E-RAB. This
+triggers PFCP Session Deletion towards the UPF. Use with caution on
+live connections.
+
+Returns HTTP 200 on success, HTTP 404 if no matching E-RAB is found.
+
+[[rest_cli]]
+=== Interactive CLI (`osmo-s1gw-cli`)
+
+`osmo-s1gw-cli` is an interactive command-line shell built on Python's
+https://cmd2.readthedocs.io/[cmd2] library. It provides a convenient
+alternative to issuing raw HTTP requests, with tab-completion, filtering
+(`CMD | grep ...`), and output redirection (`CMD > FILE`).
+
+After installation, the CLI is available as `osmo-s1gw-cli`. It
+communicates with OsmoS1GW via the REST interface.
+
+----
+osmo-s1gw-cli [-h] [-v] [-p PORT] [HOST]
+
+ HOST OsmoS1GW REST host/address (default: localhost)
+ -p REST port (default: 8080)
+ -v Enable verbose/debug logging
+----
+
+Available commands can be listed within the shell using `help -v`, and
+per-command help is available with `help <command>`. The following
+commands are supported:
+
+[options="header",cols="30,70"]
+|===
+| Command | Description
+| `fetch_openapi_spec` | Fetch and display the OpenAPI specification
+| `metrics_list` | List metrics, optionally filtered by type and/or name path
+| `pfcp_assoc_state` | Display the PFCP association state
+| `pfcp_heartbeat` | Send a PFCP Heartbeat Request
+| `mme_list` | List registered MMEs
+| `mme_add` | Add an MME to the pool
+| `mme_info` | Show details for a specific MME
+| `mme_delete` | Remove an MME from the pool
+| `enb_list` | List connected eNBs
+| `enb_info` | Show details for a specific eNB
+| `enb_delete` | Force-disconnect an eNB
+| `enb_erab_list` | List E-RABs for a specific eNB
+| `erab_list` | List all E-RABs across all eNBs
+| `erab_info` | Show details for a specific E-RAB
+| `erab_delete` | Terminate an E-RAB FSM process
+|===
+
+// vim:set ts=4 sw=4 et:
diff --git a/doc/manuals/osmo-s1gw-usermanual.adoc b/doc/manuals/osmo-s1gw-usermanual.adoc
index 2427d31..c565911 100644
--- a/doc/manuals/osmo-s1gw-usermanual.adoc
+++ b/doc/manuals/osmo-s1gw-usermanual.adoc
@@ -19,6 +19,8 @@
include::{srcdir}/chapters/gtpu_kpi.adoc[]
+include::{srcdir}/chapters/rest.adoc[]
+
include::{commondir}/chapters/glossary.adoc[]
include::{commondir}/chapters/bibliography.adoc[]
--
To view, visit https://gerrit.osmocom.org/c/erlang/osmo-s1gw/+/42367?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: I8bc9183fff8f65db71554ee26369db9bdb61b78a
Gerrit-Change-Number: 42367
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/+/42364?usp=email )
Change subject: doc/manuals: add overview, document running and configuration
......................................................................
doc/manuals: add overview, document running and configuration
Change-Id: I4ceca069866d7191ef2b153af95a20cb522bffeb
Related: OS#6671
---
M README.md
A doc/manuals/Makefile
A doc/manuals/chapters/configuration.adoc
A doc/manuals/chapters/overview.adoc
A doc/manuals/chapters/running.adoc
A doc/manuals/osmo-s1gw-usermanual-docinfo.xml
A doc/manuals/osmo-s1gw-usermanual.adoc
7 files changed, 730 insertions(+), 38 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/erlang/osmo-s1gw refs/changes/64/42364/1
diff --git a/README.md b/README.md
index 5ff4589..d6a5299 100644
--- a/README.md
+++ b/README.md
@@ -54,8 +54,10 @@
Documentation
-------------
-Once the project reaches a usable milestone, we will be working on a
-user manual. Stay tuned.
+The user manual source is in [`doc/manuals/`](doc/manuals/). It covers
+installation, configuration, metrics, the REST API, and the interactive CLI.
+A pre-built PDF is published on the
+[Osmocom documentation server](https://ftp.osmocom.org/docs/osmo-s1gw).
Contributing
@@ -113,54 +115,39 @@
Installation
------------
-OsmoS1GW is built for common versions of Debian, Ubuntu and other distributions as a part of
-the [Osmocom binary packages](https://osmocom.org/projects/cellular-infrastructure/wiki/Binary_….
-If you're not doing development, it is suggested to simply use those binary packages, rather
-than building from source. Otherwise, you can invoke the `install` target:
+Osmocom provides binary packages for common Debian and Ubuntu releases via
+the [Osmocom binary package feed](https://osmocom.org/projects/cellular-infrastructure/wiki/Binary_Pack….
+Both a stable feed (tracking the latest release) and a nightly feed are
+available. If you are not doing development, using the binary packages is
+the recommended approach.
+
+To build and install from source:
```
+$ make
$ sudo make install
```
-This will install the following:
+`make install` deploys a complete ERTS release together with a convenience
+wrapper script and the interactive CLI tool:
-* `/usr/lib/osmo-s1gw` - complete OTP release package
-* `/usr/bin/osmo-s1gw` - convenience script for running `osmo-s1gw`
-* `/usr/bin/osmo-s1gw-cli` - interactive CLI for `osmo-s1gw`
-* `/lib/systemd/system/osmo-s1gw.service` - systemd unit file
-* `/etc/osmocom/osmo-s1gw.config` - the configuration file
+* `/usr/lib/osmo-s1gw` — complete OTP/ERTS release package
+* `/usr/bin/osmo-s1gw` — bootstrap script for starting the release
+* `/usr/bin/osmo-s1gw-cli` — interactive CLI tool
+* `/lib/systemd/system/osmo-s1gw.service` — systemd unit file
+* `/etc/osmocom/osmo-s1gw.config` — default configuration file
-The installation paths can be adjusted using `DESTDIR`, `LIBDIR`, `BINDIR`,
-`CONFDIR`, and `SYSTEMDUNITDIR` variables.
+Installation paths can be adjusted with `DESTDIR`, `LIBDIR`, `BINDIR`,
+`CONFDIR`, and `SYSTEMDUNITDIR`. See the user manual for full details.
Configuration
-------------
-The default configuration can be found in
-[config/sys.config](config/sys.config).
-
-The existing parameters can be represented as follows:
-
-```
- eNB S1GW
-+-----+ +----------------+
-| ... | --> | s1gw_bind_addr | MME
-+-----+ +----------------+ +-----------------+
- | mme_loc_addr | --> | mme_rem_addr |
- +----------------+ +-----------------+
-```
-
-* `s1gw_bind_addr` - S1GW bind address for incoming eNB connections
-* `mme_loc_addr` - local address for outgoing connections to the MME
-* `mme_rem_addr` - remote address for outgoing connections to the MME
-
-Logging can be configured in the `kernel` section:
-
-* `{logger_level, info}` - logging level (one of `emergency | alert |
- critical | error | warning | notice |
- info | debug`)
-* `#{formatter => { ... }` - logging formatting configuration
+The default configuration file is [`config/sys.config`](config/sys.config).
+For a full description of all available configuration parameters, see the
+Configuration chapter in the user manual
+([`doc/manuals/chapters/configuration.adoc`](doc/manuals/chapters/configuration.adoc)).
REST interface
diff --git a/doc/manuals/Makefile b/doc/manuals/Makefile
new file mode 100644
index 0000000..b56e51d
--- /dev/null
+++ b/doc/manuals/Makefile
@@ -0,0 +1,16 @@
+OSMO_GSM_MANUALS_DIR ?= $(shell pkg-config osmo-gsm-manuals --variable=osmogsmmanualsdir 2>/dev/null)
+ifeq ($(OSMO_GSM_MANUALS_DIR),)
+$(error "osmo-gsm-manuals not found via pkg-config. Please install it.")
+endif
+
+# Without autotools, srcdir must be set explicitly so that Makefile.asciidoc.inc
+# can resolve {srcdir} in AsciiDoc include directives correctly.
+srcdir ?= $(CURDIR)
+
+ASCIIDOC = osmo-s1gw-usermanual.adoc
+include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.asciidoc.inc
+
+osmo-s1gw-usermanual.pdf: $(wildcard chapters/*.adoc)
+
+OSMO_REPOSITORY = osmo-s1gw
+include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.common.inc
diff --git a/doc/manuals/chapters/configuration.adoc b/doc/manuals/chapters/configuration.adoc
new file mode 100644
index 0000000..53e23e5
--- /dev/null
+++ b/doc/manuals/chapters/configuration.adoc
@@ -0,0 +1,304 @@
+[[configuration]]
+== Configuration
+
+OsmoS1GW is configured through an Erlang/OTP system configuration file.
+By default this file is `config/sys.config` in the source tree, or
+`/etc/osmocom/osmo-s1gw.config` after installation. A different path
+can be supplied at start time via the `-c` option of the `osmo-s1gw`
+bootstrap script (see <<running_bootstrap_script>>) or via the `CONFIG`
+variable when using the project Makefile (see <<running_building_make_targets>>).
+
+The file uses Erlang term syntax. The top level is a list of
+`{ApplicationName, [{Key, Value}, ...]}` tuples. OsmoS1GW-specific
+parameters live under the `osmo_s1gw` application key. Kernel
+parameters (logging) live under the standard `kernel` key, and metrics
+reporting parameters under the `exometer_core` key.
+
+[[config_sctp_server]]
+=== `sctp_server` — eNB-Facing SCTP Listener
+
+This section controls the SCTP socket on which OsmoS1GW listens for
+incoming connections from eNodeBs.
+
+----
+{sctp_server, #{
+ laddr => "127.0.1.1", %% local bind address
+ lport => 36412, %% local bind port (S1AP standard port)
+ sockopts => #{ } %% optional socket options (see below)
+}}
+----
+
+`laddr`::
+ IP address to bind to. Accepts a string in dotted-decimal (IPv4) or
+ colon-separated (IPv6) notation, or the atom `any` to bind to all
+ interfaces. Default: `"127.0.1.1"`.
+
+`lport`::
+ TCP/SCTP port to listen on. Default: `36412` (the IANA-assigned S1AP
+ port).
+
+`sockopts`::
+ An optional map of additional SCTP socket options:
++
+[options="header",cols="20,60,20"]
+|===
+| Option | Description | Default
+| `recbuf` | Receive buffer size in bytes | `65536`
+| `sndbuf` | Send buffer size in bytes | `65536`
+| `nodelay` | Disable Nagle algorithm (`true` to disable) | `true`
+|===
+
+[[config_mme_pool]]
+=== `mme_pool` — MME Pool Configuration
+
+The `mme_pool` key defines the list of MMEs that OsmoS1GW may connect to
+on behalf of connecting eNBs. This is the recommended way to configure
+MME connectivity; it supports multiple MMEs and TAC-based selection.
+
+----
+{mme_pool, [
+ #{
+ name => "mme0", %% unique name (required)
+ raddr => "192.168.2.10", %% MME IP address (required)
+ rport => 36412, %% MME SCTP port (default: 36412)
+ laddr => any, %% local bind address (default: any)
+ tac_list => [] %% allowed TACs (default: [] = all)
+ },
+ #{
+ name => "mme1",
+ raddr => "192.168.2.20",
+ tac_list => [100, 101, 102]
+ }
+]}
+----
+
+Each entry in the list is a map with the following fields:
+
+`name`::
+ A unique, human-readable string identifying this MME in log messages,
+ the REST API, and per-MME metrics. Required.
+
+`raddr`::
+ The remote IP address of the MME. Required.
+
+`rport`::
+ The remote SCTP port of the MME. Default: `36412`.
+
+`laddr`::
+ The local IP address to bind to when connecting to this MME. Accepts
+ a string or the atom `any`. Default: `any`.
+
+`tac_list`::
+ A list of Tracking Area Codes (TACs) that this MME is willing to serve.
+ When an eNB connects and sends its S1 Setup Request, OsmoS1GW filters
+ the pool to MMEs whose `tac_list` is a superset of the eNB's
+ advertised TACs. An empty list means the MME accepts all TACs.
+ Default: `[]`.
+
+MMEs can also be added and removed at run time via the REST API without
+restarting OsmoS1GW (see <<rest_mme>>).
+
+NOTE: The `mme_pool` key is mutually exclusive with the deprecated
+`sctp_client` key described in the next section. If `mme_pool` is
+present, keys `laddr`, `raddr`, and `rport` from the `sctp_client`
+block are ignored.
+
+[[config_sctp_client]]
+=== `sctp_client` — Single MME (Deprecated)
+
+Prior to the introduction of MME pooling, the outbound MME connection was
+configured via the `sctp_client` section:
+
+----
+{sctp_client, #{
+ laddr => "127.0.2.1", %% local bind address
+ raddr => "127.0.2.10", %% MME IP address
+ rport => 36412, %% MME SCTP port
+ sockopts => #{ } %% optional socket options (same as sctp_server)
+}}
+----
+
+When OsmoS1GW starts and finds no `mme_pool` key in the configuration,
+it automatically creates a single `"default"` MME pool entry from the
+`sctp_client` parameters and logs a deprecation warning. This allows
+existing single-MME deployments to continue working without changes, but
+migration to `mme_pool` is strongly recommended.
+
+NOTE: The socket options (`sockopts`) from the `sctp_client` section are
+still used for the outbound SCTP socket regardless of whether `mme_pool`
+or `sctp_client` is used for MME addressing.
+
+[[config_pfcp]]
+=== PFCP — User Plane Function
+
+These parameters control the PFCP session between OsmoS1GW and the UPF.
+
+----
+{pfcp_loc_addr, "127.0.1.1"}, %% local address for PFCP (UDP)
+{pfcp_rem_addr, "127.0.1.2"}, %% remote address of the UPF
+
+%% Optional Network Instance IEs:
+%% {pfcp_net_inst_core, "core-side"},
+%% {pfcp_net_inst_access, "radio-side"}
+----
+
+`pfcp_loc_addr`::
+ Local IP address on which OsmoS1GW listens for PFCP messages from the
+ UPF. Default: `"127.0.1.1"`.
+
+`pfcp_rem_addr`::
+ Remote IP address of the UPF. Default: `"127.0.1.2"`.
+
+`pfcp_net_inst_core`::
+ Value for the PFCP Network Instance IE on the core-network side of each
+ GTP-U session. Omit if the UPF does not require Network Instance IEs.
+
+`pfcp_net_inst_access`::
+ Value for the PFCP Network Instance IE on the radio-access side of each
+ GTP-U session. Omit if the UPF does not require Network Instance IEs.
+
+[[config_gtpu_kpi]]
+=== 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.
+
+----
+%% {gtpu_kpi_enable, true},
+%% {gtpu_kpi_table_name, "osmo-s1gw"},
+%% {gtpu_kpi_ul_addr, s1ap},
+%% {gtpu_kpi_dl_addr, s1ap},
+%% {gtpu_kpi_interval, 3000}
+----
+
+`gtpu_kpi_enable`::
+ Set to `true` to enable the GTP-U KPI module. Default: `false`.
+
+`gtpu_kpi_table_name`::
+ The nftables table name to read counters from.
+ Default: `"osmo-s1gw"`.
+
+`gtpu_kpi_ul_addr`::
+ Source of the uplink GTP-U address used to match nftables counters.
+ `s1ap` means learn the address from S1AP signalling; `sctp` means use
+ the eNB's SCTP source address. Default: `s1ap`.
+
+`gtpu_kpi_dl_addr`::
+ Source of the downlink GTP-U address. Same options as `gtpu_kpi_ul_addr`.
+ Default: `s1ap`.
+
+`gtpu_kpi_interval`::
+ How often (in milliseconds) to poll the nftables counters.
+ Default: `3000`.
+
+[[config_rest]]
+=== REST Interface
+
+----
+%% {rest_srv_port, 8080},
+%% {rest_srv_swagger_ui, true}
+----
+
+`rest_srv_port`::
+ TCP port on which the HTTP REST server listens. Default: `8080`.
+
+`rest_srv_swagger_ui`::
+ Whether to serve the Swagger UI at `http://host:rest_srv_port/swagger`.
+ Default: `true`.
+
+[[config_kernel]]
+=== `kernel` — Logging
+
+OsmoS1GW uses the standard Erlang/OTP `logger` framework. The `kernel`
+application section controls log levels and handlers. See
+<<running_logging>> for a description of the log handlers configured by
+default.
+
+----
+{kernel, [
+ {logger_level, debug},
+ {logger, [
+ {handler, gsmtap, logger_gsmtap_h,
+ #{level => debug,
+ config => #{rem_addr => "127.0.0.1",
+ app_name => "OsmoS1GW"}}},
+ {handler, default, logger_std_h,
+ #{level => info,
+ formatter => {logger_color_formatter, #{...}}}}
+ ]}
+]}
+----
+
+`logger_level`::
+ The global minimum log level. Log records below this level are
+ discarded before reaching any handler. Common values: `debug`,
+ `info`, `notice`, `warning`, `error`.
+
+For each handler in the `logger` list:
+
+`level`::
+ Handler-specific minimum log level. Can be set independently per
+ handler to, for example, send only `warning` and above to the console
+ while sending all `debug` output over GSMTAP.
+
+`gsmtap` handler (`logger_gsmtap_h`)::
+ Sends log messages as GSMTAP frames over UDP.
++
+`rem_addr`::: Destination IP address. Default: `"127.0.0.1"`.
+`app_name`::: Application name tag embedded in each GSMTAP frame.
+
+`default` handler (`logger_std_h`)::
+ Writes log lines to standard output. When OsmoS1GW runs under systemd
+ this output is captured by the journal.
+
+[[config_exometer]]
+=== `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.
+
+The default configuration reports all counters and gauges to a StatsD
+server:
+
+----
+{exometer_core, [
+ {report, [
+ {reporters, [
+ {exometer_report_statsd, [
+ {hostname, "127.0.4.10"},
+ {port, 8125},
+ {prefix, "s1gw"},
+ {type_map, []}
+ ]}
+ ]},
+ {subscribers, [
+ {select, {[{ {['_'|'_'], counter, '_'}, [], ['$_']}],
+ exometer_report_statsd, value, 1000, true,
+ [{report_type, counter}]}},
+ {select, {[{ {['_'|'_'], gauge, '_'}, [], ['$_']}],
+ exometer_report_statsd, value, 1000, true,
+ [{report_type, gauge}]}}
+ ]}
+ ]}
+]}
+----
+
+`hostname`::
+ IP address or hostname of the StatsD server.
+
+`port`::
+ UDP port of the StatsD server. Default: `8125`.
+
+`prefix`::
+ String prepended to all metric names as reported to StatsD.
+ Default: `"s1gw"`.
+
+The `subscribers` list uses exometer's `select` mechanism to
+automatically subscribe all counters and gauges to the StatsD reporter
+with a reporting interval of 1000 ms. To disable StatsD reporting,
+comment out or remove the `exometer_report_statsd` reporter entry.
+
+// vim:set ts=4 sw=4 et:
diff --git a/doc/manuals/chapters/overview.adoc b/doc/manuals/chapters/overview.adoc
new file mode 100644
index 0000000..d8248ca
--- /dev/null
+++ b/doc/manuals/chapters/overview.adoc
@@ -0,0 +1,121 @@
+[[overview]]
+== Overview
+
+[[about]]
+=== About OsmoS1GW
+
+OsmoS1GW is an S1 Gateway for LTE (4G) networks, developed by
+https://www.sysmocom.de/[sysmocom]. It acts as a transparent proxy
+between eNodeBs (eNBs, i.e. radio base stations) and one or more MMEs
+(Mobility Management Entities), relaying S1AP signalling over SCTP/IP in
+both directions.
+
+In addition to S1AP proxying, OsmoS1GW manages GTP-U data plane tunnels
+(E-RABs / EPS bearers) by communicating with a co-located UPF (User
+Plane Function) via PFCP. OsmoS1GW does not carry GTP-U traffic itself:
+GTP-U flows directly between the eNB and the UPF (access side), and
+between the UPF and the S-GW of the core network (core side). OsmoS1GW
+only instructs the UPF — via PFCP Session Establishment, Modification,
+and Deletion procedures — to create, update, or tear down the
+corresponding forwarding rules. It also rewrites the GTP-U TEID and
+Transport Layer Address (TLA) IEs inside S1AP messages so that eNBs send
+their GTP-U traffic to the UPF rather than directly to the core network.
+
+[[architecture]]
+=== Architecture
+
+The following diagram shows the high-level data flow through OsmoS1GW:
+
+----
+ S1AP/SCTP S1AP/SCTP
+eNB <----------> S1GW <----------> MME (core)
+ ^ ^
+ | |
+ | GTP-U | PFCP
+ | |
+ | GTP-U V GTP-U
+ +-------------> UPF <-----------> S-GW (core)
+----
+
+All S1AP messages are inspected by the gateway. Most are forwarded
+unchanged; those that carry GTP-U endpoint information (E-RAB Setup,
+Modify, Release, Initial Context Setup, etc.) are rewritten so that the
+UPF's TLA/TEID is substituted for the core network's endpoint before
+forwarding to the eNB. GTP-U traffic itself never passes through
+OsmoS1GW — it flows directly between the eNB and the UPF, and between
+the UPF and the S-GW.
+
+Internally, OsmoS1GW is structured as a set of Erlang/OTP processes:
+
+* *`sctp_server`* — Listens for incoming eNB SCTP connections and spawns
+ one `enb_proxy` instance per connection.
+* *`enb_proxy`* — One instance per connected eNB. Manages the outbound
+ SCTP connection to the selected MME and drives the S1 Setup handshake.
+ Implements MME pooling and retry logic.
+* *`s1ap_proxy`* — Paired with each `enb_proxy`. Inspects S1AP PDUs in
+ both directions and manages per-UE `erab_fsm` instances.
+* *`erab_fsm`* — One instance per active E-RAB. Exchanges PFCP Session
+ Establishment/Modification/Deletion messages with the UPF and rewrites
+ GTP-U F-TEID IEs in S1AP messages.
+* *`pfcp_peer`* — Manages the PFCP association with the UPF (UDP-based),
+ including periodic heartbeat and SEID allocation.
+* *`mme_registry`* — Manages the pool of known MMEs. MMEs can be
+ provisioned statically via the configuration file or dynamically via
+ the REST API.
+* *`enb_registry`* — Tracks all active eNB connections and their state.
+ Queryable via the REST API.
+* *`rest_server`* — OpenAPI-based HTTP REST interface for monitoring and
+ management.
+
+[[use_cases]]
+=== Use Cases
+
+[[use_case_isolated_networks]]
+==== Separated Core and Access Networks
+
+A common deployment scenario in private or industrial LTE networks is one
+where the core network (EPC) and the radio access network (RAN) reside in
+strictly separated IP domains with no direct routing between them — for
+example, a dedicated operations network for eNBs and a separate
+production network for the EPC.
+
+In this configuration, OsmoS1GW is deployed at the boundary between the
+two networks. Each eNB connects to the gateway's access-facing SCTP
+listener, and the gateway in turn connects outward to the MME. The eNBs
+never need a route to the core, and the EPC never needs a route to the
+radio access domain.
+
+----
+ +-----------+ +----------+ +-----+
+ | eNB |--S1AP/-->| OsmoS1GW |--S1AP/-->| MME |
+ | (RAN net) | SCTP | (border) | SCTP +-----+
+ +-----------+ +----------+
+ | | PFCP
+ | GTP-U +----+
+ +-------------->| UPF |-----> S-GW (EPC net)
+ +-----+
+----
+
+The gateway acts as the sole point of contact between the two networks,
+providing a natural place to apply access control, logging, and
+monitoring.
+
+[[use_case_mme_pooling]]
+==== MME Pooling
+
+OsmoS1GW supports connecting multiple MMEs in a pool. When an eNB
+connects and performs the S1 Setup procedure, the gateway selects an MME
+from the pool, establishes an SCTP connection to it, and forwards the S1
+Setup Request. If the selected MME rejects the setup or is unreachable,
+the gateway automatically retries with the next candidate in the pool
+before returning a failure to the eNB.
+
+Pool members can be filtered by Tracking Area Code (TAC): each MME entry
+in the pool can carry an optional list of TACs it is willing to serve.
+The gateway uses the TAC list advertised by the eNB in the S1 Setup
+Request to restrict selection to compatible MMEs.
+
+MMEs can be configured statically in the configuration file or managed
+dynamically at run time via the REST API (see <<rest_mme>>).
+
+// vim:set ts=4 sw=4 et:
diff --git a/doc/manuals/chapters/running.adoc b/doc/manuals/chapters/running.adoc
new file mode 100644
index 0000000..743456f
--- /dev/null
+++ b/doc/manuals/chapters/running.adoc
@@ -0,0 +1,204 @@
+[[running]]
+== Running OsmoS1GW
+
+[[running_requirements]]
+=== Requirements
+
+OsmoS1GW requires:
+
+* Erlang/OTP 25 or later.
+* A Linux kernel with SCTP support (`sctp` kernel module).
+* A reachable UPF that speaks PFCP (e.g. https://osmocom.org/projects/osmo-upf[OsmoUPF]).
+* One or more reachable MMEs (e.g. https://github.com/open5gs/open5gs[Open5GS]).
+
+[[running_installation_options]]
+=== Installation Options
+
+[[running_binary_packages]]
+==== Official Osmocom Binary Packages
+
+Osmocom provides binary packages of OsmoS1GW for a variety of GNU/Linux
+distributions, primarily Debian based ones. This is the recommended
+installation method for production deployments.
+
+Two package feeds are available:
+
+`latest`::
+ Contains the most recent tagged release of each program.
+ Suitable for production use.
+
+`nightly`::
+ Contains automatic nightly builds from the current master branch.
+ Useful for testing new features or bug fixes before they are formally released.
+
+For up-to-date instructions on how to add the Osmocom package repository
+for your distribution, see:
+https://osmocom.org/projects/cellular-infrastructure/wiki/Binary_Packages
+
+[[running_building]]
+==== Building from Source
+
+OsmoS1GW uses https://rebar3.org[rebar3] as its build tool, wrapped by a
+convenience `Makefile` in the project root. To fetch dependencies and
+compile:
+
+----
+git clone https://gitea.osmocom.org/osmocom/osmo-s1gw.git
+cd osmo-s1gw
+make
+----
+
+[[running_building_make_targets]]
+===== Available Make Targets
+
+The following targets are available:
+
+`make` / `make build`::
+ Compile the application and all dependencies (default target).
+
+`make shell` / `make run`::
+ Compile and start OsmoS1GW in an interactive Erlang shell. Intended
+ for development and local testing. The config file used is controlled
+ by the `CONFIG` variable (default: `config/sys.config`).
+
+`make check`::
+ Run the EUnit test suite. Additional arguments can be passed to the
+ test runner via the `EUNIT_ARGS` variable.
+
+`make analyze`::
+ Run Dialyzer static type analysis.
+
+`make release`::
+ Build a self-contained Erlang/OTP release package (includes the ERTS
+ runtime) under `_build/default/rel/osmo-s1gw/`.
+
+`make run-release`::
+ Build the release and immediately start it using the `osmo-s1gw.sh`
+ bootstrap script (see <<running_bootstrap_script>>). The `CONFIG`
+ variable selects the config file.
+
+`make install`::
+ Build the release and install OsmoS1GW system-wide. See
+ <<running_building_installation>> for details.
+
+`make clean`::
+ Remove all build artefacts.
+
+[[running_building_make_variables]]
+===== Make Variables
+
+The following variables customise the build and installation:
+
+[options="header",cols="25,50,25"]
+|===
+| Variable | Description | Default
+| `CONFIG` | Config file used by `make shell` and `make run-release` | `config/sys.config`
+| `EUNIT_ARGS` | Extra arguments forwarded to `rebar3 eunit` | (none)
+| `BINDIR` | Installation directory for executables | `/usr/bin`
+| `LIBDIR` | Installation directory for the release package | `/usr/lib`
+| `CONFDIR` | Installation directory for the config file | `/etc/osmocom`
+| `SYSTEMDUNITDIR` | Installation directory for the systemd unit | `/lib/systemd/system`
+| `DESTDIR` | Staging root prefix (for package builds) | (empty)
+|===
+
+[[running_building_installation]]
+===== Installation
+
+Running `make install` (typically as root, or with `DESTDIR` set for
+packaging) performs the following steps:
+
+* Copies the self-contained Erlang/OTP release to `$(LIBDIR)/osmo-s1gw`
+ (default: `/usr/lib/osmo-s1gw`). This directory bundles the ERTS
+ runtime and all application code, so no separate Erlang installation is
+ required on the target system.
+* Installs the `osmo-s1gw.sh` bootstrap script (see
+ <<running_bootstrap_script>>) as `$(BINDIR)/osmo-s1gw`
+ (default: `/usr/bin/osmo-s1gw`).
+* Installs the `osmo-s1gw-cli.py` management CLI as
+ `$(BINDIR)/osmo-s1gw-cli` (default: `/usr/bin/osmo-s1gw-cli`).
+* Installs the example `config/sys.config` as
+ `$(CONFDIR)/osmo-s1gw.config` (default: `/etc/osmocom/osmo-s1gw.config`).
+* Installs the systemd unit file to `$(SYSTEMDUNITDIR)/osmo-s1gw.service`
+ (default: `/lib/systemd/system/osmo-s1gw.service`).
+
+[[running_options]]
+=== Running Options
+
+[[running_bootstrap_script]]
+==== The `osmo-s1gw` Bootstrap Script
+
+The installed `osmo-s1gw` executable is a POSIX shell script
+(`contrib/osmo-s1gw.sh`) that locates the bundled ERTS runtime inside
+the release package and launches `erlexec` with the correct boot, config,
+and node parameters. It is the standard entry point both for systemd and
+for manual invocation.
+
+Usage:
+
+----
+osmo-s1gw [-s] [-r ROOTDIR] [-c CONFIG] [-C COOKIE] [-n NAME@HOST]
+----
+
+Options:
+
+`-r ROOTDIR`::
+ Path to the Erlang/OTP release root directory.
+ Default: `/usr/lib/osmo-s1gw`.
+
+`-c CONFIG`::
+ Path to the configuration file.
+ Default: `/etc/osmocom/osmo-s1gw.config`.
+
+`-C COOKIE`::
+ Erlang distribution cookie used for inter-node communication.
+ Default: `osmo-s1gw`.
+
+`-n NAME@HOST`::
+ Erlang node name. Default: `osmo-s1gw@<hostname>`.
+
+`-s`::
+ Start with an interactive Erlang shell instead of running headless.
+ Useful for debugging on a deployed system.
+
+[[running_systemd]]
+==== Running Under systemd
+
+After installation, enable and start OsmoS1GW as a systemd service:
+
+----
+systemctl enable osmo-s1gw
+systemctl start osmo-s1gw
+----
+
+The unit file runs OsmoS1GW as the `osmocom` user and group and requests
+the `CAP_NET_ADMIN` capability (required for GTP-U KPI monitoring).
+The service is restarted automatically on failure with a 2-second delay.
+OsmoS1GW reads its configuration from `/etc/osmocom/osmo-s1gw.config`.
+
+To inspect the log output:
+
+----
+journalctl -u osmo-s1gw -f
+----
+
+[[running_logging]]
+=== Logging
+
+OsmoS1GW uses the standard Erlang/OTP `logger` framework. Two log
+handlers are configured by default in `config/sys.config`:
+
+`default`::
+ Writes formatted log lines to standard output. When running under
+ systemd this output is captured by the journal. The log level is set
+ to `info` by default.
+
+`gsmtap`::
+ Sends log messages as GSMTAP frames over UDP to a configurable
+ destination (default: `127.0.0.1`). These frames can be captured with
+ Wireshark and are tagged with the application name `OsmoS1GW`.
+
+The global minimum log level is controlled by the `logger_level` kernel
+parameter; individual handler levels can be overridden independently.
+See <<config_kernel>> for the relevant configuration section.
+
+// vim:set ts=4 sw=4 et:
diff --git a/doc/manuals/osmo-s1gw-usermanual-docinfo.xml b/doc/manuals/osmo-s1gw-usermanual-docinfo.xml
new file mode 100644
index 0000000..27fd2f3
--- /dev/null
+++ b/doc/manuals/osmo-s1gw-usermanual-docinfo.xml
@@ -0,0 +1,38 @@
+<revhistory>
+ <revision>
+ <revnumber>1</revnumber>
+ <date>March 2026</date>
+ <authorinitials>s</authorinitials>
+ <revremark>Initial version</revremark>
+ </revision>
+</revhistory>
+
+<authorgroup>
+ <author>
+ <firstname>sysmocom</firstname>
+ <surname>- s.f.m.c. GmbH</surname>
+ <email>info(a)sysmocom.de</email>
+ </author>
+</authorgroup>
+
+<copyright>
+ <year>2025-2026</year>
+ <holder>sysmocom - s.f.m.c. GmbH</holder>
+</copyright>
+
+<legalnotice>
+ <para>
+ Permission is granted to copy, distribute and/or modify this document
+ under the terms of the GNU Free Documentation License, Version 1.3 or
+ any later version published by the Free Software Foundation; with no
+ Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A
+ copy of the license is included in the section entitled "GNU Free
+ Documentation License".
+ </para>
+ <para>
+ The Asciidoc source code of this manual can be found at
+ <ulink url="https://gitea.osmocom.org/osmocom/osmo-s1gw">
+ https://gitea.osmocom.org/osmocom/osmo-s1gw
+ </ulink>
+ </para>
+</legalnotice>
diff --git a/doc/manuals/osmo-s1gw-usermanual.adoc b/doc/manuals/osmo-s1gw-usermanual.adoc
new file mode 100644
index 0000000..13dcd4b
--- /dev/null
+++ b/doc/manuals/osmo-s1gw-usermanual.adoc
@@ -0,0 +1,22 @@
+OsmoS1GW User Manual
+====================
+:author: sysmocom - s.f.m.c. GmbH
+:toc:
+:numbered:
+:toclevels: 5
+:sectnumlevels: 5
+
+
+include::{commondir}/chapters/preface.adoc[]
+
+include::{srcdir}/chapters/overview.adoc[]
+
+include::{srcdir}/chapters/running.adoc[]
+
+include::{srcdir}/chapters/configuration.adoc[]
+
+include::{commondir}/chapters/glossary.adoc[]
+
+include::{commondir}/chapters/bibliography.adoc[]
+
+include::{commondir}/chapters/gfdl.adoc[]
--
To view, visit https://gerrit.osmocom.org/c/erlang/osmo-s1gw/+/42364?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: I4ceca069866d7191ef2b153af95a20cb522bffeb
Gerrit-Change-Number: 42364
Gerrit-PatchSet: 1
Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de>
Hello Jenkins Builder,
I'd like you to reexamine a change. Please visit
https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/42360?usp=email
to look at the new patch set (#2).
The following approvals got outdated and were removed:
Verified+1 by Jenkins Builder
Change subject: s1gw: add tests for MME registry REST procedures
......................................................................
s1gw: add tests for MME registry REST procedures
Add three test cases exercising the S1GW REST interface for MME pool
management. The REST TCs are gated on the mp_rest_enable module
parameter in the control block.
TC_rest_mme_list: query the MME pool list via REST and verify it
matches the three static entries from the 'mme_pool' section in
osmo-s1gw.config (mme0/mme1/mme2 with their respective addresses).
TC_rest_mme_add_del: add a new MME entry at runtime via REST, verify
it appears in both the list and individual GET responses, then delete
it and confirm it is gone.
TC_rest_mme_del_fallback: delete mme0 from the pool at runtime and
verify that a connecting eNB is routed directly to mme1, skipping the
deleted entry. The pool is restored to its original state afterwards
via f_REST_mme_pool_restore().
Also add:
* {ts,tr}_MmeItem templates to S1GW_REST_Types.ttcn
* f_REST_mme_find(): returns the integer index of a named entry in a
MmeList, or -1 if not found; used for both presence and absence checks
* f_REST_mme_pool_restore(): deletes all current entries and re-adds
mme0/mme1/mme2 in original order to keep pool state predictable
across test cases
Change-Id: I260bc987ab8ae0ecb547d0b69b261fd97c5c9c23
Related: SYS#7052
---
M s1gw/S1GW_REST_Types.ttcn
M s1gw/S1GW_Tests.ttcn
M s1gw/expected-results.xml
3 files changed, 199 insertions(+), 1 deletion(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-ttcn3-hacks refs/changes/60/42360/2
--
To view, visit https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/42360?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: newpatchset
Gerrit-Project: osmo-ttcn3-hacks
Gerrit-Branch: master
Gerrit-Change-Id: I260bc987ab8ae0ecb547d0b69b261fd97c5c9c23
Gerrit-Change-Number: 42360
Gerrit-PatchSet: 2
Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
fixeria has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/42362?usp=email )
Change subject: s1gw: use REST interface to check PFCP assoc state
......................................................................
s1gw: use REST interface to check PFCP assoc state
It's quicker to query the IUT using the REST interface rather than
waiting for StatsD metric "gauge.pfcp.associated.value" to be received.
As a bonus, we "learn" the local/remote RTS from the S1GW, which can
be used in new PFCP related testcases.
Change-Id: Iec7594e79f533b08ee93b443a39cb9c8ff03da43
---
M s1gw/S1GW_ConnHdlr.ttcn
M s1gw/S1GW_Tests.ttcn
2 files changed, 13 insertions(+), 16 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-ttcn3-hacks refs/changes/62/42362/1
diff --git a/s1gw/S1GW_ConnHdlr.ttcn b/s1gw/S1GW_ConnHdlr.ttcn
index 574a2d0..fd171d3 100644
--- a/s1gw/S1GW_ConnHdlr.ttcn
+++ b/s1gw/S1GW_ConnHdlr.ttcn
@@ -434,16 +434,7 @@
function f_ConnHdlr_pfcp_assoc_handler(charstring id)
runs on ConnHdlr {
- var charstring key_name := g_pars.statsd_prefix & "gauge.pfcp.associated.value";
- var StatsDMetricKeys statsd_keys := { valueof(ts_StatsDMetricKey(key_name, "g")) };
- var StatsDMetrics statsd_snapshot := f_statsd_snapshot(statsd_keys, since_last_snapshot := false);
- var boolean pfcp_associated := statsd_snapshot[0].val == 1;
-
- if (not pfcp_associated) {
- log("Waiting for IUT to associate over PFCP");
- f_ConnHdlr_pfcp_assoc_setup();
- }
-
+ f_ConnHdlr_pfcp_assoc_setup();
setverdict(pass);
}
diff --git a/s1gw/S1GW_Tests.ttcn b/s1gw/S1GW_Tests.ttcn
index b7b01b1..f86546c 100644
--- a/s1gw/S1GW_Tests.ttcn
+++ b/s1gw/S1GW_Tests.ttcn
@@ -76,6 +76,7 @@
var S1AP_ServerList vc_S1APSRVs := {};
var PFCP_Emulation_CT vc_PFCP;
var StatsD_Checker_CT vc_STATSD;
+ var PfcpAssocInfo g_pfcp_assoc;
};
private altstep as_Tguard() runs on test_CT {
@@ -98,11 +99,11 @@
if (s1apsrv_start) {
f_init_s1ap_srv(num_mmes);
}
+ f_init_rest();
if (upf_start) {
f_init_pfcp();
f_pfcp_assoc();
}
- f_init_rest();
}
/* compute the IP address for pool MME server [idx]: mp_mme_bind_ip + idx */
@@ -140,11 +141,16 @@
var verdicttype verdict;
var ConnHdlr vc_conn;
- vc_conn := f_ConnHdlr_spawn(refers(f_ConnHdlr_pfcp_assoc_handler),
- pars := valueof(t_ConnHdlrPars));
- vc_conn.done -> value verdict;
- if (verdict != pass) {
- Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
+ g_pfcp_assoc := f_REST_PfcpAssocState();
+ if (g_pfcp_assoc.state != connected) {
+ log("Waiting for IUT to associate over PFCP");
+ vc_conn := f_ConnHdlr_spawn(refers(f_ConnHdlr_pfcp_assoc_handler),
+ pars := valueof(t_ConnHdlrPars));
+ vc_conn.done -> value verdict;
+ if (verdict != pass) {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
+ }
+ g_pfcp_assoc := f_REST_PfcpAssocState();
}
}
--
To view, visit https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/42362?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: Iec7594e79f533b08ee93b443a39cb9c8ff03da43
Gerrit-Change-Number: 42362
Gerrit-PatchSet: 1
Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de>
Hello Jenkins Builder,
I'd like you to reexamine a change. Please visit
https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/42361?usp=email
to look at the new patch set (#2).
The following approvals got outdated and were removed:
Verified+1 by Jenkins Builder
Change subject: s1gw: enable the REST interface, fix wrong REST port
......................................................................
s1gw: enable the REST interface, fix wrong REST port
REST had been disabled because only nightly builds supported it.
The latest stable release (v0.4.0) also supports the REST interface,
so let's enable it unconditionally by removing the mp_rest_enable.
Also fix the REST port: mp_rest_port was incorrectly set
to 8125 (the StatsD port) instead of the actual REST port 8080.
Change-Id: I012749076c652ab541e569026eb01c696ad5adc8
Related: SYS#7052, SYS#7066
---
M s1gw/S1GW_Tests.cfg
M s1gw/S1GW_Tests.ttcn
2 files changed, 8 insertions(+), 16 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-ttcn3-hacks refs/changes/61/42361/2
--
To view, visit https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/42361?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: newpatchset
Gerrit-Project: osmo-ttcn3-hacks
Gerrit-Branch: master
Gerrit-Change-Id: I012749076c652ab541e569026eb01c696ad5adc8
Gerrit-Change-Number: 42361
Gerrit-PatchSet: 2
Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
fixeria has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/42359?usp=email )
Change subject: s1gw: add testcases for impatient eNB during MME pool selection
......................................................................
s1gw: add testcases for impatient eNB during MME pool selection
Two new test cases covering scenarios where the eNB disconnects before
S1 setup completes, targeting specific states of the enb_proxy FSM:
* TC_mme_pool_enb_disc_wait_s1setup_req: eNB connects but disconnects
before sending S1SetupReq (enb_proxy in wait_s1setup_req). No MME
connection is ever attempted; S1GW must handle the disconnect cleanly.
* TC_mme_pool_enb_disc_wait_s1setup_rsp: eNB sends S1SetupReq, S1GW
forwards it to the first pool MME (enb_proxy in wait_s1setup_rsp),
then eNB disconnects before the response arrives. S1GW must detect
the eNB disconnect and close the open MME connection in response.
A new helper S1GW_ConnHdlr.f_ConnHdlr_s1ap_close() is added for these
tests: unlike f_ConnHdlr_s1ap_disconnect(), it closes the eNB-side
socket without waiting for an S1APSRV_EVENT_CONN_DOWN from a pool
server (since in these scenarios either no MME connection exists
yet, or the CONN_DOWN is captured by the test body directly).
Change-Id: I5d27cdafcb9f595a2d3db59beff17cd55de2539e
Related: SYS#7052
---
M s1gw/S1GW_ConnHdlr.ttcn
M s1gw/S1GW_Tests.ttcn
M s1gw/expected-results.xml
3 files changed, 82 insertions(+), 1 deletion(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-ttcn3-hacks refs/changes/59/42359/1
diff --git a/s1gw/S1GW_ConnHdlr.ttcn b/s1gw/S1GW_ConnHdlr.ttcn
index 2c900fe..574a2d0 100644
--- a/s1gw/S1GW_ConnHdlr.ttcn
+++ b/s1gw/S1GW_ConnHdlr.ttcn
@@ -179,6 +179,18 @@
log("eNB connection closed");
}
+/* Close the eNB-side SCTP connection without waiting for pool server events.
+ * For use in 'impatient eNB' scenarios where the eNB initiates teardown before
+ * S1 setup completes and no S1APSRV_EVENT_CONN_DOWN is expected in return. */
+function f_ConnHdlr_s1ap_close() runs on ConnHdlr {
+ f_ConnHdlr_conn_track_disable();
+ S1AP_CodecPort_CtrlFunct.f_IPL4_close(S1AP_ENB, g_s1ap_conn_id,
+ { sctp := c_SctpTuple_S1AP });
+ g_s1ap_conn_id := -1;
+ unmap(self:S1AP_ENB, system:S1AP_CODEC_PT);
+ log("eNB connection closed");
+}
+
function f_ConnHdlr_s1ap_expect_shutdown() runs on ConnHdlr {
S1AP_ENB.receive(tr_SctpShutDownEvent(g_s1ap_conn_id));
S1AP_ENB.receive(tr_SctpAssocChange(SCTP_SHUTDOWN_COMP, g_s1ap_conn_id));
diff --git a/s1gw/S1GW_Tests.ttcn b/s1gw/S1GW_Tests.ttcn
index 5fffb09..d870be8 100644
--- a/s1gw/S1GW_Tests.ttcn
+++ b/s1gw/S1GW_Tests.ttcn
@@ -1135,6 +1135,71 @@
{ S1APSRV_SETUP_REJECT, S1APSRV_SETUP_REJECT, S1APSRV_SETUP_REJECT });
}
+/* MME pool test: eNB connects but disconnects before sending S1SetupReq
+ * (S1GW is in wait_s1setup_req); S1GW must handle the disconnect cleanly
+ * and must not attempt to connect to any MME. */
+function f_TC_mme_pool_enb_disc_wait_s1setup_req(charstring id) runs on ConnHdlr {
+ f_ConnHdlr_s1ap_connect(mp_enb_bind_ip, mp_s1gw_enb_ip);
+
+ /* disconnect before S1SetupReq: S1GW is in wait_s1setup_req,
+ * no MME connection is ever attempted */
+ f_ConnHdlr_s1ap_close();
+ setverdict(pass);
+}
+testcase TC_mme_pool_enb_disc_wait_s1setup_req() runs on test_CT {
+ f_TC_exec_pool(refers(f_TC_mme_pool_enb_disc_wait_s1setup_req), 1,
+ { S1APSRV_SETUP_ACCEPT });
+}
+
+/* MME pool test: eNB connects, sends S1SetupReq, S1GW forwards it to an MME
+ * (S1GW is in wait_s1setup_rsp), then eNB disconnects before the response arrives.
+ * S1GW must detect the eNB disconnect and close the MME connection. */
+function f_TC_mme_pool_enb_disc_wait_s1setup_rsp(charstring id) runs on ConnHdlr {
+ var S1AP_Server_CT vc_srv := g_pars.pool_srvs[0];
+ var S1AP_PDU pdu;
+ timer T;
+
+ f_ConnHdlr_s1ap_connect(mp_enb_bind_ip, mp_s1gw_enb_ip);
+ f_ConnHdlr_conn_track_disable();
+
+ /* pre-register with the pool server, then trigger MME selection */
+ f_ConnHdlr_s1ap_register_to(g_pars.genb_id, vc_srv);
+ f_ConnHdlr_tx_s1ap_from_enb(ts_S1AP_SetupReq(g_pars.genb_id, c_SupportedTAs, v32));
+
+ /* wait until S1GW has forwarded SetupReq to the MME (now in wait_s1setup_rsp) */
+ g_s1ap_server := vc_srv;
+ T.start(10.0);
+ alt {
+ [] S1AP_CONN.receive(S1APSRV_Event:S1APSRV_EVENT_CONN_UP) from vc_srv { repeat; }
+ [] S1AP_CONN.receive(tr_S1AP_SetupReq) from vc_srv -> value pdu { T.stop; }
+ [] T.timeout {
+ setverdict(fail, "Timeout waiting for S1SetupReq on pool server");
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
+ }
+ }
+
+ /* eNB disconnects impatient; S1GW must close the MME connection in response */
+ f_ConnHdlr_s1ap_close();
+
+ T.start(10.0);
+ alt {
+ [] S1AP_CONN.receive(S1APSRV_Event:S1APSRV_EVENT_CONN_DOWN) from vc_srv {
+ T.stop;
+ setverdict(pass);
+ }
+ [] T.timeout {
+ setverdict(fail, "S1GW did not close MME connection after eNB disconnect");
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
+ }
+ }
+
+ f_ConnHdlr_s1ap_unregister_from(g_pars.genb_id, vc_srv);
+}
+testcase TC_mme_pool_enb_disc_wait_s1setup_rsp() runs on test_CT {
+ f_TC_exec_pool(refers(f_TC_mme_pool_enb_disc_wait_s1setup_rsp), 1,
+ { S1APSRV_SETUP_ACCEPT });
+}
+
control {
execute( TC_setup() );
execute( TC_setup_multi() );
@@ -1174,6 +1239,8 @@
execute( TC_mme_pool_reject_fallback() );
execute( TC_mme_pool_timeout_fallback() );
execute( TC_mme_pool_all_reject() );
+ execute( TC_mme_pool_enb_disc_wait_s1setup_req() );
+ execute( TC_mme_pool_enb_disc_wait_s1setup_rsp() );
}
}
diff --git a/s1gw/expected-results.xml b/s1gw/expected-results.xml
index 28fcf71..0769764 100644
--- a/s1gw/expected-results.xml
+++ b/s1gw/expected-results.xml
@@ -1,5 +1,5 @@
<?xml version="1.0"?>
-<testsuite name='S1GW_Tests' tests='36' failures='0' errors='0' skipped='0' inconc='0' time='MASKED'>
+<testsuite name='S1GW_Tests' tests='38' failures='0' errors='0' skipped='0' inconc='0' time='MASKED'>
<testcase classname='S1GW_Tests' name='TC_setup' time='MASKED'/>
<testcase classname='S1GW_Tests' name='TC_setup_multi' time='MASKED'/>
<testcase classname='S1GW_Tests' name='TC_conn_term_by_mme' time='MASKED'/>
@@ -38,4 +38,6 @@
<testcase classname='S1GW_Tests' name='TC_mme_pool_reject_fallback' time='MASKED'/>
<testcase classname='S1GW_Tests' name='TC_mme_pool_timeout_fallback' time='MASKED'/>
<testcase classname='S1GW_Tests' name='TC_mme_pool_all_reject' time='MASKED'/>
+ <testcase classname='S1GW_Tests' name='TC_mme_pool_enb_disc_wait_s1setup_req' time='MASKED'/>
+ <testcase classname='S1GW_Tests' name='TC_mme_pool_enb_disc_wait_s1setup_rsp' time='MASKED'/>
</testsuite>
--
To view, visit https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/42359?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: I5d27cdafcb9f595a2d3db59beff17cd55de2539e
Gerrit-Change-Number: 42359
Gerrit-PatchSet: 1
Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de>