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


Change subject: enb_proxy: add inital MME pooling support
......................................................................

enb_proxy: add inital MME pooling support

Change-Id: I83dc4a78c78a7b87e87f5ca9a941a168d6c1dc36
Related: SYS#7052
---
M src/enb_proxy.erl
M src/s1ap_utils.erl
2 files changed, 74 insertions(+), 32 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/erlang/osmo-s1gw 
refs/changes/24/41624/1

diff --git a/src/enb_proxy.erl b/src/enb_proxy.erl
index 7a51221..bc36c96 100644
--- a/src/enb_proxy.erl
+++ b/src/enb_proxy.erl
@@ -71,6 +71,8 @@
                 enb_conn_info :: sctp_server:conn_info(),
                 mme_conn_cfg :: sctp_client:cfg(),
                 s1setup_req :: undefined | binary(),
+                mme_name :: undefined | mme_registry:mme_name(),
+                enb_tacs :: undefined | [s1ap_utils:tac()],
                 sock :: undefined | gen_sctp:sctp_socket(),
                 enb_handle :: enb_registry:enb_handle(),
                 genb_id_str :: undefined | string(),
@@ -155,9 +157,13 @@
             s1ap_proxy:set_genb_id(S#state.handler, GlobalENBId),
             enb_registry:enb_event(S#state.enb_handle, {s1setup, GENBId}),
             gtpu_kpi_enb_register(S#state{genb_id_str = GlobalENBId}),
+            %% fetch the TAC (Tracking Area Code) list
+            TACs = proplists:get_value(?'id-SupportedTAs', IEs),
+            ?LOG_DEBUG("Broadcast TACs: ~p", [TACs]),
             {next_state, connecting,
              S#state{s1setup_req = Data,
-                     genb_id_str = GlobalENBId}};
+                     genb_id_str = GlobalENBId,
+                     enb_tacs = TACs}};
         {{Proc, Type}, IEs} ->
             ?LOG_ERROR("Rx unexpected S1AP PDU from eNB: ~p/~p, ~p", [Proc, 
Type, IEs]),
             {stop, {shutdown, s1setup_error}};
@@ -171,17 +177,40 @@

 %% CONNECTING state
 connecting(enter, OldState,
-           #state{mme_conn_cfg = MmeConnCfg} = S) ->
+           #state{mme_name = MmeName,
+                  enb_tacs = EnbTACs} = S) ->
     ?LOG_INFO("State change: ~p -> ~p", [OldState, ?FUNCTION_NAME]),
-    %% Initiate connection establishment with the MME
-    {ok, Sock} = sctp_client:connect(MmeConnCfg),
-    %% loop transition to enable state_timeout
-    {next_state, ?FUNCTION_NAME, S#state{sock = Sock},
-     [{state_timeout, 2_000, conn_est_timeout}]};
+    %% Select an MME from the pool
+    case mme_registry:mme_select(#{prev_mme => MmeName,
+                                   enb_tacs => EnbTACs}) of
+        {ok, MmeInfo} ->
+            ?LOG_INFO("MME selection: trying ~p", [maps:get(name, MmeInfo)]),
+            %% Close the old connection, if any
+            close_sock(S),
+            %% Initiate connection establishment with the MME
+            MmeSockOpts = maps:get(sockopts, S#state.mme_conn_cfg),
+            MmeConnCfg = #{laddr => maps:get(laddr, MmeInfo),
+                           raddr => maps:get(raddr, MmeInfo),
+                           rport => maps:get(rport, MmeInfo),
+                           sockopts => MmeSockOpts},
+            {ok, Sock} = sctp_client:connect(MmeConnCfg),
+            {next_state, ?FUNCTION_NAME, %% loop transition to enable 
state_timeout
+             S#state{sock = Sock,
+                     mme_aid = undefined,
+                     mme_name = maps:get(name, MmeInfo),
+                     mme_conn_cfg = MmeConnCfg},
+             [{state_timeout, 2_000, conn_est_timeout}]};
+        error ->
+            ?LOG_ERROR("Failed to select an MME"),
+            {stop, {shutdown, mme_select_error}}
+    end;

 %% Handle connection establishment timeout
-connecting(state_timeout, conn_est_timeout, _S) ->
-    {stop, {shutdown, conn_est_timeout}};
+connecting(state_timeout, conn_est_timeout,
+           #state{mme_name = MmeName}) ->
+    ?LOG_ERROR("Timeout establishing connection with MME ~p", [MmeName]),
+    %% re-enter the state to try again (or another MME)
+    repeat_state_and_data;

 %% Handle PDUs coming from the eNB
 connecting(cast, {send_data, Data}, _S) ->
@@ -202,7 +231,8 @@
             {next_state, wait_s1setup_rsp, S#state{mme_aid = Aid}};
         _ ->
             ?LOG_NOTICE("MME connection establishment failed: ~p", 
[ConnState]),
-            {stop, {shutdown, conn_est_fail}}
+            %% re-enter the state to try again (or another MME)
+            repeat_state_and_data
     end;

 connecting(Event, EventData, S) ->
@@ -216,9 +246,10 @@
      [{state_timeout, 5_000, s1setup_rsp_timeout}]};

 %% Handle S1 SETUP RESPONSE timeout
-wait_s1setup_rsp(state_timeout, s1setup_rsp_timeout, _S) ->
-    ?LOG_ERROR("Timeout waiting for S1 SETUP RESPONSE from MME"),
-    {stop, {shutdown, s1setup_rsp_timeout}};
+wait_s1setup_rsp(state_timeout, s1setup_rsp_timeout, S) ->
+    ?LOG_ERROR("Timeout waiting for S1 SETUP RESPONSE from the MME"),
+    %% re-enter state 'connecting' to try again (or another MME)
+    {next_state, connecting, S};

 %% Handle PDUs coming from the eNB
 wait_s1setup_rsp(cast, {send_data, Data}, _S) ->
@@ -243,13 +274,16 @@
             {next_state, connected, S};
         {{?'id-S1Setup', unsuccessfulOutcome}, _IEs} ->
             ?LOG_NOTICE("Rx S1 SETUP FAILURE from MME"),
-            sctp_send_from_mme(Data, S),
-            {stop, {shutdown, s1setup_error}};
+            %% XXX: sctp_send_from_mme(Data, S),
+            %% re-enter state 'connecting' to try again (or another MME)
+            {next_state, connecting, S};
         {{Proc, Type}, IEs} ->
             ?LOG_ERROR("Rx unexpected S1AP PDU from MME: ~p/~p, ~p", [Proc, 
Type, IEs]),
-            {stop, {shutdown, s1setup_error}};
+            %% re-enter state 'connecting' to try again (or another MME)
+            {next_state, connecting, S};
         {error, _Error} ->
-            {stop, {shutdown, s1setup_error}}
+            %% re-enter state 'connecting' to try again (or another MME)
+            {next_state, connecting, S}
     end;

 %% Handle an #sctp_assoc_change event (MME connection state)
@@ -264,7 +298,8 @@
             {keep_state, S};
         _ ->
             ?LOG_NOTICE("MME connection state: ~p", [ConnState]),
-            {stop, {shutdown, conn_fail}}
+            %% re-enter state 'connecting' to try again (or another MME)
+            {next_state, connecting, S}
     end;

 wait_s1setup_rsp(Event, EventData, S) ->
@@ -353,22 +388,11 @@

 terminate(Reason, State,
           #state{handler = Pid,
-                 enb_handle = Handle,
-                 sock = Sock,
-                 mme_aid = MmeAid}) ->
+                 enb_handle = Handle} = S) ->
     ?LOG_NOTICE("Terminating in state ~p, reason ~p", [State, Reason]),
     enb_registry:enb_unregister(Handle),
     s1ap_proxy:shutdown(Pid),
-    case Sock of
-        undefined -> ok;
-        _ ->
-            case MmeAid of
-                undefined -> ok;
-                _ ->
-                    sctp_common:shutdown({Sock, MmeAid})
-            end,
-            gen_sctp:close(Sock)
-    end.
+    close_sock(S).


 %% ------------------------------------------------------------------
@@ -455,4 +479,20 @@
     end.


+-spec close_sock(state()) -> ok | {error, term()}.
+close_sock(#state{sock = undefined}) -> ok;
+
+close_sock(#state{sock = Sock} = S) ->
+    close_conn(S), %% terminate the MME connection, if needed
+    gen_sctp:close(Sock).
+
+
+
+-spec close_conn(state()) -> ok | {error, term()}.
+close_conn(#state{mme_aid = undefined}) -> ok;
+
+close_conn(#state{sock = Sock, mme_aid = MmeAid}) ->
+    sctp_common:shutdown({Sock, MmeAid}).
+
+
 %% vim:set ts=4 sw=4 et:
diff --git a/src/s1ap_utils.erl b/src/s1ap_utils.erl
index 6f7e6b6..d813e76 100644
--- a/src/s1ap_utils.erl
+++ b/src/s1ap_utils.erl
@@ -68,13 +68,15 @@
               s1ap_pdu_info/0]).


+-type tac() :: 0..16#ffff.
 -type enb_id() :: 0..16#fffffff.
 -type plmn_id() :: {MCC :: nonempty_string(),
                     MNC :: nonempty_string()}.
 -type genb_id() :: #{enb_id => enb_id(),
                      plmn_id => plmn_id()}.

--export_type([enb_id/0,
+-export_type([tac/0,
+              enb_id/0,
               plmn_id/0,
               genb_id/0]).


--
To view, visit https://gerrit.osmocom.org/c/erlang/osmo-s1gw/+/41624?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: I83dc4a78c78a7b87e87f5ca9a941a168d6c1dc36
Gerrit-Change-Number: 41624
Gerrit-PatchSet: 1
Gerrit-Owner: fixeria <[email protected]>

Reply via email to