fixeria has uploaded this change for review. ( https://gerrit.osmocom.org/c/erlang/osmo-s1gw/+/37804?usp=email )
Change subject: erab_fsm: implement handling of GTP-U address ......................................................................
erab_fsm: implement handling of GTP-U address
Change-Id: Ifdc492c41266d07d0e951dcdcc1e4ba74da0b13b --- M src/erab_fsm.erl M test/erab_fsm_test.erl M test/pfcp_mock.erl M test/pfcp_mock.hrl 4 files changed, 87 insertions(+), 57 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/erlang/osmo-s1gw refs/changes/04/37804/1
diff --git a/src/erab_fsm.erl b/src/erab_fsm.erl index abc25b1..d2aa065 100644 --- a/src/erab_fsm.erl +++ b/src/erab_fsm.erl @@ -64,12 +64,17 @@ -define(ERAB_T_SESSION_DELETE, 2_000).
-type teid() :: 0..16#ffffffff. +-type addr() :: << _:32 >> | << _:128 >>. + +-type teid_addr() :: {teid(), %% GTP-U TEID + addr() %% GTP-U Transport Layer Address + }.
-record(erab_state, {from :: undefined | gen_statem:from(), %% destination to use when replying - teid_upf2core :: undefined | teid(), %% TEID to be used in UPF -> Core - teid_core2upf :: undefined | teid(), %% TEID to be used in UPF <- Core - teid_acc2upf :: undefined | teid(), %% TEID to be used in UPF <- Access - teid_upf2acc :: undefined | teid(), %% TEID to be used in UPF -> Access + u2c :: undefined | teid_addr(), %% GTP-U params for UPF -> Core + c2u :: undefined | teid_addr(), %% GTP-U params for UPF <- Core + a2u :: undefined | teid_addr(), %% GTP-U params for UPF <- Access + u2a :: undefined | teid_addr(), %% GTP-U params for UPF -> Access 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 }). @@ -91,24 +96,24 @@
%% @doc Indicate reception of E-RAB setup request (from core). %% @param Pid PID of an erab_fsm. -%% @param TEID TEID indicated by the MME. -%% @returns TEID to be sent to the eNB; an error otherwise. +%% @param TA TEID and bind address indicated by the MME. +%% @returns TEID and Addr to be sent to the eNB; an error otherwise. %% @end --spec erab_setup_req(pid(), teid()) -> {ok, teid()} | - {error, term()}. -erab_setup_req(Pid, TEID) -> - gen_statem:call(Pid, {?FUNCTION_NAME, TEID}). +-spec erab_setup_req(pid(), teid_addr()) -> {ok, teid_addr()} | + {error, term()}. +erab_setup_req(Pid, TA) -> + gen_statem:call(Pid, {?FUNCTION_NAME, TA}).
%% @doc Indicate reception of E-RAB setup response (from access). %% @param Pid PID of an erab_fsm. -%% @param TEID TEID indicated by the eNB. -%% @returns TEID to be sent to the MME; an error otherwise. +%% @param TA TEID and bind address indicated by the eNB. +%% @returns TEID and Addr to be sent to the MME; an error otherwise. %% @end --spec erab_setup_rsp(pid(), teid()) -> {ok, teid()} | - {error, term()}. -erab_setup_rsp(Pid, TEID) -> - gen_statem:call(Pid, {?FUNCTION_NAME, TEID}). +-spec erab_setup_rsp(pid(), teid_addr()) -> {ok, teid_addr()} | + {error, term()}. +erab_setup_rsp(Pid, TA) -> + gen_statem:call(Pid, {?FUNCTION_NAME, TA}).
-spec erab_release_req(pid()) -> ok. @@ -148,12 +153,12 @@ {keep_state, S};
erab_wait_setup_req({call, From}, - {erab_setup_req, TEID_U2C}, + {erab_setup_req, U2C}, #erab_state{} = S) -> - ?LOG_DEBUG("Rx E-RAB SETUP Req (TEID UPF -> Core ~p)", [TEID_U2C]), + ?LOG_DEBUG("Rx E-RAB SETUP Req (U2C ~p)", [U2C]), {next_state, session_establish, S#erab_state{from = From, - teid_upf2core = TEID_U2C}}; + u2c = U2C}};
erab_wait_setup_req(Event, EventData, S) -> ?LOG_ERROR("Unexpected event ~p: ~p", [Event, EventData]), @@ -182,15 +187,16 @@ seid = SEID_Rsp, %% matches F-SEID we sent in the ESTABLISH Req ie = #{pfcp_cause := 'Request accepted', f_seid := #f_seid{seid = F_SEID}, - created_pdr := [#{f_teid := #f_teid{teid = TEID_C2U}}, - #{f_teid := #f_teid{teid = TEID_A2U}}]}} -> - ?LOG_DEBUG("PFCP session established"), + created_pdr := [#{f_teid := F_TEID_C2U}, + #{f_teid := F_TEID_A2U}]}} -> + C2U = {F_TEID_C2U#f_teid.teid, f_teid_addr(F_TEID_C2U)}, + A2U = {F_TEID_A2U#f_teid.teid, f_teid_addr(F_TEID_A2U)}, + ?LOG_DEBUG("PFCP session established (C2U ~p, A2U ~p)", [C2U, A2U]), {next_state, erab_wait_setup_rsp, S#erab_state{from = undefined, seid_rem = F_SEID, %% SEID to be used in further requests from us - teid_core2upf = TEID_C2U, - teid_acc2upf = TEID_A2U}, - [{reply, From, {ok, TEID_A2U}}]}; + c2u = C2U, a2u = A2U}, + [{reply, From, {ok, A2U}}]}; _ -> ?LOG_ERROR("Rx unexpected PFCP PDU: ~p", [PDU]), {stop_and_reply, @@ -213,12 +219,12 @@ {stop, {shutdown, timeout}};
erab_wait_setup_rsp({call, From}, - {erab_setup_rsp, TEID_U2A}, + {erab_setup_rsp, U2A}, #erab_state{} = S) -> - ?LOG_DEBUG("Rx E-RAB SETUP Rsp (TEID UPF -> Access ~p)", [TEID_U2A]), + ?LOG_DEBUG("Rx E-RAB SETUP Rsp (U2A ~p)", [U2A]), {next_state, session_modify, S#erab_state{from = From, - teid_upf2acc = TEID_U2A}}; + u2a = U2A}};
%% Catch-all handler for this state erab_wait_setup_rsp(Event, EventData, S) -> @@ -243,7 +249,7 @@ session_modify(info, #pfcp{} = PDU, #erab_state{from = From, seid_loc = SEID_Rsp, - teid_core2upf = TEID_C2U} = S) -> + c2u = C2U} = S) -> case PDU of #pfcp{type = session_modification_response, seid = SEID_Rsp, %% matches F-SEID we sent in the ESTABLISH Req @@ -251,7 +257,7 @@ ?LOG_DEBUG("PFCP session modified"), {next_state, erab_setup, S#erab_state{from = undefined}, - [{reply, From, {ok, TEID_C2U}}]}; + [{reply, From, {ok, C2U}}]}; _ -> ?LOG_ERROR("Rx unexpected PFCP PDU: ~p", [PDU]), {stop_and_reply, @@ -371,7 +377,7 @@
-spec session_establish_req(erab_state()) -> pfcp_peer:pfcp_session_rsp(). session_establish_req(#erab_state{seid_loc = F_SEID, %% used as F-SEID - teid_upf2core = TEID_U2C}) -> + u2c = U2C}) -> %% Packet Detection Rules OHR = #outer_header_removal{header = 'GTP-U/UDP/IPv4'}, PDRs = [#{pdr_id => {pdr_id, 1}, %% -- for Core -> Access @@ -389,11 +395,6 @@ ipv4 = choose}, source_interface => {source_interface, 'Access'}}}], %% Forwarding Action Rules - OHC = #outer_header_creation{n6 = false, - n19 = false, - type = 'GTP-U', - teid = TEID_U2C, - ipv4 = <<127,0,0,1>>}, %% XXX: Core facing addr of the UPF FARs = [#{far_id => {far_id, 1}, %% -- for Core -> Access %% We don't know the Access side TEID / GTP-U address yet, so we set %% this FAR to DROP and modify it when we get E-RAB SETUP RESPONSE. @@ -401,27 +402,44 @@ #{far_id => {far_id, 2}, %% -- for Access -> Core apply_action => #{'FORW' => []}, forwarding_parameters => - #{outer_header_creation => OHC, + #{outer_header_creation => ohc(U2C), destination_interface => {destination_interface, 'Core'}}}], pfcp_peer:session_establish_req(F_SEID, PDRs, FARs).
-spec session_modify_req(erab_state()) -> pfcp_peer:pfcp_session_rsp(). session_modify_req(#erab_state{seid_rem = SEID, %% SEID allocated to us - teid_upf2acc = TEID_U2A}) -> + u2a = U2A}) -> %% Forwarding Action Rules - OHC = #outer_header_creation{n6 = false, - n19 = false, - type = 'GTP-U', - teid = TEID_U2A, - ipv4 = <<127,0,0,1>>}, %% XXX: Access facing addr of the UPF FARs = [#{far_id => {far_id, 1}, %% -- for Core -> Access %% Now we know the Core side TEID / GTP-U address, so we modify %% this FAR (which was previously set to DROP) to FORW. apply_action => #{'FORW' => []}, forwarding_parameters => - #{outer_header_creation => OHC, + #{outer_header_creation => ohc(U2A), destination_interface => {destination_interface, 'Access'}}}], pfcp_peer:session_modify_req(SEID, [], FARs).
+ +ohc({TEID, Addr}) -> + OHC = #outer_header_creation{n6 = false, + n19 = false, + type = 'GTP-U', + teid = TEID}, + case Addr of + << _:32 >> -> + OHC#outer_header_creation{ipv4 = Addr}; + << _:128 >> -> + OHC#outer_header_creation{ipv6 = Addr} + end. + + +%% select an address from F-SEID (prefer IPv6 over IPv4) +f_teid_addr(#f_teid{ipv6 = IPv6}) when is_binary(IPv6) -> + IPv6; +f_teid_addr(#f_teid{ipv4 = IPv4}) when is_binary(IPv4) -> + IPv4; +f_teid_addr(#f_teid{}) -> + undefined. %% TODO: erlang:error()? + %% vim:set ts=4 sw=4 et: diff --git a/test/erab_fsm_test.erl b/test/erab_fsm_test.erl index 5c42f61..1722b3c 100644 --- a/test/erab_fsm_test.erl +++ b/test/erab_fsm_test.erl @@ -3,6 +3,11 @@ -include_lib("eunit/include/eunit.hrl"). -include("pfcp_mock.hrl").
+-define(U2C, {?TEID_U2C, ?ADDR_U2C}). +-define(C2U, {?TEID_C2U, ?ADDR_C2U}). +-define(A2U, {?TEID_A2U, ?ADDR_A2U}). +-define(U2A, {?TEID_U2A, ?ADDR_U2A}). + %% ------------------------------------------------------------------ %% setup functions %% ------------------------------------------------------------------ @@ -57,8 +62,8 @@ %% ------------------------------------------------------------------
test_erab_setup_success(Pid) -> - [?_assertEqual({ok, ?TEID_A2U}, erab_fsm:erab_setup_req(Pid, ?TEID_U2C)), - ?_assertEqual({ok, ?TEID_C2U}, erab_fsm:erab_setup_rsp(Pid, ?TEID_U2A)), + [?_assertEqual({ok, ?A2U}, erab_fsm:erab_setup_req(Pid, ?U2C)), + ?_assertEqual({ok, ?C2U}, erab_fsm:erab_setup_rsp(Pid, ?U2A)), ?_assertEqual(ok, erab_fsm:shutdown(Pid)), ?_assertNot(erlang:is_process_alive(Pid))].
@@ -71,7 +76,7 @@ pfcp_mock:mock_req(session_establish_req, PDU), unlink(Pid), %% we expect the FSM to terminate abnormally Error = {unexp_pdu, session_establish}, - [?_assertEqual({error, Error}, erab_fsm:erab_setup_req(Pid, ?TEID_U2C)), + [?_assertEqual({error, Error}, erab_fsm:erab_setup_req(Pid, ?U2C)), ?_assertNot(erlang:is_process_alive(Pid))].
@@ -81,14 +86,14 @@ pfcp_mock:mock_req(session_modify_req, PDU), unlink(Pid), %% we expect the FSM to terminate abnormally Error = {unexp_pdu, session_modify}, - [?_assertEqual({ok, ?TEID_A2U}, erab_fsm:erab_setup_req(Pid, ?TEID_U2C)), - ?_assertEqual({error, Error}, erab_fsm:erab_setup_rsp(Pid, ?TEID_U2A)), + [?_assertEqual({ok, ?A2U}, erab_fsm:erab_setup_req(Pid, ?U2C)), + ?_assertEqual({error, Error}, erab_fsm:erab_setup_rsp(Pid, ?U2A)), ?_assertNot(erlang:is_process_alive(Pid))].
test_erab_release_success(Pid) -> - [?_assertEqual({ok, ?TEID_A2U}, erab_fsm:erab_setup_req(Pid, ?TEID_U2C)), - ?_assertEqual({ok, ?TEID_C2U}, erab_fsm:erab_setup_rsp(Pid, ?TEID_U2A)), + [?_assertEqual({ok, ?A2U}, erab_fsm:erab_setup_req(Pid, ?U2C)), + ?_assertEqual({ok, ?C2U}, erab_fsm:erab_setup_rsp(Pid, ?U2A)), ?_assertEqual(ok, erab_fsm:erab_release_req(Pid)), ?_assertEqual(ok, erab_fsm:erab_release_rsp(Pid)), ?_assertNot(erlang:is_process_alive(Pid))]. @@ -100,8 +105,8 @@ pfcp_mock:mock_req(session_delete_req, PDU), unlink(Pid), %% we expect the FSM to terminate abnormally Error = {unexp_pdu, session_delete}, - [?_assertEqual({ok, ?TEID_A2U}, erab_fsm:erab_setup_req(Pid, ?TEID_U2C)), - ?_assertEqual({ok, ?TEID_C2U}, erab_fsm:erab_setup_rsp(Pid, ?TEID_U2A)), + [?_assertEqual({ok, ?A2U}, erab_fsm:erab_setup_req(Pid, ?U2C)), + ?_assertEqual({ok, ?C2U}, erab_fsm:erab_setup_rsp(Pid, ?U2A)), ?_assertEqual({error, Error}, erab_fsm:erab_release_req(Pid)), ?_assertNot(erlang:is_process_alive(Pid))].
@@ -114,8 +119,8 @@
test_erab_shutdown_session_del(Pid) -> - [?_assertEqual({ok, ?TEID_A2U}, erab_fsm:erab_setup_req(Pid, ?TEID_U2C)), - ?_assertEqual({ok, ?TEID_C2U}, erab_fsm:erab_setup_rsp(Pid, ?TEID_U2A)), + [?_assertEqual({ok, ?A2U}, erab_fsm:erab_setup_req(Pid, ?U2C)), + ?_assertEqual({ok, ?C2U}, erab_fsm:erab_setup_rsp(Pid, ?U2A)), ?_assertEqual(ok, erab_fsm:shutdown(Pid)), ?_assertNot(erlang:is_process_alive(Pid))].
diff --git a/test/pfcp_mock.erl b/test/pfcp_mock.erl index 635223a..0df8c0b 100644 --- a/test/pfcp_mock.erl +++ b/test/pfcp_mock.erl @@ -89,8 +89,10 @@ pdu_session_establish_rsp() -> IEs = #{pfcp_cause => 'Request accepted', f_seid => #f_seid{seid = ?SEID_Rem}, - created_pdr => [#{f_teid => #f_teid{teid = ?TEID_C2U}}, - #{f_teid => #f_teid{teid = ?TEID_A2U}}]}, + created_pdr => [#{f_teid => #f_teid{teid = ?TEID_C2U, + ipv4 = ?ADDR_C2U}}, + #{f_teid => #f_teid{teid = ?TEID_A2U, + ipv4 = ?ADDR_A2U}}]}, pdu_rsp(session_establishment_response, ?SEID_Loc, IEs).
diff --git a/test/pfcp_mock.hrl b/test/pfcp_mock.hrl index 3a54ade..c044939 100644 --- a/test/pfcp_mock.hrl +++ b/test/pfcp_mock.hrl @@ -6,4 +6,9 @@ -define(TEID_A2U, 16#0202). %% UPF <- Access -define(TEID_U2A, 16#0002). %% UPF -> Access
+-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 +-define(ADDR_A2U, << 16#7f, 16#00, 16#02, 16#02 >>). %% UPF <- Access +-define(ADDR_U2A, << 16#7f, 16#00, 16#00, 16#02 >>). %% UPF -> Access + %% vim:set ts=4 sw=4 et: