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

Change subject: [REST] Implement eNB/MME selection by addr-port
......................................................................

[REST] Implement eNB/MME selection by addr-port

Add support for selecting an MME or eNB by remote address and port
in the REST API and CLI.  The selector format is `addr:IP:PORT` for
MMEs and `enb-conn:IP:PORT` for eNBs, where IP can be an IPv4 or
IPv6 address.  The colon is used as the address/port separator.

Change-Id: If02c8de1e1b7214bba868eee35233a79d0704dc5
Related: SYS#7066
---
M contrib/openapi.yaml
M contrib/osmo-s1gw-cli.py
M doc/manuals/chapters/cli.adoc
M priv/openapi.json
M src/rest_server.erl
5 files changed, 99 insertions(+), 33 deletions(-)

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




diff --git a/contrib/openapi.yaml b/contrib/openapi.yaml
index c50ccce..d07dd21 100644
--- a/contrib/openapi.yaml
+++ b/contrib/openapi.yaml
@@ -244,9 +244,9 @@
             description: MME name
             example: mme0
           - type: string
-            pattern: '^addr:[0-9a-f:.]+-[0-9]+$'
+            pattern: '^addr:[0-9a-f:.]+:[0-9]+$'
             description: MME remote address/port
-            example: addr:192.168.1.1-36412
+            example: addr:192.168.1.1:36412

     EnbId:
       name: EnbId
@@ -272,9 +272,9 @@
             description: eNB/MME SCTP association identifier
             example: enb-aid:42
           - type: string
-            pattern: '^enb-conn:[0-9a-f:.]+-[0-9]+$'
+            pattern: '^enb-conn:[0-9a-f:.]+:[0-9]+$'
             description: eNB connection address/port
-            example: enb-conn:192.168.1.1-34650
+            example: enb-conn:192.168.1.1:34650

     ErabId:
       name: ErabId
diff --git a/contrib/osmo-s1gw-cli.py b/contrib/osmo-s1gw-cli.py
index 5c37bdc..51a9c4f 100755
--- a/contrib/osmo-s1gw-cli.py
+++ b/contrib/osmo-s1gw-cli.py
@@ -117,14 +117,14 @@
         with self.send_post_req('mme-list', mme_info) as f:
             return f.status

-    def mme_info(self, name: str) -> RESTResponse:
+    def mme_info(self, mme_id: str) -> RESTResponse:
         ''' MmeInfo :: Get information about a specific MME '''
-        with self.send_get_req(f'mme/name:{name}') as f:
+        with self.send_get_req(f'mme/{mme_id}') as f:
             return json.load(f)

-    def mme_delete(self, name: str) -> int:
-        ''' MmeInfo :: Get information about a specific MME '''
-        with self.send_delete_req(f'mme/name:{name}') as f:
+    def mme_delete(self, mme_id: str) -> int:
+        ''' MmeDelete :: Delete an MME from the pool '''
+        with self.send_delete_req(f'mme/{mme_id}') as f:
             return f.status

     def enb_list(self) -> RESTResponse:
@@ -349,6 +349,18 @@
         self.iface.mme_add(mme_info)

     @staticmethod
+    def gen_mme_id(opts) -> str:
+        ''' Generate the MmeId parameter value (for URL) '''
+        if opts.name is not None:
+            return f'name:{opts.name}'
+        elif opts.addr is not None:
+            addr, _, port = opts.addr.rpartition(':')
+            if addr and port.isdigit():
+                return f'addr:{opts.addr}'
+            return f'addr:{opts.addr}:36412'
+        raise ValueError # shall not happen
+
+    @staticmethod
     def add_mme_id_group(parser):
         ''' Add argparse group for the MmeId parameter '''
         mme_id_group = parser.add_argument_group('MME ID')
@@ -356,7 +368,10 @@
         mme_id_group.add_argument('-N', '--name',
                                   type=str,
                                   help='MME name (example: mme0)')
-        # TODO: address/port
+        mme_id_group.add_argument('-a', '--addr',
+                                  type=str, metavar='ADDR[:PORT]',
+                                  help='MME address with optional port 
(default: 36412), '
+                                       'e.g. 192.168.1.1 or 192.168.1.1:36412')
         return mme_id_group
 
     mme_info_parser = cmd2.Cmd2ArgumentParser()
@@ -366,14 +381,14 @@
     @cmd2.with_category(CAT_MME)
     def do_mme_info(self, opts) -> None:
         ''' Get information about a specific MME '''
