diff --git a/src/sdlan_network.erl b/src/sdlan_network.erl index 7ed9b03..fb5ec2b 100644 --- a/src/sdlan_network.erl +++ b/src/sdlan_network.erl @@ -161,10 +161,11 @@ debug_info(Pid) when is_pid(Pid) -> gen_server:call(Pid, debug_info). %% @doc Spawns the server and registers the local name (unique) --spec(start_link(Name :: atom(), Id :: integer()) -> +-spec(start_link(Name :: atom(), NetworkData :: tuple()) -> {ok, Pid :: pid()} | ignore | {error, Reason :: term()}). -start_link(Name, Id) when is_atom(Name), is_integer(Id) -> - gen_server:start_link({local, Name}, ?MODULE, [Id], []). +start_link(Name, NetworkData = {network, Id, _NetworkName, _Domain, _IpAddr, _MaskLen, _OwnerId, _Algorithm}) + when is_atom(Name), is_integer(Id) -> + gen_server:start_link({local, Name}, ?MODULE, [NetworkData], []). %%%=================================================================== %%% gen_server callbacks @@ -175,32 +176,22 @@ start_link(Name, Id) when is_atom(Name), is_integer(Id) -> -spec(init(Args :: term()) -> {ok, State :: #state{}} | {ok, State :: #state{}, timeout() | hibernate} | {stop, Reason :: term()} | ignore). -init([Id]) when is_integer(Id) -> +init([{network, Id, Name, Domain, IpAddr, MaskLen, OwnerId, Algorithm0}]) -> erlang:process_flag(trap_exit, true), - case sdlan_api:get_network(Id) of - {ok, #{<<"ipaddr">> := Null}} when Null == <<"null">>; Null == <<"NULL">> -> - {stop, <<"ipaddrr is null">>}; - {ok, NetworkInfo = #{<<"id">> := Id, <<"name">> := Name, <<"domain">> := Domain, <<"algorithm">> := Algorithm0, <<"ipaddr">> := IpAddr0, <<"owner_id">> := OwnerId}} -> - logger:debug("[sdlan_network] load network info: ~p", [NetworkInfo]), - {IpAddr, MaskLen} = parse_ipaddr(IpAddr0), - %% 限流key - ThrottleKey = list_to_atom("network_throttle:" ++ integer_to_list(Id)), - %% 绑定到资源协调器 - sdlan_network_coordinator:attach(self(), ThrottleKey), + %% 限流key + ThrottleKey = list_to_atom("network_throttle:" ++ integer_to_list(Id)), + %% 绑定到资源协调器 + sdlan_network_coordinator:attach(self(), ThrottleKey), - sdlan_domain_regedit:insert(Domain), + sdlan_domain_regedit:insert(Domain), - %% 处理加密算法 - Algorithm = normalization_algorithm(Algorithm0), - Key = gen_key(Algorithm), - EndpointTable = new_endpoint_table(Id), + %% 处理加密算法 + Algorithm = normalization_algorithm(Algorithm0), + Key = gen_key(Algorithm), + EndpointTable = new_endpoint_table(Id), - {ok, #state{network_id = Id, name = Name, domain = Domain, ipaddr = IpAddr, algorithm = Algorithm, - owner_id = OwnerId, mask_len = MaskLen, key = Key, throttle_key = ThrottleKey, endpoint_table = EndpointTable}}; - {error, Reason} -> - logger:warning("[sdlan_network] load network: ~p, get error: ~p", [Id, Reason]), - {stop, Reason} - end. + {ok, #state{network_id = Id, name = Name, domain = Domain, ipaddr = IpAddr, algorithm = Algorithm, + owner_id = OwnerId, mask_len = MaskLen, key = Key, throttle_key = ThrottleKey, endpoint_table = EndpointTable}}. %% @private %% @doc Handling call messages @@ -426,17 +417,6 @@ code_change(_OldVsn, State = #state{}, _Extra) -> %%% Internal functions %%%=================================================================== -%% 解析IpAddr: <<"192.168.172/24">> --spec parse_ipaddr(IpAddr0 :: binary()) -> {IpAddr :: binary(), MaskLen :: integer()}. -parse_ipaddr(IpAddr0) when is_binary(IpAddr0) -> - case binary:split(IpAddr0, <<"/">>) of - [IpAddr, MaskLen] -> - MaskLen1 = binary_to_integer(MaskLen), - {IpAddr, MaskLen1}; - _ -> - {IpAddr0, 24} - end. - -spec limiting_check(ThrottleKey :: any()) -> pass | denied. limiting_check(ThrottleKey) -> case throttle:check(sdlan_network, ThrottleKey) of diff --git a/src/sdlan_network_sup.erl b/src/sdlan_network_sup.erl index 069cd36..0e5bb57 100644 --- a/src/sdlan_network_sup.erl +++ b/src/sdlan_network_sup.erl @@ -40,11 +40,16 @@ start_link() -> %% specifications. init([]) -> SupFlags = #{strategy => one_for_one, intensity => 1000, period => 3600}, - {ok, NetworkIds} = sdlan_api:get_all_networks(), - Specs = lists:map(fun child_spec/1, NetworkIds), - set_network_bind(length(Specs)), + case sdlan_api:get_all_networks() of + {ok, NetworkIds} -> + Specs = lists:filtermap(fun load_child_spec/1, NetworkIds), + set_network_bind(length(Specs)), - {ok, {SupFlags, Specs}}. + {ok, {SupFlags, Specs}}; + {error, Reason} -> + logger:warning("[sdlan_network_sup] load all networks error: ~p", [Reason]), + {stop, {load_networks_failed, Reason}} + end. %%%=================================================================== %%% Internal functions @@ -54,15 +59,11 @@ init([]) -> ensure_network_started(Id) when is_integer(Id) -> case sdlan_network:get_pid(Id) of undefined -> - case supervisor:start_child(?MODULE, child_spec(Id)) of - {ok, Pid} when is_pid(Pid) -> - {ok, Pid}; - {ok, undefined} -> - {error, ignored}; - {error, {'already_started', Pid}} when is_pid(Pid) -> - {ok, Pid}; - {error, Error} -> - {error, Error} + case child_spec(Id) of + {ok, Spec} -> + start_child(Spec); + {error, Reason} -> + {error, Reason} end; Pid when is_pid(Pid) -> {ok, Pid} @@ -70,9 +71,20 @@ ensure_network_started(Id) when is_integer(Id) -> -spec start_network(Id :: integer()) -> {ok, Pid :: pid()} | {error, Reason :: any()}. start_network(Id) when is_integer(Id) -> - case supervisor:start_child(?MODULE, child_spec(Id)) of + case child_spec(Id) of + {ok, Spec} -> + start_child(Spec); + {error, Reason} -> + {error, Reason} + end. + +-spec start_child(Spec :: map()) -> {ok, Pid :: pid()} | {error, Reason :: any()}. +start_child(Spec) -> + case supervisor:start_child(?MODULE, Spec) of {ok, Pid} when is_pid(Pid) -> {ok, Pid}; + {ok, undefined} -> + {error, ignored}; {error, {'already_started', Pid}} when is_pid(Pid) -> {ok, Pid}; {error, Error} -> @@ -99,17 +111,72 @@ delete_network(NetworkId) when is_integer(NetworkId) -> Error end. --spec child_spec(Id :: integer()) -> map(). +-spec child_spec(Id :: integer()) -> {ok, map()} | {error, Reason :: any()}. child_spec(Id) when is_integer(Id) -> - Name = sdlan_network:get_name(Id), - #{ - id => Name, - start => {sdlan_network, start_link, [Name, Id]}, - restart => permanent, - shutdown => 2000, - type => worker, - modules => ['sdlan_network'] - }. + case load_network_data(Id) of + {ok, NetworkData} -> + Name = sdlan_network:get_name(Id), + {ok, #{ + id => Name, + start => {sdlan_network, start_link, [Name, NetworkData]}, + restart => permanent, + shutdown => 2000, + type => worker, + modules => ['sdlan_network'] + }}; + {error, Reason} -> + {error, Reason} + end. + +-spec load_child_spec(Id :: integer()) -> {true, map()} | false. +load_child_spec(Id) -> + case child_spec(Id) of + {ok, Spec} -> + {true, Spec}; + {error, Reason} -> + logger:warning("[sdlan_network_sup] skip network: ~p, reason: ~p", [Id, Reason]), + false + end. + +-spec load_network_data(Id :: integer()) -> {ok, tuple()} | {error, Reason :: any()}. +load_network_data(Id) when is_integer(Id) -> + case sdlan_api:get_network(Id) of + {ok, #{<<"ipaddr">> := Null}} when Null == <<"null">>; Null == <<"NULL">> -> + {error, <<"ipaddrr is null">>}; + {ok, #{<<"id">> := NetworkId}} when NetworkId =/= Id -> + {error, {network_id_mismatch, Id, NetworkId}}; + {ok, NetworkInfo = #{<<"id">> := Id, <<"name">> := Name, <<"domain">> := Domain, + <<"algorithm">> := Algorithm, <<"ipaddr">> := IpAddr0, <<"owner_id">> := OwnerId}} -> + logger:debug("[sdlan_network_sup] load network info: ~p", [NetworkInfo]), + case parse_ipaddr(IpAddr0) of + {ok, IpAddr, MaskLen} -> + {ok, {network, Id, Name, Domain, IpAddr, MaskLen, OwnerId, Algorithm}}; + {error, Reason} -> + {error, Reason} + end; + {ok, NetworkInfo} -> + {error, {invalid_network_info, NetworkInfo}}; + {error, Reason} -> + logger:warning("[sdlan_network_sup] load network: ~p, get error: ~p", [Id, Reason]), + {error, Reason} + end. + +%% 解析IpAddr: <<"192.168.172/24">> +-spec parse_ipaddr(IpAddr0 :: binary()) -> {ok, IpAddr :: binary(), MaskLen :: integer()} | {error, Reason :: any()}. +parse_ipaddr(IpAddr0) when is_binary(IpAddr0) -> + try + case binary:split(IpAddr0, <<"/">>) of + [IpAddr, MaskLen] -> + {ok, IpAddr, binary_to_integer(MaskLen)}; + _ -> + {ok, IpAddr0, 24} + end + catch + _:_ -> + {error, {invalid_ipaddr, IpAddr0}} + end; +parse_ipaddr(IpAddr0) -> + {error, {invalid_ipaddr, IpAddr0}}. set_network_bind(0) -> ok; @@ -117,4 +184,4 @@ set_network_bind(Count) when is_integer(Count) -> {ok, BindWidth} = application:get_env(sdlan, band_width), NetworkBindWidth = BindWidth div Count, application:set_env(sdlan, network_bind_width, NetworkBindWidth), - throttle:setup(sdlan_network, NetworkBindWidth, per_second). \ No newline at end of file + throttle:setup(sdlan_network, NetworkBindWidth, per_second).