fixeria submitted this change.
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(-)
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
To view, visit change 41006. To unsubscribe, or for help writing mail filters, visit settings.