fixeria has uploaded this change for review. ( https://gerrit.osmocom.org/c/erlang/osmo-s1gw/+/39147?usp=email )
Change subject: erab_fsm: implement E-RAB MODIFY Ind/Cnf procedure ......................................................................
erab_fsm: implement E-RAB MODIFY Ind/Cnf procedure
The eNB-initiated E-RAB modification procedure is defined in 3GPP TS 36.413 section 8.2.4. This is pretty much the same as the MME-initiated E-RAB modification.
Change-Id: I750ada0a5a21edc8bc06d567c8000b6304966474 --- M src/erab_fsm.erl M test/erab_fsm_test.erl M test/pfcp_mock.hrl 3 files changed, 119 insertions(+), 3 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/erlang/osmo-s1gw refs/changes/47/39147/1
diff --git a/src/erab_fsm.erl b/src/erab_fsm.erl index c684510..9d11be6 100644 --- a/src/erab_fsm.erl +++ b/src/erab_fsm.erl @@ -51,6 +51,8 @@ erab_setup_rsp/2, erab_modify_req/2, erab_modify_rsp/2, + erab_modify_ind/2, + erab_modify_cnf/2, erab_release/2, erab_release_cmd/1, erab_release_rsp/1, @@ -77,7 +79,9 @@
-type mod_kind() :: setup_rsp | modify_req | - modify_rsp_nack. + modify_rsp_nack | + modify_ind | + modify_cnf_nack. -type rel_kind() :: cmd | ind.
-record(erab_state, {uid :: term(), %% unique E-RAB identifier @@ -87,6 +91,7 @@ a2u :: undefined | teid_addr(), %% GTP-U params for UPF <- Access u2a :: undefined | teid_addr(), %% GTP-U params for UPF -> Access u2cm :: undefined | teid_addr(), %% GTP-U params for UPF -> Core (modified) + u2am :: undefined | teid_addr(), %% GTP-U params for UPF -> Access (modified) seid_loc :: undefined | pfcp_peer:pfcp_seid(), %% local SEID, chosen by us seid_rem :: undefined | pfcp_peer:pfcp_seid(), %% remote SEID, chosen by the UPF mod_kind :: undefined | mod_kind(), %% E-RAB MODIFY kind @@ -156,6 +161,28 @@ gen_statem:call(Pid, {?FUNCTION_NAME, Res}).
+%% @doc Indicate reception of E-RAB modify indication (from access). +%% @param Pid PID of an erab_fsm. +%% @param F_TEID TEID and bind address indicated by the eNB. +%% @returns TEID and Addr to be sent to the MME; an error otherwise. +%% @end +-spec erab_modify_ind(pid(), teid_addr()) -> {ok, teid_addr()} | + {error, term()}. +erab_modify_ind(Pid, F_TEID) -> + gen_statem:call(Pid, {?FUNCTION_NAME, F_TEID}). + + +%% @doc Indicate reception of E-RAB modify confirmation (from core). +%% @param Pid PID of an erab_fsm. +%% @param Res ack if MME indicates successful modification; +%% nack if MME indicates unsuccessful modification. +%% @returns ok or an error. +%% @end +-spec erab_modify_cnf(pid(), ack | nack) -> ok | {error, term()}. +erab_modify_cnf(Pid, Res) -> + gen_statem:call(Pid, {?FUNCTION_NAME, Res}). + + -spec erab_release(pid(), rel_kind()) -> ok. erab_release(Pid, cmd) -> erab_release_cmd(Pid); @@ -320,6 +347,10 @@ modify_req -> {ok, S#erab_state.a2u}; modify_rsp_nack -> + ok; + modify_ind -> + {ok, S#erab_state.c2u}; + modify_cnf_nack -> ok end, {next_state, erab_setup, @@ -379,6 +410,41 @@ end;
erab_setup({call, From}, + {erab_modify_ind, U2AM}, + #erab_state{} = S) -> + ?LOG_DEBUG("Rx E-RAB MODIFY Ind (U2AM ~p)", [U2AM]), + {next_state, session_modify, + S#erab_state{mod_kind = modify_ind, + from = From, + u2am = U2AM}}; + +erab_setup({call, From}, + {erab_modify_cnf, Res}, + #erab_state{u2am = undefined}) -> + %% Ignore erab_modify_cnf events without prior erab_modify_ind. This happens + %% when the S1AP E-RAB MODIFY Ind contains no F-TEID (nothing to modify). + ?LOG_DEBUG("Rx E-RAB MODIFY Cnf (~p), F-TEID remains unchanged", [Res]), + {keep_state_and_data, {reply, From, ok}}; + +erab_setup({call, From}, + {erab_modify_cnf, Res}, + #erab_state{u2am = U2AM} = S0) -> + ?LOG_DEBUG("Rx E-RAB MODIFY Cnf (~p)", [Res]), + case Res of + ack -> + {keep_state, + S0#erab_state{u2a = U2AM, + u2am = undefined}, + {reply, From, ok}}; + nack -> + %% revert PFCP session params + {next_state, session_modify, + S0#erab_state{mod_kind = modify_cnf_nack, + u2am = undefined, + from = From}} + end; + +erab_setup({call, From}, erab_release_cmd, #erab_state{} = S) -> ?LOG_DEBUG("Rx E-RAB RELEASE Cmd"), @@ -559,7 +625,21 @@ u2c = U2C}) -> %% E-RAB MODIFY Rsp (NACK) - eNB NACK's E-RAB modification %% so we modify the respective FAR (id=2) - session_modify_req(SEID, 2, U2C). + session_modify_req(SEID, 2, U2C); + +session_modify_req(#erab_state{mod_kind = modify_ind, + seid_rem = SEID, + u2am = U2AM}) -> + %% E-RAB MODIFY Ind - eNB orders modification of U2A F-TEID, + %% so we modify the respective FAR (id=1) + session_modify_req(SEID, 1, U2AM); + +session_modify_req(#erab_state{mod_kind = modify_cnf_nack, + seid_rem = SEID, + u2a = U2A}) -> + %% E-RAB MODIFY Cnf (NACK) - MME NACK's E-RAB modification + %% so we modify the respective FAR (id=1) + session_modify_req(SEID, 1, U2A).
-spec session_modify_req(SEID, FAR_ID, F_TEID) -> Result diff --git a/test/erab_fsm_test.erl b/test/erab_fsm_test.erl index 5563d02..c000701 100644 --- a/test/erab_fsm_test.erl +++ b/test/erab_fsm_test.erl @@ -9,6 +9,7 @@ -define(U2A, {?TEID_U2A, ?ADDR_U2A}).
-define(U2CM, {?TEID_U2CM, ?ADDR_U2CM}). +-define(U2AM, {?TEID_U2AM, ?ADDR_U2AM}).
%% ------------------------------------------------------------------ %% setup/misc functions @@ -54,7 +55,11 @@ [{"E-RAB MODIFY REQ :: ACK", ?TC(fun test_erab_modify_req_ack/1)}, {"E-RAB MODIFY REQ :: NACK", - ?TC(fun test_erab_modify_req_nack/1)}]. + ?TC(fun test_erab_modify_req_nack/1)}, + {"E-RAB MODIFY IND :: ACK", + ?TC(fun test_erab_modify_ind_ack/1)}, + {"E-RAB MODIFY IND :: NACK", + ?TC(fun test_erab_modify_ind_nack/1)}].
erab_release_test_() -> @@ -143,6 +148,35 @@ test_erab_modify_req(Pid, nack).
+test_erab_modify_ind(Pid, Res) -> + U2A = case Res of + ack -> ?U2AM; + nack -> ?U2A + end, + [?_assertEqual({ok, ?A2U}, erab_fsm:erab_setup_req(Pid, ?U2C)), + ?_assertEqual({ok, ?C2U}, erab_fsm:erab_setup_rsp(Pid, ?U2A)), + %% E-RAB MODIFY Ind indicates the new (modified) F-TEID to be used + %% in the UPF -> Access direction. The FSM logic indicates the old + %% (unmodified) F-TEID to be used in the UPF <- Core direction. + ?_assertEqual({ok, ?C2U}, erab_fsm:erab_modify_ind(Pid, ?U2AM)), + %% Before getting the Rsp, the U2C F-TEID remains unchanged + ?_assertEqual(?U2A, erab_fsm_info(Pid, f_teid_u2a)), + %% After getting the Cnf (ACK), the new (modified) U2A F-TEID is used + %% After getting the Cnf (NACK), the U2A F-TEID remains unchanged + ?_assertEqual(ok, erab_fsm:erab_modify_cnf(Pid, Res)), + ?_assertEqual(U2A, erab_fsm_info(Pid, f_teid_u2a)), + ?_assertEqual(ok, erab_fsm:shutdown(Pid)), + ?_assertNot(erlang:is_process_alive(Pid))]. + + +test_erab_modify_ind_ack(Pid) -> + test_erab_modify_ind(Pid, ack). + + +test_erab_modify_ind_nack(Pid) -> + test_erab_modify_ind(Pid, nack). + + test_erab_release_cmd_success(Pid) -> [?_assertEqual({ok, ?A2U}, erab_fsm:erab_setup_req(Pid, ?U2C)), ?_assertEqual({ok, ?C2U}, erab_fsm:erab_setup_rsp(Pid, ?U2A)), diff --git a/test/pfcp_mock.hrl b/test/pfcp_mock.hrl index 9a0232a..609d5f2 100644 --- a/test/pfcp_mock.hrl +++ b/test/pfcp_mock.hrl @@ -7,6 +7,7 @@ -define(TEID_U2A, 16#0002). %% UPF -> Access
-define(TEID_U2CM, 16#0f0001). %% UPF -> Core (modified) +-define(TEID_U2AM, 16#0f0002). %% UPF -> Access (modified)
-define(ADDR_U2C, << 16#7f, 16#00, 16#00, 16#01 >>). %% UPF -> Core -define(ADDR_C2U, << 16#7f, 16#00, 16#01, 16#01 >>). %% UPF <- Core @@ -14,5 +15,6 @@ -define(ADDR_U2A, << 16#7f, 16#00, 16#00, 16#02 >>). %% UPF -> Access
-define(ADDR_U2CM, << 16#7f, 16#0f, 16#00, 16#01 >>). %% UPF -> Core (modified) +-define(ADDR_U2AM, << 16#7f, 16#0f, 16#00, 16#02 >>). %% UPF -> Access (modified)
%% vim:set ts=4 sw=4 et: