fixeria has submitted this change. ( https://gerrit.osmocom.org/c/erlang/osmo-s1gw/+/41006?usp=email )
Change subject: s1ap_proxy: Add support for S1 HANDOVER procedure ......................................................................
s1ap_proxy: Add support for S1 HANDOVER procedure
The HANDOVER procedure consists of two parts:
* Preparation of handover on the source eNB
A list of E-RABs to be released are processed by the proxy.
* Resource allocation on the target eNB
A list of E-RABs to be established are processed by the proxy. GTP-TEIDs and transport layer addresses will be modified.
Change-Id: Ib2c8b1787c60d35a512c3c78d35e1f72a9d7bb08 Related: osmo-ttcn3-hacks.git Id349c84749f7e897defa8cfd2ecd2c1f2fb52fc7 Related: SYS#7309 --- M include/s1gw_metrics.hrl M src/s1ap_proxy.erl M src/s1gw_metrics.erl 3 files changed, 127 insertions(+), 4 deletions(-)
Approvals: pespin: Looks good to me, approved Jenkins Builder: Verified fixeria: Looks good to me, but someone else must approve
diff --git a/include/s1gw_metrics.hrl b/include/s1gw_metrics.hrl index 83ec768..5afbff0 100644 --- a/include/s1gw_metrics.hrl +++ b/include/s1gw_metrics.hrl @@ -31,6 +31,9 @@ -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_compl]). +-define(S1GW_CTR_S1AP_PROXY_IN_PKT_HANDOVER_CMD, [ctr, s1ap, proxy, in_pkt, handover_cmd]). +-define(S1GW_CTR_S1AP_PROXY_IN_PKT_HANDOVER_REQ, [ctr, s1ap, proxy, in_pkt, handover_req]). +-define(S1GW_CTR_S1AP_PROXY_IN_PKT_HANDOVER_REQ_ACK, [ctr, s1ap, proxy, in_pkt, handover_req_ack]). -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 a08f61d..0046167 100644 --- a/src/s1ap_proxy.erl +++ b/src/s1ap_proxy.erl @@ -626,10 +626,58 @@ 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, -%% (O) UL/DL Transport Layer Address +%% 9.1.5.2 HANDOVER COMMAND +handle_pdu({successfulOutcome, + #'SuccessfulOutcome'{procedureCode = ?'id-HandoverPreparation', + value = C0}}, S0) -> + ?LOG_DEBUG("Processing HANDOVER COMMAND"), + ctr_inc(?S1GW_CTR_S1AP_PROXY_IN_PKT_HANDOVER_CMD, S0), + case handle_ies(?'id-E-RABtoReleaseListHOCmd', + C0#'HandoverCommand'.protocolIEs, S0) of + {{ok, _}, S1} -> + {forward, S1}; %% forward as-is, there's nothing to patch + {{error, Reason}, S1} -> + ?LOG_NOTICE("Failed to process HANDOVER COMMAND: ~p", [Reason]), + ctr_inc(?S1GW_CTR_S1AP_PROXY_IN_PKT_PROC_ERROR, S1), + {forward, S1} + end; + +%% 9.1.5.4 HANDOVER REQUEST +handle_pdu({Outcome = initiatingMessage, + #'InitiatingMessage'{procedureCode = ?'id-HandoverResourceAllocation', + value = C0} = Msg}, S0) -> + ?LOG_DEBUG("Processing HANDOVER REQUEST"), + ctr_inc(?S1GW_CTR_S1AP_PROXY_IN_PKT_HANDOVER_REQ, S0), + case handle_ies(?'id-E-RABToBeSetupListHOReq', + C0#'HandoverRequest'.protocolIEs, S0) of + {{ok, IEs}, S1} -> + C1 = C0#'HandoverRequest'{protocolIEs = IEs}, + PDU = {Outcome, Msg#'InitiatingMessage'{value = C1}}, + {{forward, PDU}, S1}; %% forward patched PDU + {{error, Reason}, S1} -> + ?LOG_NOTICE("Failed to process HANDOVER REQUEST: ~p", [Reason]), + ctr_inc(?S1GW_CTR_S1AP_PROXY_IN_PKT_PROC_ERROR, S1), + {drop, S1} %% drop this PDU + end; + +%% 9.1.5.5 HANDOVER REQUEST ACKNOWLEDGE, +handle_pdu({Outcome = successfulOutcome, + #'SuccessfulOutcome'{procedureCode = ?'id-HandoverResourceAllocation', + value = C0} = Msg}, S0) -> + ?LOG_DEBUG("Processing HANDOVER REQUEST ACKNOWLEDGE"), + ctr_inc(?S1GW_CTR_S1AP_PROXY_IN_PKT_HANDOVER_REQ_ACK, S0), + case handle_ies(?'id-E-RABAdmittedList', + C0#'HandoverRequestAcknowledge'.protocolIEs, S0) of + {{ok, IEs}, S1} -> + C1 = C0#'HandoverRequestAcknowledge'{protocolIEs = IEs}, + PDU = {Outcome, Msg#'SuccessfulOutcome'{value = C1}}, + {{forward, PDU}, S1}; %% forward patched PDU + {{error, Reason}, S1} -> + ?LOG_NOTICE("Failed to process HANDOVER REQUEST ACKNOWLEDGE: ~p", [Reason]), + ctr_inc(?S1GW_CTR_S1AP_PROXY_IN_PKT_PROC_ERROR, S1), + {drop, S1} %% drop this PDU + end; + %% TODO: 9.1.5.8 PATH SWITCH REQUEST :: (M) Transport Layer Address %% TODO: 9.1.5.9 PATH SWITCH REQUEST ACKNOWLEDGE :: (M) Transport Layer Address
@@ -1010,6 +1058,74 @@ {{error, erab_not_registered}, S} end;
+%% HANDOVER COMMAND related IEs +handle_ie([?'id-E-RABtoReleaseListHOCmd'], C, S) -> + %% This IE contains a list of E-RABItem, so patch inner IEs + handle_ies(?'id-E-RABItem', C, S); + +handle_ie([?'id-E-RABItem', + ?'id-E-RABtoReleaseListHOCmd'], + #'E-RABItem'{'e-RAB-ID' = ERABId} = C, S) -> + %% poke E-RAB FSM + case erab_fsm_find(ERABId, S) of + {ok, Pid} -> + ok = erab_fsm:erab_release_ind(Pid), + {{ok, C}, S}; + error -> + ?LOG_ERROR("E-RAB-ID ~p is not registered", [erab_uid(ERABId, S)]), + {{error, erab_not_registered}, S} + end; + +%% HANDOVER REQUEST related IEs +handle_ie([?'id-E-RABToBeSetupListHOReq'], C, S) -> + %% This IE contains a list of E-RABToBeSetupItemHOReq, so patch inner IEs + handle_ies(?'id-E-RABToBeSetupItemHOReq', C, S); + +handle_ie([?'id-E-RABToBeSetupItemHOReq', + ?'id-E-RABToBeSetupListHOReq'], + #'E-RABToBeSetupItemHOReq'{'e-RAB-ID' = ERABId, + 'transportLayerAddress' = TLA_In, + 'gTP-TEID' = << TEID_In:32/big >>} = C0, S0) -> + %% start and register an E-RAB FSM + {Pid, S1} = erab_fsm_start_reg(ERABId, S0), + case erab_fsm:erab_setup_req(Pid, {TEID_In, TLA_In}) of + {ok, {TEID_Out, TLA_Out}} -> + C1 = C0#'E-RABToBeSetupItemHOReq'{'transportLayerAddress' = TLA_Out, + 'gTP-TEID' = << TEID_Out:32/big >>}, + {{ok, C1}, S1}; + {error, Reason} -> + {{error, Reason}, S1} + end; + +%% HANDOVER REQUEST ACKNOWLEDGE related IEs +handle_ie([?'id-E-RABAdmittedList'], C, S) -> + %% This IE contains a list of E-RABAdmittedItem, so patch inner IEs + handle_ies(?'id-E-RABAdmittedItem', C, S); + +handle_ie([?'id-E-RABAdmittedItem', + ?'id-E-RABAdmittedList'], + #'E-RABAdmittedItem'{'e-RAB-ID' = ERABId, + 'transportLayerAddress' = TLA_In, + 'gTP-TEID' = << TEID_In:32/big >>} = C0, S) -> + %% indicate eNB's address to the gtpu_kpi module + gtpu_kpi_enb_set_addr({s1ap, tla_str(TLA_In)}), + %% poke E-RAB FSM + case erab_fsm_find(ERABId, S) of + {ok, Pid} -> + case erab_fsm:erab_setup_rsp(Pid, {TEID_In, TLA_In}) of + {ok, {TEID_Out, TLA_Out}} -> + C1 = C0#'E-RABAdmittedItem'{'transportLayerAddress' = TLA_Out, + 'gTP-TEID' = << TEID_Out:32/big >>}, + {{ok, C1}, S}; + {error, Reason} -> + {{error, Reason}, S} + end; + error -> + ?LOG_ERROR("E-RAB-ID ~p is not registered", [erab_uid(ERABId, S)]), + {{error, erab_not_registered}, S} + end; + + %% Catch-all variant, which should not be called normally handle_ie(P, C, S) -> ?LOG_ERROR("[BUG] Unhandled S1AP IE: ~p, ~p", [P, C]), diff --git a/src/s1gw_metrics.erl b/src/s1gw_metrics.erl index 1c3d76e..8a74774 100644 --- a/src/s1gw_metrics.erl +++ b/src/s1gw_metrics.erl @@ -86,6 +86,10 @@ ?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 + ?S1GW_CTR_S1AP_PROXY_IN_PKT_HANDOVER_CMD, %% HANDOVER COMMAND PDUs + ?S1GW_CTR_S1AP_PROXY_IN_PKT_HANDOVER_REQ, %% HANDOVER REQUEST PDUs + ?S1GW_CTR_S1AP_PROXY_IN_PKT_HANDOVER_REQ_ACK, %% HANDOVER REQUEST ACKNOWLEDGE 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