Skip to content

Commit

Permalink
add UP Feature checking
Browse files Browse the repository at this point in the history
  • Loading branch information
RoadRunnr committed Apr 15, 2021
1 parent 1c4e690 commit bfcc631
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 18 deletions.
44 changes: 44 additions & 0 deletions apps/ergw/priv/schemas/ergw_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -687,6 +687,50 @@ properties:
upf_nodes:
type: object
properties:
required_upff:
type: array
items:
type: string
enum:
- treu
- heeu
- pfdm
- ftup
- trst
- dlbd
- ddnd
- bucp
- epfar
- pfde
- frrt
- trace
- quoac
- udbc
- pdiu
- empu
- gcom
- bundl
- mte
- mnop
- sset
- ueip
- adpdp
- dpdra
- mptcp
- tscu
- ip6pl
- iptv
- norp
- vtime
- rttl
- mpas
- ethar
- ciot
- mt_edt
- gpqm
- qfqm
- atsss_ll

default:
type: object
properties:
Expand Down
16 changes: 15 additions & 1 deletion apps/ergw/src/ergw_config.erl
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,8 @@ config_meta_nodes() ->
raddr => ip_address,
rport => integer
},
#{default => Default,
#{required_upff => upff,
default => Default,
entries => {map, {name, binary}, Node}}.

config_meta_path_management() ->
Expand Down Expand Up @@ -963,6 +964,11 @@ to_aaa_avp(K0, V0, M) ->
to_aaa_avp(Map) when is_map(Map) ->
maps:fold(fun to_aaa_avp/3, #{}, Map).

to_upff(V) when is_list(V) ->
MinUpFF = #up_function_features{_ = '_'},
lists:foldl(
fun(X) -> to_atom(X) end, MinUpFF, V).

%% complex types

to_object(Meta, K, V)
Expand Down Expand Up @@ -1126,6 +1132,9 @@ from_aaa_avp(_K, Value) ->
from_aaa_avp(Map) when is_map(Map) ->
maps:fold(fun from_aaa_avp/3, #{}, Map).

from_upff(V) ->
[X || X <- '#info-'(up_function_features), '#get-'(X, V) =:= 1].

%% complex types

from_object(Meta, K, V) when is_map(Meta), is_map_key(K, Meta) ->
Expand Down Expand Up @@ -1338,6 +1347,11 @@ load_typespecs() ->
#cnf_type{
coerce = fun to_aaa_avp/1,
serialize = fun from_aaa_avp/1
},
upff =>
#cnf_type{
coerce = fun to_upff/1,
serialize = fun from_upff/1
}
},
register_typespec(Spec).
Expand Down
1 change: 1 addition & 0 deletions apps/ergw/test/config_SUITE_data/pgw.json
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@
}
],
"upf_nodes": {
"required_upff": ["ftup", "treu", "empu"],
"default": {
"heartbeat": {
"interval": {
Expand Down
11 changes: 10 additions & 1 deletion apps/ergw_core/src/ergw_core.erl
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
terminate/3, code_change/4]).

-include_lib("kernel/include/logger.hrl").
-include_lib("pfcplib/include/pfcp_packet.hrl").
-include("ergw_core_config.hrl").
-include("include/ergw.hrl").

Expand Down Expand Up @@ -114,12 +115,16 @@ setopts(node_selection = What, Opts0) ->
setopts(sx_defaults = What, Opts0) ->
Opts = ergw_sx_node:validate_defaults(Opts0),
gen_statem:call(?SERVER, {setopts, What, Opts});
setopts(required_upff = What, Opts) when is_record(Opts, up_function_features) ->
gen_statem:call(?SERVER, {setopts, What, Opts});
setopts(path_management = What, Opts0) ->
Opts = gtp_path:validate_options(Opts0),
gen_statem:call(?SERVER, {setopts, What, Opts});
setopts(proxy_map = What, Opts0) ->
Opts = gtp_proxy_ds:validate_options(Opts0),
gen_statem:call(?SERVER, {setopts, What, Opts}).
gen_statem:call(?SERVER, {setopts, What, Opts});
setopts(What, Opts) ->
error(badarg, [What, Opts]).

%%
%% Initialize a new PFCP, GTPv1/v2-c or GTPv1-u socket
Expand Down Expand Up @@ -380,6 +385,10 @@ handle_event({call, From}, {setopts, sx_defaults, Opts}, running, _) ->
Reply = ergw_sx_node:set_defaults(Opts),
{keep_state_and_data, [{reply, From, Reply}]};

handle_event({call, From}, {setopts, required_upff, Opts}, running, _) ->
Reply = ergw_sx_node:set_required_upff(Opts),
{keep_state_and_data, [{reply, From, Reply}]};

handle_event({call, From}, {setopts, path_management, Opts}, running, _) ->
Reply = gtp_path:setopts(Opts),
{keep_state_and_data, [{reply, From, Reply}]};
Expand Down
64 changes: 48 additions & 16 deletions apps/ergw_core/src/ergw_sx_node.erl
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
%% API
-export([request_connect/3, request_connect/5, wait_connect/1,
attach/1, attach_tdf/2, notify_up/2,
set_defaults/1, add_sx_node/2]).
set_defaults/1, set_required_upff/1, add_sx_node/2]).
-export([start_link/5, send/4, call/2,
handle_request/3, response/3]).
-export([validate_options/2, validate_defaults/1]).
Expand Down Expand Up @@ -43,7 +43,8 @@
-include("ergw_core_config.hrl").
-include("include/ergw.hrl").

