fixeria has uploaded this change for review.
[REST] Add GET /config endpoint for reading the current configuration
Change-Id: Ic6c9562a541e4a0728257538887537aac6b99b97
Related: SYS#7066
---
M contrib/openapi.yaml
M contrib/osmo-s1gw-cli.py
M doc/manuals/chapters/cli.adoc
M doc/manuals/chapters/rest.adoc
A include/osmo_s1gw.hrl
M priv/openapi.json
M src/osmo_s1gw_sup.erl
M src/rest_server.erl
8 files changed, 472 insertions(+), 13 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/erlang/osmo-s1gw refs/changes/16/42416/1
diff --git a/contrib/openapi.yaml b/contrib/openapi.yaml
index 6ab1346..c50ccce 100644
--- a/contrib/openapi.yaml
+++ b/contrib/openapi.yaml
@@ -66,6 +66,18 @@
'200':
$ref: '#/components/responses/OperationResult'
+ /config:
+ get:
+ summary: Get the current runtime configuration
+ operationId: ConfigRead
+ responses:
+ '200':
+ description: Current runtime configuration
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Config'
+
/mme-list:
get:
summary: Get a list of registered MMEs
@@ -427,6 +439,96 @@
type: integer
description: SCTP association identifier of the S1GW-MME connection
+ Config:
+ type: object
+ properties:
+ sctp_server:
+ $ref: '#/components/schemas/SctpServerCfg'
+ sctp_client:
+ $ref: '#/components/schemas/SctpClientCfg'
+ pfcp:
+ $ref: '#/components/schemas/PfcpCfg'
+ gtpu_kpi:
+ $ref: '#/components/schemas/GtpuKpiCfg'
+ rest:
+ $ref: '#/components/schemas/RestCfg'
+
+ SctpSockOptsCfg:
+ type: object
+ properties:
+ sctp_nodelay:
+ type: boolean
+ description: Disable/enable SCTP Nagle algorithm
+ recbuf:
+ type: integer
+ description: Receive buffer size (bytes)
+ sndbuf:
+ type: integer
+ description: Send buffer size (bytes)
+
+ SctpServerCfg:
+ type: object
+ properties:
+ laddr:
+ type: string
+ description: Local (bind) IP address for eNB-facing SCTP server
+ lport:
+ type: integer
+ description: Local (bind) port for eNB-facing SCTP server
+ sockopts:
+ $ref: '#/components/schemas/SctpSockOptsCfg'
+
+ SctpClientCfg:
+ description: >
+ Legacy/deprecated section kept for backwards compatibility.
+ MME pool entries are managed via the /mme-list endpoint.
+ type: object
+ properties:
+ laddr:
+ type: string
+ description: Local (bind) IP address for MME-facing SCTP connections
+ raddr:
+ type: string
+ description: Default remote (MME) IP address
+ rport:
+ type: integer
+ description: Default remote (MME) port
+ sockopts:
+ $ref: '#/components/schemas/SctpSockOptsCfg'
+
+ PfcpCfg:
+ type: object
+ properties:
+ laddr:
+ type: string
+ description: Local IP address for PFCP communication
+ raddr:
+ type: string
+ description: Remote IP address of the UPF (PFCP peer)
+
+ GtpuKpiCfg:
+ type: object
+ properties:
+ enable:
+ type: boolean
+ description: Whether GTP-U KPI reporting is enabled
+ table_name:
+ type: string
+ description: nftables table name for GTP-U KPI counters
+ interval:
+ type: integer
+ description: KPI polling interval in milliseconds
+
+ RestCfg:
+ type: object
+ properties:
+ port:
+ type: integer
+ description: REST server listen port
+ swagger_ui:
+ type: boolean
+ description: Whether the Swagger UI is enabled
+
ErabList:
type: array
items:
diff --git a/contrib/osmo-s1gw-cli.py b/contrib/osmo-s1gw-cli.py
index 265c5fc..5c37bdc 100755
--- a/contrib/osmo-s1gw-cli.py
+++ b/contrib/osmo-s1gw-cli.py
@@ -69,6 +69,11 @@
''' Send an HTTP DELETE request to the given endpoint (path) '''
return self.send_req('DELETE', path, data)
+ def config_read(self) -> RESTResponse:
+ ''' ConfigRead :: Get the current runtime configuration '''
+ with self.send_get_req('config') as f:
+ return json.load(f)
+
def fetch_spec(self) -> RESTResponse:
''' Fetch the OpenAPI specification (JSON) '''
with self.send_get_req('swagger/spec.json') as f:
@@ -161,6 +166,7 @@
class OsmoS1GWCli(cmd2.Cmd):
DESC = 'Interactive CLI for OsmoS1GW'
+ CAT_CONFIG = 'Configuration commands'
CAT_METRICS = 'Metrics commands'
CAT_PFCP = 'PFCP related commands'
CAT_MME = 'MME related commands'
@@ -184,6 +190,17 @@
self.iface = RestIface(argv.HOST, argv.port)
+ @cmd2.with_category(CAT_CONFIG)
+ def do_config_show(self, opts) -> None:
+ ''' Show the current runtime configuration '''
+ data = self.iface.config_read()
+ for section, params in data.items():
+ self.poutput(f'\n[{section}]')
+ table = [[k, v] for k, v in params.items()]
+ self.poutput(tabulate.tabulate(table,
+ headers=['Parameter', 'Value'],
+ tablefmt=self.tablefmt))
+
def do_fetch_openapi_spec(self, opts):
''' Fetch the OpenAPI specification (JSON), dump as text '''
spec = self.iface.fetch_spec()
diff --git a/doc/manuals/chapters/cli.adoc b/doc/manuals/chapters/cli.adoc
index 5d2bd6e..0b9dade 100644
--- a/doc/manuals/chapters/cli.adoc
+++ b/doc/manuals/chapters/cli.adoc
@@ -48,6 +48,50 @@
[[cli_commands]]
=== Commands
+==== `config_show`
+
+Display the effective runtime configuration (see <<rest_config>>).
+
+Example:
+
+----
+OsmoS1GW# config_show
+
+[gtpu_kpi]
+| Parameter | Value |
+|-------------|-----------|
+| enable | False |
+| interval | 3000 |
+| table_name | osmo-s1gw |
+
+[pfcp]
+| Parameter | Value |
+|-------------|------------|
+| laddr | 127.0.3.1 |
+| raddr | 127.0.3.10 |
+
+[rest]
+| Parameter | Value |
+|-------------|---------|
+| port | 8080 |
+| swagger_ui | True |
+
+[sctp_client]
+| Parameter | Value |
+|-------------|----------------------------------------------------------|
+| laddr | 127.0.2.1 |
+| raddr | 127.0.2.10 |
+| rport | 36412 |
+| sockopts | {'recbuf': 65536, 'sctp_nodelay': True, 'sndbuf': 65536} |
+
+[sctp_server]
+| Parameter | Value |
+|-------------|----------------------------------------------------------|
+| laddr | 127.0.1.1 |
+| lport | 36412 |
+| sockopts | {'recbuf': 65536, 'sctp_nodelay': True, 'sndbuf': 65536} |
+----
+
==== `fetch_openapi_spec`
Fetch the OpenAPI specification (JSON) from the server and display it.
diff --git a/doc/manuals/chapters/rest.adoc b/doc/manuals/chapters/rest.adoc
index 2707a41..2518070 100644
--- a/doc/manuals/chapters/rest.adoc
+++ b/doc/manuals/chapters/rest.adoc
@@ -49,6 +49,72 @@
| Process ID | `pid:<x>.<y>.<z>` | `pid:0.33.1`
|===
+[[rest_config]]
+=== Configuration
+
+==== `GET /config` — Runtime Configuration
+
+Returns the effective runtime configuration that OsmoS1GW is currently
+using, with all defaults applied. This reflects the values read via
+`osmo_s1gw:get_env/2` at startup, which may differ from the raw
+`sys.config` if legacy environment variables were merged in.
+
+Response (HTTP 200):
+
+----
+{
+ "sctp_server": {
+ "laddr": "127.0.1.1",
+ "lport": 36412,
+ "sockopts": {"recbuf": 65536, "sndbuf": 65536, "sctp_nodelay": true}
+ },
+ "sctp_client": {
+ "laddr": "127.0.2.1",
+ "raddr": "127.0.2.10",
+ "rport": 36412,
+ "sockopts": {"recbuf": 65536, "sndbuf": 65536, "sctp_nodelay": true}
+ },
+ "pfcp": {
+ "laddr": "127.0.1.1",
+ "raddr": "127.0.1.2"
+ },
+ "gtpu_kpi": {
+ "enable": false,
+ "table_name": "osmo-s1gw",
+ "interval": 3000
+ },
+ "rest": {
+ "port": 8080,
+ "swagger_ui": true
+ }
+}
+----
+
+`sctp_server`:: Configuration of the eNB-facing SCTP server.
+ `laddr`::: Local bind address.
+ `lport`::: Local bind port.
+ `sockopts`::: Effective SCTP socket options, including defaults.
+
+`sctp_client`:: Legacy/deprecated section reflecting the MME-facing SCTP
+ client defaults. MME pool entries are managed via <<rest_mme>>.
+ `laddr`::: Local bind address.
+ `raddr`::: Default remote (MME) address.
+ `rport`::: Default remote (MME) port.
+ `sockopts`::: Effective SCTP socket options, including defaults.
+
+`pfcp`::
+ `laddr`::: Local PFCP bind address.
+ `raddr`::: Remote UPF (PFCP peer) address.
+
+`gtpu_kpi`::
+ `enable`::: Whether GTP-U KPI reporting via nftables counters is active.
+ `table_name`::: nftables table name used for GTP-U KPI counters.
+ `interval`::: KPI polling interval in milliseconds.
+
+`rest`::
+ `port`::: REST server listen port.
+ `swagger_ui`::: Whether the Swagger UI endpoint is enabled.
+
[[rest_metrics]]
=== Metrics
diff --git a/include/osmo_s1gw.hrl b/include/osmo_s1gw.hrl
new file mode 100644
index 0000000..f9cbe14
--- /dev/null
+++ b/include/osmo_s1gw.hrl
@@ -0,0 +1,50 @@
+%% Copyright (C) 2025 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+%% Author: Vadim Yanitskiy <vyanitskiy@sysmocom.de>
+%%
+%% All Rights Reserved
+%%
+%% SPDX-License-Identifier: AGPL-3.0-or-later
+%%
+%% This program is free software; you can redistribute it and/or modify
+%% it under the terms of the GNU Affero General Public License as
+%% published by the Free Software Foundation; either version 3 of the
+%% License, or (at your option) any later version.
+%%
+%% This program is distributed in the hope that it will be useful,
+%% but WITHOUT ANY WARRANTY; without even the implied warranty of
+%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+%% GNU General Public License for more details.
+%%
+%% You should have received a copy of the GNU Affero General Public License
+%% along with this program. If not, see <https://www.gnu.org/licenses/>.
+%%
+%% Additional Permission under GNU AGPL version 3 section 7:
+%%
+%% If you modify this Program, or any covered work, by linking or
+%% combining it with runtime libraries of Erlang/OTP as released by
+%% Ericsson on https://www.erlang.org (or a modified version of these
+%% libraries), containing parts covered by the terms of the Erlang Public
+%% License (https://www.erlang.org/EPLICENSE), the licensors of this
+%% Program grant you additional permission to convey the resulting work
+%% without the need to license the runtime libraries of Erlang/OTP under
+%% the GNU Affero General Public License. Corresponding Source for a
+%% non-source form of such a combination shall include the source code
+%% for the parts of the runtime libraries of Erlang/OTP used as well as
+%% that of the covered work.
+
+%% Default values for application environment parameters (osmo_s1gw:get_env/2)
+
+-define(ENV_DEFAULT_S1GW_BIND_ADDR, "127.0.1.1").
+-define(ENV_DEFAULT_S1GW_BIND_PORT, 36412).
+-define(ENV_DEFAULT_MME_LOC_ADDR, "127.0.2.1").
+-define(ENV_DEFAULT_MME_REM_ADDR, "127.0.2.10").
+-define(ENV_DEFAULT_MME_REM_PORT, 36412).
+-define(ENV_DEFAULT_PFCP_LOC_ADDR, "127.0.1.1").
+-define(ENV_DEFAULT_PFCP_REM_ADDR, "127.0.1.2").
+-define(ENV_DEFAULT_GTPU_KPI_ENABLE, false).
+-define(ENV_DEFAULT_GTPU_KPI_TABLE_NAME, "osmo-s1gw").
+-define(ENV_DEFAULT_GTPU_KPI_INTERVAL, 3000).
+-define(ENV_DEFAULT_REST_SRV_PORT, 8080).
+-define(ENV_DEFAULT_REST_SRV_SWAGGER_UI, true).
+
+%% vim:set ts=4 sw=4 et:
diff --git a/priv/openapi.json b/priv/openapi.json
index 87aafac..8289c02 100644
--- a/priv/openapi.json
+++ b/priv/openapi.json
@@ -100,6 +100,24 @@
}
}
},
+ "/config": {
+ "get": {
+ "summary": "Get the current runtime configuration",
+ "operationId": "ConfigRead",
+ "responses": {
+ "200": {
+ "description": "Current runtime configuration",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Config"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/mme-list": {
"get": {
"summary": "Get a list of registered MMEs",
@@ -630,6 +648,123 @@
}
}
},
+ "Config": {
+ "type": "object",
+ "properties": {
+ "sctp_server": {
+ "$ref": "#/components/schemas/SctpServerCfg"
+ },
+ "sctp_client": {
+ "$ref": "#/components/schemas/SctpClientCfg"
+ },
+ "pfcp": {
+ "$ref": "#/components/schemas/PfcpCfg"
+ },
+ "gtpu_kpi": {
+ "$ref": "#/components/schemas/GtpuKpiCfg"
+ },
+ "rest": {
+ "$ref": "#/components/schemas/RestCfg"
+ }
+ }
+ },
+ "SctpSockOptsCfg": {
+ "type": "object",
+ "properties": {
+ "sctp_nodelay": {
+ "type": "boolean",
+ "description": "Disable/enable SCTP Nagle algorithm"
+ },
+ "recbuf": {
+ "type": "integer",
+ "description": "Receive buffer size (bytes)"
+ },
+ "sndbuf": {
+ "type": "integer",
+ "description": "Send buffer size (bytes)"
+ }
+ }
+ },
+ "SctpServerCfg": {
+ "type": "object",
+ "properties": {
+ "laddr": {
+ "type": "string",
+ "description": "Local (bind) IP address for eNB-facing SCTP server"
+ },
+ "lport": {
+ "type": "integer",
+ "description": "Local (bind) port for eNB-facing SCTP server"
+ },
+ "sockopts": {
+ "$ref": "#/components/schemas/SctpSockOptsCfg"
+ }
+ }
+ },
+ "SctpClientCfg": {
+ "description": "Legacy/deprecated section kept for backwards compatibility. MME pool entries are managed via the /mme-list endpoint.\n",
+ "type": "object",
+ "properties": {
+ "laddr": {
+ "type": "string",
+ "description": "Local (bind) IP address for MME-facing SCTP connections"
+ },
+ "raddr": {
+ "type": "string",
+ "description": "Default remote (MME) IP address"
+ },
+ "rport": {
+ "type": "integer",
+ "description": "Default remote (MME) port"
+ },
+ "sockopts": {
+ "$ref": "#/components/schemas/SctpSockOptsCfg"
+ }
+ }
+ },
+ "PfcpCfg": {
+ "type": "object",
+ "properties": {
+ "laddr": {
+ "type": "string",
+ "description": "Local IP address for PFCP communication"
+ },
+ "raddr": {
+ "type": "string",
+ "description": "Remote IP address of the UPF (PFCP peer)"
+ }
+ }
+ },
+ "GtpuKpiCfg": {
+ "type": "object",
+ "properties": {
+ "enable": {
+ "type": "boolean",
+ "description": "Whether GTP-U KPI reporting is enabled"
+ },
+ "table_name": {
+ "type": "string",
+ "description": "nftables table name for GTP-U KPI counters"
+ },
+ "interval": {
+ "type": "integer",
+ "description": "KPI polling interval in milliseconds"
+ }
+ }
+ },
+ "RestCfg": {
+ "type": "object",
+ "properties": {
+ "port": {
+ "type": "integer",
+ "description": "REST server listen port"
+ },
+ "swagger_ui": {
+ "type": "boolean",
+ "description": "Whether the Swagger UI is enabled"
+ }
+ }
+ },
"ErabList": {
"type": "array",
"items": {
diff --git a/src/osmo_s1gw_sup.erl b/src/osmo_s1gw_sup.erl
index 875e19b..502ba04 100644
--- a/src/osmo_s1gw_sup.erl
+++ b/src/osmo_s1gw_sup.erl
@@ -38,21 +38,10 @@
-export([init/1,
start_link/0]).
+-include("osmo_s1gw.hrl").
-include("s1ap.hrl").
-define(SERVER, ?MODULE).
--define(ENV_DEFAULT_S1GW_BIND_ADDR, "127.0.1.1").
--define(ENV_DEFAULT_S1GW_BIND_PORT, ?S1AP_PORT).
--define(ENV_DEFAULT_MME_LOC_ADDR, "127.0.2.1").
--define(ENV_DEFAULT_MME_REM_ADDR, "127.0.2.10").
--define(ENV_DEFAULT_MME_REM_PORT, ?S1AP_PORT).
--define(ENV_DEFAULT_PFCP_LOC_ADDR, "127.0.1.1").
--define(ENV_DEFAULT_PFCP_REM_ADDR, "127.0.1.2").
--define(ENV_DEFAULT_GTPU_KPI_ENABLE, false).
--define(ENV_DEFAULT_GTPU_KPI_TABLE_NAME, "osmo-s1gw").
--define(ENV_DEFAULT_GTPU_KPI_INTERVAL, 3000).
--define(ENV_DEFAULT_REST_SRV_PORT, 8080).
--define(ENV_DEFAULT_REST_SRV_SWAGGER_UI, true).
%% ------------------------------------------------------------------
%% supervisor API
diff --git a/src/rest_server.erl b/src/rest_server.erl
index 79090e8..dae276f 100644
--- a/src/rest_server.erl
+++ b/src/rest_server.erl
@@ -34,7 +34,8 @@
-module(rest_server).
--export([metrics_list/1,
+-export([config_read/1,
+ metrics_list/1,
pfcp_assoc_state/1,
pfcp_heartbeat/1,
mme_list/1,
@@ -52,6 +53,7 @@
-include_lib("kernel/include/logger.hrl").
+-include("osmo_s1gw.hrl").
-include("s1gw_metrics.hrl").
@@ -59,6 +61,17 @@
%% public API
%% ------------------------------------------------------------------
+%% ConfigRead :: Get the current runtime configuration
+config_read(#{}) ->
+ {200, [], #{
+ <<"sctp_server">> => config_sctp_server(),
+ <<"sctp_client">> => config_sctp_client(),
+ <<"pfcp">> => config_pfcp(),
+ <<"gtpu_kpi">> => config_gtpu_kpi(),
+ <<"rest">> => config_rest()
+ }}.
+
+
%% MetricsList :: Get a list of metrics
metrics_list(#{query_parameters := QP}) ->
L0 = case proplists:get_value(<< "type" >>, QP, << "all" >>) of
@@ -221,6 +234,49 @@
%% private API
%% ------------------------------------------------------------------
+-spec config_sctp_server() -> map().
+config_sctp_server() ->
+ Cfg = osmo_s1gw:get_env(sctp_server, #{}),
+ SockOptsCfg = maps:get(sockopts, Cfg, #{}),
+ #{<<"laddr">> => bval(maps:get(laddr, Cfg, ?ENV_DEFAULT_S1GW_BIND_ADDR)),
+ <<"lport">> => maps:get(lport, Cfg, ?ENV_DEFAULT_S1GW_BIND_PORT),
+ <<"sockopts">> => sockopts_to_map(sctp_common:gen_sockopts(SockOptsCfg))}.
+
+
+-spec config_sctp_client() -> map().
+config_sctp_client() ->
+ Cfg = osmo_s1gw:get_env(sctp_client, #{}),
+ SockOpts = maps:get(sockopts, Cfg, []),
+ #{<<"laddr">> => bval(maps:get(laddr, Cfg, ?ENV_DEFAULT_MME_LOC_ADDR)),
+ <<"raddr">> => bval(maps:get(raddr, Cfg, ?ENV_DEFAULT_MME_REM_ADDR)),
+ <<"rport">> => maps:get(rport, Cfg, ?ENV_DEFAULT_MME_REM_PORT),
+ <<"sockopts">> => sockopts_to_map(SockOpts)}.
+
+
+-spec config_pfcp() -> map().
+config_pfcp() ->
+ #{<<"laddr">> => bval(osmo_s1gw:get_env(pfcp_loc_addr, ?ENV_DEFAULT_PFCP_LOC_ADDR)),
+ <<"raddr">> => bval(osmo_s1gw:get_env(pfcp_rem_addr, ?ENV_DEFAULT_PFCP_REM_ADDR))}.
+
+
+-spec config_gtpu_kpi() -> map().
+config_gtpu_kpi() ->
+ #{<<"enable">> => osmo_s1gw:get_env(gtpu_kpi_enable, ?ENV_DEFAULT_GTPU_KPI_ENABLE),
+ <<"table_name">> => bval(osmo_s1gw:get_env(gtpu_kpi_table_name, ?ENV_DEFAULT_GTPU_KPI_TABLE_NAME)),
+ <<"interval">> => osmo_s1gw:get_env(gtpu_kpi_interval, ?ENV_DEFAULT_GTPU_KPI_INTERVAL)}.
+
+
+-spec config_rest() -> map().
+config_rest() ->
+ #{<<"port">> => osmo_s1gw:get_env(rest_srv_port, ?ENV_DEFAULT_REST_SRV_PORT),
+ <<"swagger_ui">> => osmo_s1gw:get_env(rest_srv_swagger_ui, ?ENV_DEFAULT_REST_SRV_SWAGGER_UI)}.
+
+
+-spec sockopts_to_map([gen_sctp:option()]) -> map().
+sockopts_to_map(SockOpts) ->
+ maps:from_list([{atom_to_binary(K), V} || {K, V} <- SockOpts]).
+
+
-spec metric_list(list()) -> [map()].
metric_list(Path) ->
L = exometer:get_values(Path),
To view, visit change 42416. To unsubscribe, or for help writing mail filters, visit settings.