fixeria has submitted this change. ( https://gerrit.osmocom.org/c/erlang/osmo-s1gw/+/39118?usp=email )
Change subject: s1ap_proxy: handle E-RAB MODIFICATION IND/CNF ......................................................................
s1ap_proxy: handle E-RAB MODIFICATION IND/CNF
Change-Id: Icc16a57d40b68bd17c5d207b643927d58176e088 Related: osmo-ttcn3-hacks.git Iec95ca0ecf37290bddfbefce1861f8ae66bf4db1 Related: SYS#7308 --- M include/s1gw_metrics.hrl M src/s1ap_proxy.erl M src/s1gw_metrics.erl M test/erab_fsm_test.erl M test/s1ap_proxy_test.erl 5 files changed, 209 insertions(+), 19 deletions(-)
Approvals: Jenkins Builder: Verified pespin: Looks good to me, approved laforge: Looks good to me, but someone else must approve
diff --git a/include/s1gw_metrics.hrl b/include/s1gw_metrics.hrl index a2a0afd..940529b 100644 --- a/include/s1gw_metrics.hrl +++ b/include/s1gw_metrics.hrl @@ -24,6 +24,7 @@ -define(S1GW_CTR_S1AP_PROXY_IN_PKT_ERAB_RELEASE_RSP, [ctr, s1ap, proxy, in_pkt, erab_release_rsp]). -define(S1GW_CTR_S1AP_PROXY_IN_PKT_ERAB_RELEASE_IND, [ctr, s1ap, proxy, in_pkt, erab_release_ind]). -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_ERAB_MOD_CNF, [ctr, s1ap, proxy, in_pkt, erab_mod_cnf]). -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]). diff --git a/src/s1ap_proxy.erl b/src/s1ap_proxy.erl index 402eaaa..db72dab 100644 --- a/src/s1ap_proxy.erl +++ b/src/s1ap_proxy.erl @@ -399,6 +399,25 @@ PDU = {Outcome, Msg#'InitiatingMessage'{value = C1}}, {{forward, PDU}, S2};
+%% 9.1.3.9 E-RAB MODIFICATION CONFIRM +handle_pdu({successfulOutcome, + #'SuccessfulOutcome'{procedureCode = ?'id-E-RABModificationIndication', + value = C0}}, S0) -> + ?LOG_DEBUG("Processing E-RAB MODIFICATION CONFIRM"), + s1gw_metrics:ctr_inc(?S1GW_CTR_S1AP_PROXY_IN_PKT_ERAB_MOD_CNF), + IEs = C0#'E-RABModificationConfirm'.protocolIEs, + %% E-RAB Modify List + %% TODO: handle {error, Reason} + {_, S1} = handle_ies(?'id-E-RABModifyListBearerModConf', IEs, S0), + %% E-RAB Failed to Modify List + %% TODO: handle {error, Reason} + {_, S2} = handle_ies(?'id-E-RABFailedToModifyListBearerModConf', IEs, S1), + %% E-RAB To Be Released List + %% TODO: handle {error, Reason} + {_, S3} = handle_ies(?'id-E-RABToBeReleasedListBearerModConf', IEs, S2), + %% there's nothing to patch in this PDU, so we forward it as-is + {forward, S3}; + %% 9.1.4.1 INITIAL CONTEXT SETUP REQUEST handle_pdu({Outcome = initiatingMessage, #'InitiatingMessage'{procedureCode = ?'id-InitialContextSetup', @@ -700,16 +719,31 @@ {{error, erab_not_registered}, S} end;
-%% E-RAB MODIFICATION INDICATION related IEs +%% 9.1.3.8 E-RAB MODIFICATION INDICATION related IEs handle_ie([?'id-E-RABToBeModifiedListBearerModInd'], C, S) -> %% This IE contains a list of BearerModInd, so patch inner IEs handle_ies(?'id-E-RABToBeModifiedItemBearerModInd', C, S);
handle_ie([?'id-E-RABToBeModifiedItemBearerModInd', ?'id-E-RABToBeModifiedListBearerModInd'], - #'E-RABToBeModifiedItemBearerModInd'{} = C, S) -> - %% TODO: find and poke an E-RAB FSM associated with this E-RAB - {{ok, C}, S}; + #'E-RABToBeModifiedItemBearerModInd'{'e-RAB-ID' = ERABId, + 'transportLayerAddress' = TLA_In, + 'dL-GTP-TEID' = << TEID_In:32/big >>} = C0, S) -> + %% poke E-RAB FSM + case erab_fsm_find(ERABId, S) of + {ok, Pid} -> + case erab_fsm:erab_modify_ind(Pid, {TEID_In, TLA_In}) of + {ok, {TEID_Out, TLA_Out}} -> + C1 = C0#'E-RABToBeModifiedItemBearerModInd'{'transportLayerAddress' = TLA_Out, + 'dL-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;
handle_ie([?'id-E-RABNotToBeModifiedListBearerModInd'], C, S) -> %% This IE contains a list of BearerModInd, so patch inner IEs @@ -717,9 +751,77 @@
handle_ie([?'id-E-RABNotToBeModifiedItemBearerModInd', ?'id-E-RABNotToBeModifiedListBearerModInd'], - #'E-RABNotToBeModifiedItemBearerModInd'{} = C, S) -> - %% TODO: find and poke an E-RAB FSM associated with this E-RAB - {{ok, C}, S}; + #'E-RABNotToBeModifiedItemBearerModInd'{'e-RAB-ID' = ERABId} = C0, S) -> + %% poke E-RAB FSM + case erab_fsm_find(ERABId, S) of + {ok, Pid} -> + %% Ignore F-TEID in the original message, just replace it with C2U F-TEID + Info = erab_fsm:fetch_info(Pid), + case proplists:get_value(f_teid_c2u, Info) of + {TEID, TLA} -> + C1 = C0#'E-RABNotToBeModifiedItemBearerModInd'{'transportLayerAddress' = TLA, + 'dL-GTP-TEID' = << TEID:32/big >>}, + {{ok, C1}, S}; + undefined -> + ?LOG_ERROR("E-RAB-ID ~p :: missing C2U F-TEID", [erab_uid(ERABId, S)]), + {{error, missing_f_teid}, S} + end; + error -> + ?LOG_ERROR("E-RAB-ID ~p is not registered", [erab_uid(ERABId, S)]), + {{error, erab_not_registered}, S} + end; + +%% 9.1.3.9 E-RAB MODIFICATION CONFIRM related IEs +handle_ie([?'id-E-RABModifyListBearerModConf'], C, S) -> + %% This IE contains a list of BearerModConf, so patch inner IEs + handle_ies(?'id-E-RABModifyItemBearerModConf', C, S); + +handle_ie([?'id-E-RABModifyItemBearerModConf', + ?'id-E-RABModifyListBearerModConf'], + #'E-RABModifyItemBearerModConf'{'e-RAB-ID' = ERABId} = C, S) -> + %% poke E-RAB FSM + case erab_fsm_find(ERABId, S) of + {ok, Pid} -> + ok = erab_fsm:erab_modify_cnf(Pid, ack), + {{ok, C}, S}; + error -> + ?LOG_ERROR("E-RAB-ID ~p is not registered", [erab_uid(ERABId, S)]), + {{error, erab_not_registered}, S} + end; + +handle_ie([?'id-E-RABFailedToModifyListBearerModConf'], 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-RABFailedToModifyListBearerModConf'], + #'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_modify_cnf(Pid, nack), + {{ok, C}, S}; + error -> + ?LOG_ERROR("E-RAB-ID ~p is not registered", [erab_uid(ERABId, S)]), + {{error, erab_not_registered}, S} + end; + +handle_ie([?'id-E-RABToBeReleasedListBearerModConf'], 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-RABToBeReleasedListBearerModConf'], + #'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;
%% INITIAL CONTEXT SETUP REQUEST related IEs handle_ie([?'id-E-RABToBeSetupListCtxtSUReq'], C, S) -> diff --git a/src/s1gw_metrics.erl b/src/s1gw_metrics.erl index c2785de..9f7b2e8 100644 --- a/src/s1gw_metrics.erl +++ b/src/s1gw_metrics.erl @@ -75,6 +75,7 @@ ?S1GW_CTR_S1AP_PROXY_IN_PKT_ERAB_RELEASE_RSP, %% E-RAB RELEASE.rsp PDUs ?S1GW_CTR_S1AP_PROXY_IN_PKT_ERAB_RELEASE_IND, %% E-RAB RELEASE.ind PDUs ?S1GW_CTR_S1AP_PROXY_IN_PKT_ERAB_MOD_IND, %% E-RAB MODIFY.ind PDUs + ?S1GW_CTR_S1AP_PROXY_IN_PKT_ERAB_MOD_CNF, %% E-RAB MODIFY.cnf 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 diff --git a/test/erab_fsm_test.erl b/test/erab_fsm_test.erl index 3740f9a..a3dfb4d 100644 --- a/test/erab_fsm_test.erl +++ b/test/erab_fsm_test.erl @@ -51,6 +51,9 @@ ?TC(fun test_erab_setup_pfcp_modify_error/1)}].
+%% 8.2.4.2 Interactions with E-RAB Setup procedure or E-RAB Modify procedure: +%% TODO: test E-RAB MODIFY IND/CNF during E-RAB SETUP +%% TODO: test E-RAB MODIFY IND/CNF during E-RAB MODIFY erab_modify_test_() -> [{"E-RAB MODIFY REQ :: ACK", ?TC(fun test_erab_modify_req_ack/1)}, diff --git a/test/s1ap_proxy_test.erl b/test/s1ap_proxy_test.erl index 6c04d1b..74f3f05 100644 --- a/test/s1ap_proxy_test.erl +++ b/test/s1ap_proxy_test.erl @@ -46,8 +46,12 @@ ?TC(fun test_e_rab_modify_req_rsp/1)}, {"E-RAB MODIFY REQUEST/RESPONSE (failure)", ?TC(fun test_e_rab_modify_req_rsp_fail/1)}, - {"E-RAB MODIFICATION INDICATION", - ?TC(fun test_e_rab_modify_ind/1)}, + {"E-RAB MODIFICATION INDICATION (modified)", + ?TC(fun test_e_rab_modify_ind_cnf_modified/1)}, + {"E-RAB MODIFICATION INDICATION (not modified)", + ?TC(fun test_e_rab_modify_ind_cnf_not_modified/1)}, + {"E-RAB MODIFICATION INDICATION (release)", + ?TC(fun test_e_rab_modify_ind_cnf_release/1)}, {"INITIAL CONTEXT SETUP REQUEST/RESPONSE", ?TC(fun test_initial_context_setup/1)}, {"UE CONTEXT RELEASE REQUEST", @@ -168,13 +172,70 @@ ?_assertEqual([], s1ap_proxy:fetch_erab_list(Pid))].
-test_e_rab_modify_ind(#{handler := Pid}) -> - %% [eNB -> MME] E-RAB MODIFICATION INDICATION - ModifyIndIn = e_rab_modify_ind_pdu(?ADDR_U2A, ?TEID_U2A), - %% XXX: not implemented, we should actually expect ?ADDR_C2U, ?TEID_C2U - ModifyIndExp = e_rab_modify_ind_pdu(?ADDR_U2A, ?TEID_U2A), +test_e_rab_modify_ind_cnf_modified(#{handler := Pid}) -> + %% [eNB <- MME] E-RAB SETUP REQUEST + SetupReq = e_rab_setup_req_pdu(?ADDR_U2C, ?TEID_U2C), + %% [eNB -> MME] E-RAB SETUP RESPONSE + SetupRsp = e_rab_setup_rsp_pdu(?ADDR_U2A, ?TEID_U2A), + %% [eNB -> S1GW] -> MME E-RAB MODIFICATION INDICATION (new F-TEID) + ModifyIndIn = e_rab_modify_ind_pdu(?ADDR_U2AM, ?TEID_U2AM), + %% eNB -> [S1GW -> MME] E-RAB MODIFICATION INDICATION + %% for the MME F-TEID remains unchanged + ModifyIndExp = e_rab_modify_ind_pdu(?ADDR_C2U, ?TEID_C2U), + %% [eNB <- MME] E-RAB MODIFICATION CONFIRMATION + ModifyCnf = e_rab_modify_cnf_pdu(modified), + %% [eNB -> MME] E-RAB RELEASE INDICATION + ReleaseInd = e_rab_release_ind_pdu(),
- [?_assertEqual({forward, ModifyIndExp}, s1ap_proxy:process_pdu(Pid, ModifyIndIn))]. + [?_assertMatch({forward, _}, s1ap_proxy:process_pdu(Pid, SetupReq)), + ?_assertMatch({forward, _}, s1ap_proxy:process_pdu(Pid, SetupRsp)), + ?_assertEqual({forward, ModifyIndExp}, s1ap_proxy:process_pdu(Pid, ModifyIndIn)), + ?_assertEqual({forward, ModifyCnf}, s1ap_proxy:process_pdu(Pid, ModifyCnf)), + ?_assertEqual({forward, ReleaseInd}, s1ap_proxy:process_pdu(Pid, ReleaseInd)), + ?_assertEqual([], s1ap_proxy:fetch_erab_list(Pid))]. + + +test_e_rab_modify_ind_cnf_not_modified(#{handler := Pid}) -> + %% [eNB <- MME] E-RAB SETUP REQUEST + SetupReq = e_rab_setup_req_pdu(?ADDR_U2C, ?TEID_U2C), + %% [eNB -> MME] E-RAB SETUP RESPONSE + SetupRsp = e_rab_setup_rsp_pdu(?ADDR_U2A, ?TEID_U2A), + %% [eNB -> S1GW] -> MME E-RAB MODIFICATION INDICATION (new F-TEID) + ModifyIndIn = e_rab_modify_ind_pdu(?ADDR_U2AM, ?TEID_U2AM), + %% eNB -> [S1GW -> MME] E-RAB MODIFICATION INDICATION + %% for the MME F-TEID remains unchanged + ModifyIndExp = e_rab_modify_ind_pdu(?ADDR_C2U, ?TEID_C2U), + %% [eNB <- MME] E-RAB MODIFICATION CONFIRMATION + ModifyCnf = e_rab_modify_cnf_pdu(not_modified), + %% [eNB -> MME] E-RAB RELEASE INDICATION + ReleaseInd = e_rab_release_ind_pdu(), + + [?_assertMatch({forward, _}, s1ap_proxy:process_pdu(Pid, SetupReq)), + ?_assertMatch({forward, _}, s1ap_proxy:process_pdu(Pid, SetupRsp)), + ?_assertEqual({forward, ModifyIndExp}, s1ap_proxy:process_pdu(Pid, ModifyIndIn)), + ?_assertEqual({forward, ModifyCnf}, s1ap_proxy:process_pdu(Pid, ModifyCnf)), + ?_assertEqual({forward, ReleaseInd}, s1ap_proxy:process_pdu(Pid, ReleaseInd)), + ?_assertEqual([], s1ap_proxy:fetch_erab_list(Pid))]. + + +test_e_rab_modify_ind_cnf_release(#{handler := Pid}) -> + %% [eNB <- MME] E-RAB SETUP REQUEST + SetupReq = e_rab_setup_req_pdu(?ADDR_U2C, ?TEID_U2C), + %% [eNB -> MME] E-RAB SETUP RESPONSE + SetupRsp = e_rab_setup_rsp_pdu(?ADDR_U2A, ?TEID_U2A), + %% [eNB -> S1GW] -> MME E-RAB MODIFICATION INDICATION (new F-TEID) + ModifyIndIn = e_rab_modify_ind_pdu(?ADDR_U2AM, ?TEID_U2AM), + %% eNB -> [S1GW -> MME] E-RAB MODIFICATION INDICATION + %% for the MME F-TEID remains unchanged + ModifyIndExp = e_rab_modify_ind_pdu(?ADDR_C2U, ?TEID_C2U), + %% [eNB <- MME] E-RAB MODIFICATION CONFIRMATION + ModifyCnf = e_rab_modify_cnf_pdu(release), + + [?_assertMatch({forward, _}, s1ap_proxy:process_pdu(Pid, SetupReq)), + ?_assertMatch({forward, _}, s1ap_proxy:process_pdu(Pid, SetupRsp)), + ?_assertEqual({forward, ModifyIndExp}, s1ap_proxy:process_pdu(Pid, ModifyIndIn)), + ?_assertEqual({forward, ModifyCnf}, s1ap_proxy:process_pdu(Pid, ModifyCnf)), + ?_assertEqual([], s1ap_proxy:fetch_erab_list(Pid))].
test_initial_context_setup(#{handler := Pid}) -> @@ -349,15 +410,37 @@ %% [eNB -> MME] E-RAB MODIFICATION INDICATION e_rab_modify_ind_pdu(TLA, TEID) when is_binary(TLA), is_integer(TEID) -> - << 16#00, 16#32, 16#00, 16#24, 16#00, 16#00, 16#03, 16#00, - 16#00, 16#00, 16#02, 16#00, 16#02, 16#00, 16#08, 16#00, - 16#04, 16#80, 16#06, 16#69, 16#2d, 16#00, 16#c7, 16#00, - 16#0f, 16#00, 16#00, 16#c8, 16#00, 16#0a, 16#0a, 16#1f, + << 16#00, 16#32, 16#00, 16#22, 16#00, 16#00, 16#03, 16#00, + 16#00, 16#00, 16#02, 16#00, 16#07, 16#00, 16#08, 16#00, + 16#02, 16#00, 16#09, 16#00, 16#c7, 16#00, 16#0f, 16#00, + 16#00, 16#c8, 16#00, 16#0a, 16#0c, 16#1f, TLA/bytes, %% transportLayerAddress (IPv4) TEID:32/big %% GTP-TEID >>.
+%% [eNB -> MME] E-RAB MODIFICATION CONFIRMATION +e_rab_modify_cnf_pdu(Res) -> + IEs = case Res of + modified -> + << 16#00, 16#cb, 16#40, 16#06, 16#00, + 16#00, 16#cc, 16#40, 16#01, 16#0c >>; + not_modified -> + %% cause: transport: transport-resource-unavailable (0) + << 16#00, 16#cd, 16#40, 16#07, 16#00, + 16#00, 16#23, 16#40, 16#02, 16#0c, 16#20 >>; + release -> + %% cause: transport: transport-resource-unavailable (0) + << 16#00, 16#d2, 16#40, 16#07, 16#00, + 16#00, 16#23, 16#40, 16#02, 16#0c, 16#20 >> + end, + << 16#20, 16#32, 16#00, (15 + byte_size(IEs)), + 16#00, 16#00, 16#03, 16#00, 16#00, 16#40, 16#02, 16#00, + 16#07, 16#00, 16#08, 16#40, 16#02, 16#00, 16#09, + IEs/bytes + >>. + + %% [eNB <- MME] INITIAL CONTEXT SETUP REQUEST initial_context_setup_req_pdu(TLA, TEID) when is_binary(TLA), is_integer(TEID) ->