-record(data, {cfg,
-record(data, {required_upff,
cfg,
mode = transient :: 'transient' | 'persistent',
node_select :: atom(),
retries = 0 :: non_neg_integer(),
Expand Down Expand Up @@ -151,6 +152,11 @@ set_defaults(Opts0) ->
Opts = ergw_sx_node:validate_defaults(Opts0),
ergw_core_config:put(up_node_defaults, Opts).

set_required_upff(Opts) when is_record(Opts, up_function_features) ->
ergw_core_config:put(up_required_feature, Opts);
set_required_upff(Opts) ->
error(badarg, [Opts]).

add_sx_node(Name, Opts0) ->
Opts = validate_options(Name, Opts0),
{ok, Nodes} = ergw_core_config:get([nodes], #{}),
Expand Down Expand Up @@ -319,14 +325,17 @@ init([Parent, Node, NodeSelect, IP4, IP6, NotifyUp]) ->
#seid_key{seid = SEID}],
gtp_context_reg:register(RegKeys, ?MODULE, self()),

{ok, ReqUpFF} =
ergw_core_config:get([up_required_feature], #up_function_features{_ = '_'}),
{ok, Default} = ergw_core_config:get([up_node_defaults], #{}),
Cfg = case ergw_core_config:get([nodes, Node], Default) of
{ok, Cfg0} -> Cfg0;
_ -> Default
end,

IP = select_node_ip(IP4, IP6),
Data0 = #data{cfg = maps:merge(Default, Cfg),
Data0 = #data{required_upff = ReqUpFF,
cfg = maps:merge(Default, Cfg),
mode = mode(Cfg),
node_select = NodeSelect,
retries = 0,
Expand Down Expand Up @@ -412,14 +421,13 @@ handle_event(cast, {response, association_setup_request, Error},
{next_state, dead, Data#data{retries = Retries + 1}};

handle_event(cast, {response, _, #pfcp{version = v1, type = association_setup_response, ie = IEs}},
connecting, Data0) ->
connecting, Data) ->
case IEs of
#{pfcp_cause := #pfcp_cause{cause = 'Request accepted'}} ->
Data = handle_nodeup(IEs, Data0),
{next_state, {connected, init}, Data};
handle_nodeup(IEs, Data);
Other ->
?LOG(debug, "Other: ~p", [Other]),
{next_state, dead, Data0}
{next_state, dead, Data}
end;

handle_event(cast, {send, 'Access', _VRF, Data}, {connected, _},
Expand Down Expand Up @@ -789,21 +797,45 @@ heartbeat_response(ReqKey, #pfcp{type = heartbeat_request} = Request) ->
ergw_sx_socket:send_response(ReqKey, Response, true).

handle_nodeup(#{recovery_time_stamp := #recovery_time_stamp{time = RecoveryTS}} = IEs,
#data{pfcp_ctx = PNodeCtx,
#data{required_upff = ReqUpFF,
pfcp_ctx = PNodeCtx,
dp = #node{node = Node, ip = IP},
vrfs = VRFs} = Data0) ->
?LOG(debug, "Node ~s (~s) is up", [Node, inet:ntoa(IP)]),
?LOG(debug, "Node IEs: ~s", [pfcp_packet:pretty_print(IEs)]),

UPFeatures = maps:get(up_function_features, IEs, #up_function_features{_ = 0}),
UPIPResInfo = maps:get(user_plane_ip_resource_information, IEs, []),
Data = Data0#data{
pfcp_ctx = PNodeCtx#pfcp_ctx{features = UPFeatures},
recovery_ts = RecoveryTS,
features = UPFeatures,
vrfs = init_vrfs(VRFs, UPIPResInfo)
},
install_cp_rules(Data).
case validate_up_features(UPFeatures, ReqUpFF) of
true ->
UPIPResInfo = maps:get(user_plane_ip_resource_information, IEs, []),
Data1 = Data0#data{
pfcp_ctx = PNodeCtx#pfcp_ctx{features = UPFeatures},
recovery_ts = RecoveryTS,
features = UPFeatures,
vrfs = init_vrfs(VRFs, UPIPResInfo)
},
Data = install_cp_rules(Data1),
{next_state, {connected, init}, Data};
{H, Got, Wanted} ->
?LOG(critical, "~s UP Function Feature, wanted ~p to be ~p, got ~p",
[inet:ntoa(IP), H, Wanted, Got]),
{next_state, dead, Data0}
end.

validate_up_features(UpFF, ReqUpFF) ->
validate_up_ff(
ergw_config:'#info-'(up_function_features),
tl(tuple_to_list(UpFF)),
tl(tuple_to_list(ReqUpFF))).

validate_up_ff(_, List, List) ->
true;
validate_up_ff([_|T], [V|UpFF], [V|ReqUpFF]) ->
validate_up_ff(T, UpFF, ReqUpFF);
validate_up_ff([_|T], [_|UpFF], ['_'|ReqUpFF]) ->
validate_up_ff(T, UpFF, ReqUpFF);
validate_up_ff([H|_], [Got|_], [Wanted|_]) ->
{H, Got, Wanted}.

init_node_cfg(#data{cfg = Cfg} = Data) ->
Data#data{
Expand Down

0 comments on commit bfcc631

Please sign in to comment.