aboutsummaryrefslogtreecommitdiffstats
path: root/lib/snmp/src/agent
diff options
context:
space:
mode:
Diffstat (limited to 'lib/snmp/src/agent')
-rw-r--r--lib/snmp/src/agent/snmp_framework_mib.erl86
-rw-r--r--lib/snmp/src/agent/snmp_target_mib.erl12
-rw-r--r--lib/snmp/src/agent/snmpa_conf.erl93
-rw-r--r--lib/snmp/src/agent/snmpa_net_if.erl1020
-rw-r--r--lib/snmp/src/agent/snmpa_trap.erl145
5 files changed, 881 insertions, 475 deletions
diff --git a/lib/snmp/src/agent/snmp_framework_mib.erl b/lib/snmp/src/agent/snmp_framework_mib.erl
index 4599f05f47..3b33cae3ec 100644
--- a/lib/snmp/src/agent/snmp_framework_mib.erl
+++ b/lib/snmp/src/agent/snmp_framework_mib.erl
@@ -41,7 +41,7 @@
-compile({no_auto_import,[error/1]}).
-export([init/0, configure/1]).
-export([intContextTable/1, intContextTable/3,
- intAgentTransportDomain/1,
+ intAgentTransportDomain/1, intAgentTransports/1,
intAgentUDPPort/1, intAgentIpAddress/1,
snmpEngineID/1,
snmpEngineBoots/1,
@@ -137,8 +137,9 @@ read_agent(Dir) ->
error({failed_reading_config_file, Dir, FileName, Reason})
end,
Mand =
- [{intAgentIpAddress, mandatory},
- {intAgentUDPPort, mandatory},
+ [{intAgentTransports, mandatory},
+%%% {intAgentIpAddress, mandatory},
+%%% {intAgentUDPPort, mandatory},
{snmpEngineMaxMessageSize, mandatory},
{snmpEngineID, mandatory}],
{ok, Conf} = snmp_conf:check_mandatory(Conf0, Mand),
@@ -190,27 +191,63 @@ check_context(Context) ->
%% Agent
%% {Name, Value}.
%%-----------------------------------------------------------------
-check_agent({intAgentTransportDomain, D}, _Domain) ->
- {snmp_conf:check_domain(D), D};
-check_agent({intAgentIpAddress = Tag, Value}, D) ->
- Domain =
- case D of
- undefined ->
- snmp_target_mib:default_domain();
- _ ->
- D
- end,
- {case snmp_conf:check_ip(Domain, Value) of
+check_agent(Entry, undefined) ->
+ check_agent(Entry, {snmp_target_mib:default_domain(), undefined});
+check_agent({intAgentTransportDomain, Domain}, {_, Port}) ->
+ {snmp_conf:check_domain(Domain), {Domain, Port}};
+check_agent({intAgentUDPPort, Port}, {Domain, _}) ->
+ ok = snmp_conf:check_port(Port),
+ {ok, {Domain, Port}};
+check_agent({intAgentIpAddress, _}, {_, undefined}) ->
+ error({missing_mandatory, intAgentUDPPort});
+check_agent({intAgentIpAddress = Tag, Ip} = Entry, {Domain, Port} = State) ->
+ {case snmp_conf:check_ip(Domain, Ip) of
ok ->
- ok;
+ [Entry, {intAgentTransports, [{Domain, {Ip, Port}}]}];
{ok, FixedIp} ->
- {ok, {Tag, FixedIp}}
- end, Domain};
-check_agent(Entry, Domain) ->
- {check_agent(Entry), Domain}.
+ [{Tag, Ip}, {intAgentTransports, [{Domain, {FixedIp, Port}}]}]
+ end, State};
+check_agent({intAgentTransports = Tag, Transports}, {_, Port} = State) ->
+ CheckedTransports =
+ [case
+ case Port of
+ undefined ->
+ snmp_conf:check_address(Domain, Address);
+ _ ->
+ snmp_conf:check_address(Domain, Address, Port)
+ end
+ of
+ ok ->
+ Transport;
+ {ok, FixedAddress} ->
+ {Domain, FixedAddress}
+ end
+ || {Domain, Address} = Transport <- Transports],
+ {{ok, {Tag, CheckedTransports}}, State};
+check_agent(Entry, State) ->
+ {check_agent(Entry), State}.
+
+%%% XXX remove
+%%%
+%%% check_agent({intAgentTransportDomain, D}, _Domain) ->
+%%% {snmp_conf:check_domain(D), D};
+%%% check_agent({intAgentIpAddress = Tag, Value}, D) ->
+%%% Domain =
+%%% case D of
+%%% undefined ->
+%%% snmp_target_mib:default_domain();
+%%% _ ->
+%%% D
+%%% end,
+%%% {case snmp_conf:check_ip(Domain, Value) of
+%%% ok ->
+%%% ok;
+%%% {ok, FixedIp} ->
+%%% {ok, {Tag, FixedIp}}
+%%% end, Domain};
+%%% check_agent(Entry, Domain) ->
+%%% {check_agent(Entry), Domain}.
-check_agent({intAgentUDPPort, Value}) ->
- snmp_conf:check_integer(Value);
%% This one is kept for backwards compatibility
check_agent({intAgentMaxPacketSize, Value}) ->
snmp_conf:check_packet_size(Value);
@@ -224,7 +261,9 @@ check_agent(X) ->
%% Ordering function to sort intAgentTransportDomain first
%% hence before intAgentIpAddress. Sort other entries on the key.
order_agent(EntryA, EntryB) ->
- snmp_conf:keyorder(1, EntryA, EntryB, [intAgentTransportDomain | sort]).
+ snmp_conf:keyorder(
+ 1, EntryA, EntryB,
+ [intAgentTransportDomain, intAgentUDPPort | sort]).
@@ -402,6 +441,9 @@ intAgentIpAddress(Op) ->
intAgentTransportDomain(Op) ->
snmp_generic:variable_func(Op, db(intAgentTransportDomain)).
+intAgentTransports(Op) ->
+ snmp_generic:variable_func(Op, db(intAgentTransports)).
+
snmpEngineID(print) ->
diff --git a/lib/snmp/src/agent/snmp_target_mib.erl b/lib/snmp/src/agent/snmp_target_mib.erl
index 932829e150..e916f17d6a 100644
--- a/lib/snmp/src/agent/snmp_target_mib.erl
+++ b/lib/snmp/src/agent/snmp_target_mib.erl
@@ -174,7 +174,8 @@ check_target_addr(
EngineId, TMask, MMS);
check_target_addr(
{Name, Ip, Udp, Timeout, RetryCount, TagList, Params,
- EngineId, TMask, MMS}) -> % Arity 10
+ EngineId, TMask, MMS})
+ when is_integer(Udp) -> % Arity 10
Domain = default_domain(),
Address = {Ip, Udp},
check_target_addr(
@@ -189,7 +190,8 @@ check_target_addr(
EngineId);
check_target_addr(
{Name, Ip, Udp, Timeout, RetryCount, TagList, Params,
- EngineId}) -> % Arity 8
+ EngineId}) % Arity 8
+ when is_integer(Udp) ->
Domain = default_domain(),
Address = {Ip, Udp},
check_target_addr(
@@ -202,7 +204,8 @@ check_target_addr(
check_target_addr(
Name, Domain, Address, Timeout, RetryCount, TagList, Params);
check_target_addr(
- {Name, Ip, Udp, Timeout, RetryCount, TagList, Params}) -> % Arity 7
+ {Name, Ip, Udp, Timeout, RetryCount, TagList, Params}) % Arity 7
+ when is_integer(Udp) ->
Domain = default_domain(),
Address = {Ip, Udp},
check_target_addr(
@@ -216,7 +219,8 @@ check_target_addr(
Name, Domain, Address, Timeout, RetryCount, TagList, Params, TMask, MMS);
check_target_addr(
{Name, Ip, Udp, Timeout, RetryCount, TagList, Params,
- TMask, MMS}) -> % Arity 9
+ TMask, MMS}) % Arity 9
+ when is_integer(Udp) ->
Domain = default_domain(),
Address = {Ip, Udp},
check_target_addr(
diff --git a/lib/snmp/src/agent/snmpa_conf.erl b/lib/snmp/src/agent/snmpa_conf.erl
index 2569b01b55..b4d32dc928 100644
--- a/lib/snmp/src/agent/snmpa_conf.erl
+++ b/lib/snmp/src/agent/snmpa_conf.erl
@@ -140,6 +140,8 @@ write_agent_conf(Fd, [H|T]) ->
do_write_agent_conf(Fd, H),
write_agent_conf(Fd, T).
+do_write_agent_conf(Fd, {intAgentTransports = Tag, Val}) ->
+ io:format(Fd, "{~w, ~w}.~n", [Tag, Val]);
do_write_agent_conf(Fd, {intAgentTransportDomain = Tag, Val}) ->
io:format(Fd, "{~w, ~w}.~n", [Tag, Val]);
do_write_agent_conf(Fd, {intAgentIpAddress = Tag, Val}) ->
@@ -379,72 +381,35 @@ do_write_standard_conf(_Fd, Tag, Val) ->
%% ------ target_addr.conf ------
%%
-target_addr_entry(Name,
- Ip,
- TagList,
- ParamsName,
- EngineId) ->
+target_addr_entry(
+ Name, Ip, TagList, ParamsName, EngineId) ->
target_addr_entry(Name, Ip, TagList, ParamsName, EngineId, []).
-target_addr_entry(Name,
- Ip,
- TagList,
- ParamsName,
- EngineId,
- TMask) ->
- target_addr_entry(Name, Ip, 162, TagList,
- ParamsName, EngineId,
- TMask, 2048).
-
-target_addr_entry(Name,
- Ip,
- Udp,
- TagList,
- ParamsName,
- EngineId,
- TMask,
- MaxMessageSize) ->
- target_addr_entry(Name, Ip, Udp, 1500, 3, TagList,
- ParamsName, EngineId,
- TMask, MaxMessageSize).
-
-target_addr_entry(Name,
- Ip,
- Udp,
- Timeout,
- RetryCount,
- TagList,
- ParamsName,
- EngineId,
- TMask,
- MaxMessageSize) ->
- target_addr_entry(Name, snmp_target_mib:default_domain(), Ip, Udp,
- Timeout, RetryCount, TagList,
- ParamsName, EngineId,
- TMask, MaxMessageSize).
-
-target_addr_entry(Name,
- Domain,
- Ip,
- Udp,
- Timeout,
- RetryCount,
- TagList,
- ParamsName,
- EngineId,
- TMask,
- MaxMessageSize) ->
- {Name,
- Domain,
- Ip,
- Udp,
- Timeout,
- RetryCount,
- TagList,
- ParamsName,
- EngineId,
- TMask,
- MaxMessageSize}.
+target_addr_entry(
+ Name, Ip, TagList, ParamsName,
+ EngineId, TMask) ->
+ target_addr_entry(
+ Name, Ip, 162, TagList, ParamsName,
+ EngineId, TMask, 2048).
+
+target_addr_entry(
+ Name, Domain_or_Ip, Addr_or_Port, TagList,
+ ParamsName, EngineId, TMask, MaxMessageSize) ->
+ target_addr_entry(
+ Name, Domain_or_Ip, Addr_or_Port, 1500, 3, TagList,
+ ParamsName, EngineId, TMask, MaxMessageSize).
+
+target_addr_entry(
+ Name, Domain_or_Ip, Addr_or_Port, Timeout, RetryCount, TagList,
+ ParamsName, EngineId, TMask, MaxMessageSize) ->
+ {Name, Domain_or_Ip, Addr_or_Port, Timeout, RetryCount, TagList,
+ ParamsName, EngineId, TMask, MaxMessageSize}.
+
+target_addr_entry(
+ Name, Domain, Ip, Udp, Timeout, RetryCount, TagList,
+ ParamsName, EngineId,TMask, MaxMessageSize) ->
+ {Name, Domain, Ip, Udp, Timeout, RetryCount, TagList,
+ ParamsName, EngineId, TMask, MaxMessageSize}.
write_target_addr_config(Dir, Conf) ->
diff --git a/lib/snmp/src/agent/snmpa_net_if.erl b/lib/snmp/src/agent/snmpa_net_if.erl
index 875ea19097..f5fd377341 100644
--- a/lib/snmp/src/agent/snmpa_net_if.erl
+++ b/lib/snmp/src/agent/snmpa_net_if.erl
@@ -35,19 +35,27 @@
-include("snmp_debug.hrl").
-include("snmp_verbosity.hrl").
--record(state, {parent,
- note_store,
- master_agent,
- usock,
- usock_opts,
- mpd_state,
- log,
- reqs = [],
- debug = false,
- limit = infinity,
- rcnt = [],
- filter,
- domain = snmpUDPDomain}).
+-record(state,
+ {parent,
+ note_store,
+ master_agent,
+ transports = [],
+%% usock,
+%% usock_opts,
+ mpd_state,
+ log,
+ reqs = [],
+ debug = false,
+ limit = infinity,
+%% rcnt = [],
+ filter}).
+%% domain = snmpUDPDomain}).
+
+-record(transport,
+ {socket,
+ domain = snmpUDPDomain,
+ opts = [],
+ req_refs = []}).
-ifndef(default_verbosity).
-define(default_verbosity,silence).
@@ -105,21 +113,27 @@ get_request_limit(Pid) ->
set_request_limit(Pid, NewLimit) ->
call(Pid, {set_request_limit, NewLimit}).
-get_port() ->
- {value, UDPPort} = snmp_framework_mib:intAgentUDPPort(get),
- UDPPort.
+get_transports() ->
+ {value, Transports} = snmp_framework_mib:intAgentTransports(get),
+ Transports.
-get_address() ->
- {value, IPAddress} = snmp_framework_mib:intAgentIpAddress(get),
- IPAddress.
-
-get_domain() ->
- case snmp_framework_mib:intAgentTransportDomain(get) of
- {value, Domain} ->
- Domain;
- genErr ->
- snmpUDPDomain
- end.
+%%% XXX remove
+%%%
+%%% get_ip_port() ->
+%%% {value, UDPPort} = snmp_framework_mib:intAgentUDPPort(get),
+%%% UDPPort.
+%%%
+%%% get_address() ->
+%%% {value, IPAddress} = snmp_framework_mib:intAgentIpAddress(get),
+%%% IPAddress.
+%%%
+%%% get_domain() ->
+%%% case snmp_framework_mib:intAgentTransportDomain(get) of
+%%% {value, Domain} ->
+%%% Domain;
+%%% genErr ->
+%%% snmpUDPDomain
+%%% end.
filter_reset(Pid) ->
Pid ! filter_reset.
@@ -170,13 +184,15 @@ do_init(Prio, NoteStore, MasterAgent, Parent, Opts) ->
put(verbosity,get_verbosity(Opts)),
?vlog("starting",[]),
- %% -- Port and address --
- Domain = get_domain(),
- ?vdebug("domain: ~w",[Domain]),
- UDPPort = get_port(),
- ?vdebug("port: ~w",[UDPPort]),
- IPAddress = get_address(),
- ?vdebug("addr: ~w",[IPAddress]),
+%%% XXX remove
+%%%
+%%% %% -- Port and address --
+%%% Domain = get_domain(),
+%%% ?vdebug("domain: ~w",[Domain]),
+%%% UDPPort = get_ip_port(),
+%%% ?vdebug("port: ~w",[UDPPort]),
+%%% IPAddress = get_address(),
+%%% ?vdebug("addr: ~w",[IPAddress]),
%% -- Versions --
Vsns = get_vsns(Opts),
@@ -193,37 +209,73 @@ do_init(Prio, NoteStore, MasterAgent, Parent, Opts) ->
Log = create_log(),
?vdebug("Log: ~w",[Log]),
-
- %% -- Socket --
- IPOpts1 = ip_opt_bind_to_ip_address(Opts, IPAddress),
- IPOpts2 = ip_opt_no_reuse_address(Opts),
- IPOpts3 = ip_opt_recbuf(Opts),
- IPOpts4 = ip_opt_sndbuf(Opts),
- IPOpts =
- [binary, snmp_conf:tdomain_to_family(Domain)
- | IPOpts1 ++ IPOpts2 ++ IPOpts3 ++ IPOpts4],
- case gen_udp_open(UDPPort, IPOpts) of
- {ok, Sock} ->
+ DomainAddresses = get_transports(),
+ ?vdebug("DomainAddresses: ~w",[DomainAddresses]),
+ try
+ [begin
+ SocketOpts = socket_opts(Domain, Address, Opts),
+ Socket = socket_open(Domain, SocketOpts),
+ active_once(Socket),
+ #transport{
+ socket = Socket,
+ domain = Domain,
+ opts = SocketOpts}
+ end || {Domain, Address} <- DomainAddresses]
+ of
+ [] ->
+ ?vinfo("No transports configured: ~p", [DomainAddresses]),
+ {error, {no_transports,DomainAddresses}};
+ Transports ->
MpdState = snmpa_mpd:init(Vsns),
- init_counters(),
- active_once(Sock),
+ init_counters(),
S = #state{parent = Parent,
note_store = NoteStore,
master_agent = MasterAgent,
mpd_state = MpdState,
- usock = Sock,
- usock_opts = IPOpts,
+ transports = Transports,
log = Log,
limit = Limit,
- filter = FilterMod,
- domain = Domain},
+ filter = FilterMod},
?vdebug("started with MpdState: ~p", [MpdState]),
- {ok, S};
- {error, Reason} ->
- ?vinfo("Failed to open UDP socket: ~p", [Reason]),
- {error, {udp_open, UDPPort, Reason}}
+ {ok, S}
+ catch
+ Error ->
+ ?vinfo("Failed to initialize socket(s): ~p", [Error]),
+ {error, Error}
end.
+%%% XXX remove
+%%%
+%%% %% -- Socket --
+%%% IPOpts1 = ip_opt_bind_to_ip_address(Opts, IPAddress),
+%%% IPOpts2 = ip_opt_no_reuse_address(Opts),
+%%% IPOpts3 = ip_opt_recbuf(Opts),
+%%% IPOpts4 = ip_opt_sndbuf(Opts),
+%%% IPOpts =
+%%% [binary, snmp_conf:tdomain_to_family(Domain)
+%%% | IPOpts1 ++ IPOpts2 ++ IPOpts3 ++ IPOpts4],
+%%% case gen_udp_open(UDPPort, IPOpts) of
+%%% {ok, Sock} ->
+%%% MpdState = snmpa_mpd:init(Vsns),
+%%% init_counters(),
+%%% active_once(Sock),
+%%% S = #state{parent = Parent,
+%%% note_store = NoteStore,
+%%% master_agent = MasterAgent,
+%%% mpd_state = MpdState,
+%%% usock = Sock,
+%%% usock_opts = IPOpts,
+%%% log = Log,
+%%% limit = Limit,
+%%% filter = FilterMod,
+%%% domain = Domain},
+%%% ?vdebug("started with MpdState: ~p", [MpdState]),
+%%% {ok, S};
+%%% {error, Reason} ->
+%%% ?vinfo("Failed to open UDP socket: ~p", [Reason]),
+%%% {error, {udp_open, UDPPort, Reason}}
+%%% end.
+
create_log() ->
case ets:lookup(snmp_agent_table, audit_trail_log) of
@@ -298,33 +350,63 @@ format_address(Address) ->
iolist_to_binary(snmp_conf:mk_addr_string(Address)).
-
-gen_udp_open(Port, Opts) ->
+socket_open(snmpUDPDomain = Domain, [IpPort | Opts]) ->
case init:get_argument(snmp_fd) of
{ok, [[FdStr]]} ->
Fd = list_to_integer(FdStr),
- ?vdebug("gen_udp_open(~p, ~p) Fd: ~p",[Port,Opts,Fd]),
- gen_udp:open(0, [{fd, Fd}|Opts]);
+ ?vdebug("socket_open(~p, [~p | ~p]) Fd: ~p",
+ [Domain, IpPort, Opts, Fd]),
+ gen_udp_open(IpPort, [{fd, Fd} | Opts]);
error ->
case init:get_argument(snmpa_fd) of
{ok, [[FdStr]]} ->
Fd = list_to_integer(FdStr),
- ?vdebug("gen_udp_open(~p, ~p) Fd: ~p",[Port,Opts,Fd]),
- gen_udp:open(0, [{fd, Fd}|Opts]);
+ ?vdebug("socket_open(~p, [~p | ~p]) Fd: ~p",
+ [Domain, IpPort, Opts, Fd]),
+ gen_udp_open(IpPort, [{fd, Fd} | Opts]);
error ->
- ?vdebug("gen_udp_open(~p, ~p)",[Port,Opts]),
- gen_udp:open(Port, Opts)
+ ?vdebug("socket_open(~p, [~p | ~p])",
+ [Domain, IpPort, Opts]),
+ gen_udp_open(IpPort, Opts)
end
+ end;
+socket_open(Domain, [IpPort | Opts])
+ when Domain =:= transportDomainUdpIpv4;
+ Domain =:= transportDomainUdpIpv6 ->
+ ?vdebug("socket_open(~p, [~p | ~p])", [Domain, IpPort, Opts]),
+ gen_udp_open(IpPort, Opts);
+socket_open(Domain, Opts) ->
+ throw({socket_open, Domain, Opts}).
+
+gen_udp_open(IpPort, Opts) ->
+ case gen_udp:open(IpPort, Opts) of
+ {ok, Socket} ->
+ Socket;
+ {error, Reason} ->
+ throw({udp_open, IpPort, Reason})
end.
-loop(#state{domain = Domain} = S) ->
+
+loop(#state{transports = Transports, limit = Limit, parent = Parent} = S) ->
+ ?vdebug("loop(~p)", [S]),
receive
- {udp, _UdpId, Ip, Port, Packet} ->
- ?vlog("got paket from ~w:~w",[Ip,Port]),
- From = fix_filter_address(Domain, {Domain, {Ip, Port}}),
- NewS = maybe_handle_recv(S, From, Packet),
- loop(NewS);
+ {udp, Socket, IpAddr, IpPort, Packet} = Msg when is_port(Socket) ->
+ ?vlog("got paket from ~w:~w on ~w", [IpAddr, IpPort, Socket]),
+ case lists:keyfind(Socket, #transport.socket, Transports) of
+ #transport{socket = Socket, domain = Domain} = Transport ->
+ From =
+ case Domain of
+ snmpUDPDomain ->
+ {IpAddr, IpPort};
+ _ ->
+ {Domain, {IpAddr, IpPort}}
+ end,
+ loop(maybe_handle_recv(S, Transport, From, Packet));
+ false ->
+ error_msg("Packet on unknown port: ~p", [Msg]),
+ loop(S)
+ end;
{info, ReplyRef, Pid} ->
Info = get_info(S),
@@ -332,12 +414,35 @@ loop(#state{domain = Domain} = S) ->
loop(S);
%% response (to get/get_next/get_bulk/set requests)
- {snmp_response, Vsn, RePdu, Type, ACMData, To, []} ->
+ {snmp_response, Vsn, RePdu, Type, ACMData, To, Extra} ->
?vlog("reply pdu: "
"~n ~s",
[?vapply(snmp_misc, format, [256, "~w", [RePdu]])]),
- NewS = maybe_handle_reply_pdu(S, Vsn, RePdu, Type, ACMData, To),
- loop(NewS);
+ {_, ReqRef} = lists:keyfind(request_ref, 1, Extra),
+ case
+ case
+ (Limit =/= infinity) andalso
+ select_transport_from_req_ref(ReqRef, Transports)
+ of
+ false ->
+ select_transport_from_domain(
+ address_to_domain(To),
+ Transports);
+ T ->
+ T
+ end
+ of
+ false ->
+ error_msg(
+ "Can not find transport for response PDU to: ~s",
+ [format_address(To)]),
+ loop(S);
+ Transport ->
+ NewS = update_req_counter_outgoing(S, Transport, ReqRef),
+ maybe_handle_reply_pdu(
+ NewS, Transport, Vsn, RePdu, Type, ACMData, To),
+ loop(NewS)
+ end;
%% Traps/notification
{send_pdu, Vsn, Pdu, MsgData, TDomAddrs} ->
@@ -406,15 +511,34 @@ loop(#state{domain = Domain} = S) ->
NewS = handle_send_discovery(S, Pdu, MsgData, To, From),
loop(NewS);
- {discarded_pdu, _Vsn, ReqId, _ACMData, Variable, _Extra} ->
- ?vdebug("discard PDU: ~p", [Variable]),
+ {discarded_pdu, _Vsn, ReqId, _ACMData, Variable, Extra} ->
+ ?vdebug("discard PDU: ~p - ~p - ~p",
+ [Variable, Extra, Transports]),
snmpa_mpd:discarded_pdu(Variable),
- NewS = update_req_counter_outgoing(S, ReqId),
- loop(NewS);
+ {_, ReqRef} = lists:keyfind(request_ref, 1, Extra),
+ if
+ Limit =:= infinity ->
+ %% The incoming PDU was not registered
+ loop(update_req_counter_outgoing(S, false, ReqRef));
+ true ->
+ case
+ select_transport_from_req_ref(ReqRef, Transports)
+ of
+ false ->
+ error_msg(
+ "Can not find transport for discarded PDU: ~p",
+ [ReqId]),
+ loop(S);
+ Transport ->
+ loop(
+ update_req_counter_outgoing(
+ S, Transport, ReqRef))
+ end
+ end;
{get_log_type, ReplyRef, Pid} ->
?vdebug("get log type: ~p", []),
- #state{log = {_, LogType}} = S,
+ {_, LogType} = S#state.log,
Pid ! {ReplyRef, {ok, LogType}, self()},
loop(S);
@@ -426,7 +550,6 @@ loop(#state{domain = Domain} = S) ->
{get_request_limit, ReplyRef, Pid} ->
?vdebug("get request limit: ~p", []),
- #state{limit = Limit} = S,
Pid ! {ReplyRef, {ok, Limit}, self()},
loop(S);
@@ -450,36 +573,50 @@ loop(#state{domain = Domain} = S) ->
reset_counters(),
loop(S);
- {'EXIT', Parent, Reason} when Parent == S#state.parent ->
+ {'EXIT', Parent, Reason} ->
?vlog("parent (~p) exited: "
"~n ~p", [Parent, Reason]),
exit(Reason);
- {'EXIT', Port, Reason} when Port == S#state.usock ->
- UDPPort = get_port(),
- NewS =
- case gen_udp_open(UDPPort, S#state.usock_opts) of
- {ok, Id} ->
- error_msg("Port ~p exited for reason"
- "~n ~p"
- "~n Re-opened (~p)", [Port, Reason, Id]),
- S#state{usock = Id};
- {error, ReopenReason} ->
- error_msg("Port ~p exited for reason"
- "~n ~p"
- "~n Re-open failed with reason"
- "~n ~p",
- [Port, Reason, ReopenReason]),
- ok
- end,
- loop(NewS);
-
- {'EXIT', Port, Reason} when is_port(Port) ->
- error_msg("Exit message from port ~p for reason ~p~n",
- [Port, Reason]),
- loop(S);
+ {'EXIT', Socket, Reason} when is_port(Socket) ->
+ case lists:keyfind(Socket, #transport.socket, Transports) of
+ #transport{
+ socket = Socket,
+ domain = Domain,
+ opts = SocketOpts,
+ req_refs = ReqRefs} = Transport ->
+ try socket_open(Domain, SocketOpts) of
+ NewSocket ->
+ error_msg(
+ "Socket ~p exited for reason"
+ "~n ~p"
+ "~n Re-opened (~p)",
+ [Socket, Reason, NewSocket]),
+ (length(ReqRefs) < Limit) andalso
+ active_once(NewSocket),
+ S#state{
+ transports =
+ lists:keyreplace(
+ Socket, #transport.socket, Transports,
+ Transport#transport{socket = NewSocket})}
+ catch
+ ReopenReason ->
+ error_msg(
+ "Socket ~p exited for reason"
+ "~n ~p"
+ "~n Re-open failed with reason"
+ "~n ~p",
+ [Socket, Reason, ReopenReason]),
+ exit(ReopenReason)
+ end;
+ false ->
+ error_msg(
+ "Exit message from port ~p for reason ~p~n",
+ [Socket, Reason]),
+ loop(S)
+ end;
- {'EXIT', Pid, Reason} ->
+ {'EXIT', Pid, Reason} when is_pid(Pid) ->
?vlog("~p exited: "
"~n ~p", [Pid, Reason]),
NewS = clear_reqs(Pid, S),
@@ -487,71 +624,144 @@ loop(#state{domain = Domain} = S) ->
{system, From, Msg} ->
?vdebug("system event ~p from ~p", [Msg, From]),
- sys:handle_system_msg(Msg, From, S#state.parent, ?MODULE, [], S);
+ sys:handle_system_msg(Msg, From, Parent, ?MODULE, [], S);
_ ->
loop(S)
end.
-update_req_counter_incomming(#state{limit = infinity, usock = Sock} = S, _) ->
- active_once(Sock), %% No limit so activate directly
+update_req_counter_incoming(
+ #state{limit = infinity} = S,
+ #transport{socket = Socket},
+ _ReqRef) ->
+ active_once(Socket), %% No limit so activate directly
S;
-update_req_counter_incomming(#state{limit = Limit,
- rcnt = RCnt,
- usock = Sock} = S, Rid)
- when length(RCnt) + 1 == Limit ->
+update_req_counter_incoming(
+ #state{limit = Limit} = S,
+ #transport{socket = Socket, req_refs = ReqRefs} = T,
+ ReqRef) when length(ReqRefs) + 1 >= Limit ->
%% Ok, one more and we are at the limit.
%% Just make sure we are not already processing this one...
- case lists:member(Rid, RCnt) of
+ case lists:member(ReqRef, ReqRefs) of
false ->
%% We are at the limit, do _not_ activate socket
- S#state{rcnt = [Rid|RCnt]};
+ update_transport_req_refs(S, T, [ReqRef | ReqRefs]);
true ->
- active_once(Sock),
+ active_once(Socket),
S
end;
-update_req_counter_incomming(#state{rcnt = RCnt,
- usock = Sock} = S, Rid) ->
- active_once(Sock),
- case lists:member(Rid, RCnt) of
+update_req_counter_incoming(
+ #state{} = S,
+ #transport{socket = Socket, req_refs = ReqRefs} = T,
+ ReqRef) ->
+ active_once(Socket),
+ case lists:member(ReqRef, ReqRefs) of
false ->
- S#state{rcnt = [Rid|RCnt]};
+ update_transport_req_refs(S, T, [ReqRef | ReqRefs]);
true ->
S
end.
-
-update_req_counter_outgoing(#state{limit = infinity} = S, _Rid) ->
+update_transport_req_refs(
+ #state{transports = Transports} = S,
+ #transport{socket = Socket} = T,
+ ReqRefs) ->
+ S#state{
+ transports =
+ lists:keyreplace(
+ Socket, #transport.socket, Transports,
+ T#transport{req_refs = ReqRefs})}.
+
+%%% XXX remove
+%%%
+%%% update_req_counter_incoming(#state{limit = infinity, usock = Sock} = S, _) ->
+%%% active_once(Sock), %% No limit so activate directly
+%%% S;
+%%% update_req_counter_incoming(#state{limit = Limit,
+%%% rcnt = RCnt,
+%%% usock = Sock} = S, Rid)
+%%% when length(RCnt) + 1 >= Limit ->
+%%% %% Ok, one more and we are at the limit.
+%%% %% Just make sure we are not already processing this one...
+%%% case lists:member(Rid, RCnt) of
+%%% false ->
+%%% %% We are at the limit, do _not_ activate socket
+%%% S#state{rcnt = [Rid|RCnt]};
+%%% true ->
+%%% active_once(Sock),
+%%% S
+%%% end;
+%%% update_req_counter_incoming(#state{rcnt = RCnt,
+%%% usock = Sock} = S, Rid) ->
+%%% active_once(Sock),
+%%% case lists:member(Rid, RCnt) of
+%%% false ->
+%%% S#state{rcnt = [Rid|RCnt]};
+%%% true ->
+%%% S
+%%% end.
+
+
+update_req_counter_outgoing(
+ #state{limit = infinity} = S,
+ _Transport, _ReqRef) ->
%% Already activated (in the incoming function)
S;
-update_req_counter_outgoing(#state{limit = Limit,
- rcnt = RCnt,
- usock = Sock} = S, Rid)
- when length(RCnt) == Limit ->
- ?vtrace("handle_req_counter_outgoing(~w) -> entry with"
- "~n Rid: ~w"
- "~n length(RCnt): ~w", [Limit, Rid, length(RCnt)]),
- case lists:delete(Rid, RCnt) of
- NewRCnt when length(NewRCnt) < Limit ->
+update_req_counter_outgoing(
+ #state{limit = Limit, transports = Transports} = S,
+ #transport{socket = Socket, req_refs = ReqRefs} = Transport,
+ ReqRef) ->
+ LengthReqRefs = length(ReqRefs),
+ ?vtrace("update_req_counter_outgoing() -> entry with~n"
+ " Limit: ~w~n"
+ " ReqRef: ~w~n"
+ " length(ReqRefs): ~w", [Limit, ReqRef, LengthReqRefs]),
+ NewReqRefs = lists:delete(ReqRef, ReqRefs),
+ (LengthReqRefs >= Limit) andalso (length(NewReqRefs) < Limit) andalso
+ begin
?vtrace("update_req_counter_outgoing -> "
- "passed below limit: activate", []),
- active_once(Sock),
- S#state{rcnt = NewRCnt};
- _ ->
- S
- end;
-update_req_counter_outgoing(#state{limit = Limit, rcnt = RCnt} = S,
- Rid) ->
- ?vtrace("handle_req_counter_outgoing(~w) -> entry with"
- "~n Rid: ~w"
- "~n length(RCnt): ~w", [Limit, Rid, length(RCnt)]),
- NewRCnt = lists:delete(Rid, RCnt),
- S#state{rcnt = NewRCnt}.
+ "passed below limit: activate", []),
+ active_once(Socket)
+ end,
+ S#state{
+ transports =
+ snmp_misc:keyreplace(
+ Socket, #transport.socket, Transports,
+ Transport#transport{req_refs = NewReqRefs})}.
+
+%%% XXX remove
+%%%
+%%% update_req_counter_outgoing(
+%%% #state{limit = Limit,
+%%% rcnt = RCnt,
+%%% usock = Sock} = S, Rid)
+%%% when length(RCnt) >= Limit ->
+%%% ?vtrace("handle_req_counter_outgoing(~w) -> entry with"
+%%% "~n Rid: ~w"
+%%% "~n length(RCnt): ~w", [Limit, Rid, length(RCnt)]),
+%%% case lists:delete(Rid, RCnt) of
+%%% NewRCnt when length(NewRCnt) < Limit ->
+%%% ?vtrace("update_req_counter_outgoing -> "
+%%% "passed below limit: activate", []),
+%%% active_once(Sock),
+%%% S#state{rcnt = NewRCnt};
+%%% _ ->
+%%% S
+%%% end;
+%%% update_req_counter_outgoing(#state{limit = Limit, rcnt = RCnt} = S,
+%%% Rid) ->
+%%% ?vtrace("handle_req_counter_outgoing(~w) -> entry with"
+%%% "~n Rid: ~w"
+%%% "~n length(RCnt): ~w", [Limit, Rid, length(RCnt)]),
+%%% NewRCnt = lists:delete(Rid, RCnt),
+%%% S#state{rcnt = NewRCnt}.
maybe_handle_recv(
- #state{usock = Sock, filter = FilterMod} = S, From, Packet) ->
+ #state{filter = FilterMod} = S,
+ #transport{socket = Socket} = Transport,
+ From, Packet) ->
{From_1, From_2} = From,
case
try FilterMod:accept_recv(From_1, From_2)
@@ -566,7 +776,7 @@ maybe_handle_recv(
false ->
%% Drop the received packet
inc(netIfMsgInDrops),
- active_once(Sock),
+ active_once(Socket),
S;
Other ->
case Other of
@@ -577,28 +787,13 @@ maybe_handle_recv(
"FilterMod:accept_recv(~p, ~p) returned: ~p",
[From_1,From_2,Other])
end,
- handle_recv(S, From, Packet)
- end.
-
-handle_discovery_response(_From, #pdu{request_id = ReqId} = Pdu,
- ManagerEngineId,
- #state{usock = Sock, reqs = Reqs} = S) ->
- case lists:keysearch(ReqId, 1, S#state.reqs) of
- {value, {_, Pid}} ->
- active_once(Sock),
- Pid ! {snmp_discovery_response_received, Pdu, ManagerEngineId},
- NReqs = lists:keydelete(ReqId, 1, Reqs),
- S#state{reqs = NReqs};
- _ ->
- %% Ouch, timeout? resend?
- S
+ handle_recv(S, Transport, From, Packet)
end.
handle_recv(
- #state{usock = Sock,
- mpd_state = MpdState,
- note_store = NS,
- log = Log} = S, From, Packet) ->
+ #state{mpd_state = MpdState, note_store = NS, log = Log} = S,
+ #transport{socket = Socket} = Transport,
+ From, Packet) ->
put(n1, erlang:now()),
LogF =
fun(Type, Data) ->
@@ -607,48 +802,72 @@ handle_recv(
case (catch snmpa_mpd:process_packet(
Packet, From, MpdState, NS, LogF)) of
{ok, _Vsn, Pdu, _PduMS, {discovery, ManagerEngineId}} ->
- handle_discovery_response(From, Pdu, ManagerEngineId, S);
+ handle_discovery_response(
+ S, Transport, From, Pdu, ManagerEngineId);
{ok, _Vsn, Pdu, _PduMS, discovery} ->
- handle_discovery_response(From, Pdu, undefined, S);
+ handle_discovery_response(
+ S, Transport, From, Pdu, undefined);
{ok, Vsn, Pdu, PduMS, ACMData} ->
?vlog("got pdu ~s",
[?vapply(snmp_misc, format, [256, "~w", [Pdu]])]),
- %% handle_recv_pdu(From, Vsn, Pdu, PduMS, ACMData, S);
- maybe_handle_recv_pdu(From, Vsn, Pdu, PduMS, ACMData, S);
+ %% handle_recv_pdu(S, Transport, From, Vsn, Pdu, PduMS, ACMData);
+ maybe_handle_recv_pdu(
+ S, Transport, From, Vsn, Pdu, PduMS, ACMData);
{discarded, Reason} ->
?vlog("packet discarded for reason: ~s",
[?vapply(snmp_misc, format, [256, "~w", [Reason]])]),
- active_once(Sock),
+ active_once(Socket),
S;
{discarded, Reason, ReportPacket} ->
?vlog("sending report for reason: "
"~n ~s",
[?vapply(snmp_misc, format, [256, "~w", [Reason]])]),
- (catch udp_send(S#state.usock, From, ReportPacket)),
- active_once(Sock),
+ (catch udp_send(Socket, From, ReportPacket)),
+ active_once(Socket),
S;
{discovery, ReportPacket} ->
?vlog("sending discovery report", []),
- (catch udp_send(S#state.usock, From, ReportPacket)),
- active_once(Sock),
+ (catch udp_send(Socket, From, ReportPacket)),
+ active_once(Socket),
S;
Error ->
error_msg("processing of received message failed: "
"~n ~p", [Error]),
- active_once(Sock),
+ active_once(Socket),
+ S
+ end.
+
+handle_discovery_response(
+ #state{reqs = Reqs} = S,
+ #transport{socket = Socket},
+ _From,
+ #pdu{request_id = ReqId} = Pdu,
+ ManagerEngineId) ->
+ case lists:keyfind(ReqId, 1, S#state.reqs) of
+ {ReqId, Pid} ->
+ active_once(Socket),
+ Pid ! {snmp_discovery_response_received, Pdu, ManagerEngineId},
+ %% XXX Strange... Reqs from this Pid should be reaped
+ %% at process exit by clear_reqs/2 so the following
+ %% should be redundant.
+ NReqs = lists:keydelete(ReqId, 1, Reqs),
+ S#state{reqs = NReqs};
+ false ->
+ %% Ouch, timeout? resend?
S
end.
maybe_handle_recv_pdu(
+ #state{filter = FilterMod} = S,
+ #transport{socket = Socket} = Transport,
From, Vsn,
- #pdu{type = Type} = Pdu, PduMS, ACMData,
- #state{usock = Sock, filter = FilterMod} = S) ->
+ #pdu{type = Type} = Pdu, PduMS, ACMData) ->
{From_1, From_2} = From,
case
try FilterMod:accept_recv_pdu(From_1, From_2, Type)
@@ -664,8 +883,8 @@ maybe_handle_recv_pdu(
of
false ->
inc(netIfPduInDrops),
- active_once(Sock),
- ok;
+ active_once(Socket),
+ S;
Other ->
case Other of
true ->
@@ -675,39 +894,72 @@ maybe_handle_recv_pdu(
"FilterMod:accept_recv_pdu(~p, ~p, ~p) returned: ~p",
[From_1,From_2,Type,Other])
end,
- handle_recv_pdu(From, Vsn, Pdu, PduMS, ACMData, S)
+ handle_recv_pdu(S, Transport, From, Vsn, Pdu, PduMS, ACMData)
end.
handle_recv_pdu(
+ #state{reqs = Reqs} = S,
+ #transport{socket = Socket},
From, Vsn,
- #pdu{type = 'get-response'} = Pdu, _PduMS, _ACMData,
- #state{usock = Sock} = S) ->
- active_once(Sock),
- handle_response(Vsn, Pdu, From, S),
+ #pdu{type = 'get-response', request_id = ReqId} = Pdu,
+ _PduMS, _ACMData) ->
+ active_once(Socket),
+ case lists:keyfind(ReqId, 1, Reqs) of
+ {ReqId, Pid} ->
+ ?vdebug("handle_recv_pdu -> "
+ "~n send response to receiver ~p", [Pid]),
+ Pid ! {snmp_response_received, Vsn, Pdu, From};
+ false ->
+ ?vdebug("handle_recv_pdu -> "
+ "~n No receiver available for response pdu", [])
+ end,
S;
-handle_recv_pdu(From, Vsn, #pdu{request_id = Rid, type = Type} = Pdu,
- PduMS, ACMData, #state{master_agent = Pid} = S)
- when ((Type =:= 'get-request') orelse
- (Type =:= 'get-next-request') orelse
- (Type =:= 'get-bulk-request')) ->
- ?vtrace("handle_recv_pdu -> received get (~w)", [Type]),
- Pid ! {snmp_pdu, Vsn, Pdu, PduMS, ACMData, From, []},
- update_req_counter_incomming(S, Rid);
-handle_recv_pdu(From, Vsn, Pdu, PduMS, ACMData,
- #state{usock = Sock, master_agent = Pid} = S) ->
+%%% XXX remove
+%%%
+%%% handle_recv_pdu(
+%%% #state{} = S,
+%%% #transport{socket = Socket} = Transport,
+%%% From, Vsn,
+%%% #pdu{type = 'get-response'} = Pdu,
+%%% _PduMS, _ACMData) ->
+%%% active_once(Socket),
+%%% handle_response(S, Pdu, From, Vsn),
+%%% S;
+handle_recv_pdu(
+ #state{master_agent = Pid} = S,
+ #transport{} = Transport,
+ From, Vsn,
+ #pdu{type = Type} = Pdu,
+ PduMS, ACMData)
+ when Type =:= 'set-request';
+ Type =:= 'get-request';
+ Type =:= 'get-next-request';
+ Type =:= 'get-bulk-request' ->
+ ?vtrace("handle_recv_pdu -> received request (~w)", [Type]),
+ ReqRef = make_ref(),
+ Extra = [{request_ref, ReqRef}],
+ Pid ! {snmp_pdu, Vsn, Pdu, PduMS, ACMData, From, Extra},
+ NewS = update_req_counter_incoming(S, Transport, ReqRef),
+ ?vdebug("handle_recv_pdu -> ~p", [NewS]),
+ NewS;
+handle_recv_pdu(
+ #state{master_agent = Pid} = S,
+ #transport{socket = Socket},
+ From, Vsn, Pdu, PduMS, ACMData) ->
?vtrace("handle_recv_pdu -> received other request", []),
- active_once(Sock),
+ active_once(Socket),
Pid ! {snmp_pdu, Vsn, Pdu, PduMS, ACMData, From, []},
S.
maybe_handle_reply_pdu(
- #state{filter = FilterMod, domain = Domain} = S, Vsn,
- #pdu{request_id = Rid} = Pdu,
+ #state{filter = FilterMod, transports = Transports} = S,
+ #transport{} = Transport,
+ Vsn,
+ #pdu{} = Pdu,
Type, ACMData, To) ->
-
- S1 = update_req_counter_outgoing(S, Rid),
- Addresses = [fix_filter_address(Domain, To)],
+ %%
+ Addresses = [fix_filter_address(Transports, To)],
case
try
FilterMod:accept_send_pdu(Addresses, Type)
@@ -715,7 +967,8 @@ maybe_handle_reply_pdu(
Class:Exception ->
error_msg(
"FilterMod:accept_send_pdu(~p, ~p) crashed: ~w:~w~n ~p",
- [Addresses,Type,Class,Exception,erlang:get_stacktrace()]),
+ [Addresses, Type, Class, Exception,
+ erlang:get_stacktrace()]),
true
end
of
@@ -731,11 +984,16 @@ maybe_handle_reply_pdu(
"FilterMod:accept_send_pdu(~p, ~p) returned: ~p",
[Addresses,Type,Other])
end,
- handle_reply_pdu(S1, Vsn, Pdu, Type, ACMData, To)
- end,
- S1.
+ handle_reply_pdu(S, Transport, Vsn, Pdu, Type, ACMData, To)
+ end.
-handle_reply_pdu(#state{log = Log} = S, Vsn, Pdu, Type, ACMData, To) ->
+handle_reply_pdu(
+ #state{log = Log} = S,
+ #transport{} = Transport,
+ Vsn,
+ #pdu{} = Pdu,
+ Type, ACMData, To) ->
+ %%
LogF =
fun(Type2, Data) ->
log(Log, Type2, Data, To)
@@ -744,7 +1002,15 @@ handle_reply_pdu(#state{log = Log} = S, Vsn, Pdu, Type, ACMData, To) ->
ACMData, LogF)) of
{ok, Packet} ->
?vinfo("time in agent: ~w mysec", [time_in_agent()]),
- maybe_udp_send(S, To, Packet);
+ try maybe_udp_send(S, Transport, To, Packet)
+ catch
+ {Reason, Sz} ->
+ error_msg("Cannot send message "
+ "~n size: ~p"
+ "~n reason: ~p"
+ "~n pdu: ~p",
+ [Sz, Reason, Pdu])
+ end;
{discarded, Reason} ->
?vlog("handle_reply_pdu -> "
"~n reply discarded for reason: ~s",
@@ -758,7 +1024,7 @@ handle_reply_pdu(#state{log = Log} = S, Vsn, Pdu, Type, ACMData, To) ->
maybe_handle_send_pdu(
- #state{filter = FilterMod, domain = Domain} = S,
+ #state{filter = FilterMod, transports = Transports} = S,
Vsn, Pdu, MsgData, TDomAddrSecs, From) ->
?vtrace("maybe_handle_send_pdu -> entry with~n"
@@ -767,26 +1033,15 @@ maybe_handle_send_pdu(
DomAddrSecs = snmpa_mpd:process_taddrs(TDomAddrSecs),
AddressesToFilter =
- [case Domain of
- snmpUDPDomain ->
- case DAS of
- {{Dom, Addr}, _SecData}
- when is_atom(Dom) -> % v3
- Addr;
- {Dom, Addr}
- when is_atom(Dom) -> % v1 & v2
- Addr
- end;
- _ ->
- case DAS of
- {{Dom, _Addr} = DomAddr, _SecData}
- when is_atom(Dom) -> % v3
- DomAddr;
- {Dom, _Addr} = DomAddr
- when is_atom(Dom) -> % v1 & v2
- DomAddr
- end
- end || DAS <- DomAddrSecs],
+ case is_legacy_transports(Transports) of
+ true ->
+ [fix_filter_legacy_mpd_address(DAS)
+ || DAS <- DomAddrSecs];
+ false ->
+ [fix_filter_mpd_address(DAS)
+ || DAS <- DomAddrSecs]
+ end,
+
Type = pdu_type_of(Pdu),
case
@@ -806,33 +1061,24 @@ maybe_handle_send_pdu(
true ->
handle_send_pdu(S, Vsn, Pdu, MsgData, DomAddrSecs, From);
FilteredAddresses when is_list(FilteredAddresses) ->
- MergedDomAddrSecs =
- [DAS ||
- DAS <- DomAddrSecs,
- lists:member(
- case Domain of
- snmpUDPDomain ->
- case DAS of
- {{Dom, Addr}, _SData}
- when is_atom(Dom) -> % v3
- Addr;
- {Dom, Addr}
- when is_atom(Dom) -> % v1 & v2
- Addr
- end;
- true ->
- case DAS of
- {{Dom, _Addr} = DomAddr, _SData}
- when is_atom(Dom) -> % v3
- DomAddr;
- {Dom, _Addr} = DomAddr
- when is_atom(Dom) -> % v1 & v2
- DomAddr
- end
- end, FilteredAddresses)],
- ?vtrace("maybe_handle_send_pdu -> MergedDomAddrSecs:~n"
- " ~p", [MergedDomAddrSecs]),
- handle_send_pdu(S, Vsn, Pdu, MsgData, MergedDomAddrSecs, From);
+ FilteredDomAddrSecs =
+ case is_legacy_transports(Transports) of
+ true ->
+ [DAS ||
+ DAS <- DomAddrSecs,
+ lists:member(
+ fix_filter_legacy_mpd_address(DAS),
+ FilteredAddresses)];
+ false ->
+ [DAS ||
+ DAS <- DomAddrSecs,
+ lists:member(
+ fix_filter_mpd_address(DAS),
+ FilteredAddresses)]
+ end,
+ ?vtrace("maybe_handle_send_pdu -> FilteredDomAddrSecs:~n"
+ " ~p", [FilteredDomAddrSecs]),
+ handle_send_pdu(S, Vsn, Pdu, MsgData, FilteredDomAddrSecs, From);
Other ->
error_msg(
"FilterMod:accept_send_pdu(~p, ~p) returned: ~p",
@@ -841,8 +1087,9 @@ maybe_handle_send_pdu(
end.
handle_send_pdu(
- #state{note_store = NS} = S, Vsn, Pdu, MsgData, DomAddrSecs, From) ->
-
+ #state{note_store = NS} = S,
+ Vsn, Pdu, MsgData, DomAddrSecs, From) ->
+ %%
?vtrace("handle_send_pdu -> entry with~n"
" Pdu: ~p~n"
" DomAddrSecs: ~p", [Pdu, DomAddrSecs]),
@@ -863,23 +1110,24 @@ handle_send_pdu(
case From of
undefined ->
S;
- Pid ->
+ Pid when is_pid(Pid) ->
?vtrace("link to ~p and add to request list", [Pid]),
link(Pid),
- NReqs = snmp_misc:keyreplaceadd(
- Pid, 2, S#state.reqs, {Pdu#pdu.request_id, From}),
+ NReqs =
+ snmp_misc:keyreplaceadd(
+ Pid, 2, S#state.reqs, {Pdu#pdu.request_id, From}),
S#state{reqs = NReqs}
end.
handle_send_discovery(
- #state{note_store = NS,
- log = Log,
- usock = Sock,
- reqs = Reqs} = S,
- #pdu{type = Type,
- request_id = ReqId} = Pdu,
- MsgData, To, From) ->
+ #state{
+ note_store = NS,
+ log = Log,
+ reqs = Reqs,
+ transports = Transports} = S,
+ #pdu{type = Type, request_id = ReqId} = Pdu,
+ MsgData, To, From) when is_pid(From) ->
?vtrace("handle_send_discovery -> entry with"
"~n Pdu: ~p"
@@ -889,20 +1137,28 @@ handle_send_discovery(
case (catch snmpa_mpd:generate_discovery_msg(NS, Pdu, MsgData, To)) of
{ok, {Domain, Address, Packet}} ->
- log(Log, Type, Packet, {Domain, Address}),
- udp_send(Sock, {Domain, Address}, Packet),
- ?vtrace("handle_send_discovery -> sent (~w)", [ReqId]),
- NReqs = snmp_misc:keyreplaceadd(From, 2, Reqs, {ReqId, From}),
- S#state{reqs = NReqs};
+ case select_transport_from_domain(Domain, Transports) of
+ false ->
+ error_msg(
+ "Can not find transport to: ~s",
+ [format_address(To)]),
+ S;
+ #transport{socket = Socket} ->
+ log(Log, Type, Packet, {Domain, Address}),
+ udp_send(Socket, {Domain, Address}, Packet),
+ ?vtrace("handle_send_discovery -> sent (~w)", [ReqId]),
+ NReqs = snmp_misc:keyreplaceadd(From, 2, Reqs, {ReqId, From}),
+ S#state{reqs = NReqs}
+ end;
{discarded, Reason} ->
?vlog("handle_send_discovery -> "
"~n Discovery PDU ~p not sent due to ~p", [Pdu, Reason]),
- ok;
+ S;
{'EXIT', Reason} ->
user_err("failed generating discovery message: "
"~n PDU: ~p"
"~n Reason: ~p", [Pdu, Reason]),
- ok
+ S
end.
@@ -912,18 +1168,20 @@ do_handle_send_pdu(S, Trap, Addresses) ->
do_handle_send_pdu(S, trappdu, Trap, Addresses).
do_handle_send_pdu(S, Type, Pdu, Addresses) ->
- case (catch do_handle_send_pdu1(S, Type, Addresses)) of
+ try do_handle_send_pdu1(S, Type, Addresses)
+ catch
{Reason, Sz} ->
- error_msg("Cannot send message "
- "~n size: ~p"
- "~n reason: ~p"
- "~n pdu: ~p",
- [Sz, Reason, Pdu]);
- _ ->
- ok
+ error_msg(
+ "Can not send message~n"
+ " size: ~p~n"
+ " reason: ~p~n"
+ " pdu: ~p",
+ [Sz, Reason, Pdu])
end.
-do_handle_send_pdu1(S, Type, Addresses) ->
+do_handle_send_pdu1(
+ #state{transports = Transports} = S,
+ Type, Addresses) ->
lists:foreach(
fun ({Domain, Address, Packet}) when is_binary(Packet) ->
?vdebug(
@@ -931,32 +1189,55 @@ do_handle_send_pdu1(S, Type, Addresses) ->
" size: ~p~n"
" to: ~p", [Domain, sz(Packet), Address]),
To = {Domain, Address},
- maybe_udp_send(S, To, Packet);
+ case select_transport_from_domain(Domain, Transports) of
+ false ->
+ error_msg(
+ "Can not find transport~n"
+ " size: ~p~n"
+ " to: ~s",
+ [sz(Packet), To]);
+ Transport ->
+ maybe_udp_send(S, Transport, To, Packet)
+ end;
({Domain, Address, {Packet, LogData}}) when is_binary(Packet) ->
?vdebug(
"[~w] sending encrypted packet:~n"
" size: ~p~n"
" to: ~p", [Domain, sz(Packet), Address]),
To = {Domain, Address},
- maybe_udp_send(S, To, Packet, Type, LogData)
+ case select_transport_from_domain(Domain, Transports) of
+ false ->
+ error_msg(
+ "Can not find transport~n"
+ " size: ~p~n"
+ " to: ~s",
+ [sz(Packet), To]);
+ Transport ->
+ maybe_udp_send(S, Transport, To, Packet, Type, LogData)
+ end
end,
Addresses).
-handle_response(Vsn, Pdu, From, S) ->
- case lists:keysearch(Pdu#pdu.request_id, 1, S#state.reqs) of
- {value, {_, Pid}} ->
- ?vdebug("handle_response -> "
- "~n send response to receiver ~p", [Pid]),
- Pid ! {snmp_response_received, Vsn, Pdu, From};
- _ ->
- ?vdebug("handle_response -> "
- "~n No receiver available for response pdu", [])
- end.
+%%% XXX remove
+%%%
+%%% handle_response(
+%%% #state{reqs = Reqs} = S, Pdu#pdu{request_id = ReqId}, From, Vsn)
+%%% when is_pid(From) ->
+%%% case lists:keyfind(ReqId, 1, S#state.reqs) of
+%%% {ReqId, Pid} ->
+%%% ?vdebug("handle_response -> "
+%%% "~n send response to receiver ~p", [Pid]),
+%%% Pid ! {snmp_response_received, Vsn, Pdu, From};
+%%% false ->
+%%% ?vdebug("handle_response -> "
+%%% "~n No receiver available for response pdu", [])
+%%% end.
maybe_udp_send(
- #state{usock = Sock, filter = FilterMod, domain = Domain},
+ #state{filter = FilterMod, transports = Transports},
+ #transport{socket = Socket},
To, Packet) ->
- {To_1, To_2} = fix_filter_address(Domain, To),
+ {To_1, To_2} = fix_filter_address(Transports, To),
case
try FilterMod:accept_send(To_1, To_2)
catch
@@ -979,25 +1260,21 @@ maybe_udp_send(
"FilterMod:accept_send(~p, ~p) returned: ~p",
[To_1,To_2,Other])
end,
- %% XXX should be some kind of lookup of domain to socket
- (catch udp_send(Sock, To, Packet))
+ udp_send(Socket, To, Packet)
end.
maybe_udp_send(
- #state{
- log = Log,
- usock = Sock,
- filter = FilterMod,
- domain = Domain},
+ #state{log = Log, filter = FilterMod, transports = Transports},
+ #transport{socket = Socket},
To, Packet, Type, _LogData) ->
- {To_1, To_2} = fix_filter_address(Domain, To),
+ {To_1, To_2} = fix_filter_address(Transports, To),
case
try FilterMod:accept_send(To_1, To_2)
catch
Class:Exception ->
error_msg(
"FilterMod:accept_send(~p, ~p) crashed for: ~w:~w~n ~p",
- [To_1,To_2,Class,Exception,erlang:get_stacktrace()]),
+ [To_1, To_2, Class, Exception, erlang:get_stacktrace()]),
true
end
of
@@ -1014,32 +1291,33 @@ maybe_udp_send(
[To_1,To_2,Other])
end,
log(Log, Type, Packet, To),
- (catch udp_send(Sock, To, Packet))
+ udp_send(Socket, To, Packet)
end.
-udp_send(UdpId, To, B) ->
- %% XXX should be some kind of lookup of domain to socket
- {Ip, Port} =
+udp_send(Socket, To, B) ->
+ {IpAddr, IpPort} =
case To of
{Domain, Addr} when is_atom(Domain) ->
Addr;
{_, P} = Addr when is_integer(P) ->
Addr
end,
- case (catch gen_udp:send(UdpId, Ip, Port, B)) of
+ try gen_udp:send(Socket, IpAddr, IpPort, B) of
{error, emsgsize} ->
%% From this message we cannot recover, so exit sending loop
throw({emsgsize, sz(B)});
{error, ErrorReason} ->
error_msg("[error] cannot send message "
"(destination: ~p:~p, size: ~p, reason: ~p)",
- [Ip, Port, sz(B), ErrorReason]);
- {'EXIT', ExitReason} ->
- error_msg("[exit] cannot send message "
- "(destination: ~p:~p, size: ~p, reason: ~p)",
- [Ip, Port, sz(B), ExitReason]);
- _ ->
+ [IpAddr, IpPort, sz(B), ErrorReason]);
+ ok ->
ok
+ catch
+ error:ExitReason ->
+ error_msg("[exit] cannot send message "
+ "(destination: ~p:~p, size: ~p, reason: ~p, at: ~p)",
+ [IpAddr, IpPort, sz(B), ExitReason,
+ erlang:get_stacktrace()])
end.
sz(L) when is_list(L) -> length(L);
@@ -1089,21 +1367,74 @@ active_once(Sock) ->
inet:setopts(Sock, [{active, once}]).
+select_transport_from_req_ref(_, []) ->
+ false;
+select_transport_from_req_ref(
+ ReqRef,
+ [#transport{req_refs = ReqRefs} = Transport | Transports]) ->
+ case lists:member(ReqRef, ReqRefs) of
+ true ->
+ Transport;
+ false ->
+ select_transport_from_req_ref(ReqRef, Transports)
+ end.
+
+select_transport_from_domain(Domain, Transports) when is_atom(Domain) ->
+ Pos = #transport.domain,
+ case lists:keyfind(Domain, Pos, Transports) of
+ #transport{domain = Domain} = Transport ->
+ Transport;
+ false when Domain == snmpUDPDomain ->
+ lists:keyfind(transportDomainUdpIpv4, Pos, Transports);
+ false when Domain == transportDomainUdpIpv4 ->
+ lists:keyfind(snmpUDPDomain, Pos, Transports);
+ false ->
+ false
+ end.
+
+address_to_domain({Domain, _Addr}) when is_atom(Domain) ->
+ Domain;
+address_to_domain({_Ip, Port}) when is_integer(Port) ->
+ snmpUDPDomain.
+
%% If the agent uses legacy snmpUDPDomain e.g has not set
%% intAgentTransportDomain, then make sure
%% snmpa_network_interface_filter gets legacy arguments
%% to not break backwards compatibility.
%%
-fix_filter_address(snmpUDPDomain, {Domain, Addr})
- when Domain =:= snmpUDPDomain;
- Domain =:= transportDomainUdpIpv4 ->
- Addr;
-fix_filter_address(_AgentDomain, {Domain, _} = Address)
- when is_atom(Domain) ->
- Address;
-fix_filter_address(snmpUDPDomain, {_, Port} = Addr)
- when is_integer(Port) ->
- Addr.
+fix_filter_address(Transports, Address) ->
+ case is_legacy_transports(Transports) of
+ true ->
+ case Address of
+ {Domain, Addr} when is_atom(Domain) ->
+ Addr;
+ {_, IpPort} = Addr when is_integer(IpPort) ->
+ Addr
+ end;
+ false ->
+ Address
+ end.
+
+is_legacy_transports([#transport{domain = snmpUDPDomain}]) ->
+ true;
+is_legacy_transports([#transport{} | _]) ->
+ false.
+
+fix_filter_legacy_mpd_address(Domain_Address_SecData) ->
+ case Domain_Address_SecData of
+ {{Domain, Addr}, _SecData} when is_atom(Domain) -> % v3
+ Addr;
+ {Domain, Addr} when is_atom(Domain) -> % v1 & v2
+ Addr
+ end.
+
+fix_filter_mpd_address(Domain_Address_SecData) ->
+ case Domain_Address_SecData of
+ {{Domain, _Addr} = Address, _SecData} when is_atom(Domain) -> % v3
+ Address;
+ {Domain, _Addr} = Address when is_atom(Domain) -> % v1 & v2
+ Address
+ end.
%%%-----------------------------------------------------------------
@@ -1261,6 +1592,35 @@ get_counters([Counter|Counters], Acc) ->
%% ----------------------------------------------------------------
+socket_opts(Domain, {IpAddr, IpPort}, Opts) ->
+ [IpPort, % Picked off at socket open, separate argument
+ binary,
+ snmp_conf:tdomain_to_family(Domain)
+ | case get_bind_to_ip_address(Opts) of
+ true ->
+ [{ip, IpAddr}];
+ _ ->
+ []
+ end ++
+ case get_no_reuse_address(Opts) of
+ false ->
+ [{reuseaddr, true}];
+ _ ->
+ []
+ end ++
+ case get_recbuf(Opts) of
+ use_default ->
+ [];
+ Sz ->
+ [{recbuf, Sz}]
+ end ++
+ case get_sndbuf(Opts) of
+ use_default ->
+ [];
+ Sz ->
+ [{sndbuf, Sz}]
+ end].
+
ip_opt_bind_to_ip_address(Opts, Ip) ->
case get_bind_to_ip_address(Opts) of
true ->
@@ -1378,14 +1738,14 @@ call(Pid, Req) ->
%% ----------------------------------------------------------------
-get_info(#state{usock = Id, reqs = Reqs}) ->
+get_info(#state{transports = Transports, reqs = Reqs}) ->
ProcSize = proc_mem(self()),
- PortInfo = get_port_info(Id),
Counters = get_counters(),
- [{reqs, Reqs},
- {counters, Counters},
- {process_memory, ProcSize},
- {port_info, PortInfo}].
+ [{reqs, Reqs},
+ {counters, Counters},
+ {process_memory, ProcSize}
+ | [{port_info, get_port_info(Socket)}
+ || #transport{socket = Socket} <- Transports]].
proc_mem(P) when is_pid(P) ->
case (catch erlang:process_info(P, memory)) of
diff --git a/lib/snmp/src/agent/snmpa_trap.erl b/lib/snmp/src/agent/snmpa_trap.erl
index ac0739860b..40956c40fb 100644
--- a/lib/snmp/src/agent/snmpa_trap.erl
+++ b/lib/snmp/src/agent/snmpa_trap.erl
@@ -790,42 +790,45 @@ send_trap_pdus([], ContextName, {TrapRec, Vbs},
send_v1_trap(_TrapRec, [], _Vbs, _ExtraInfo, _NetIf, _SysUpTime) ->
ok;
-send_v1_trap(#trap{enterpriseoid = Enter, specificcode = Spec},
- V1Res, Vbs, ExtraInfo, NetIf, SysUpTime) ->
+send_v1_trap(
+ #trap{enterpriseoid = Enter, specificcode = Spec},
+ V1Res, Vbs, ExtraInfo, NetIf, SysUpTime) ->
?vdebug("prepare to send v1 trap "
"~n '~p'"
"~n with"
"~n ~p"
"~n to"
"~n ~p", [Enter, Spec, V1Res]),
- AgentDomain =
- case snmp_framework_mib:intAgentTransportDomain(get) of
- {value, AD} ->
- AD;
- genErr ->
- snmp_target_mib:default_domain()
- end,
- case AgentDomain of
- snmpUDPDomain ->
- {value, AgentIp} = snmp_framework_mib:intAgentIpAddress(get),
- TrapPdu = make_v1_trap_pdu(Enter, Spec, Vbs, SysUpTime, AgentIp),
- AddrCommunities = mk_addr_communities(V1Res),
- lists:foreach(
- fun ({Community, Addrs}) ->
- ?vtrace("send v1 trap pdu to ~p",[Addrs]),
- NetIf ! {send_pdu, 'version-1', TrapPdu,
- {community, Community}, Addrs, ExtraInfo}
- end, AddrCommunities);
- _ ->
- ?vtrace(
- "snmpa_trap: can not send v1 trap with domain: ~w",
- [AgentDomain]),
- user_err(
- "snmpa_trap: can not send v1 trap with domain: ~w",
- [AgentDomain])
- end;
-send_v1_trap(#notification{oid = Oid}, V1Res, Vbs, ExtraInfo, NetIf,
- SysUpTime) ->
+ do_send_v1_trap(Enter, Spec, V1Res, Vbs, ExtraInfo, NetIf, SysUpTime);
+%%% AgentDomain =
+%%% case snmp_framework_mib:intAgentTransportDomain(get) of
+%%% {value, AD} ->
+%%% AD;
+%%% genErr ->
+%%% snmp_target_mib:default_domain()
+%%% end,
+%%% case AgentDomain of
+%%% snmpUDPDomain ->
+%%% {value, AgentIp} = snmp_framework_mib:intAgentIpAddress(get),
+%%% TrapPdu = make_v1_trap_pdu(Enter, Spec, Vbs, SysUpTime, AgentIp),
+%%% AddrCommunities = mk_addr_communities(V1Res),
+%%% lists:foreach(
+%%% fun ({Community, Addrs}) ->
+%%% ?vtrace("send v1 trap pdu to ~p",[Addrs]),
+%%% NetIf ! {send_pdu, 'version-1', TrapPdu,
+%%% {community, Community}, Addrs, ExtraInfo}
+%%% end, AddrCommunities);
+%%% _ ->
+%%% ?vtrace(
+%%% "snmpa_trap: can not send v1 trap with domain: ~w",
+%%% [AgentDomain]),
+%%% user_err(
+%%% "snmpa_trap: can not send v1 trap with domain: ~w",
+%%% [AgentDomain])
+%%% end;
+send_v1_trap(
+ #notification{oid = Oid},
+ V1Res, Vbs, ExtraInfo, NetIf, SysUpTime) ->
%% Use alg. in rfc2089 to map a v2 trap to a v1 trap
% delete Counter64 objects from vbs
?vdebug("prepare to send v1 trap '~p'",[Oid]),
@@ -842,32 +845,64 @@ send_v1_trap(#notification{oid = Oid}, V1Res, Vbs, ExtraInfo, NetIf,
{lists:reverse(First),Last}
end
end,
- AgentDomain =
- case snmp_framework_mib:intAgentTransportDomain(get) of
- {value, AD} ->
- AD;
- genErr ->
- snmp_target_mib:default_domain()
+ do_send_v1_trap(Enter, Spec, V1Res, NVbs, ExtraInfo, NetIf, SysUpTime).
+
+do_send_v1_trap(Enter, Spec, V1Res, NVbs, ExtraInfo, NetIf, SysUpTime) ->
+ {value, Transports} = snmp_framework_mib:intAgentTransports(get),
+ {_Domain, {AgentIp, _AgentPort}} =
+ case lists:keyfind(snmpUDPDomain, 1, Transports) of
+ false ->
+ case lists:keyfind(transportDomainUdpIpv4, 1, Transports) of
+ false ->
+ ?vtrace(
+ "snmpa_trap: can not send v1 trap "
+ "without IPv4 domain: ~p",
+ [Transports]),
+ user_err(
+ "snmpa_trap: can not send v1 trap "
+ "without IPv4 domain: ~p",
+ [Transports]);
+ DomainAddr ->
+ DomainAddr
+ end;
+ DomainAddr ->
+ DomainAddr
end,
- case AgentDomain of
- snmpUDPDomain ->
- {value, AgentIp} = snmp_framework_mib:intAgentIpAddress(get),
- TrapPdu = make_v1_trap_pdu(Enter, Spec, NVbs, SysUpTime, AgentIp),
- AddrCommunities = mk_addr_communities(V1Res),
- lists:foreach(
- fun ({Community, Addrs}) ->
- ?vtrace("send v1 trap to ~p",[Addrs]),
- NetIf ! {send_pdu, 'version-1', TrapPdu,
- {community, Community}, Addrs, ExtraInfo}
- end, AddrCommunities);
- _ ->
- ?vtrace(
- "snmpa_trap: can not send v1 trap with domain: ~w",
- [AgentDomain]),
- user_err(
- "snmpa_trap: can not send v1 trap with domain: ~w",
- [AgentDomain])
- end.
+ TrapPdu = make_v1_trap_pdu(Enter, Spec, NVbs, SysUpTime, AgentIp),
+ AddrCommunities = mk_addr_communities(V1Res),
+ lists:foreach(
+ fun ({Community, Addrs}) ->
+ ?vtrace("send v1 trap to ~p",[Addrs]),
+ NetIf ! {send_pdu, 'version-1', TrapPdu,
+ {community, Community}, Addrs, ExtraInfo}
+ end, AddrCommunities).
+
+%%% AgentDomain =
+%%% case snmp_framework_mib:intAgentTransportDomain(get) of
+%%% {value, AD} ->
+%%% AD;
+%%% genErr ->
+%%% snmp_target_mib:default_domain()
+%%% end,
+%%% case AgentDomain of
+%%% snmpUDPDomain ->
+%%% {value, AgentIp} = snmp_framework_mib:intAgentIpAddress(get),
+%%% TrapPdu = make_v1_trap_pdu(Enter, Spec, NVbs, SysUpTime, AgentIp),
+%%% AddrCommunities = mk_addr_communities(V1Res),
+%%% lists:foreach(
+%%% fun ({Community, Addrs}) ->
+%%% ?vtrace("send v1 trap to ~p",[Addrs]),
+%%% NetIf ! {send_pdu, 'version-1', TrapPdu,
+%%% {community, Community}, Addrs, ExtraInfo}
+%%% end, AddrCommunities);
+%%% _ ->
+%%% ?vtrace(
+%%% "snmpa_trap: can not send v1 trap with domain: ~w",
+%%% [AgentDomain]),
+%%% user_err(
+%%% "snmpa_trap: can not send v1 trap with domain: ~w",
+%%% [AgentDomain])
+%%% end.
send_v2_trap(_TrapRec, [], _Vbs, _Recv, _ExtraInfo, _NetIf, _SysUpTime) ->
ok;