fixeria has uploaded this change for review. ( 
https://gerrit.osmocom.org/c/erlang/osmo-s1gw/+/42416?usp=email )


Change subject: [REST] Add GET /config endpoint for reading the current 
configuration
......................................................................

[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 <[email protected]>
+%% Author: Vadim Yanitskiy <[email protected]>
+%%
+%% 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 https://gerrit.osmocom.org/c/erlang/osmo-s1gw/+/42416?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: Ic6c9562a541e4a0728257538887537aac6b99b97
Gerrit-Change-Number: 42416
Gerrit-PatchSet: 1
Gerrit-Owner: fixeria <[email protected]>

Reply via email to