-module(s1ap_proxy_test). -include_lib("eunit/include/eunit.hrl"). -include("s1gw_metrics.hrl"). -include("pfcp_mock.hrl"). -define(GlobalENBId, "001-01-0"). -define(_assertMetric(Name, Value), ?_assertEqual(Value, s1gw_metrics:get_current_value(Name))). -define(_assertMetricENB(Name, Value), ?_assertMetric(s1gw_metrics:enb_metric(Name, ?GlobalENBId), Value)). %% ------------------------------------------------------------------ %% setup functions %% ------------------------------------------------------------------ -define(TC(Fun), {setup, fun start/0, fun stop/1, Fun}). start() -> pfcp_mock:mock_all(), exometer:start(), s1gw_metrics:init(), enb_registry:start_link(), gtpu_kpi:start_link(#{enable => false}), {ok, EnbHandle} = enb_registry:enb_register(), {ok, Pid} = s1ap_proxy:start_link(EnbHandle, #{addr => {127,0,0,0}, port => 1337}), ok = enb_registry:enb_unregister(EnbHandle), #{handler => Pid}. stop(#{handler := Pid}) -> s1ap_proxy:shutdown(Pid), exometer:stop(), gtpu_kpi:shutdown(), enb_registry:shutdown(), pfcp_mock:unmock_all(). %% ------------------------------------------------------------------ %% testcase descriptions %% ------------------------------------------------------------------ s1ap_proxy_test_() -> [{"S1 SETUP REQUEST/RESPONSE (unmodified)", ?TC(fun test_s1_setup/1)}, {"E-RAB SETUP REQUEST/RESPONSE", ?TC(fun test_e_rab_setup/1)}, {"E-RAB SETUP REQUEST (failure)", ?TC(fun test_e_rab_setup_req_fail/1)}, {"E-RAB SETUP RESPONSE during RELEASE", ?TC(fun test_e_rab_setup_rsp_during_release/1)}, {"E-RAB SETUP REQUEST (duplicate)", ?TC(fun test_e_rab_setup_dup/1)}, {"E-RAB RELEASE COMMAND/RESPONSE", ?TC(fun test_e_rab_release_cmd/1)}, {"E-RAB RELEASE INDICATION", ?TC(fun test_e_rab_release_ind/1)}, {"E-RAB MODIFY REQUEST/RESPONSE (success)", ?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 (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)}, {"INITIAL CONTEXT SETUP REQUEST/RESPONSE (duplicate)", ?TC(fun test_initial_context_setup_dup/1)}, {"INITIAL CONTEXT SETUP RESPONSE during RELEASE", ?TC(fun test_initial_context_setup_rsp_during_release/1)}, {"HANDOVER REQUIRED/COMMAND", ?TC(fun test_handover_preparation/1)}, {"HANDOVER REQUEST/REQUEST ACKNOWLEDGE", ?TC(fun test_handover_res_alloc/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)}, {"ASN.1 parsing error (drop)", ?TC(fun test_drop_asn1_error/1)}, {"PDU processing error (drop)", ?TC(fun test_drop_proc_error/1)}]. %% ------------------------------------------------------------------ %% actual testcases %% ------------------------------------------------------------------ test_s1_setup(#{handler := Pid}) -> SetupReq = s1ap_samples:s1_setup_req_pdu(), SetupRsp = s1ap_samples:s1_setup_rsp_pdu(), %% Expect the PDUs to be proxied unmodified [?_assertEqual({forward, SetupReq}, s1ap_proxy:process_pdu(Pid, SetupReq)), ?_assertEqual({forward, SetupRsp}, s1ap_proxy:process_pdu(Pid, SetupRsp)), %% global counters ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_ALL, 2), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_ALL, 2), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_UNMODIFIED, 2), %% per-eNB counters ?_assertMetricENB(?S1GW_CTR_S1AP_PROXY_IN_PKT_ALL, 2), ?_assertMetricENB(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_ALL, 2), ?_assertMetricENB(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_UNMODIFIED, 2)]. test_e_rab_setup(#{handler := Pid}) -> %% [eNB <- MME] E-RAB SETUP REQUEST SetupReqIn = s1ap_samples:e_rab_setup_req_pdu(?ADDR_U2C, ?TEID_U2C), SetupReqExp = s1ap_samples:e_rab_setup_req_pdu(?ADDR_A2U, ?TEID_A2U), %% [eNB -> MME] E-RAB SETUP RESPONSE SetupRspIn = s1ap_samples:e_rab_setup_rsp_pdu(?ADDR_U2A, ?TEID_U2A), SetupRspExp = s1ap_samples:e_rab_setup_rsp_pdu(?ADDR_C2U, ?TEID_C2U), [?_assertMatch({forward, _}, s1ap_proxy:process_pdu(Pid, s1ap_samples:s1_setup_req_pdu())), ?_assertMatch({forward, _}, s1ap_proxy:process_pdu(Pid, s1ap_samples:s1_setup_rsp_pdu())), ?_assertEqual({forward, SetupReqExp}, s1ap_proxy:process_pdu(Pid, SetupReqIn)), ?_assertEqual({forward, SetupRspExp}, s1ap_proxy:process_pdu(Pid, SetupRspIn)), %% global counters ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_ALL, 2 + 2), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_ERAB_SETUP_REQ, 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_ERAB_SETUP_RSP, 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_ALL, 2 + 2), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_PROC, 2), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_UNMODIFIED, 2), %% per-eNB counters ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_ALL, 2 + 2), ?_assertMetricENB(?S1GW_CTR_S1AP_PROXY_IN_PKT_ERAB_SETUP_REQ, 1), ?_assertMetricENB(?S1GW_CTR_S1AP_PROXY_IN_PKT_ERAB_SETUP_RSP, 1), ?_assertMetricENB(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_ALL, 2 + 2), ?_assertMetricENB(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_PROC, 2), ?_assertMetricENB(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_UNMODIFIED, 2), ?_assertMatch({ok, _}, s1ap_proxy:fetch_erab(Pid, {7, 6})), ?_assertMatch([_], s1ap_proxy:fetch_erab_list(Pid))]. test_e_rab_setup_req_fail(#{handler := Pid}) -> %% pfcp_peer:session_establish_req/3 responds with a reject PDU = pfcp_mock:pdu_rsp_reject(session_establishment_response, ?SEID_Loc), pfcp_mock:mock_req(session_establish_req, PDU), %% eNB <- [S1GW <- MME] E-RAB SETUP REQUEST %% eNB -- [S1GW -> MME] E-RAB SETUP RESPONSE (failure) SetupReqIn = s1ap_samples:e_rab_setup_req_pdu(?ADDR_U2C, ?TEID_U2C), SetupRspExp = s1ap_samples:e_rab_setup_rsp_fail_pdu(), [?_assertEqual({reply, SetupRspExp}, s1ap_proxy:process_pdu(Pid, SetupReqIn)), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_ALL, 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_ERAB_SETUP_REQ, 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_ALL, 0), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_PROC, 0), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_REPLY_ALL, 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_REPLY_ERAB_SETUP_RSP, 1), ?_assertEqual([], s1ap_proxy:fetch_erab_list(Pid))]. test_e_rab_setup_rsp_during_release(#{handler := Pid}) -> %% [eNB <- MME] E-RAB SETUP REQUEST SetupReqIn = s1ap_samples:e_rab_setup_req_pdu(?ADDR_U2C, ?TEID_U2C), SetupReqExp = s1ap_samples:e_rab_setup_req_pdu(?ADDR_A2U, ?TEID_A2U), %% [eNB -> MME] E-RAB SETUP RESPONSE SetupRspIn = s1ap_samples:e_rab_setup_rsp_pdu(?ADDR_U2A, ?TEID_U2A), SetupRspExp = s1ap_samples:e_rab_setup_rsp_pdu(?ADDR_C2U, ?TEID_C2U), %% [eNB <- MME] E-RAB RELEASE COMMAND ReleaseCmd = s1ap_samples:e_rab_release_cmd_pdu(), %% [eNB -> MME] E-RAB RELEASE RESPONSE ReleaseRsp = s1ap_samples:e_rab_release_rsp_pdu(), [%% MME orders allocation of an E-RAB ?_assertEqual({forward, SetupReqExp}, s1ap_proxy:process_pdu(Pid, SetupReqIn)), %% MME orders release of an E-RAB, even before the eNB responds ?_assertEqual({forward, ReleaseCmd}, s1ap_proxy:process_pdu(Pid, ReleaseCmd)), %% eNB confirms allocation of an E-RAB ?_assertEqual({forward, SetupRspExp}, s1ap_proxy:process_pdu(Pid, SetupRspIn)), %% eNB confirms release of an E-RAB ?_assertEqual({forward, ReleaseRsp}, s1ap_proxy:process_pdu(Pid, ReleaseRsp)), %% E-RAB have been released at this point ?_assertEqual([], s1ap_proxy:fetch_erab_list(Pid)), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_ALL, 4), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_ERAB_SETUP_REQ, 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_ERAB_SETUP_RSP, 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_ERAB_RELEASE_CMD, 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_ERAB_RELEASE_RSP, 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_ALL, 4), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_PROC, 2), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_UNMODIFIED, 2)]. test_e_rab_setup_dup(#{handler := Pid}) -> %% [eNB <- MME] E-RAB SETUP REQUEST SetupReqIn = s1ap_samples:e_rab_setup_req_pdu(?ADDR_U2C, ?TEID_U2C), %% [eNB -> MME] E-RAB SETUP RESPONSE SetupRspIn = s1ap_samples:e_rab_setup_rsp_pdu(?ADDR_U2A, ?TEID_U2A), %% eNB <- [S1GW <- MME] E-RAB SETUP REQUEST (duplicate) %% eNB -- [S1GW -> MME] E-RAB SETUP RESPONSE (failure) SetupRspExp = s1ap_samples:e_rab_setup_rsp_fail_pdu(), [?_assertMatch({forward, _}, s1ap_proxy:process_pdu(Pid, SetupReqIn)), ?_assertMatch({forward, _}, s1ap_proxy:process_pdu(Pid, SetupRspIn)), %% duplicate E-RAB SETUP REQUEST triggers a reply ?_assertEqual({reply, SetupRspExp}, s1ap_proxy:process_pdu(Pid, SetupReqIn)), ?_assertMatch({ok, _}, s1ap_proxy:fetch_erab(Pid, {7, 6})), ?_assertMatch([_], s1ap_proxy:fetch_erab_list(Pid))]. test_e_rab_release_cmd(#{handler := Pid}) -> %% [eNB <- MME] E-RAB SETUP REQUEST SetupReq = s1ap_samples:e_rab_setup_req_pdu(?ADDR_U2C, ?TEID_U2C), %% [eNB -> MME] E-RAB SETUP RESPONSE SetupRsp = s1ap_samples:e_rab_setup_rsp_pdu(?ADDR_U2A, ?TEID_U2A), %% [eNB <- MME] E-RAB RELEASE COMMAND ReleaseCmd = s1ap_samples:e_rab_release_cmd_pdu(), %% [eNB -> MME] E-RAB RELEASE RESPONSE ReleaseRsp = s1ap_samples:e_rab_release_rsp_pdu(), [?_assertMatch({forward, _}, s1ap_proxy:process_pdu(Pid, SetupReq)), ?_assertMatch({forward, _}, s1ap_proxy:process_pdu(Pid, SetupRsp)), ?_assertMatch([_], s1ap_proxy:fetch_erab_list(Pid)), ?_assertEqual({forward, ReleaseCmd}, s1ap_proxy:process_pdu(Pid, ReleaseCmd)), ?_assertEqual({forward, ReleaseRsp}, s1ap_proxy:process_pdu(Pid, ReleaseRsp)), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_ALL, 2 + 2), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_ERAB_RELEASE_CMD, 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_ERAB_RELEASE_RSP, 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_ALL, 2 + 2), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_PROC, 2), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_UNMODIFIED, 2), ?_assertEqual([], s1ap_proxy:fetch_erab_list(Pid))]. test_e_rab_release_ind(#{handler := Pid}) -> %% [eNB <- MME] E-RAB SETUP REQUEST SetupReq = s1ap_samples:e_rab_setup_req_pdu(?ADDR_U2C, ?TEID_U2C), %% [eNB -> MME] E-RAB SETUP RESPONSE SetupRsp = s1ap_samples:e_rab_setup_rsp_pdu(?ADDR_U2A, ?TEID_U2A), %% [eNB -> MME] E-RAB RELEASE INDICATION ReleaseInd = s1ap_samples:e_rab_release_ind_pdu(), [?_assertMatch({forward, _}, s1ap_proxy:process_pdu(Pid, SetupReq)), ?_assertMatch({forward, _}, s1ap_proxy:process_pdu(Pid, SetupRsp)), ?_assertEqual({forward, ReleaseInd}, s1ap_proxy:process_pdu(Pid, ReleaseInd)), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_ALL, 3), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_ERAB_RELEASE_IND, 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_ALL, 2 + 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_UNMODIFIED, 1), ?_assertEqual([], s1ap_proxy:fetch_erab_list(Pid))]. test_e_rab_modify_req_rsp(#{handler := Pid}) -> %% [eNB <- MME] E-RAB SETUP REQUEST SetupReq = s1ap_samples:e_rab_setup_req_pdu(?ADDR_U2C, ?TEID_U2C), %% [eNB -> MME] E-RAB SETUP RESPONSE SetupRsp = s1ap_samples:e_rab_setup_rsp_pdu(?ADDR_U2A, ?TEID_U2A), %% eNB <- [S1GW <- MME] E-RAB MODIFY REQUEST (new F-TEID) ModifyReqIn = s1ap_samples:e_rab_modify_req_pdu(?ADDR_U2CM, ?TEID_U2CM), %% [eNB <- S1GW] <- MME E-RAB MODIFY REQUEST %% for the eNB F-TEID remains unchanged ModifyReqExp = s1ap_samples:e_rab_modify_req_pdu(?ADDR_A2U, ?TEID_A2U), %% [eNB -> MME] E-RAB MODIFY RESPONSE ModifyRsp = s1ap_samples:e_rab_modify_rsp_pdu(), %% [eNB -> MME] E-RAB RELEASE INDICATION ReleaseInd = s1ap_samples:e_rab_release_ind_pdu(), [?_assertMatch({forward, _}, s1ap_proxy:process_pdu(Pid, SetupReq)), ?_assertMatch({forward, _}, s1ap_proxy:process_pdu(Pid, SetupRsp)), ?_assertEqual({forward, ModifyReqExp}, s1ap_proxy:process_pdu(Pid, ModifyReqIn)), ?_assertEqual({forward, ModifyRsp}, s1ap_proxy:process_pdu(Pid, ModifyRsp)), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_ALL, 2 + 2), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_ERAB_MODIFY_REQ, 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_ERAB_MODIFY_RSP, 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_ALL, 2 + 2), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_PROC, 2 + 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_UNMODIFIED, 1), ?_assertEqual({forward, ReleaseInd}, s1ap_proxy:process_pdu(Pid, ReleaseInd)), ?_assertEqual([], s1ap_proxy:fetch_erab_list(Pid))]. test_e_rab_modify_req_rsp_fail(#{handler := Pid}) -> %% [eNB <- MME] E-RAB SETUP REQUEST SetupReq = s1ap_samples:e_rab_setup_req_pdu(?ADDR_U2C, ?TEID_U2C), %% [eNB -> MME] E-RAB SETUP RESPONSE SetupRsp = s1ap_samples:e_rab_setup_rsp_pdu(?ADDR_U2A, ?TEID_U2A), %% [eNB <- MME] E-RAB MODIFY REQUEST (new F-TEID) ModifyReq = s1ap_samples:e_rab_modify_req_pdu(?ADDR_U2CM, ?TEID_U2CM), %% [eNB -> MME] E-RAB MODIFY RESPONSE (failure) ModifyRsp = s1ap_samples:e_rab_modify_rsp_fail_pdu(), %% [eNB -> MME] E-RAB RELEASE INDICATION ReleaseInd = s1ap_samples:e_rab_release_ind_pdu(), [?_assertMatch({forward, _}, s1ap_proxy:process_pdu(Pid, SetupReq)), ?_assertMatch({forward, _}, s1ap_proxy:process_pdu(Pid, SetupRsp)), ?_assertMatch({forward, _}, s1ap_proxy:process_pdu(Pid, ModifyReq)), ?_assertEqual({forward, ModifyRsp}, s1ap_proxy:process_pdu(Pid, ModifyRsp)), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_ALL, 2 + 2), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_ERAB_MODIFY_REQ, 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_ERAB_MODIFY_RSP, 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_ALL, 2 + 2), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_PROC, 2 + 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_UNMODIFIED, 1), ?_assertEqual({forward, ReleaseInd}, s1ap_proxy:process_pdu(Pid, ReleaseInd)), ?_assertEqual([], s1ap_proxy:fetch_erab_list(Pid))]. test_e_rab_modify_ind_cnf_modified(#{handler := Pid}) -> %% [eNB <- MME] E-RAB SETUP REQUEST SetupReq = s1ap_samples:e_rab_setup_req_pdu(?ADDR_U2C, ?TEID_U2C), %% [eNB -> MME] E-RAB SETUP RESPONSE SetupRsp = s1ap_samples:e_rab_setup_rsp_pdu(?ADDR_U2A, ?TEID_U2A), %% [eNB -> S1GW] -> MME E-RAB MODIFICATION INDICATION (new F-TEID) ModifyIndIn = s1ap_samples:e_rab_modify_ind_pdu(?ADDR_U2AM, ?TEID_U2AM), %% eNB -> [S1GW -> MME] E-RAB MODIFICATION INDICATION %% for the MME F-TEID remains unchanged ModifyIndExp = s1ap_samples:e_rab_modify_ind_pdu(?ADDR_C2U, ?TEID_C2U), %% [eNB <- MME] E-RAB MODIFICATION CONFIRMATION ModifyCnf = s1ap_samples:e_rab_modify_cnf_pdu(modified), %% [eNB -> MME] E-RAB RELEASE INDICATION ReleaseInd = s1ap_samples: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)), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_ALL, 2 + 2), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_ERAB_MOD_IND, 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_ERAB_MOD_CNF, 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_ALL, 2 + 2), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_PROC, 2 + 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_UNMODIFIED, 1), ?_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 = s1ap_samples:e_rab_setup_req_pdu(?ADDR_U2C, ?TEID_U2C), %% [eNB -> MME] E-RAB SETUP RESPONSE SetupRsp = s1ap_samples:e_rab_setup_rsp_pdu(?ADDR_U2A, ?TEID_U2A), %% [eNB -> S1GW] -> MME E-RAB MODIFICATION INDICATION (new F-TEID) ModifyIndIn = s1ap_samples:e_rab_modify_ind_pdu(?ADDR_U2AM, ?TEID_U2AM), %% eNB -> [S1GW -> MME] E-RAB MODIFICATION INDICATION %% for the MME F-TEID remains unchanged ModifyIndExp = s1ap_samples:e_rab_modify_ind_pdu(?ADDR_C2U, ?TEID_C2U), %% [eNB <- MME] E-RAB MODIFICATION CONFIRMATION ModifyCnf = s1ap_samples:e_rab_modify_cnf_pdu(not_modified), %% [eNB -> MME] E-RAB RELEASE INDICATION ReleaseInd = s1ap_samples: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)), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_ALL, 2 + 2), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_ERAB_MOD_IND, 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_ERAB_MOD_CNF, 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_ALL, 2 + 2), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_PROC, 2 + 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_UNMODIFIED, 1), ?_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 = s1ap_samples:e_rab_setup_req_pdu(?ADDR_U2C, ?TEID_U2C), %% [eNB -> MME] E-RAB SETUP RESPONSE SetupRsp = s1ap_samples:e_rab_setup_rsp_pdu(?ADDR_U2A, ?TEID_U2A), %% [eNB -> S1GW] -> MME E-RAB MODIFICATION INDICATION (new F-TEID) ModifyIndIn = s1ap_samples:e_rab_modify_ind_pdu(?ADDR_U2AM, ?TEID_U2AM), %% eNB -> [S1GW -> MME] E-RAB MODIFICATION INDICATION %% for the MME F-TEID remains unchanged ModifyIndExp = s1ap_samples:e_rab_modify_ind_pdu(?ADDR_C2U, ?TEID_C2U), %% [eNB <- MME] E-RAB MODIFICATION CONFIRMATION ModifyCnf = s1ap_samples: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)), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_ALL, 2 + 2), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_ERAB_MOD_IND, 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_ERAB_MOD_CNF, 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_ALL, 2 + 2), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_PROC, 2 + 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_UNMODIFIED, 1), ?_assertEqual([], s1ap_proxy:fetch_erab_list(Pid))]. test_initial_context_setup(#{handler := Pid}) -> %% [eNB <- MME] INITIAL CONTEXT SETUP REQUEST InitCtxSetupReqIn = s1ap_samples:initial_context_setup_req_pdu(?ADDR_U2C, ?TEID_U2C), InitCtxSetupReqExp = s1ap_samples:initial_context_setup_req_pdu(?ADDR_A2U, ?TEID_A2U), %% [eNB -> MME] INITIAL CONTEXT SETUP RESPONSE InitCtxSetupRspIn = s1ap_samples:initial_context_setup_rsp_pdu(?ADDR_U2A, ?TEID_U2A), InitCtxSetupRspExp = s1ap_samples:initial_context_setup_rsp_pdu(?ADDR_C2U, ?TEID_C2U), [?_assertMatch({forward, _}, s1ap_proxy:process_pdu(Pid, s1ap_samples:s1_setup_req_pdu())), ?_assertMatch({forward, _}, s1ap_proxy:process_pdu(Pid, s1ap_samples:s1_setup_rsp_pdu())), ?_assertEqual({forward, InitCtxSetupReqExp}, s1ap_proxy:process_pdu(Pid, InitCtxSetupReqIn)), ?_assertEqual({forward, InitCtxSetupRspExp}, s1ap_proxy:process_pdu(Pid, InitCtxSetupRspIn)), %% global counters ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_ALL, 2 + 2), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_INIT_CTX_REQ, 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_INIT_CTX_RSP, 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_ALL, 2 + 2), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_PROC, 2), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_UNMODIFIED, 2), %% per-eNB counters ?_assertMetricENB(?S1GW_CTR_S1AP_PROXY_IN_PKT_ALL, 2 + 2), ?_assertMetricENB(?S1GW_CTR_S1AP_PROXY_IN_PKT_INIT_CTX_REQ, 1), ?_assertMetricENB(?S1GW_CTR_S1AP_PROXY_IN_PKT_INIT_CTX_RSP, 1), ?_assertMetricENB(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_ALL, 2 + 2), ?_assertMetricENB(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_PROC, 2), ?_assertMetricENB(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_UNMODIFIED, 2), ?_assertMatch({ok, _}, s1ap_proxy:fetch_erab(Pid, {1, 5})), ?_assertMatch([_], s1ap_proxy:fetch_erab_list(Pid))]. test_initial_context_setup_dup(#{handler := Pid}) -> %% [eNB <- MME] INITIAL CONTEXT SETUP REQUEST InitCtxSetupReqIn = s1ap_samples:initial_context_setup_req_pdu(?ADDR_U2C, ?TEID_U2C), %% [eNB -> MME] INITIAL CONTEXT SETUP RESPONSE InitCtxSetupRspIn = s1ap_samples:initial_context_setup_rsp_pdu(?ADDR_U2A, ?TEID_U2A), [?_assertMatch({forward, _}, s1ap_proxy:process_pdu(Pid, InitCtxSetupReqIn)), ?_assertMatch({forward, _}, s1ap_proxy:process_pdu(Pid, InitCtxSetupRspIn)), %% duplicate INITIAL CONTEXT SETUP REQUEST results in the PDU being dropped ?_assertEqual({drop, InitCtxSetupReqIn}, s1ap_proxy:process_pdu(Pid, InitCtxSetupReqIn)), ?_assertMatch({ok, _}, s1ap_proxy:fetch_erab(Pid, {1, 5})), ?_assertMatch([_], s1ap_proxy:fetch_erab_list(Pid))]. test_initial_context_setup_rsp_during_release(#{handler := Pid}) -> %% [eNB <- MME] INITIAL CONTEXT SETUP REQUEST InitCtxSetupReq = s1ap_samples:initial_context_setup_req_pdu(?ADDR_U2C, ?TEID_U2C), InitCtxSetupReqExp = s1ap_samples:initial_context_setup_req_pdu(?ADDR_A2U, ?TEID_A2U), %% [eNB -> MME] INITIAL CONTEXT SETUP RESPONSE InitCtxSetupRsp = s1ap_samples:initial_context_setup_rsp_pdu(?ADDR_U2A, ?TEID_U2A), InitCtxSetupRspExp = s1ap_samples:initial_context_setup_rsp_pdu(?ADDR_C2U, ?TEID_C2U), %% [eNB -> MME] UE CONTEXT RELEASE REQUEST UeCtxReleaseReq = s1ap_samples:ue_ctx_release_req_pdu(), %% [eNB <- MME] UE CONTEXT RELEASE COMMAND UeCtxReleaseCmd = s1ap_samples:ue_ctx_release_cmd_pdu(), %% [eNB -> MME] UE CONTEXT RELEASE COMPLETE UeCtxReleaseCompl = s1ap_samples:ue_ctx_release_compl_pdu(), [%% MME orders creation of the UE context ?_assertMatch({forward, InitCtxSetupReqExp}, s1ap_proxy:process_pdu(Pid, InitCtxSetupReq)), %% eNB requests the UE context release before even responding to the first PDU ?_assertEqual({forward, UeCtxReleaseReq}, s1ap_proxy:process_pdu(Pid, UeCtxReleaseReq)), %% MME orders release of the UE context, as requested ?_assertEqual({forward, UeCtxReleaseCmd}, s1ap_proxy:process_pdu(Pid, UeCtxReleaseCmd)), %% eNB confirms creation of the UE context ?_assertEqual({forward, InitCtxSetupRspExp}, s1ap_proxy:process_pdu(Pid, InitCtxSetupRsp)), %% eNB confirms release of the UE context ?_assertEqual({forward, UeCtxReleaseCompl}, s1ap_proxy:process_pdu(Pid, UeCtxReleaseCompl)), %% the UE context has been released, so no E-RAB FSMs shall remain ?_assertEqual([], s1ap_proxy:fetch_erab_list(Pid)), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_ALL, 5), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_INIT_CTX_REQ, 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_INIT_CTX_RSP, 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_RELEASE_CTX_REQ, 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_RELEASE_CTX_CMD, 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_RELEASE_CTX_COMPL, 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_ALL, 5), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_PROC, 2), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_UNMODIFIED, 3)]. test_handover_preparation(#{handler := Pid}) -> %% [eNB -> MME] HANDOVER REQUIRED HandoverRqd = s1ap_samples:handover_required_pdu(), %% [MME -> eNB] HANDOVER COMMAND HandoverCmd = s1ap_samples:handover_command_pdu(), [?_assertMatch({forward, HandoverRqd}, s1ap_proxy:process_pdu(Pid, HandoverRqd)), ?_assertMatch({forward, HandoverCmd}, s1ap_proxy:process_pdu(Pid, HandoverCmd)), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_ALL, 2), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_HANDOVER_CMD, 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_ALL, 2), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_PROC, 0), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_UNMODIFIED, 2), ?_assertMatch([], s1ap_proxy:fetch_erab_list(Pid))]. test_handover_res_alloc(#{handler := Pid}) -> %% [MME -> eNB] HANDOVER REQUEST HandoverReqIn = s1ap_samples:handover_request_pdu(?ADDR_U2C, ?TEID_U2C), HandoverReqExp = s1ap_samples:handover_request_pdu(?ADDR_A2U, ?TEID_A2U), %% [eNB -> MME] HANDOVER REQUEST ACKNOWLEDGE HandoverAckIn = s1ap_samples:handover_request_ack_pdu(?ADDR_U2A, ?TEID_U2A), HandoverAckExp = s1ap_samples:handover_request_ack_pdu(?ADDR_C2U, ?TEID_C2U), [?_assertMatch({forward, _}, s1ap_proxy:process_pdu(Pid, s1ap_samples:s1_setup_req_pdu())), ?_assertMatch({forward, _}, s1ap_proxy:process_pdu(Pid, s1ap_samples:s1_setup_rsp_pdu())), ?_assertEqual({forward, HandoverReqExp}, s1ap_proxy:process_pdu(Pid, HandoverReqIn)), ?_assertEqual({forward, HandoverAckExp}, s1ap_proxy:process_pdu(Pid, HandoverAckIn)), %% global counters ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_ALL, 2 + 2), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_HANDOVER_REQ, 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_HANDOVER_REQ_ACK, 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_ALL, 2 + 2), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_PROC, 2), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_UNMODIFIED, 2), %% per-eNB counters ?_assertMetricENB(?S1GW_CTR_S1AP_PROXY_IN_PKT_ALL, 2 + 2), ?_assertMetricENB(?S1GW_CTR_S1AP_PROXY_IN_PKT_HANDOVER_REQ, 1), ?_assertMetricENB(?S1GW_CTR_S1AP_PROXY_IN_PKT_HANDOVER_REQ_ACK, 1), ?_assertMetricENB(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_ALL, 2 + 2), ?_assertMetricENB(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_PROC, 2), ?_assertMetricENB(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_UNMODIFIED, 2), ?_assertMatch([_], s1ap_proxy:fetch_erab_list(Pid))]. test_ue_ctx_release_req(#{handler := Pid}) -> %% [eNB <- MME] INITIAL CONTEXT SETUP REQUEST InitCtxSetupReq = s1ap_samples:initial_context_setup_req_pdu(?ADDR_U2C, ?TEID_U2C), %% [eNB -> MME] INITIAL CONTEXT SETUP RESPONSE InitCtxSetupRsp = s1ap_samples:initial_context_setup_rsp_pdu(?ADDR_U2A, ?TEID_U2A), %% [eNB -> MME] UE CONTEXT RELEASE REQUEST UeCtxReleaseReq = s1ap_samples: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)), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_ALL, 2 + 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_RELEASE_CTX_REQ, 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_ALL, 2 + 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_PROC, 2), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_UNMODIFIED, 1), %% The E-RAB FSM is expected to remain alive and unchanged, %% since this procedure itself does not terminate the UE contect. ?_assertMatch([_], s1ap_proxy:fetch_erab_list(Pid))]. test_ue_ctx_release_cmd(#{handler := Pid}) -> %% [eNB <- MME] INITIAL CONTEXT SETUP REQUEST InitCtxSetupReq = s1ap_samples:initial_context_setup_req_pdu(?ADDR_U2C, ?TEID_U2C), %% [eNB -> MME] INITIAL CONTEXT SETUP RESPONSE InitCtxSetupRsp = s1ap_samples:initial_context_setup_rsp_pdu(?ADDR_U2A, ?TEID_U2A), %% [eNB <- MME] UE CONTEXT RELEASE COMMAND UeCtxReleaseCmd = s1ap_samples:ue_ctx_release_cmd_pdu(), %% [eNB -> MME] UE CONTEXT RELEASE COMPLETE UeCtxReleaseCompl = s1ap_samples: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)), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_ALL, 2 + 2), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_RELEASE_CTX_CMD, 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_RELEASE_CTX_COMPL, 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_ALL, 2 + 2), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_PROC, 2), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_OUT_PKT_FWD_UNMODIFIED, 2), ?_assertMatch([], s1ap_proxy:fetch_erab_list(Pid))]. test_drop_asn1_error(#{handler := Pid}) -> PDU = << 16#de, 16#ad, 16#be, 16#ef >>, [?_assertEqual({drop, PDU}, s1ap_proxy:process_pdu(Pid, PDU)), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_ALL, 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_DROP_ALL, 1)]. test_drop_proc_error(#{handler := Pid}) -> %% [eNB -> MME] INITIAL CONTEXT SETUP RESPONSE InitCtxSetupRsp = s1ap_samples:initial_context_setup_rsp_pdu(?ADDR_U2A, ?TEID_U2A), [?_assertMatch({forward, _}, s1ap_proxy:process_pdu(Pid, s1ap_samples:s1_setup_req_pdu())), ?_assertMatch({forward, _}, s1ap_proxy:process_pdu(Pid, s1ap_samples:s1_setup_rsp_pdu())), %% INITIAL CONTEXT SETUP RESPONSE without prior request %% "Failed to process INITIAL CONTEXT SETUP RESPONSE: erab_not_registered" ?_assertMatch({drop, _}, s1ap_proxy:process_pdu(Pid, InitCtxSetupRsp)), %% global metrics ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_ALL, 2 + 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_PROC_ERROR, 1), ?_assertMetric(?S1GW_CTR_S1AP_PROXY_IN_PKT_DROP_ALL, 1), %% per-eNB metrics ?_assertMetricENB(?S1GW_CTR_S1AP_PROXY_IN_PKT_ALL, 2 + 1), ?_assertMetricENB(?S1GW_CTR_S1AP_PROXY_IN_PKT_PROC_ERROR, 1), ?_assertMetricENB(?S1GW_CTR_S1AP_PROXY_IN_PKT_DROP_ALL, 1)]. %% vim:set ts=4 sw=4 et: