Skip to content

Commit

Permalink
add PSDBU part or the EPFAR feature
Browse files Browse the repository at this point in the history
Support `PFCP Session Deleted By the UP function` procedure that is part
of the EPFAR (Enhanced PFCP Association Release) feature.
The actually release procedure is not supported, but the "Deleted By the UPF"
can already be used to signal session deletion in the UPF
  • Loading branch information
RoadRunnr committed Jun 4, 2021
1 parent 803d142 commit 74d1e9f
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 9 deletions.
15 changes: 10 additions & 5 deletions apps/ergw_core/src/ergw_gtp_gsn_lib.erl
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
{parse_transform, cut}]).

-export([connect_upf_candidates/4, create_session/10]).
-export([triggered_charging_event/4, usage_report/3, close_context/3]).
-export([triggered_charging_event/4, usage_report/3, close_context/3, close_context/4]).
-export([update_tunnel_endpoint/3, handle_peer_change/3, update_tunnel_endpoint/2,
apply_bearer_change/5]).

Expand Down Expand Up @@ -232,15 +232,20 @@ usage_report(URRActions, UsageReport, #{pfcp := PCtx, 'Session' := Session}) ->
%% close_context/3
close_context(_, {API, TermCause}, Context) ->
close_context(API, TermCause, Context);
close_context(API, TermCause, #{pfcp := PCtx, 'Session' := Session} = Data)
close_context(API, TermCause, #{pfcp := PCtx} = Data)
when is_atom(TermCause) ->
UsageReport = ergw_pfcp_context:delete_session(TermCause, PCtx),
ergw_gtp_gsn_session:close_context(TermCause, UsageReport, PCtx, Session),
ergw_prometheus:termination_cause(API, TermCause),
maps:remove(pfcp, Data);
close_context(API, TermCause, UsageReport, Data);
close_context(_API, _TermCause, Data) ->
Data.

%% close_context/4
close_context(API, TermCause, UsageReport, #{pfcp := PCtx, 'Session' := Session} = Data)
when is_atom(TermCause) ->
ergw_gtp_gsn_session:close_context(TermCause, UsageReport, PCtx, Session),
ergw_prometheus:termination_cause(API, TermCause),
maps:remove(pfcp, Data).

%%====================================================================
%% Helper
%%====================================================================
Expand Down
17 changes: 17 additions & 0 deletions apps/ergw_core/src/gtp_context.erl
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,23 @@ handle_event({call, From},
{next_state, shutdown, Data, [{reply, From, {ok, PCtx}}]}
end;

%% PFCP Session Deleted By the UP function
handle_event({call, From},
{sx, #pfcp{type = session_report_request,
ie = #{pfcpsrreq_flags := #pfcpsrreq_flags{psdbu = 1},
report_type := ReportType} = IEs}},
_State, #{pfcp := PCtx} = Data0) ->
TermCause =
case ReportType of
#report_type{upir = 1} ->
up_inactivity_timeout;
_ ->
deleted_by_upf
end,
UsageReport = maps:get(usage_report_srr, IEs, undefined),
Data = ergw_gtp_gsn_lib:close_context('pfcp', TermCause, UsageReport, Data0),
{next_state, shutdown, Data, [{reply, From, {ok, PCtx}}]};

%% User Plane Inactivity Timer expired
handle_event({call, From},
{sx, #pfcp{type = session_report_request,
Expand Down
11 changes: 7 additions & 4 deletions apps/ergw_core/test/ergw_test_sx_up.erl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

%% API
-export([start/2, stop/1, restart/1,
send/2, send/3, usage_report/4,
send/2, send/3, usage_report/4, usage_report/5,
up_inactivity_timer_expiry/2,
up_quota_validity_time_expiry/2,
reset/1, history/1, history/2,
Expand Down Expand Up @@ -73,7 +73,10 @@ send(Role, SEID, Msg) ->
gen_server:call(server_name(Role), {send, SEID, Msg}).

usage_report(Role, PCtx, MatchSpec, Report) ->
gen_server:call(server_name(Role), {usage_report, PCtx, MatchSpec, Report}).
usage_report(Role, PCtx, MatchSpec, [], Report).

usage_report(Role, PCtx, MatchSpec, IEs, Report) ->
gen_server:call(server_name(Role), {usage_report, PCtx, MatchSpec, IEs, Report}).

up_inactivity_timer_expiry(Role, PCtx) ->
gen_server:call(server_name(Role), {up_inactivity_timer_expiry, PCtx}).
Expand Down Expand Up @@ -215,15 +218,15 @@ handle_call({send, Msg}, _From,
{reply, ok, State};

handle_call({usage_report, #pfcp_ctx{seid = #seid{cp = SEID}, urr_by_id = Rules},
MatchSpec, Report}, _From, State0) ->
MatchSpec, IEs0, Report}, _From, State0) ->
Ids = ets:match_spec_run(maps:to_list(Rules), ets:match_spec_compile(MatchSpec)),
URRs =
if is_function(Report, 2) ->
lists:foldl(Report, [], Ids);
true ->
[#usage_report_srr{group = [#urr_id{id = Id}|Report]} || Id <- Ids]
end,
IEs = [#report_type{usar = 1}|URRs],
IEs = IEs0 ++ [#report_type{usar = 1}|URRs],
SRreq = #pfcp{version = v1, type = session_report_request, ie = IEs},
State = do_send(SEID, SRreq, State0),
{reply, ok, State};
Expand Down
40 changes: 40 additions & 0 deletions apps/ergw_core/test/pgw_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,7 @@ common() ->
sx_upf_restart,
sx_timeout,
sx_ondemand,
pfcp_session_deleted_by_the_up_function,
gy_validity_timer_cp,
gy_validity_timer_up,
simple_aaa,
Expand Down Expand Up @@ -2941,6 +2942,45 @@ sx_ondemand(Config) ->
ok = meck:wait(?HUT, terminate, '_', ?TIMEOUT),
wait4contexts(?TIMEOUT).

%%--------------------------------------------------------------------
pfcp_session_deleted_by_the_up_function() ->
[{doc, "Test TEBUR with PSDBU (Ts 29.244, clause 5.18"}].
pfcp_session_deleted_by_the_up_function(Config) ->
CtxKey = #context_key{socket = 'irx-socket', id = {imsi, ?'IMSI', 5}},

{GtpC, _, _} = create_session(Config),

{_Handler, Server} = gtp_context_reg:lookup(CtxKey),
true = is_pid(Server),
{ok, PCtx} = gtp_context:test_cmd(Server, pfcp_ctx),

MatchSpec = ets:fun2ms(fun({Id, _}) -> Id end),
IEs = [#pfcpsrreq_flags{psdbu = 1}],
Report =
[#usage_report_trigger{tebur = 1, _= 0},
#volume_measurement{total = 5, uplink = 2, downlink = 3},
#tp_packet_measurement{total = 12, uplink = 5, downlink = 7}],

lists:foreach(
fun(_X) ->
ct:sleep(100),
ergw_test_sx_up:usage_report('pgw-u01', PCtx, MatchSpec, IEs, Report)
end, lists:seq(1, 3)),

ct:sleep(100),
delete_session(not_found, GtpC),

?equal(true, meck:called(ergw_aaa_session, invoke, ['_', '_', {gx, 'CCR-Terminate'}, '_'])),
?equal(true, meck:called(ergw_aaa_session, invoke, ['_', '_', {gy, 'CCR-Terminate'}, '_'])),
?equal(true, meck:called(ergw_aaa_session, invoke, ['_', '_', stop, '_'])),

?equal([], outstanding_requests()),
ok = meck:wait(?HUT, terminate, '_', ?TIMEOUT),
wait4contexts(?TIMEOUT),

meck_validate(Config),
ok.

%%--------------------------------------------------------------------

gy_validity_timer_cp() ->
Expand Down

0 comments on commit 74d1e9f

Please sign in to comment.