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]>