-        data = self.iface.mme_info(opts.name)
+        data = self.iface.mme_info(self.gen_mme_id(opts))
         self.mme_info_print(data)

     @cmd2.with_argparser(mme_info_parser)
     @cmd2.with_category(CAT_MME)
     def do_mme_delete(self, opts) -> None:
         ''' Delete an MME from the pool '''
-        self.iface.mme_delete(opts.name)
+        self.iface.mme_delete(self.gen_mme_id(opts))

     @staticmethod
     def enb_list_item(item: dict) -> dict:
@@ -429,6 +444,8 @@
             return f'enb-sctp-aid:{opts.enb_sctp_aid}'
         elif opts.mme_sctp_aid is not None:
             return f'mme-sctp-aid:{opts.mme_sctp_aid}'
+        elif opts.enb_conn is not None:
+            return f'enb-conn:{opts.enb_conn}'
         raise ValueError # shall not happen

     @staticmethod
@@ -451,6 +468,9 @@
         enb_id_group.add_argument('--mme-sctp-aid',
                                   type=int, metavar='AID',
                                   help='MME association identifier (example: 
42)')
+        enb_id_group.add_argument('--enb-conn',
+                                  type=str, metavar='ADDR:PORT',
+                                  help='eNB connection address/port (example: 
192.168.1.1:34650)')
         return enb_id_group

     enb_info_parser = cmd2.Cmd2ArgumentParser()
diff --git a/doc/manuals/chapters/cli.adoc b/doc/manuals/chapters/cli.adoc
index 418cd4b..279c445 100644
--- a/doc/manuals/chapters/cli.adoc
+++ b/doc/manuals/chapters/cli.adoc
@@ -218,13 +218,15 @@

 ==== `mme_info`

-Show configuration details for a specific MME, selected by name.
+Show configuration details for a specific MME.

 ----
-Usage: mme_info [-h] -N NAME
+Usage: mme_info [-h] (-N NAME | -a ADDR[:PORT])

 MME ID:
-  -N, --name NAME  MME name (example: mme0)
+  -N, --name NAME          MME name (example: mme0)
+  -a, --addr ADDR[:PORT]   MME address with optional port (default: 36412),
+                           e.g. 192.168.1.1 or 192.168.1.1:36412
 ----

 Example:
@@ -241,13 +243,15 @@

 ==== `mme_delete`

-Remove an MME from the pool, selected by name.
+Remove an MME from the pool.

 ----
-Usage: mme_delete [-h] -N NAME
+Usage: mme_delete [-h] (-N NAME | -a ADDR[:PORT])

 MME ID:
-  -N, --name NAME  MME name (example: mme0)
+  -N, --name NAME          MME name (example: mme0)
+  -a, --addr ADDR[:PORT]   MME address with optional port (default: 36412),
+                           e.g. 192.168.1.1 or 192.168.1.1:36412
 ----

 Example:
@@ -287,14 +291,16 @@

 ----
 Usage: enb_info [-h] (-H HANDLE | -P PID | -G GENBID |
-                      --enb-sctp-aid AID | --mme-sctp-aid AID)
+                      --enb-sctp-aid AID | --mme-sctp-aid AID |
+                      --enb-conn ADDR:PORT)

 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 SCTP association identifier
-  --mme-sctp-aid AID   MME SCTP association identifier
+  -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 SCTP association identifier
+  --mme-sctp-aid AID       MME SCTP association identifier
+  --enb-conn ADDR:PORT     eNB connection address/port (example: 
192.168.1.1:34650)
 ----

 Example: selecting by handle.
@@ -315,8 +321,8 @@

 ==== `enb_delete`

-Force-disconnect an eNB, terminating its SCTP connection.  The same
-selectors as `enb_info` are accepted.
+Force-disconnect an eNB, terminating its SCTP connection.  Accepts the
+same selectors as `enb_info`.

 ==== `enb_erab_list`

@@ -326,7 +332,8 @@
 Usage: enb_erab_list [-h] [-f] [-S {pid,state,mme_ue_id,erab_id}]
                      [--reverse]
                      (-H HANDLE | -P PID | -G GENBID |
-                      --enb-sctp-aid AID | --mme-sctp-aid AID)
+                      --enb-sctp-aid AID | --mme-sctp-aid AID |
+                      --enb-conn ADDR:PORT)

 optional arguments:
   -f, --full   Print full table including PFCP and GTP-U F-TEID columns
