fixeria has submitted this change. ( 
https://gerrit.osmocom.org/c/erlang/osmo-s1gw/+/41103?usp=email )

Change subject: [REST] Implement EnbErabList
......................................................................

[REST] Implement EnbErabList

Change-Id: I846974dd79e737acaac17918d18da55967a9abf2
Related: SYS#7066
---
M contrib/openapi.yaml
M contrib/osmo-s1gw-cli.py
M doc/osmo-s1gw-cli.md
M priv/openapi.json
M src/rest_server.erl
5 files changed, 323 insertions(+), 1 deletion(-)

Approvals:
  osmith: Looks good to me, but someone else must approve
  laforge: Looks good to me, but someone else must approve
  Jenkins Builder: Verified
  fixeria: Looks good to me, approved




diff --git a/contrib/openapi.yaml b/contrib/openapi.yaml
index 24bc2c8..0041274 100644
--- a/contrib/openapi.yaml
+++ b/contrib/openapi.yaml
@@ -92,6 +92,22 @@
         '404':
           description: Unsuccessful outcome (eNB not found)

+  /enb/{EnbId}/erab-list:
+    get:
+      summary: Get E-RAB list for a specific eNB
+      operationId: EnbErabList
+      parameters:
+        - $ref: '#/components/parameters/EnbId'
+      responses:
+        '200':
+          description: Successful outcome (E-RAB list)
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErabList'
+        '404':
+          description: Unsuccessful outcome (eNB not found)
+
 components:
   responses:
     OperationResult:
@@ -248,3 +264,62 @@
         mme_sctp_aid:
           type: integer
           description: SCTP association identifier of the S1GW-MME connection
+
+    ErabList:
+      type: array
+      items:
+        $ref: '#/components/schemas/ErabItem'
+
+    FTEID:
+      type: object
+      required:
+        - teid
+        - tla
+      properties:
+        teid:
+          type: integer
+          description: GTP-U TEID
+        tla:
+          type: string
+          description: GTP-U TLA (Transport Layer Address)
+
+    ErabItem:
+      type: object
+      required:
+        - mme_ue_id
+        - erab_id
+        - state
+        - pid
+      properties:
+        mme_ue_id:
+          type: integer
+          description: MME-UE-S1AP-ID
+        erab_id:
+          type: integer
+          description: E-RAB-ID
+        state:
+          type: string
+          description: E-RAB FSM state
+          example: erab_wait_release_rsp
+        pid:
+          type: string
+          pattern: '^<[0-9]+\.[0-9]+\.[0-9]+>$'
+          description: E-RAB FSM process ID
+        pfcp_lseid:
+          type: integer
+          description: PFCP SEID (local)
+        pfcp_rseid:
+          type: integer
+          description: PFCP SEID (remote)
+        f_teid_u2c:
+          $ref: '#/components/schemas/FTEID'
+          description: GTP-U F-TEID for UPF -> Core
+        f_teid_c2u:
+          $ref: '#/components/schemas/FTEID'
+          description: GTP-U F-TEID for UPF <- Core
+        f_teid_a2u:
+          $ref: '#/components/schemas/FTEID'
+          description: GTP-U F-TEID for UPF <- Access
+        f_teid_u2a:
+          $ref: '#/components/schemas/FTEID'
+          description: GTP-U F-TEID for UPF -> Access
diff --git a/contrib/osmo-s1gw-cli.py b/contrib/osmo-s1gw-cli.py
index 56d08c3..5b749aa 100755
--- a/contrib/osmo-s1gw-cli.py
+++ b/contrib/osmo-s1gw-cli.py
@@ -112,6 +112,11 @@
         with self.send_get_req(f'enb/{enb_id}') as f:
             return json.load(f)

+    def enb_erab_list(self, enb_id: str) -> RESTResponse:
+        ''' EnbErabList :: Get E-RAB list for a specific eNB '''
+        with self.send_get_req(f'enb/{enb_id}/erab-list') as f:
+            return json.load(f)
+

 class OsmoS1GWCli(cmd2.Cmd):
     DESC = 'Interactive CLI for OsmoS1GW'
@@ -283,6 +288,51 @@
         data = self.iface.enb_info(enb_id)
         self.enb_info_print(data)

+    @staticmethod
+    def erab_list_item(item: dict) -> dict:
+        ''' Generate a table row for the given E-RAB (brief) '''
+        return {
+            'PID': item.get('pid'),
+            'MME-UE-S1AP-ID': item.get('mme_ue_id'),
+            'E-RAB-ID': item.get('erab_id'),
+            'State': item.get('state'),
+        }
+
+    @classmethod
+    def erab_list_item_full(cls, item: dict) -> dict:
+        ''' Generate a table row for the given E-RAB (full) '''
+        f_teid = lambda params: '0x{teid:08x}@{tla}'.format(**params)
+        seid = lambda val: f'0x{val:016x}'
+        return {
+            **cls.erab_list_item(item),
+            'SEID (local)': seid(item.get('pfcp_lseid')) if 'pfcp_lseid' in 
item else None,
+            'SEID (remote)': seid(item.get('pfcp_rseid')) if 'pfcp_rseid' in 
item else None,
+            'U2C F-TEID': f_teid(item.get('f_teid_u2c')) if 'f_teid_u2c' in 
item else None,
+            'C2U F-TEID': f_teid(item.get('f_teid_c2u')) if 'f_teid_c2u' in 
item else None,
+            'A2U F-TEID': f_teid(item.get('f_teid_a2u')) if 'f_teid_a2u' in 
item else None,
+            'U2A F-TEID': f_teid(item.get('f_teid_u2a')) if 'f_teid_u2a' in 
item else None,
+        }
+
+    def erab_list_print(self, items: list[dict], full: bool) -> None:
+        ''' Print a list of E-RABs in tabular form '''
+        func = self.erab_list_item_full if full else self.erab_list_item
+        self.poutput(tabulate.tabulate(map(func, items),
+                                       headers='keys', tablefmt=self.tablefmt))
+
+    enb_erab_list_parser = cmd2.Cmd2ArgumentParser()
+    enb_erab_list_parser.add_argument('-f', '--full',
+                                      action='store_true',
+                                      help='Print full table (more columns)')
+    add_enb_id_group(enb_erab_list_parser)
+
+    @cmd2.with_argparser(enb_erab_list_parser)
+    @cmd2.with_category(CAT_ENB)
+    def do_enb_erab_list(self, opts) -> None:
+        ''' Get E-RAB list for a specific eNB '''
+        enb_id = self.gen_enb_id(opts)
+        data = self.iface.enb_erab_list(enb_id)
+        self.erab_list_print(data, opts.full)
+

 ap = argparse.ArgumentParser(prog='osmo-s1gw-cli', 
description=OsmoS1GWCli.DESC)

diff --git a/doc/osmo-s1gw-cli.md b/doc/osmo-s1gw-cli.md
index 3ae2da6..6509563 100644
--- a/doc/osmo-s1gw-cli.md
+++ b/doc/osmo-s1gw-cli.md
@@ -236,3 +236,35 @@
 EXCEPTION of type 'HTTPError' occurred with message: HTTP Error 400: Bad 
Request
 To enable full traceback, run the following command: 'set debug true'
 ```
+
+### `enb_erab_list`
+
+Get E-RAB list for a specific eNB.
+
+```
+Usage: enb_erab_list [-h] [-f] (-H HANDLE | -P PID | -G GENBID | 
--enb-sctp-aid AID | --mme-sctp-aid AID)
+
+Get E-RAB list for a specific eNB
+
+optional arguments:
+  -h, --help           show this help message and exit
+  -f, --full           Print full table (more columns)
+
+eNB ID:
+  -H, --handle HANDLE  eNB handle (example: 0)
+  -P, --pid PID        eNB process ID (example: 0.33.1)
+  -G, --genbid GENBID  Global-eNB-ID (example: 262-42-1337)
+  --enb-sctp-aid AID   eNB association identifier (example: 42)
+  --mme-sctp-aid AID   MME association identifier (example: 42)
+```
+
+Example: Obtaining E-RAB list for an eNB with the given Global-eNB-ID.
+
+```
+OsmoS1GW# enb_erab_list -G 001-01-0
+| PID       |   MME-UE-S1AP-ID |   E-RAB-ID | State      |
+|-----------|------------------|------------|------------|
+| <0.708.0> |             4242 |          1 | erab_setup |
+| <0.707.0> |             4242 |          0 | erab_setup |
+| <0.709.0> |             4242 |          2 | erab_setup |
+```
diff --git a/priv/openapi.json b/priv/openapi.json
index 3e8f22e..07a11b8 100644
--- a/priv/openapi.json
+++ b/priv/openapi.json
@@ -140,6 +140,32 @@
                     }
                 }
             }
+        },
+        "/enb/{EnbId}/erab-list": {
+            "get": {
+                "summary": "Get E-RAB list for a specific eNB",
+                "operationId": "EnbErabList",
+                "parameters": [
+                    {
+                        "$ref": "#/components/parameters/EnbId"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Successful outcome (E-RAB list)",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/ErabList"
+                                }
+                            }
+                        }
+                    },
+                    "404": {
+                        "description": "Unsuccessful outcome (eNB not found)"
+                    }
+                }
+            }
         }
     },
     "components": {
@@ -358,6 +384,82 @@
                         "description": "SCTP association identifier of the 
S1GW-MME connection"
                     }
                 }
+            },
+            "ErabList": {
+                "type": "array",
+                "items": {
+                    "$ref": "#/components/schemas/ErabItem"
+                }
+            },
+            "FTEID": {
+                "type": "object",
+                "required": [
+                    "teid",
+                    "tla"
+                ],
+                "properties": {
+                    "teid": {
+                        "type": "integer",
+                        "description": "GTP-U TEID"
+                    },
+                    "tla": {
+                        "type": "string",
+                        "description": "GTP-U TLA (Transport Layer Address)"
+                    }
+                }
+            },
+            "ErabItem": {
+                "type": "object",
+                "required": [
+                    "mme_ue_id",
+                    "erab_id",
+                    "state",
+                    "pid"
+                ],
+                "properties": {
+                    "mme_ue_id": {
+                        "type": "integer",
+                        "description": "MME-UE-S1AP-ID"
+                    },
+                    "erab_id": {
+                        "type": "integer",
+                        "description": "E-RAB-ID"
+                    },
+                    "state": {
+                        "type": "string",
+                        "description": "E-RAB FSM state",
+                        "example": "erab_wait_release_rsp"
+                    },
+                    "pid": {
+                        "type": "string",
+                        "pattern": "^<[0-9]+\\.[0-9]+\\.[0-9]+>$",
+                        "description": "E-RAB FSM process ID"
+                    },
+                    "pfcp_lseid": {
+                        "type": "integer",
+                        "description": "PFCP SEID (local)"
+                    },
+                    "pfcp_rseid": {
+                        "type": "integer",
+                        "description": "PFCP SEID (remote)"
+                    },
+                    "f_teid_u2c": {
+                        "$ref": "#/components/schemas/FTEID",
+                        "description": "GTP-U F-TEID for UPF -> Core"
+                    },
+                    "f_teid_c2u": {
+                        "$ref": "#/components/schemas/FTEID",
+                        "description": "GTP-U F-TEID for UPF <- Core"
+                    },
+                    "f_teid_a2u": {
+                        "$ref": "#/components/schemas/FTEID",
+                        "description": "GTP-U F-TEID for UPF <- Access"
+                    },
+                    "f_teid_u2a": {
+                        "$ref": "#/components/schemas/FTEID",
+                        "description": "GTP-U F-TEID for UPF -> Access"
+                    }
+                }
             }
         }
     }
diff --git a/src/rest_server.erl b/src/rest_server.erl
index f546ad9..2f805da 100644
--- a/src/rest_server.erl
+++ b/src/rest_server.erl
@@ -38,7 +38,8 @@
          pfcp_assoc_state/1,
          pfcp_heartbeat/1,
          enb_list/1,
-         enb_info/1
+         enb_info/1,
+         enb_erab_list/1
         ]).

 -include_lib("kernel/include/logger.hrl").
@@ -105,6 +106,20 @@
     end.


+%% EnbErabList :: Get E-RAB list for a specific eNB
+enb_erab_list(#{path_parameters := PP}) ->
+    [{<< "EnbId" >>, << ID/bytes >>}] = PP,
+    case fetch_enb_info(ID) of
+        [EnbInfo | _] ->
+            Rsp = fetch_erab_list(EnbInfo),
+            {200, [], Rsp};
+        [] ->
+            {404, [], undefined};
+        error ->
+            {500, [], undefined}
+    end.
+
+
 %% ------------------------------------------------------------------
 %% private API
 %% ------------------------------------------------------------------
@@ -230,6 +245,54 @@
     error.


+-spec fetch_erab_list(enb_registry:enb_info()) -> [map()].
+fetch_erab_list(#{mme_conn_info := ConnInfo}) ->
+    Pid = maps:get(handler, ConnInfo), %% s1ap_proxy process pid
+    ERABs = s1ap_proxy:fetch_erab_list(Pid),
+    lists:map(fun erab_list_item/1, ERABs);
+
+fetch_erab_list(_) -> [].
+
+
+-spec erab_list_item({term(), pid()}) -> map().
+erab_list_item({_, Pid}) ->
+    %% XXX: E-RAB FSM process might be dead here
+    Info = erab_fsm:fetch_info(Pid),
+    {MmeUeId, ErabId} = maps:get(uid, Info),
+    M0 = #{mme_ue_id => MmeUeId,
+           erab_id => ErabId,
+           state => maps:get(state, Info),
+           pid => pid_to_list(Pid)},
+    M1 = erab_list_item_add_seid(Info, M0),
+    M2 = erab_list_item_add_f_teid(f_teid_u2c, Info, M1),
+    M3 = erab_list_item_add_f_teid(f_teid_c2u, Info, M2),
+    M4 = erab_list_item_add_f_teid(f_teid_a2u, Info, M3),
+    M5 = erab_list_item_add_f_teid(f_teid_u2a, Info, M4),
+    rsp_map(M5).
+
+
+-spec erab_list_item_add_seid(erab_fsm:erab_info(), map()) -> map().
+erab_list_item_add_seid(Info, M0) ->
+    %% local SEID is always known/present
+    M1 = M0#{pfcp_lseid => maps:get(seid_loc, Info)},
+    %% remote SEID may or may not be known/present
+    case maps:find(seid_rem, Info) of
+        {ok, SEID} -> M1#{pfcp_rseid => SEID};
+        error -> M1
+    end.
+
+
+-spec erab_list_item_add_f_teid(atom(), erab_fsm:erab_info(), map()) -> map().
+erab_list_item_add_f_teid(Key, Info, M0) ->
+    case maps:find(Key, Info) of
+        {ok, {TEID, AddrBin}} ->
+            Addr = list_to_tuple(binary_to_list(AddrBin)),
+            M0#{Key => #{teid => TEID,
+                         tla => inet:ntoa(Addr)}};
+        error -> M0
+    end.
+
+
 -spec parse_pid(binary() | list()) -> pid().
 parse_pid(Data) when is_binary(Data) ->
     parse_pid(binary_to_list(Data));

--
To view, visit https://gerrit.osmocom.org/c/erlang/osmo-s1gw/+/41103?usp=email
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings?usp=email

Gerrit-MessageType: merged
Gerrit-Project: erlang/osmo-s1gw
Gerrit-Branch: master
Gerrit-Change-Id: I846974dd79e737acaac17918d18da55967a9abf2
Gerrit-Change-Number: 41103
Gerrit-PatchSet: 8
Gerrit-Owner: fixeria <[email protected]>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <[email protected]>
Gerrit-Reviewer: laforge <[email protected]>
Gerrit-Reviewer: osmith <[email protected]>

Reply via email to