fixeria has uploaded this change for review. (
https://gerrit.osmocom.org/c/erlang/osmo-s1gw/+/39463?usp=email )
Change subject: s1ap_proxy: handle UE CONTEXT RELEASE PDUs
......................................................................
s1ap_proxy: handle UE CONTEXT RELEASE PDUs
On receipt of UE CONTEXT RELEASE PDUs, signal the release of all
affected E-RAB FSMs with the matching {MME,eNB}-UE-S1AP-ID.
Change-Id: Ic94489e3d3052221b49431da3a95e5c1eb0e0ba0
Related: osmo-ttcn3-hacks.git I065692f311e9d03630ab3ca2f6a03465418f0e71
Related: SYS#7310
---
M include/s1gw_metrics.hrl
M src/s1ap_proxy.erl
M src/s1gw_metrics.erl
M test/s1ap_proxy_test.erl
4 files changed, 149 insertions(+), 1 deletion(-)
git pull ssh://gerrit.osmocom.org:29418/erlang/osmo-s1gw refs/changes/63/39463/1
diff --git a/include/s1gw_metrics.hrl b/include/s1gw_metrics.hrl
index 77d6a8e..268b2e9 100644
--- a/include/s1gw_metrics.hrl
+++ b/include/s1gw_metrics.hrl
@@ -24,6 +24,9 @@
-define(S1GW_CTR_S1AP_PROXY_IN_PKT_ERAB_MOD_IND, [ctr, s1ap, proxy, in_pkt,
erab_mod_ind]).
-define(S1GW_CTR_S1AP_PROXY_IN_PKT_INIT_CTX_REQ, [ctr, s1ap, proxy, in_pkt,
init_ctx_req]).
-define(S1GW_CTR_S1AP_PROXY_IN_PKT_INIT_CTX_RSP, [ctr, s1ap, proxy, in_pkt,
init_ctx_rsp]).
+-define(S1GW_CTR_S1AP_PROXY_IN_PKT_RELEASE_CTX_REQ, [ctr, s1ap, proxy, in_pkt,
release_ctx_req]).
+-define(S1GW_CTR_S1AP_PROXY_IN_PKT_RELEASE_CTX_CMD, [ctr, s1ap, proxy, in_pkt,
release_ctx_cmd]).
+-define(S1GW_CTR_S1AP_PROXY_IN_PKT_RELEASE_CTX_COMPL, [ctr, s1ap, proxy, in_pkt,
release_ctx_cnf]).
-define(S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_ALL, [ctr, s1ap, proxy, out_pkt, forward, all]).
-define(S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_PROC, [ctr, s1ap, proxy, out_pkt, forward,
proc]).
-define(S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_UNMODIFIED, [ctr, s1ap, proxy, out_pkt, forward,
unmodified]).
diff --git a/src/s1ap_proxy.erl b/src/s1ap_proxy.erl
index f04fb61..56e5dee 100644
--- a/src/s1ap_proxy.erl
+++ b/src/s1ap_proxy.erl
@@ -172,6 +172,28 @@
{MmeUeId, EnbUeId, ERABId}.
+-spec erab_for_each(UID, Fun, ERABs) -> ok
+ when UID :: {mme_ue_id(), enb_ue_id()} | {mme_ue_id()},
+ Fun :: fun((pid()) -> term()),
+ ERABs :: [{erab_uid(), pid()}].
+erab_for_each({MMEUEId, ENBUEId} = UID, Fun,
+ [{{MMEUEId, ENBUEId, _}, Pid} | ERABs]) ->
+ Fun(Pid), %% matched by a pair of {MME,eNB}-UE-S1AP-ID
+ erab_for_each(UID, Fun, ERABs);
+
+erab_for_each({MMEUEId} = UID, Fun,
+ [{{MMEUEId, _, _}, Pid} | ERABs]) ->
+ Fun(Pid), %% matched by an MME-UE-S1AP-ID
+ erab_for_each(UID, Fun, ERABs);
+
+erab_for_each(UID, Fun,
+ [_ERAB | ERABs]) ->
+ erab_for_each(UID, Fun, ERABs);
+
+erab_for_each(_UID, _Fun, []) ->
+ ok.
+
+
%% Encode an S1AP PDU
-spec encode_pdu(s1ap_pdu()) -> {ok, binary()} |
{error, {asn1, tuple()}}.
@@ -377,6 +399,66 @@
{forward, S1} %% XXX: forward as-is or drop?
end;
+%% 9.1.4.5 UE CONTEXT RELEASE REQUEST
+handle_pdu({initiatingMessage,
+ #'InitiatingMessage'{procedureCode =
?'id-UEContextReleaseRequest',
+ value = #'UEContextReleaseRequest'{protocolIEs =
IEs}}},
+ #proxy_state{erabs = ERABs} = S) ->
+ ?LOG_DEBUG("Processing UE CONTEXT RELEASE REQUEST"),
+ s1gw_metrics:ctr_inc(?S1GW_CTR_S1AP_PROXY_IN_PKT_RELEASE_CTX_REQ),
+ %% fetch {MME,eNB}-UE-S1AP-ID values (mandatory IEs)
+ #'ProtocolIE-Field'{id = ?'id-MME-UE-S1AP-ID',
+ value = MMEUEId} = lists:nth(1, IEs),
+ #'ProtocolIE-Field'{id = ?'id-eNB-UE-S1AP-ID',
+ value = ENBUEId} = lists:nth(2, IEs),
+ %% poke E-RAB FSMs with the matching {MME,eNB}-UE-S1AP-ID
+ erab_for_each({MMEUEId, ENBUEId},
+ fun erab_fsm:erab_release_ind/1,
+ dict:to_list(ERABs)),
+ {forward, S}; %% forward as-is, there's nothing to patch
+
+%% 9.1.4.6 UE CONTEXT RELEASE COMMAND
+handle_pdu({initiatingMessage,
+ #'InitiatingMessage'{procedureCode = ?'id-UEContextRelease',
+ value = #'UEContextReleaseCommand'{protocolIEs =
IEs}}},
+ #proxy_state{erabs = ERABs} = S) ->
+ ?LOG_DEBUG("Processing UE CONTEXT RELEASE COMMAND"),
+ s1gw_metrics:ctr_inc(?S1GW_CTR_S1AP_PROXY_IN_PKT_RELEASE_CTX_CMD),
+ #'ProtocolIE-Field'{id = ?'id-UE-S1AP-IDs',
+ value = S1APIDs} = lists:nth(1, IEs),
+ case S1APIDs of
+ {'uE-S1AP-ID-pair', #'UE-S1AP-ID-pair'{'mME-UE-S1AP-ID' =
MMEUEId,
+ 'eNB-UE-S1AP-ID' = ENBUEId}}
->
+ %% poke E-RAB FSMs with the matching {MME,eNB}-UE-S1AP-ID
+ erab_for_each({MMEUEId, ENBUEId},
+ fun erab_fsm:erab_release_cmd/1,
+ dict:to_list(ERABs));
+ {'mME-UE-S1AP-ID', MMEUEId} ->
+ %% poke E-RAB FSMs with the matching MME-UE-S1AP-ID
+ erab_for_each({MMEUEId},
+ fun erab_fsm:erab_release_cmd/1,
+ dict:to_list(ERABs))
+ end,
+ {forward, S}; %% forward as-is, there's nothing to patch
+
+%% 9.1.4.7 UE CONTEXT RELEASE COMPLETE
+handle_pdu({successfulOutcome,
+ #'SuccessfulOutcome'{procedureCode = ?'id-UEContextRelease',
+ value = #'UEContextReleaseComplete'{protocolIEs
= IEs}}},
+ #proxy_state{erabs = ERABs} = S) ->
+ ?LOG_DEBUG("Processing UE CONTEXT RELEASE COMPLETE"),
+ s1gw_metrics:ctr_inc(?S1GW_CTR_S1AP_PROXY_IN_PKT_RELEASE_CTX_COMPL),
+ %% fetch {MME,eNB}-UE-S1AP-ID values (mandatory IEs)
+ #'ProtocolIE-Field'{id = ?'id-MME-UE-S1AP-ID',
+ value = MMEUEId} = lists:nth(1, IEs),
+ #'ProtocolIE-Field'{id = ?'id-eNB-UE-S1AP-ID',
+ value = ENBUEId} = lists:nth(2, IEs),
+ %% poke E-RAB FSMs with the matching {MME,eNB}-UE-S1AP-ID
+ erab_for_each({MMEUEId, ENBUEId},
+ fun erab_fsm:erab_release_rsp/1,
+ dict:to_list(ERABs)),
+ {forward, S}; %% forward as-is, there's nothing to patch
+
%% TODO: 9.1.5.2 HANDOVER COMMAND :: (O) UL/DL Transport Layer Address
%% TODO: 9.1.5.4 HANDOVER REQUEST :: (M) Transport Layer Address
%% TODO: 9.1.5.5 HANDOVER REQUEST ACKNOWLEDGE :: (M) Transport Layer Address,
diff --git a/src/s1gw_metrics.erl b/src/s1gw_metrics.erl
index 55421e7..50cab10 100644
--- a/src/s1gw_metrics.erl
+++ b/src/s1gw_metrics.erl
@@ -75,6 +75,9 @@
?S1GW_CTR_S1AP_PROXY_IN_PKT_ERAB_MOD_IND, %% E-RAB MODIFY.ind PDUs
?S1GW_CTR_S1AP_PROXY_IN_PKT_INIT_CTX_REQ, %% INITIAL CONTEXT SETUP.req
PDUs
?S1GW_CTR_S1AP_PROXY_IN_PKT_INIT_CTX_RSP, %% INITIAL CONTEXT SETUP.rsp
PDUs
+ ?S1GW_CTR_S1AP_PROXY_IN_PKT_RELEASE_CTX_REQ, %% UE CONTEXT RELEASE.req
PDUs
+ ?S1GW_CTR_S1AP_PROXY_IN_PKT_RELEASE_CTX_CMD, %% UE CONTEXT RELEASE.cmd
PDUs
+ ?S1GW_CTR_S1AP_PROXY_IN_PKT_RELEASE_CTX_COMPL, %% UE CONTEXT RELEASE.compl
PDUs
%% s1ap_proxy: OUTgoing PDU counters
?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_ALL, %% forwarded: total
?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_PROC, %% forwarded: processed
diff --git a/test/s1ap_proxy_test.erl b/test/s1ap_proxy_test.erl
index 917b63e..ce9032e 100644
--- a/test/s1ap_proxy_test.erl
+++ b/test/s1ap_proxy_test.erl
@@ -45,7 +45,11 @@
{"E-RAB MODIFICATION INDICATION",
?TC(fun test_e_rab_modify_ind/1)},
{"INITIAL CONTEXT SETUP REQUEST/RESPONSE",
- ?TC(fun test_initial_context_setup/1)}].
+ ?TC(fun test_initial_context_setup/1)},
+ {"UE CONTEXT RELEASE REQUEST",
+ ?TC(fun test_ue_ctx_release_req/1)},
+ {"UE CONTEXT RELEASE COMMAND/COMPLETE",
+ ?TC(fun test_ue_ctx_release_cmd/1)}].
%% ------------------------------------------------------------------
@@ -139,6 +143,37 @@
?_assertMatch([_], s1ap_proxy:fetch_erab_list(Pid))].
+test_ue_ctx_release_req(#{handler := Pid}) ->
+ %% [eNB <- MME] INITIAL CONTEXT SETUP REQUEST
+ InitCtxSetupReq = initial_context_setup_req_pdu(?ADDR_U2C, ?TEID_U2C),
+ %% [eNB -> MME] INITIAL CONTEXT SETUP RESPONSE
+ InitCtxSetupRsp = initial_context_setup_rsp_pdu(?ADDR_U2A, ?TEID_U2A),
+ %% [eNB -> MME] UE CONTEXT RELEASE REQUEST
+ UeCtxReleaseReq = ue_ctx_release_req_pdu(),
+
+ [?_assertMatch({forward, _}, s1ap_proxy:process_pdu(Pid, InitCtxSetupReq)),
+ ?_assertMatch({forward, _}, s1ap_proxy:process_pdu(Pid, InitCtxSetupRsp)),
+ ?_assertEqual({forward, UeCtxReleaseReq}, s1ap_proxy:process_pdu(Pid,
UeCtxReleaseReq)),
+ ?_assertMatch([], s1ap_proxy:fetch_erab_list(Pid))].
+
+
+test_ue_ctx_release_cmd(#{handler := Pid}) ->
+ %% [eNB <- MME] INITIAL CONTEXT SETUP REQUEST
+ InitCtxSetupReq = initial_context_setup_req_pdu(?ADDR_U2C, ?TEID_U2C),
+ %% [eNB -> MME] INITIAL CONTEXT SETUP RESPONSE
+ InitCtxSetupRsp = initial_context_setup_rsp_pdu(?ADDR_U2A, ?TEID_U2A),
+ %% [eNB <- MME] UE CONTEXT RELEASE COMMAND
+ UeCtxReleaseCmd = ue_ctx_release_cmd_pdu(),
+ %% [eNB -> MME] UE CONTEXT RELEASE COMPLETE
+ UeCtxReleaseCompl = ue_ctx_release_compl_pdu(),
+
+ [?_assertMatch({forward, _}, s1ap_proxy:process_pdu(Pid, InitCtxSetupReq)),
+ ?_assertMatch({forward, _}, s1ap_proxy:process_pdu(Pid, InitCtxSetupRsp)),
+ ?_assertEqual({forward, UeCtxReleaseCmd}, s1ap_proxy:process_pdu(Pid,
UeCtxReleaseCmd)),
+ ?_assertEqual({forward, UeCtxReleaseCompl}, s1ap_proxy:process_pdu(Pid,
UeCtxReleaseCompl)),
+ ?_assertMatch([], s1ap_proxy:fetch_erab_list(Pid))].
+
+
%% ------------------------------------------------------------------
%% S1AP PDU templates
%% ------------------------------------------------------------------
@@ -298,4 +333,29 @@
TEID:32/big %% GTP-TEID
>.
+
+%% [eNB -> MME] UE CONTEXT RELEASE REQUEST
+ue_ctx_release_req_pdu() ->
+ << 16#00, 16#12, 16#40, 16#14, 16#00, 16#00, 16#03, 16#00,
+ 16#00, 16#00, 16#02, 16#00, 16#01, 16#00, 16#08, 16#00,
+ 16#02, 16#00, 16#01, 16#00, 16#02, 16#40, 16#01, 16#20
+ >>.
+
+
+%% [eNB <- MME] UE CONTEXT RELEASE COMMAND
+ue_ctx_release_cmd_pdu() ->
+ << 16#00, 16#17, 16#00, 16#10, 16#00, 16#00, 16#02, 16#00,
+ 16#63, 16#00, 16#04, 16#00, 16#01, 16#00, 16#01, 16#00,
+ 16#02, 16#40, 16#01, 16#20
+ >>.
+
+
+%% [eNB -> MME] UE CONTEXT RELEASE COMPLETE
+ue_ctx_release_compl_pdu() ->
+ << 16#20, 16#17, 16#00, 16#0f, 16#00, 16#00, 16#02, 16#00,
+ 16#00, 16#40, 16#02, 16#00, 16#01, 16#00, 16#08, 16#40,
+ 16#02, 16#00, 16#01
+ >>.
+
+
%% vim:set ts=4 sw=4 et:
--
To view, visit
https://gerrit.osmocom.org/c/erlang/osmo-s1gw/+/39463?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: Ic94489e3d3052221b49431da3a95e5c1eb0e0ba0
Gerrit-Change-Number: 39463
Gerrit-PatchSet: 1
Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de>