diff --git a/priv/openapi.json b/priv/openapi.json
index 8289c02..cab9fc0 100644
--- a/priv/openapi.json
+++ b/priv/openapi.json
@@ -379,9 +379,9 @@
                         },
                         {
                             "type": "string",
-                            "pattern": "^addr:[0-9a-f:.]+-[0-9]+$",
+                            "pattern": "^addr:[0-9a-f:.]+:[0-9]+$",
                             "description": "MME remote address/port",
-                            "example": "addr:192.168.1.1-36412"
+                            "example": "addr:192.168.1.1:36412"
                         }
                     ]
                 }
@@ -419,9 +419,9 @@
                         },
                         {
                             "type": "string",
-                            "pattern": "^enb-conn:[0-9a-f:.]+-[0-9]+$",
+                            "pattern": "^enb-conn:[0-9a-f:.]+:[0-9]+$",
                             "description": "eNB connection address/port",
-                            "example": "enb-conn:192.168.1.1-34650"
+                            "example": "enb-conn:192.168.1.1:34650"
                         }
                     ]
                 }
diff --git a/src/rest_server.erl b/src/rest_server.erl
index 550da3e..0beaaca 100644
--- a/src/rest_server.erl
+++ b/src/rest_server.erl
@@ -272,6 +272,25 @@
       <<"swagger_ui">> => osmo_s1gw:get_env(rest_srv_swagger_ui, 
?ENV_DEFAULT_REST_SRV_SWAGGER_UI)}.


+%% parse address/port from a string like "192.168.1.1:36412"
+-spec parse_addr_port(Data) -> {ok, {Addr, Port}} | error
+    when Data :: binary() | string(),
+         Addr :: inet:ip_address(),
+         Port :: inet:port_number().
+parse_addr_port(Data) when is_binary(Data) ->
+    parse_addr_port(binary_to_list(Data));
+
+parse_addr_port(Data) when is_list(Data) ->
+    case string:split(Data, ":", trailing) of
+        [AddrStr, PortStr] ->
+            case {inet:parse_address(AddrStr), string:to_integer(PortStr)} of
+                {{ok, Addr}, {Port, []}} -> {ok, {Addr, Port}};
+                _ -> error
+            end;
+        _ -> error
+    end.
+
+
 -spec sockopts_to_map([gen_sctp:option()]) -> map().
 sockopts_to_map(SockOpts) ->
     maps:from_list([{atom_to_binary(K), V} || {K, V} <- SockOpts]).
@@ -368,7 +387,19 @@
     MmeName = binary_to_list(Val),
     mme_registry:fetch_mme_info(MmeName);

-%% TODO: '^addr:[0-9a-f:.]+-[0-9]+$'
+fetch_mme_info(<< "addr:", Val/bytes >>) ->
+    case parse_addr_port(Val) of
+        {ok, {Addr, Port}} ->
+            Fun = fun(#{raddr := R, rport := P}) -> R =:= Addr andalso P =:= 
Port end,
+            case lists:filter(Fun, mme_registry:fetch_mme_list()) of
+                [MmeInfo | _] -> {ok, MmeInfo};
+                [] -> error
+            end;
+        error ->
+            ?LOG_ERROR("Failed to parse MME addr:port from ~p", [Val]),
+            error
+    end;
+
 fetch_mme_info(ID) ->
     ?LOG_ERROR("Unhandled MME ID ~p", [ID]),
     error.
@@ -454,7 +485,15 @@
     Aid = binary_to_integer(Val),
     enb_registry:fetch_enb_list({mme_sctp_aid, Aid});

-%% TODO: '^enb-conn:[0-9:.]+-[0-9]+$'
+fetch_enb_info(<< "enb-conn:", Val/bytes >>) ->
+    case parse_addr_port(Val) of
+        {ok, AddrPort} ->
+            enb_registry:fetch_enb_list({enb_addr_port, AddrPort});
+        error ->
+            ?LOG_ERROR("Failed to parse eNB addr:port from ~p", [Val]),
+            error
+    end;
+
 fetch_enb_info(ID) ->
     ?LOG_ERROR("Unhandled eNB ID ~p", [ID]),
     error.

--
To view, visit https://gerrit.osmocom.org/c/erlang/osmo-s1gw/+/42429?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: If02c8de1e1b7214bba868eee35233a79d0704dc5
Gerrit-Change-Number: 42429
Gerrit-PatchSet: 3
Gerrit-Owner: fixeria <[email protected]>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <[email protected]>
Gerrit-Reviewer: osmith <[email protected]>
Gerrit-Reviewer: pespin <[email protected]>

Reply via email to