diff --git a/apps/ergw_core/src/tdf.erl b/apps/ergw_core/src/tdf.erl index d4c7a8f7..bbbc7d3c 100644 --- a/apps/ergw_core/src/tdf.erl +++ b/apps/ergw_core/src/tdf.erl @@ -390,11 +390,12 @@ start_session(#data{apn = APN, context = Context, dp_node = Node, SOpts = #{now => Now}, SessionOpts0 = init_session(Data), - {_, AuthSEvs} = + {SessionOpts1, AuthSEvs} = case authenticate(Session, SessionOpts0) of {ok, Result2} -> Result2; {error, Err2} -> throw({fail, Err2}) end, + Bearer2 = apply_bearer_opts(SessionOpts1, Bearer1), %% ----------------------------------------------------------- %% TBD: maybe reselect VRF based on outcome of authenticate ?? @@ -437,12 +438,12 @@ start_session(#data{apn = APN, context = Context, dp_node = Node, PCC4 = ergw_pcc_context:session_events_to_pcc_ctx(RfSEvs, PCC3), {PCtx, Bearer, SessionInfo} = - case ergw_pfcp_context:create_session(tdf, PCC4, PendingPCtx, Bearer1, Context) of + case ergw_pfcp_context:create_session(tdf, PCC4, PendingPCtx, Bearer2, Context) of {ok, Result5} -> Result5; {error, Err5} -> throw({fail, Err5}) end, - SessionOpts = maps:merge(SessionOpts0, SessionInfo), + SessionOpts = maps:merge(SessionOpts1, SessionInfo), ergw_aaa_session:invoke(Session, SessionOpts, start, SOpts#{async => true}), Keys = context2keys(Bearer, Context), @@ -486,6 +487,14 @@ init_session(#data{context = #tdf_ctx{ms_ip = UeIP}}) -> Opts1 end. +apply_bearer_opts('NAT-Pool-Id', Id, #{right := #bearer{local = Local} = Right} = Bearer) + when is_record(Local, ue_ip) -> + Bearer#{right => Right#bearer{local = Local#ue_ip{nat = Id}}}; +apply_bearer_opts(_, _, Bearer) -> + Bearer. + +apply_bearer_opts(SOpts, Bearer) -> + maps:fold(fun apply_bearer_opts/3, Bearer, SOpts). authenticate(Session, SessionOpts) -> ?LOG(debug, "SessionOpts: ~p", [SessionOpts]), diff --git a/apps/ergw_core/test/tdf_SUITE.erl b/apps/ergw_core/test/tdf_SUITE.erl index 162939c6..5a188914 100644 --- a/apps/ergw_core/test/tdf_SUITE.erl +++ b/apps/ergw_core/test/tdf_SUITE.erl @@ -425,9 +425,14 @@ common() -> tdf_app_id ]. +only(ipv4) -> + [aa_nat_select]; +only(_) -> + []. + groups() -> - [{ipv4, [], common()}, - {ipv6, [], common()}]. + [{ipv4, [], common() ++ only(ipv4)}, + {ipv6, [], common() ++ only(ipv6)}]. all() -> [{group, ipv4}, @@ -497,6 +502,11 @@ init_per_testcase(tdf_app_id, Config0) -> Config = setup_per_testcase(Config0), ergw_test_lib:load_aaa_answer_config([{{gx, 'CCR-Initial'}, 'Initial-Gx-TDF-App'}]), Config; +init_per_testcase(aa_pool_select, Config) -> + ergw_test_sx_up:ue_ip_pools('tdf-u', [<<"pool-A">>, <<"pool-C">>, + <<"pool-D">>, <<"pool-B">>]), + setup_per_testcase(Config), + Config; init_per_testcase(_, Config) -> setup_per_testcase(Config). @@ -513,6 +523,11 @@ end_per_testcase(TestCase, Config) ok = meck:delete(ergw_aaa_session, invoke, 4), end_per_testcase(Config), Config; +end_per_testcase(aa_nat_select, Config) -> + ergw_test_sx_up:nat_port_blocks('tdf-u', []), + ok = meck:delete(ergw_aaa_session, invoke, 4), + end_per_testcase(Config), + Config; end_per_testcase(_, Config) -> end_per_testcase(Config), Config. @@ -1838,6 +1853,51 @@ tdf_app_id(Config) -> meck_validate(Config), ok. +%%-------------------------------------------------------------------- +aa_nat_select() -> + [{doc, "Select IP-NAT through AAA"}]. +aa_nat_select(Config) -> + AAAReply = #{'NAT-Pool-Id' => <<"nat-B">>}, + + ok = meck:expect(ergw_aaa_session, invoke, + fun (Session, SessionOpts, Procedure = authenticate, Opts) -> + {_, SIn, EvIn} = + meck:passthrough([Session, SessionOpts, Procedure, Opts]), + {SOut, EvOut} = + ergw_aaa_radius:to_session(authenticate, {SIn, EvIn}, AAAReply), + {ok, SOut, EvOut}; + (Session, SessionOpts, Procedure, Opts) -> + meck:passthrough([Session, SessionOpts, Procedure, Opts]) + end), + + UeIP = ergw_inet:ip2bin(proplists:get_value(ue_ip, Config)), + + packet_in(Config), + ct:sleep(100), + + {tdf, Server} = gtp_context_reg:lookup({ue, <<3, "sgi">>, UeIP}), + true = is_pid(Server), + + ct:sleep(100), + stop_session(Server), + ct:sleep(100), + + H = meck:history(ergw_aaa_session), + [SInv|_] = + lists:foldr( + fun({_, {ergw_aaa_session, invoke, [_, _, start, _]}, {ok, Opts}}, Acc) -> + [Opts|Acc]; + (_, Acc) -> + Acc + end, [], H), + ?match(#{'NAT-Pool-Id' := _, + 'NAT-IP-Address' := _, + 'NAT-Port-Start' := _}, SInv), + + ok = meck:wait(?HUT, terminate, '_', ?TIMEOUT), + meck_validate(Config), + ok. + %%%=================================================================== %%% Helper %%%===================================================================