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/depend.mk2
-rw-r--r--lib/snmp/src/agent/snmp_generic_mnesia.erl5
-rw-r--r--lib/snmp/src/agent/snmp_target_mib.erl39
-rw-r--r--lib/snmp/src/agent/snmp_view_based_acm_mib.erl35
-rw-r--r--lib/snmp/src/agent/snmpa.erl4
-rw-r--r--lib/snmp/src/agent/snmpa_agent.erl768
-rw-r--r--lib/snmp/src/agent/snmpa_conf.erl9
-rw-r--r--lib/snmp/src/agent/snmpa_internal.hrl12
-rw-r--r--lib/snmp/src/agent/snmpa_local_db.erl12
-rw-r--r--lib/snmp/src/agent/snmpa_mib.erl14
-rw-r--r--lib/snmp/src/agent/snmpa_mib_lib.erl20
-rw-r--r--lib/snmp/src/agent/snmpa_mpd.erl132
-rw-r--r--lib/snmp/src/agent/snmpa_set_lib.erl63
-rw-r--r--lib/snmp/src/agent/snmpa_supervisor.erl40
-rw-r--r--lib/snmp/src/agent/snmpa_trap.erl26
-rw-r--r--lib/snmp/src/agent/snmpa_vacm.erl52
16 files changed, 837 insertions, 396 deletions
diff --git a/lib/snmp/src/agent/depend.mk b/lib/snmp/src/agent/depend.mk
index bc39e1fa35..078ef15821 100644
--- a/lib/snmp/src/agent/depend.mk
+++ b/lib/snmp/src/agent/depend.mk
@@ -52,6 +52,7 @@ $(EBIN)/snmpa_acm.$(EMULATOR): \
$(EBIN)/snmpa_agent.$(EMULATOR): \
snmpa_agent.erl \
+ snmpa_internal.hrl \
../misc/snmp_debug.hrl \
../misc/snmp_verbosity.hrl \
../../include/snmp_types.hrl
@@ -136,6 +137,7 @@ $(EBIN)/snmpa_set_lib.$(EMULATOR): \
$(EBIN)/snmpa_supervisor.$(EMULATOR): \
snmpa_supervisor.erl \
+ snmpa_internal.hrl \
../misc/snmp_debug.hrl \
../misc/snmp_verbosity.hrl
diff --git a/lib/snmp/src/agent/snmp_generic_mnesia.erl b/lib/snmp/src/agent/snmp_generic_mnesia.erl
index a73aad5b33..ce42af404b 100644
--- a/lib/snmp/src/agent/snmp_generic_mnesia.erl
+++ b/lib/snmp/src/agent/snmp_generic_mnesia.erl
@@ -121,7 +121,7 @@ table_func(set, RowIndex, Cols, Name) ->
fun() ->
snmp_generic:table_set_row(
{Name, mnesia}, nofunc,
- {snmp_generic_mnesia, table_try_make_consistent},
+ fun table_try_make_consistent/2,
RowIndex, Cols)
end) of
{atomic, Value} ->
@@ -368,7 +368,8 @@ table_set_elements(Name, RowIndex, Cols) ->
_ -> false
end.
table_set_elements(Name, RowIndex, Cols, ConsFunc) ->
- #table_info{index_types = Indexes, first_own_index = FirstOwnIndex} =
+ #table_info{index_types = Indexes,
+ first_own_index = FirstOwnIndex} =
snmp_generic:table_info(Name),
AddCol = if
FirstOwnIndex == 0 -> 2;
diff --git a/lib/snmp/src/agent/snmp_target_mib.erl b/lib/snmp/src/agent/snmp_target_mib.erl
index 77910541a2..a45db89c09 100644
--- a/lib/snmp/src/agent/snmp_target_mib.erl
+++ b/lib/snmp/src/agent/snmp_target_mib.erl
@@ -46,8 +46,14 @@
%% Column not accessible via SNMP - needed when the agent sends informs
-define(snmpTargetAddrEngineId, 10).
%% Extra comlumns for the augmented table snmpTargetAddrExtTable
--define(snmpTargetAddrTMask, 11).
--define(snmpTargetAddrMMS, 12).
+-define(snmpTargetAddrTMask, 11).
+-define(snmpTargetAddrMMS, 12).
+
+-ifdef(snmp_extended_verbosity).
+-define(vt(F,A), ?vtrace(F, A)).
+-else.
+-define(vt(_F, _A), ok).
+-endif.
%%-----------------------------------------------------------------
@@ -383,10 +389,18 @@ is_valid_tag(Tag, TDomain, TAddress) ->
is_valid_tag(TDomain, TAddress, Tag, []).
is_valid_tag(TDomain, TAddress, Tag, Key) ->
+ ?vtrace("is_valid_tag -> entry with"
+ "~n TDomain: ~p"
+ "~n TAddress: ~p"
+ "~n Tag: ~p"
+ "~n Key: ~p", [TDomain, TAddress, Tag, Key]),
case table_next(snmpTargetAddrTable, Key) of
endOfTable ->
+ ?vtrace("is_valid_tag -> endOfTable", []),
false;
NextKey ->
+ ?vtrace("is_valid_tag -> next key found"
+ "~n NextKey: ~p", [NextKey]),
case get(snmpTargetAddrTable, NextKey, [?snmpTargetAddrTDomain,
?snmpTargetAddrTAddress,
?snmpTargetAddrTagList,
@@ -395,6 +409,8 @@ is_valid_tag(TDomain, TAddress, Tag, Key) ->
{value, TAddress}, % RFC2576: chapters 5.2.1 & 5.3
{value, TagList},
{value, []}] ->
+ ?vtrace("is_valid_tag -> found with exact match"
+ "~n TagList: ~p", [TagList]),
case snmp_misc:is_tag_member(Tag, TagList) of
true ->
?vtrace("is_valid_tag -> exact: "
@@ -410,9 +426,14 @@ is_valid_tag(TDomain, TAddress, Tag, Key) ->
{value, TAddress2},
{value, TagList},
{value, TMask}] when TMask =/= [] ->
+ ?vtrace("is_valid_tag -> found with exact match"
+ "~n TagList: ~p"
+ "~n TMask: ~p", [TagList, TMask]),
case snmp_misc:is_tmask_match(TAddress, TAddress2,
TMask) of
true ->
+ ?vtrace("is_valid_tag -> "
+ "tmask match - now check tag member", []),
case snmp_misc:is_tag_member(Tag, TagList) of
true ->
?vtrace("is_valid_tag -> masked: "
@@ -425,10 +446,12 @@ is_valid_tag(TDomain, TAddress, Tag, Key) ->
Tag, NextKey)
end;
false ->
+ ?vtrace("is_valid_tag -> tmask NO match", []),
is_valid_tag(TDomain, TAddress,
Tag, NextKey)
end;
_ ->
+ ?vtrace("is_valid_tag -> not found - try next", []),
is_valid_tag(TDomain, TAddress, Tag, NextKey)
end
end.
@@ -442,10 +465,16 @@ get_target_addrs() ->
get_target_addrs(Key, {Tab, _} = TabDb, Acc) ->
+ ?vt("get_target_addrs -> entry with"
+ "~n Key: ~p", [Key]),
case table_next(Tab, Key) of
endOfTable ->
+ ?vt("get_target_addrs -> endOfTable when"
+ "~n Acc: ~p", [Acc]),
Acc;
NextKey ->
+ ?vt("get_target_addrs -> next ok: "
+ "~n NextKey: ~p", [NextKey]),
case get_target_addr(TabDb, NextKey) of
{ok, Targ} ->
get_target_addrs(NextKey, TabDb, [Targ| Acc]);
@@ -591,9 +620,9 @@ snmpTargetAddrTable(print) ->
[Prefix, element(?snmpTargetAddrName, Row),
Prefix, element(?snmpTargetAddrTDomain, Row),
case element(?snmpTargetAddrTDomain, Row) of
- ?snmpUDPDomain -> udp;
- ?transportDomainUdpIpv4 -> udpIpv4;
- ?transportDomainUdpIpv6 -> udpIpv6;
+ ?snmpUDPDomain -> snmpUDPDomain;
+ ?transportDomainUdpIpv4 -> transportDomainUdpIpv4;
+ ?transportDomainUdpIpv6 -> transportDomainUdpIpv6;
_ -> undefined
end,
Prefix, element(?snmpTargetAddrTAddress, Row),
diff --git a/lib/snmp/src/agent/snmp_view_based_acm_mib.erl b/lib/snmp/src/agent/snmp_view_based_acm_mib.erl
index 28469a7b4e..2cee91b081 100644
--- a/lib/snmp/src/agent/snmp_view_based_acm_mib.erl
+++ b/lib/snmp/src/agent/snmp_view_based_acm_mib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -203,18 +203,16 @@ init_sec2group_table([Row | T]) ->
init_sec2group_table(T);
init_sec2group_table([]) -> true.
-init_access_table([{GN, Prefix, Model, Level, Row} | T]) ->
-%% ?vtrace("init access table: "
-%% "~n GN: ~p"
-%% "~n Prefix: ~p"
-%% "~n Model: ~p"
-%% "~n Level: ~p"
-%% "~n Row: ~p",[GN, Prefix, Model, Level, Row]),
- Key = [length(GN) | GN] ++ [length(Prefix) | Prefix] ++ [Model, Level],
- snmpa_vacm:insert([{Key, Row}], false),
- init_access_table(T);
-init_access_table([]) ->
- snmpa_vacm:dump_table().
+make_access_key(GN, Prefix, Model, Level) ->
+ [length(GN) | GN] ++ [length(Prefix) | Prefix] ++ [Model, Level].
+
+make_access_entry({GN, Prefix, Model, Level, Row}) ->
+ Key = make_access_key(GN, Prefix, Model, Level),
+ {Key, Row}.
+
+init_access_table(TableData) ->
+ TableData2 = [make_access_entry(E) || E <- TableData],
+ snmpa_vacm:insert(TableData2, true).
init_view_table([Row | T]) ->
%% ?vtrace("init view table: "
@@ -247,6 +245,7 @@ add_sec2group(SecModel, SecName, GroupName) ->
Key = [Key1, length(Key2) | Key2],
case table_cre_row(vacmSecurityToGroupTable, Key, Row) of
true ->
+ snmpa_agent:invalidate_ca_cache(),
{ok, Key};
false ->
{error, create_failed}
@@ -260,6 +259,7 @@ add_sec2group(SecModel, SecName, GroupName) ->
delete_sec2group(Key) ->
case table_del_row(vacmSecurityToGroupTable, Key) of
true ->
+ snmpa_agent:invalidate_ca_cache(),
ok;
false ->
{error, delete_failed}
@@ -274,11 +274,9 @@ add_access(GroupName, Prefix, SecModel, SecLevel, Match, RV, WV, NV) ->
Match, RV, WV, NV},
case (catch check_vacm(Access)) of
{ok, {vacmAccess, {GN, Pref, SM, SL, Row}}} ->
- Key1 = [length(GN) | GN],
- Key2 = [length(Pref) | Pref],
- Key3 = [SM, SL],
- Key = Key1 ++ Key2 ++ Key3,
+ Key = make_access_key(GN, Pref, SM, SL),
snmpa_vacm:insert([{Key, Row}], false),
+ snmpa_agent:invalidate_ca_cache(),
{ok, Key};
{error, Reason} ->
{error, Reason};
@@ -287,6 +285,7 @@ add_access(GroupName, Prefix, SecModel, SecLevel, Match, RV, WV, NV) ->
end.
delete_access(Key) ->
+ snmpa_agent:invalidate_ca_cache(),
snmpa_vacm:delete(Key).
@@ -299,6 +298,7 @@ add_view_tree_fam(ViewIndex, SubTree, Status, Mask) ->
Key = [length(Key1) | Key1] ++ [length(Key2) | Key2],
case table_cre_row(vacmViewTreeFamilyTable, Key, Row) of
true ->
+ snmpa_agent:invalidate_ca_cache(),
{ok, Key};
false ->
{error, create_failed}
@@ -312,6 +312,7 @@ add_view_tree_fam(ViewIndex, SubTree, Status, Mask) ->
delete_view_tree_fam(Key) ->
case table_del_row(vacmViewTreeFamilyTable, Key) of
true ->
+ snmpa_agent:invalidate_ca_cache(),
ok;
false ->
{error, delete_failed}
diff --git a/lib/snmp/src/agent/snmpa.erl b/lib/snmp/src/agent/snmpa.erl
index 50b169e4e7..c400aaddf7 100644
--- a/lib/snmp/src/agent/snmpa.erl
+++ b/lib/snmp/src/agent/snmpa.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -547,7 +547,7 @@ update_mibs_cache_age(Agent, Age) ->
update_mibs_cache_gclimit(GcLimit) ->
- update_mibs_cache_age(snmp_master_agent, GcLimit).
+ update_mibs_cache_gclimit(snmp_master_agent, GcLimit).
update_mibs_cache_gclimit(Agent, GcLimit) ->
snmpa_agent:update_mibs_cache_gclimit(Agent, GcLimit).
diff --git a/lib/snmp/src/agent/snmpa_agent.erl b/lib/snmp/src/agent/snmpa_agent.erl
index 82a7ec647b..9cc986cf47 100644
--- a/lib/snmp/src/agent/snmpa_agent.erl
+++ b/lib/snmp/src/agent/snmpa_agent.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -68,8 +68,11 @@
%% Internal exports
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3, tr_var/2, tr_varbind/1,
- handle_pdu/7, worker/2, worker_loop/1,
+ handle_pdu/8, worker/2, worker_loop/1,
do_send_trap/7, do_send_trap/8]).
+%% <BACKWARD-COMPAT>
+-export([handle_pdu/7]).
+%% </BACKWARD-COMPAT>
-include("snmpa_internal.hrl").
@@ -87,7 +90,6 @@
-define(DISCO_TERMINATING_TRIGGER_USERNAME, "").
-
-ifdef(snmp_debug).
-define(GS_START_LINK3(Prio, Parent, Ref, Opts),
gen_server:start_link(?MODULE, [Prio, Parent, Ref, Opts],
@@ -103,13 +105,49 @@
gen_server:start_link({local, Name}, ?MODULE,
[Prio, Parent, Ref, Opts],[])).
-endif.
-
+
+%% Increment this whenever a change is made to the worker interface
+-define(WORKER_INTERFACE_VERSION, 1).
+
+%% -- Utility macros for creating worker commands --
+-define(mk_pdu_wreq(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra),
+ #wrequest{cmd = handle_pdu,
+ info = [{vsn, Vsn},
+ {pdu, Pdu},
+ {pdu_ms, PduMS},
+ {acm_data, ACMData},
+ {addr, Address},
+ {gb_max_vbs, GbMaxVBs},
+ {extra, Extra}]}).
+-define(mk_send_trap_wreq(TrapRec, NotifyName, ContextName,
+ Recv, Vbs, LocalEngineID, Extra),
+ #wrequest{cmd = send_trap,
+ info = [{trap_rec, TrapRec},
+ {notify_name, NotifyName},
+ {context_name, ContextName},
+ {receiver, Recv},
+ {varbinds, Vbs},
+ {local_engine_id, LocalEngineID},
+ {extra, Extra}]}).
+-define(mk_terminate_wreq(), #wrequest{cmd = terminate, info = []}).
+-define(mk_verbosity_wreq(V), #wrequest{cmd = verbosity,
+ info = [{verbosity, V}]}).
+
-record(notification_filter, {id, mod, data}).
-record(disco,
{from, rec, sender, target, engine_id,
sec_level, ctx, ivbs, stage, handler, extra}).
+%% This record is used when sending requests to the worker processes
+-record(wrequest,
+ {
+ version = ?WORKER_INTERFACE_VERSION,
+ cmd,
+ info
+ }
+ ).
+
%%-----------------------------------------------------------------
%% The agent is multi-threaded, i.e. each request is handled
@@ -142,7 +180,8 @@
net_if_mod,
backup,
disco,
- mibs_cache_request}).
+ mibs_cache_request,
+ gb_max_vbs}).
%%%-----------------------------------------------------------------
@@ -330,6 +369,8 @@ do_init(Prio, Parent, Ref, Options) ->
MultiT = get_multi_threaded(Options),
Vsns = get_versions(Options),
+ GbMaxVbs = get_gb_max_vbs(Options),
+
NS = start_note_store(Prio, Ref, Options),
{Type, NetIfPid, NetIfMod} =
start_net_if(Parent, Prio, Ref, Vsns, NS, Options),
@@ -348,7 +389,8 @@ do_init(Prio, Parent, Ref, Options) ->
ref = Ref,
vsns = Vsns,
note_store = NS,
- net_if_mod = NetIfMod}}.
+ net_if_mod = NetIfMod,
+ gb_max_vbs = GbMaxVbs}}.
start_note_store(Prio, Ref, Options) ->
@@ -410,7 +452,8 @@ start_net_if(Parent, _Prio, _Ref, _Vsns, _NoteStore, _Options)
start_mib_server(Prio, Ref, Mibs, Options) ->
?vdebug("start_mib_server -> with Prio: ~p", [Prio]),
MibStorage = get_mib_storage(Options),
- MibsOpts = [{mib_storage, MibStorage}|get_option(mib_server, Options, [])],
+ MibsOpts = [{mib_storage, MibStorage} |
+ get_option(mib_server, Options, [])],
?vtrace("start_mib_server -> "
"~n Mibs: ~p"
@@ -558,25 +601,6 @@ send_trap(Agent, Trap, NotifyName, CtxName, Recv, Varbinds) ->
],
send_notification(Agent, Trap, SendOpts).
-%% send_trap(Agent, Trap, NotifyName, CtxName, Recv, Varbinds) ->
-%% ?d("send_trap -> entry with"
-%% "~n self(): ~p"
-%% "~n Agent: ~p [~p]"
-%% "~n Trap: ~p"
-%% "~n NotifyName: ~p"
-%% "~n CtxName: ~p"
-%% "~n Recv: ~p"
-%% "~n Varbinds: ~p",
-%% [self(), Agent, wis(Agent),
-%% Trap, NotifyName, CtxName, Recv, Varbinds]),
-%% Msg = {send_trap, Trap, NotifyName, CtxName, Recv, Varbinds},
-%% case (wis(Agent) =:= self()) of
-%% false ->
-%% call(Agent, Msg);
-%% true ->
-%% Agent ! Msg
-%% end.
-
send_trap(Agent, Trap, NotifyName, CtxName, Recv, Varbinds, LocalEngineID) ->
?d("send_trap -> entry with"
"~n self(): ~p"
@@ -599,27 +623,6 @@ send_trap(Agent, Trap, NotifyName, CtxName, Recv, Varbinds, LocalEngineID) ->
],
send_notification(Agent, Trap, SendOpts).
-%% send_trap(Agent, Trap, NotifyName, CtxName, Recv, Varbinds, LocalEngineID) ->
-%% ?d("send_trap -> entry with"
-%% "~n self(): ~p"
-%% "~n Agent: ~p [~p]"
-%% "~n Trap: ~p"
-%% "~n NotifyName: ~p"
-%% "~n CtxName: ~p"
-%% "~n Recv: ~p"
-%% "~n Varbinds: ~p"
-%% "~n LocalEngineID: ~p",
-%% [self(), Agent, wis(Agent),
-%% Trap, NotifyName, CtxName, Recv, Varbinds, LocalEngineID]),
-%% Msg =
-%% {send_trap, Trap, NotifyName, CtxName, Recv, Varbinds, LocalEngineID},
-%% case (wis(Agent) =:= self()) of
-%% false ->
-%% call(Agent, Msg);
-%% true ->
-%% Agent ! Msg
-%% end.
-
%% </BACKWARD-COMPAT>
@@ -709,11 +712,6 @@ wis(Atom) when is_atom(Atom) ->
whereis(Atom).
-forward_trap(Agent, TrapRecord, NotifyName, CtxName, Recv, Varbinds) ->
- ExtraInfo = ?DEFAULT_NOTIF_EXTRA_INFO,
- forward_trap(Agent, TrapRecord, NotifyName, CtxName, Recv, Varbinds,
- ExtraInfo).
-
forward_trap(Agent, TrapRecord, NotifyName, CtxName, Recv, Varbinds,
ExtraInfo) ->
Agent ! {forward_trap, TrapRecord, NotifyName, CtxName, Recv, Varbinds,
@@ -796,7 +794,8 @@ handle_info({snmp_pdu, Vsn, Pdu, PduMS, ACMData, Address, Extra}, S) ->
?vdebug("handle_info(snmp_pdu) -> entry with"
"~n Vsn: ~p"
"~n Pdu: ~p"
- "~n Address: ~p", [Vsn, Pdu, Address]),
+ "~n Address: ~p"
+ "~n Extra: ~p", [Vsn, Pdu, Address, Extra]),
NewS = handle_snmp_pdu(is_valid_pdu_type(Pdu#pdu.type),
Vsn, Pdu, PduMS, ACMData, Address, Extra, S),
@@ -808,11 +807,11 @@ handle_info(worker_available, S) ->
{noreply, S#state{worker_state = ready}};
handle_info({send_notif, Notification, SendOpts}, S) ->
- ?vlog("[handle_info] send trap request:"
+ ?vlog("[handle_info] send notif request:"
"~n Notification: ~p"
"~n SendOpts: ~p",
[Notification, SendOpts]),
- case (catch handle_send_trap(cast, S, Notification, SendOpts)) of
+ case (catch handle_send_trap(S, Notification, SendOpts)) of
{ok, NewS} ->
{noreply, NewS};
{'EXIT', R} ->
@@ -832,7 +831,7 @@ handle_info({send_trap, Trap, NotifyName, ContextName, Recv, Varbinds}, S) ->
"~n Varbinds: ~p",
[Trap, NotifyName, ContextName, Recv, Varbinds]),
ExtraInfo = ?DEFAULT_NOTIF_EXTRA_INFO,
- LocalEngineID = ?DEFAULT_LOCAL_ENGINE_ID,
+ LocalEngineID = local_engine_id(S),
case (catch handle_send_trap(S, Trap, NotifyName, ContextName,
Recv, Varbinds, LocalEngineID, ExtraInfo)) of
{ok, NewS} ->
@@ -979,6 +978,7 @@ handle_info({'EXIT', Pid, Reason}, S) ->
end,
{noreply, S}
end;
+
handle_info({'DOWN', Ref, process, Pid, {mibs_cache_reply, Reply}},
#state{mibs_cache_request = {Pid, Ref, From}} = S) ->
?vlog("reply from the mibs cache request handler (~p): ~n~p",
@@ -1014,11 +1014,11 @@ handle_call(restart_set_worker, _From, #state{set_worker = Pid} = S) ->
{reply, ok, S};
handle_call({send_notif, Notification, SendOpts}, _From, S) ->
- ?vlog("[handle_info] send trap request:"
+ ?vlog("[handle_call] send notif request:"
"~n Notification: ~p"
"~n SendOpts: ~p",
[Notification, SendOpts]),
- case (catch handle_send_trap(call, S, Notification, SendOpts)) of
+ case (catch handle_send_trap(S, Notification, SendOpts)) of
{ok, NewS} ->
{reply, ok, NewS};
{'EXIT', Reason} ->
@@ -1039,18 +1039,8 @@ handle_call({send_trap, Trap, NotifyName, ContextName, Recv, Varbinds},
"~n Recv: ~p"
"~n Varbinds: ~p",
[Trap, NotifyName, ContextName, Recv, Varbinds]),
- ExtraInfo = ?DEFAULT_NOTIF_EXTRA_INFO,
- LocalEngineID =
- case S#state.type of
- master_agent ->
- ?DEFAULT_LOCAL_ENGINE_ID;
- _ ->
- %% subagent -
- %% we don't need this now, eventually the trap send
- %% request will reach the master-agent and then it
- %% will look up the proper engine id.
- ignore
- end,
+ ExtraInfo = ?DEFAULT_NOTIF_EXTRA_INFO,
+ LocalEngineID = local_engine_id(S),
case (catch handle_send_trap(S, Trap, NotifyName, ContextName,
Recv, Varbinds, LocalEngineID, ExtraInfo)) of
{ok, NewS} ->
@@ -1130,7 +1120,7 @@ handle_call({subagent_get_next, MibView, Varbinds, PduData}, _From, S) ->
"~n PduData: ~p",
[MibView,Varbinds,PduData]),
put_pdu_data(PduData),
- {reply, do_get_next(MibView, Varbinds), S};
+ {reply, do_get_next(MibView, Varbinds, infinity), S};
handle_call({subagent_set, Arguments, PduData}, _From, S) ->
?vlog("[handle_call] subagent set:"
"~n Arguments: ~p"
@@ -1171,7 +1161,7 @@ handle_call({get_next, Vars, Context}, _From, S) ->
?vdebug("Varbinds: ~p",[Varbinds]),
MibView = snmpa_acm:get_root_mib_view(),
Reply =
- case do_get_next(MibView, Varbinds) of
+ case do_get_next(MibView, Varbinds, infinity) of
{noError, 0, NewVarbinds} ->
Vbs = lists:keysort(#varbind.org_index, NewVarbinds),
[{Oid,Val} || #varbind{oid = Oid, value = Val} <- Vbs];
@@ -1272,7 +1262,8 @@ handle_call(info, _From, S) ->
handle_call(get_net_if, _From, S) ->
{reply, get(net_if), S};
-handle_call({backup, BackupDir}, From, S) ->
+%% Only accept a backup request if there is none already in progress
+handle_call({backup, BackupDir}, From, #state{backup = undefined} = S) ->
?vlog("backup: ~p", [BackupDir]),
Pid = self(),
V = get(verbosity),
@@ -1289,7 +1280,11 @@ handle_call({backup, BackupDir}, From, S) ->
end),
?vtrace("backup server: ~p", [BackupServer]),
{noreply, S#state{backup = {BackupServer, From}}};
-
+
+handle_call({backup, _BackupDir}, From, #state{backup = Backup} = S) ->
+ ?vinfo("backup already in progress: ~p", [Backup]),
+ {reply, {error, backup_in_progress}, S};
+
handle_call(dump_mibs, _From, S) ->
Reply = snmpa_mib:dump(get(mibserver)),
{reply, Reply, S};
@@ -1338,27 +1333,27 @@ handle_call({me_of, Oid}, _From, S) ->
{reply, Reply, S};
handle_call(get_log_type, _From, S) ->
- ?vlog("get_log_type", []),
+ ?vlog("handle_call(get_log_type) -> entry with", []),
Reply = handle_get_log_type(S),
{reply, Reply, S};
handle_call({set_log_type, NewType}, _From, S) ->
- ?vlog("set_log_type -> "
+ ?vlog("handle_call(set_log_type) -> entry with"
"~n NewType: ~p", [NewType]),
Reply = handle_set_log_type(S, NewType),
{reply, Reply, S};
handle_call(get_request_limit, _From, S) ->
- ?vlog("get_request_limit", []),
+ ?vlog("handle_call(get_request_limit) -> entry with", []),
Reply = handle_get_request_limit(S),
{reply, Reply, S};
handle_call({set_request_limit, NewLimit}, _From, S) ->
- ?vlog("set_request_limit -> "
+ ?vlog("handle_call(set_request_limit) -> entry with"
"~n NewLimit: ~p", [NewLimit]),
Reply = handle_set_request_limit(S, NewLimit),
{reply, Reply, S};
-
+
handle_call(stop, _From, S) ->
{stop, normal, ok, S};
@@ -1367,15 +1362,15 @@ handle_call(Req, _From, S) ->
Reply = {error, {unknown, Req}},
{reply, Reply, S}.
-handle_cast({verbosity,Verbosity}, S) ->
- ?vlog("verbosity: ~p -> ~p",[get(verbosity),Verbosity]),
+handle_cast({verbosity, Verbosity}, S) ->
+ ?vlog("verbosity: ~p -> ~p",[get(verbosity), Verbosity]),
put(verbosity,snmp_verbosity:validate(Verbosity)),
case S#state.worker of
- Pid when is_pid(Pid) -> Pid ! {verbosity,Verbosity};
+ Pid when is_pid(Pid) -> Pid ! ?mk_verbosity_wreq(Verbosity);
_ -> ok
end,
case S#state.set_worker of
- Pid2 when is_pid(Pid2) -> Pid2 ! {verbosity,Verbosity};
+ Pid2 when is_pid(Pid2) -> Pid2 ! ?mk_verbosity_wreq(Verbosity);
_ -> ok
end,
{noreply, S};
@@ -1462,13 +1457,80 @@ handle_mibs_cache_request(MibServer, Req) ->
%% Downgrade
%%
-%% code_change({down, _Vsn}, S, downgrade_to_pre_4_13) ->
-%% {ok, S2};
+code_change({down, _Vsn}, S1, downgrade_to_pre_4_17_3) ->
+ #state{type = Type,
+ parent = Parent,
+ worker = Worker,
+ worker_state = WorkerState,
+ set_worker = SetWorker,
+ multi_threaded = MT,
+ ref = Ref,
+ vsns = Vsns,
+ nfilters = NF,
+ note_store = NoteStore,
+ mib_server = MS,
+ net_if = NetIf,
+ net_if_mod = NetIfMod,
+ backup = Backup,
+ disco = Disco,
+ mibs_cache_request = MCR} = S1,
+ S2 = {state,
+ type = Type,
+ parent = Parent,
+ worker = Worker,
+ worker_state = WorkerState,
+ set_worker = SetWorker,
+ multi_threaded = MT,
+ ref = Ref,
+ vsns = Vsns,
+ nfilters = NF,
+ note_store = NoteStore,
+ mib_server = MS,
+ net_if = NetIf,
+ net_if_mod = NetIfMod,
+ backup = Backup,
+ disco = Disco,
+ mibs_cache_request = MCR},
+ {ok, S2};
%% Upgrade
%%
-%% code_change(_Vsn, S, upgrade_from_pre_4_13) ->
-%% {ok, S2};
+code_change(_Vsn, S1, upgrade_from_pre_4_17_3) ->
+ {state,
+ type = Type,
+ parent = Parent,
+ worker = Worker,
+ worker_state = WorkerState,
+ set_worker = SetWorker,
+ multi_threaded = MT,
+ ref = Ref,
+ vsns = Vsns,
+ nfilters = NF,
+ note_store = NoteStore,
+ mib_server = MS,
+ net_if = NetIf,
+ net_if_mod = NetIfMod,
+ backup = Backup,
+ disco = Disco,
+ mibs_cache_request = MCR} = S1,
+ S2 = #state{type = Type,
+ parent = Parent,
+ worker = Worker,
+ worker_state = WorkerState,
+ set_worker = SetWorker,
+ multi_threaded = MT,
+ ref = Ref,
+ vsns = Vsns,
+ nfilters = NF,
+ note_store = NoteStore,
+ mib_server = MS,
+ net_if = NetIf,
+ net_if_mod = NetIfMod,
+ backup = Backup,
+ disco = Disco,
+ mibs_cache_request = MCR,
+ gb_max_vbs = ?DEFAULT_GB_MAX_VBS},
+ {ok, S2};
code_change(_Vsn, S, _Extra) ->
{ok, S}.
@@ -1508,7 +1570,7 @@ worker_start(Dict) ->
%% worker_stop(Pid, infinity).
worker_stop(Pid, Timeout) when is_pid(Pid) ->
- Pid ! terminate,
+ Pid ! ?mk_terminate_wreq(),
receive
{'EXIT', Pid, normal} ->
ok
@@ -1595,7 +1657,7 @@ handle_backup_res([{Who, Crap}|Results], Acc) ->
%% because we (for some reason) support the function
%% snmpa:current_community().
%%-----------------------------------------------------------------
-cheat({community, SecModel, Community, _TAddress}, Address, ContextName) ->
+cheat({community, _SecModel, Community, _TAddress}, Address, ContextName) ->
{Community, Address, ContextName};
cheat({community, _SecModel, Community, _TDomain, _TAddress},
Address, ContextName) ->
@@ -1626,7 +1688,7 @@ invalidate_ca_cache() ->
MasterAgent ! invalidate_ca_cache;
false ->
%% This is running on a sub-agent node,
- %% so sent skip it
+ %% so skip it
ok
end;
_ -> % Not on this node
@@ -1645,9 +1707,11 @@ invalidate_ca_cache() ->
%%
%%-----------------------------------------------------------------
-spawn_thread(Vsn, Pdu, PduMS, ACMData, Address, Extra) ->
+%% This functions spawns a temporary worker process,
+%% that evaluates one request and then silently exits.
+spawn_thread(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra) ->
Dict = get(),
- Args = [Vsn, Pdu, PduMS, ACMData, Address, Extra, Dict],
+ Args = [Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra, Dict],
proc_lib:spawn_link(?MODULE, handle_pdu, Args).
spawn_trap_thread(TrapRec, NotifyName, ContextName, Recv, Vbs,
@@ -1665,7 +1729,7 @@ do_send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs,
do_send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs,
LocalEngineID, ExtraInfo, Dict) ->
lists:foreach(fun({Key, Val}) -> put(Key, Val) end, Dict),
- put(sname,trap_sender_short_name(get(sname))),
+ put(sname, trap_sender_short_name(get(sname))),
?vlog("starting",[]),
snmpa_trap:send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs,
LocalEngineID, ExtraInfo, get(net_if)).
@@ -1677,58 +1741,122 @@ worker(Master, Dict) ->
worker_loop(Master).
worker_loop(Master) ->
- receive
- {Vsn, Pdu, PduMS, ACMData, Address, Extra} ->
- ?vtrace("worker_loop -> received request", []),
- handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra),
- Master ! worker_available;
-
- %% We don't trap EXITs!
- {TrapRec, NotifyName, ContextName, Recv, Vbs} ->
- ?vtrace("worker_loop -> send trap:"
- "~n ~p", [TrapRec]),
- snmpa_trap:send_trap(TrapRec, NotifyName,
- ContextName, Recv, Vbs,
- ?DEFAULT_NOTIF_EXTRA_INFO,
- get(net_if)),
- Master ! worker_available;
-
- %% We don't trap EXITs!
- {send_trap,
- TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID} ->
- ?vtrace("worker_loop -> send trap:"
- "~n ~p", [TrapRec]),
- snmpa_trap:send_trap(TrapRec, NotifyName,
- ContextName, Recv, Vbs,
- LocalEngineID, ?DEFAULT_NOTIF_EXTRA_INFO,
- get(net_if)),
- Master ! worker_available;
-
- {send_trap,
- TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID, ExtraInfo} ->
- ?vtrace("worker_loop -> send trap:"
- "~n ~p", [TrapRec]),
- snmpa_trap:send_trap(TrapRec, NotifyName,
- ContextName, Recv, Vbs,
- LocalEngineID, ExtraInfo,
- get(net_if)),
- Master ! worker_available;
-
- {verbosity, Verbosity} ->
- put(verbosity,snmp_verbosity:validate(Verbosity));
-
- terminate ->
- exit(normal);
-
- _X ->
- %% ignore
- ok
-
- after 30000 ->
- %% This is to assure that the worker process leaves a
- %% possibly old version of this module.
- ok
- end,
+ Res =
+ receive
+ #wrequest{cmd = handle_pdu,
+ info = Info} = Req ->
+ ?vtrace("worker_loop -> received handle_pdu request with"
+ "~n Info: ~p", [Info]),
+ Vsn = proplists:get_value(vsn, Info),
+ Pdu = proplists:get_value(pdu, Info),
+ PduMS = proplists:get_value(pdu_ms, Info),
+ ACMData = proplists:get_value(acm_data, Info),
+ Address = proplists:get_value(addr, Info),
+ GbMaxVBs = proplists:get_value(gb_max_vbs, Info),
+ Extra = proplists:get_value(extra, Info),
+ HandlePduRes =
+ try
+ begin
+ handle_pdu2(Vsn, Pdu, PduMS, ACMData, Address,
+ GbMaxVBs, Extra)
+ end
+ catch
+ T:E ->
+ exit({worker_crash, Req, T, E,
+ erlang:get_stacktrace()})
+ end,
+ Master ! worker_available,
+ HandlePduRes; % For debugging...
+
+
+ #wrequest{cmd = send_trap,
+ info = Info} = Req ->
+ ?vtrace("worker_loop -> received send_trap request with"
+ "~n Info: ~p", [Info]),
+ TrapRec = proplists:get_value(trap_rec, Info),
+ NotifyName = proplists:get_value(notify_name, Info),
+ ContextName = proplists:get_value(context_name, Info),
+ Recv = proplists:get_value(receiver, Info),
+ Vbs = proplists:get_value(varbinds, Info),
+ LocalEngineID = proplists:get_value(local_engine_id, Info),
+ Extra = proplists:get_value(extra, Info),
+ SendTrapRes =
+ try
+ begin
+ snmpa_trap:send_trap(TrapRec, NotifyName,
+ ContextName, Recv, Vbs,
+ LocalEngineID, Extra,
+ get(net_if))
+ end
+ catch
+ T:E ->
+ exit({worker_crash, Req, T, E,
+ erlang:get_stacktrace()})
+ end,
+ Master ! worker_available,
+ SendTrapRes; % For debugging...
+
+
+ #wrequest{cmd = verbosity,
+ info = Info} ->
+ Verbosity = proplists:get_value(verbosity, Info),
+ put(verbosity, snmp_verbosity:validate(Verbosity));
+
+
+ #wrequest{cmd = terminate} ->
+ ?vtrace("worker_loop -> received terminate request", []),
+ exit(normal);
+
+
+ %% *************************************************************
+ %%
+ %% Kept for backward compatibillity reasons
+ %%
+ %% *************************************************************
+
+ {Vsn, Pdu, PduMS, ACMData, Address, Extra} ->
+ ?vtrace("worker_loop -> received request", []),
+ handle_pdu2(Vsn, Pdu, PduMS, ACMData, Address,
+ ?DEFAULT_GB_MAX_VBS, Extra),
+ Master ! worker_available;
+
+ %% We don't trap exits!
+ {TrapRec, NotifyName, ContextName, Recv, Vbs} ->
+ ?vtrace("worker_loop -> send trap:"
+ "~n ~p", [TrapRec]),
+ snmpa_trap:send_trap(TrapRec, NotifyName,
+ ContextName, Recv, Vbs, get(net_if)),
+ Master ! worker_available;
+
+ %% We don't trap exits!
+ {send_trap,
+ TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID,
+ ExtraInfo} ->
+ ?vtrace("worker_loop -> send trap:"
+ "~n ~p", [TrapRec]),
+ snmpa_trap:send_trap(TrapRec, NotifyName,
+ ContextName, Recv, Vbs,
+ LocalEngineID, ExtraInfo,
+ get(net_if)),
+ Master ! worker_available;
+
+ {verbosity, Verbosity} ->
+ put(verbosity, snmp_verbosity:validate(Verbosity));
+
+ terminate ->
+ exit(normal);
+
+ _X ->
+ %% ignore
+ ignore_unknown
+
+ after 30000 ->
+ %% This is to assure that the worker process leaves a
+ %% possibly old version of this module.
+ ok
+ end,
+ ?vtrace("worker_loop -> wrap with"
+ "~n ~p", [Res]),
?MODULE:worker_loop(Master).
@@ -1736,42 +1864,52 @@ worker_loop(Master) ->
%%-----------------------------------------------------------------
handle_snmp_pdu(true, Vsn, Pdu, PduMS, ACMData, Address, Extra,
- #state{multi_threaded = false} = S) ->
+ #state{multi_threaded = false,
+ gb_max_vbs = GbMaxVBs} = S) ->
?vtrace("handle_snmp_pdu -> single-thread agent",[]),
- handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra),
+ handle_pdu2(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra),
S;
handle_snmp_pdu(true, Vsn, #pdu{type = 'set-request'} = Pdu, PduMS,
ACMData, Address, Extra,
#state{set_worker = Worker} = S) ->
?vtrace("handle_snmp_pdu -> multi-thread agent: "
"send set-request to main worker",[]),
- Worker ! {Vsn, Pdu, PduMS, ACMData, Address, Extra},
+ WRequest = ?mk_pdu_wreq(Vsn, Pdu, PduMS, ACMData, Address, infinity, Extra),
+ Worker ! WRequest,
S#state{worker_state = busy};
handle_snmp_pdu(true, Vsn, Pdu, PduMS,
ACMData, Address, Extra,
- #state{worker_state = busy} = S) ->
+ #state{worker_state = busy,
+ gb_max_vbs = GbMaxVBs} = S) ->
?vtrace("handle_snmp_pdu -> multi-thread agent: "
"main worker busy - create new worker",[]),
- spawn_thread(Vsn, Pdu, PduMS, ACMData, Address, Extra),
+ spawn_thread(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra),
S;
handle_snmp_pdu(true, Vsn, Pdu, PduMS, ACMData, Address, Extra,
- #state{worker = Worker} = S) ->
+ #state{worker = Worker,
+ gb_max_vbs = GbMaxVBs} = S) ->
?vtrace("handle_snmp_pdu -> multi-thread agent: "
"send to main worker",[]),
- Worker ! {Vsn, Pdu, PduMS, ACMData, Address, Extra},
+ WRequest = ?mk_pdu_wreq(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra),
+ Worker ! WRequest,
S#state{worker_state = busy};
handle_snmp_pdu(_, _Vsn, _Pdu, _PduMS, _ACMData, _Address, _Extra, S) ->
S.
%% Called via the spawn_thread function
+%% <BACKWARD-COMPAT>
handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra, Dict) ->
+ handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, ?DEFAULT_GB_MAX_VBS, Extra,
+ Dict).
+%% </BACKWARD-COMPAT>
+handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra, Dict) ->
lists:foreach(fun({Key, Val}) -> put(Key, Val) end, Dict),
put(sname, pdu_handler_short_name(get(sname))),
?vlog("new worker starting",[]),
- handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra).
+ handle_pdu2(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra).
-handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra) ->
+handle_pdu2(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra) ->
%% OTP-3324
AuthMod = get(auth_module),
case AuthMod:init_check_access(Pdu, ACMData) of
@@ -1780,7 +1918,8 @@ handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra) ->
"~n MibView: ~p"
"~n ContextName: ~p", [MibView, ContextName]),
AgentData = cheat(ACMData, Address, ContextName),
- do_handle_pdu(MibView, Vsn, Pdu, PduMS, ACMData, AgentData, Extra);
+ do_handle_pdu(MibView, Vsn, Pdu, PduMS, ACMData, AgentData,
+ GbMaxVBs, Extra);
{error, Reason} ->
?vlog("handle_pdu -> error:"
"~n Reason: ~p", [Reason]),
@@ -1794,16 +1933,19 @@ handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra) ->
end.
do_handle_pdu(MibView, Vsn, Pdu, PduMS,
- ACMData, {Community, Address, ContextName}, Extra) ->
+ ACMData, {Community, Address, ContextName},
+ GbMaxVBs, Extra) ->
put(net_if_data, Extra),
+
RePdu = process_msg(MibView, Vsn, Pdu, PduMS, Community,
- Address, ContextName),
+ Address, ContextName, GbMaxVBs),
?vtrace("do_handle_pdu -> processed:"
"~n RePdu: ~p", [RePdu]),
- get(net_if) ! {snmp_response, Vsn, RePdu,
- RePdu#pdu.type, ACMData, Address, Extra}.
+ NetIf = get(net_if),
+ NetIf ! {snmp_response, Vsn, RePdu,
+ RePdu#pdu.type, ACMData, Address, Extra}.
handle_acm_error(Vsn, Reason, Pdu, ACMData, Address, Extra) ->
@@ -1859,7 +2001,7 @@ handle_acm_error(Vsn, Reason, Pdu, ACMData, Address, Extra) ->
ok
end.
-get_opt(Key, Default, SendOpts) ->
+get_send_opt(Key, Default, SendOpts) ->
case lists:keysearch(Key, 1, SendOpts) of
{value, {Key, Value}} ->
Value;
@@ -1867,40 +2009,19 @@ get_opt(Key, Default, SendOpts) ->
Default
end.
-handle_send_trap(call, #state{type = master_agent} = S,
- Notification, SendOpts) ->
- SendOpts2 =
- case lists:keymember(local_engine_id, 1, SendOpts) of
- true ->
- SendOpts;
- false ->
- [{local_engine_id, ?DEFAULT_LOCAL_ENGINE_ID}|SendOpts]
- end,
- handle_send_trap(S, Notification, SendOpts2);
-handle_send_trap(call, S, Notification, SendOpts) ->
- SendOpts2 =
- case lists:keymember(local_engine_id, 1, SendOpts) of
- true ->
- SendOpts;
- false ->
- %% subagent -
- %% we don't need this now, eventually the trap send
- %% request will reach the master-agent and then it
- %% will look up the proper engine id.
- [{local_engine_id, ignore}|SendOpts]
- end,
- handle_send_trap(S, Notification, SendOpts2);
-handle_send_trap(_, S, Notification, SendOpts) ->
- handle_send_trap(S, Notification, SendOpts).
-
handle_send_trap(S, Notification, SendOpts) ->
- NotifyName = get_opt(name, "", SendOpts),
- ContextName = get_opt(context, "", SendOpts),
- Recv = get_opt(receiver, no_receiver, SendOpts),
- Varbinds = get_opt(varbinds, [], SendOpts),
- ExtraInfo = get_opt(extra, ?DEFAULT_NOTIF_EXTRA_INFO, SendOpts),
+ NotifyName = get_send_opt(name, "", SendOpts),
+ ContextName = get_send_opt(context, "", SendOpts),
+ Recv = get_send_opt(receiver, no_receiver, SendOpts),
+ Varbinds = get_send_opt(varbinds, [], SendOpts),
+ ExtraInfo = get_send_opt(extra, ?DEFAULT_NOTIF_EXTRA_INFO, SendOpts),
LocalEngineID =
- get_opt(local_engine_id, ?DEFAULT_LOCAL_ENGINE_ID, SendOpts),
+ case lists:keysearch(local_engine_id, 1, SendOpts) of
+ {value, {local_engine_id, Value}} ->
+ Value;
+ false ->
+ local_engine_id(S)
+ end,
handle_send_trap(S, Notification, NotifyName, ContextName, Recv, Varbinds,
LocalEngineID, ExtraInfo).
@@ -1908,11 +2029,11 @@ handle_send_trap(#state{type = Type} = S,
Notification, NotifyName, ContextName, Recv, Varbinds,
LocalEngineID, ExtraInfo) ->
?vtrace("handle_send_trap -> entry with"
- "~n Agent type: ~p"
- "~n TrapName: ~p"
- "~n NotifyName: ~p"
- "~n ContextName: ~p"
- "~n LocalEngineID: ~p",
+ "~n Agent type: ~p"
+ "~n TrapName: ~p"
+ "~n NotifyName: ~p"
+ "~n ContextName: ~p"
+ "~n LocalEngineID: ~p",
[Type, Notification, NotifyName, ContextName, LocalEngineID]),
case snmpa_trap:construct_trap(Notification, Varbinds) of
{ok, TrapRecord, VarList} ->
@@ -2025,9 +2146,9 @@ do_handle_send_trap(S, TrapRec, NotifyName, ContextName, Recv, Varbinds,
master_agent ->
%% Send to main worker
?vtrace("do_handle_send_trap -> send to main worker",[]),
- S#state.worker ! {send_trap,
- TrapRec, NotifyName, ContextName, Recv, Vbs,
- LocalEngineID, ExtraInfo},
+ S#state.worker ! ?mk_send_trap_wreq(TrapRec, NotifyName,
+ ContextName, Recv, Vbs,
+ LocalEngineID, ExtraInfo),
{ok, S#state{worker_state = busy}}
end.
@@ -2367,17 +2488,18 @@ handle_mib_of(MibServer, Oid) ->
%% Func: process_msg/7
%% Returns: RePdu
%%-----------------------------------------------------------------
-process_msg(MibView, Vsn, Pdu, PduMS, Community, {Ip, Udp}, ContextName) ->
+process_msg(MibView, Vsn, Pdu, PduMS, Community, {Ip, Udp}, ContextName,
+ GbMaxVBs) ->
#pdu{request_id = ReqId} = Pdu,
put(snmp_address, {tuple_to_list(Ip), Udp}),
put(snmp_request_id, ReqId),
put(snmp_community, Community),
put(snmp_context, ContextName),
?vtrace("process ~p",[Pdu#pdu.type]),
- process_pdu(Pdu, PduMS, Vsn, MibView).
+ process_pdu(Pdu, PduMS, Vsn, MibView, GbMaxVBs).
process_pdu(#pdu{type='get-request', request_id = ReqId, varbinds=Vbs},
- _PduMS, Vsn, MibView) ->
+ _PduMS, Vsn, MibView, _GbMaxVBs) ->
?vtrace("get ~p",[ReqId]),
Res = get_err(do_get(MibView, Vbs, false)),
?vtrace("get result: "
@@ -2398,12 +2520,12 @@ process_pdu(#pdu{type='get-request', request_id = ReqId, varbinds=Vbs},
make_response_pdu(ReqId, ErrStatus, ErrIndex, Vbs, ResponseVarbinds);
process_pdu(#pdu{type = 'get-next-request', request_id = ReqId, varbinds = Vbs},
- _PduMS, Vsn, MibView) ->
+ _PduMS, Vsn, MibView, _GbMaxVBs) ->
?vtrace("process get-next-request -> entry with"
"~n ReqId: ~p"
"~n Vbs: ~p"
"~n MibView: ~p",[ReqId, Vbs, MibView]),
- Res = get_err(do_get_next(MibView, Vbs)),
+ Res = get_err(do_get_next(MibView, Vbs, infinity)),
?vtrace("get-next result: "
"~n ~p",[Res]),
{ErrStatus, ErrIndex, ResVarbinds} =
@@ -2420,11 +2542,15 @@ process_pdu(#pdu{type = 'get-next-request', request_id = ReqId, varbinds = Vbs},
"~n ~p",[ResponseVarbinds]),
make_response_pdu(ReqId, ErrStatus, ErrIndex, Vbs, ResponseVarbinds);
-process_pdu(#pdu{type = 'get-bulk-request',request_id = ReqId,varbinds = Vbs,
- error_status = NonRepeaters, error_index = MaxRepetitions},
- PduMS, _Vsn, MibView)->
+process_pdu(#pdu{type = 'get-bulk-request',
+ request_id = ReqId,
+ varbinds = Vbs,
+ error_status = NonRepeaters,
+ error_index = MaxRepetitions},
+ PduMS, _Vsn, MibView, GbMaxVBs) ->
{ErrStatus, ErrIndex, ResponseVarbinds} =
- get_err(do_get_bulk(MibView,NonRepeaters,MaxRepetitions,PduMS,Vbs)),
+ get_err(do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Vbs,
+ GbMaxVBs)),
?vtrace("get-bulk final result: "
"~n Error status: ~p"
"~n Error index: ~p"
@@ -2433,7 +2559,7 @@ process_pdu(#pdu{type = 'get-bulk-request',request_id = ReqId,varbinds = Vbs,
make_response_pdu(ReqId, ErrStatus, ErrIndex, Vbs, ResponseVarbinds);
process_pdu(#pdu{type = 'set-request', request_id = ReqId, varbinds = Vbs},
- _PduMS, Vsn, MibView)->
+ _PduMS, Vsn, MibView, _GbMaxVbs)->
Res = do_set(MibView, Vbs),
?vtrace("set result: "
"~n ~p",[Res]),
@@ -2490,7 +2616,8 @@ validate_next_v1_2([Vb | _Vbs], _MibView, _Res)
{noSuchName, Vb#varbind.org_index};
validate_next_v1_2([Vb | Vbs], MibView, Res)
when Vb#varbind.variabletype =:= 'Counter64' ->
- case validate_next_v1(do_get_next(MibView, [mk_next_oid(Vb)]), MibView) of
+ case validate_next_v1(
+ do_get_next(MibView, [mk_next_oid(Vb)], infinity), MibView) of
{noError, 0, [NVb]} ->
validate_next_v1_2(Vbs, MibView, [NVb | Res]);
{Error, Index, _OrgVb} ->
@@ -2963,59 +3090,97 @@ validate_tab_res(_TooMany, [], Mfa, _Res, I) ->
%% that this really matters, since many nexts across the same
%% subagent must be considered to be very rare.
%%-----------------------------------------------------------------
-do_get_next(MibView, UnsortedVarbinds) ->
- SortedVarbinds = oid_sort_varbindlist(UnsortedVarbinds),
- next_loop_varbinds([], SortedVarbinds, MibView, [], []).
-oid_sort_varbindlist(Vbs) ->
+%% It may be a bit agressive to check this already,
+%% but since it is a security measure, it makes sense.
+do_get_next(_MibView, UnsortedVarbinds, GbMaxVBs)
+ when (is_integer(GbMaxVBs) andalso (length(UnsortedVarbinds) > GbMaxVBs)) ->
+ {tooBig, 0, []}; % What is the correct index in this case?
+do_get_next(MibView, UnsortedVBs, GbMaxVBs) ->
+ ?vt("do_get_next -> entry when"
+ "~n MibView: ~p"
+ "~n UnsortedVBs: ~p", [MibView, UnsortedVBs]),
+ SortedVBs = oid_sort_vbs(UnsortedVBs),
+ ?vt("do_get_next -> "
+ "~n SortedVBs: ~p", [SortedVBs]),
+ next_loop_varbinds([], SortedVBs, MibView, [], [], GbMaxVBs).
+
+oid_sort_vbs(Vbs) ->
lists:keysort(#varbind.oid, Vbs).
+next_loop_varbinds(_, Vbs, _MibView, Res, _LAVb, GbMaxVBs)
+ when (is_integer(GbMaxVBs) andalso
+ ((length(Vbs) + length(Res)) > GbMaxVBs)) ->
+ {tooBig, 0, []}; % What is the correct index in this case?
+
%% LAVb is Last Accessible Vb
-next_loop_varbinds([], [Vb | Vbs], MibView, Res, LAVb) ->
+next_loop_varbinds([], [Vb | Vbs], MibView, Res, LAVb, GbMaxVBs) ->
?vt("next_loop_varbinds -> entry when"
"~n Vb: ~p"
"~n MibView: ~p", [Vb, MibView]),
case varbind_next(Vb, MibView) of
endOfMibView ->
+ ?vt("next_loop_varbind -> endOfMibView", []),
RVb = if LAVb =:= [] -> Vb;
true -> LAVb
end,
NewVb = RVb#varbind{variabletype = 'NULL', value = endOfMibView},
- next_loop_varbinds([], Vbs, MibView, [NewVb | Res], []);
+ next_loop_varbinds([], Vbs, MibView, [NewVb | Res], [], GbMaxVBs);
+
{variable, ME, VarOid} when ((ME#me.access =/= 'not-accessible') andalso
(ME#me.access =/= 'write-only') andalso
(ME#me.access =/= 'accessible-for-notify')) ->
+ ?vt("next_loop_varbind -> variable: "
+ "~n ME: ~p"
+ "~n VarOid: ~p", [ME, VarOid]),
case try_get_instance(Vb, ME) of
{value, noValue, _NoSuchSomething} ->
+ ?vt("next_loop_varbind -> noValue", []),
%% Try next one
- NewVb = Vb#varbind{oid = VarOid, value = 'NULL'},
- next_loop_varbinds([], [NewVb | Vbs], MibView, Res, []);
+ NewVb = Vb#varbind{oid = VarOid,
+ value = 'NULL'},
+ next_loop_varbinds([], [NewVb | Vbs], MibView, Res, [],
+ GbMaxVBs);
{value, Type, Value} ->
- NewVb = Vb#varbind{oid = VarOid, variabletype = Type,
- value = Value},
- next_loop_varbinds([], Vbs, MibView, [NewVb | Res], []);
+ ?vt("next_loop_varbind -> value"
+ "~n Type: ~p"
+ "~n Value: ~p", [Type, Value]),
+ NewVb = Vb#varbind{oid = VarOid,
+ variabletype = Type,
+ value = Value},
+ next_loop_varbinds([], Vbs, MibView, [NewVb | Res], [],
+ GbMaxVBs);
{error, ErrorStatus} ->
?vdebug("next loop varbinds:"
"~n ErrorStatus: ~p",[ErrorStatus]),
{ErrorStatus, Vb#varbind.org_index, []}
end;
{variable, _ME, VarOid} ->
+ ?vt("next_loop_varbind -> variable: "
+ "~n VarOid: ~p", [VarOid]),
RVb = if LAVb =:= [] -> Vb;
true -> LAVb
end,
NewVb = Vb#varbind{oid = VarOid, value = 'NULL'},
- next_loop_varbinds([], [NewVb | Vbs], MibView, Res, RVb);
+ next_loop_varbinds([], [NewVb | Vbs], MibView, Res, RVb, GbMaxVBs);
{table, TableOid, TableRestOid, ME} ->
+ ?vt("next_loop_varbind -> table: "
+ "~n TableOid: ~p"
+ "~n TableRestOid: ~p"
+ "~n ME: ~p", [TableOid, TableRestOid, ME]),
next_loop_varbinds({table, TableOid, ME,
[{tab_oid(TableRestOid), Vb}]},
- Vbs, MibView, Res, []);
+ Vbs, MibView, Res, [], GbMaxVBs);
{subagent, SubAgentPid, SAOid} ->
+ ?vt("next_loop_varbind -> subagent: "
+ "~n SubAgentPid: ~p"
+ "~n SAOid: ~p", [SubAgentPid, SAOid]),
NewVb = Vb#varbind{variabletype = 'NULL', value = 'NULL'},
next_loop_varbinds({subagent, SubAgentPid, SAOid, [NewVb]},
- Vbs, MibView, Res, [])
+ Vbs, MibView, Res, [], GbMaxVBs)
end;
next_loop_varbinds({table, TableOid, ME, TabOids},
- [Vb | Vbs], MibView, Res, _LAVb) ->
+ [Vb | Vbs], MibView, Res, _LAVb, GbMaxVBs) ->
?vt("next_loop_varbinds(table) -> entry with"
"~n TableOid: ~p"
"~n Vb: ~p", [TableOid, Vb]),
@@ -3023,13 +3188,14 @@ next_loop_varbinds({table, TableOid, ME, TabOids},
{table, TableOid, TableRestOid, _ME} ->
next_loop_varbinds({table, TableOid, ME,
[{tab_oid(TableRestOid), Vb} | TabOids]},
- Vbs, MibView, Res, []);
+ Vbs, MibView, Res, [], GbMaxVBs);
_ ->
case get_next_table(ME, TableOid, TabOids, MibView) of
{ok, TabRes, TabEndOfTabVbs} ->
NewVbs = lists:append(TabEndOfTabVbs, [Vb | Vbs]),
NewRes = lists:append(TabRes, Res),
- next_loop_varbinds([], NewVbs, MibView, NewRes, []);
+ next_loop_varbinds([], NewVbs, MibView, NewRes, [],
+ GbMaxVBs);
{ErrorStatus, OrgIndex} ->
?vdebug("next loop varbinds: next varbind"
"~n ErrorStatus: ~p"
@@ -3039,7 +3205,7 @@ next_loop_varbinds({table, TableOid, ME, TabOids},
end
end;
next_loop_varbinds({table, TableOid, ME, TabOids},
- [], MibView, Res, _LAVb) ->
+ [], MibView, Res, _LAVb, GbMaxVBs) ->
?vt("next_loop_varbinds(table) -> entry with"
"~n TableOid: ~p", [TableOid]),
case get_next_table(ME, TableOid, TabOids, MibView) of
@@ -3048,7 +3214,8 @@ next_loop_varbinds({table, TableOid, ME, TabOids},
"~n TabRes: ~p"
"~n TabEndOfTabVbs: ~p", [TabRes, TabEndOfTabVbs]),
NewRes = lists:append(TabRes, Res),
- next_loop_varbinds([], TabEndOfTabVbs, MibView, NewRes, []);
+ next_loop_varbinds([], TabEndOfTabVbs, MibView, NewRes, [],
+ GbMaxVBs);
{ErrorStatus, OrgIndex} ->
?vdebug("next loop varbinds: next table"
"~n ErrorStatus: ~p"
@@ -3057,7 +3224,7 @@ next_loop_varbinds({table, TableOid, ME, TabOids},
{ErrorStatus, OrgIndex, []}
end;
next_loop_varbinds({subagent, SAPid, SAOid, SAVbs},
- [Vb | Vbs], MibView, Res, _LAVb) ->
+ [Vb | Vbs], MibView, Res, _LAVb, GbMaxVBs) ->
?vt("next_loop_varbinds(subagent) -> entry with"
"~n SAPid: ~p"
"~n SAOid: ~p"
@@ -3066,13 +3233,14 @@ next_loop_varbinds({subagent, SAPid, SAOid, SAVbs},
{subagent, _SubAgentPid, SAOid} ->
next_loop_varbinds({subagent, SAPid, SAOid,
[Vb | SAVbs]},
- Vbs, MibView, Res, []);
+ Vbs, MibView, Res, [], GbMaxVBs);
_ ->
case get_next_sa(SAPid, SAOid, SAVbs, MibView) of
{ok, SARes, SAEndOfMibViewVbs} ->
NewVbs = lists:append(SAEndOfMibViewVbs, [Vb | Vbs]),
NewRes = lists:append(SARes, Res),
- next_loop_varbinds([], NewVbs, MibView, NewRes, []);
+ next_loop_varbinds([], NewVbs, MibView, NewRes, [],
+ GbMaxVBs);
{noSuchName, OrgIndex} ->
%% v1 reply, treat this Vb as endOfMibView, and try again
%% for the others.
@@ -3085,12 +3253,14 @@ next_loop_varbinds({subagent, SAPid, SAOid, SAVbs},
case lists:delete(EVb, SAVbs) of
[] ->
next_loop_varbinds([], [EndOfVb, Vb | Vbs],
- MibView, Res, []);
+ MibView, Res, [],
+ GbMaxVBs);
TryAgainVbs ->
next_loop_varbinds({subagent, SAPid, SAOid,
TryAgainVbs},
[EndOfVb, Vb | Vbs],
- MibView, Res, [])
+ MibView, Res, [],
+ GbMaxVBs)
end;
false ->
%% bad index from subagent
@@ -3106,14 +3276,15 @@ next_loop_varbinds({subagent, SAPid, SAOid, SAVbs},
end
end;
next_loop_varbinds({subagent, SAPid, SAOid, SAVbs},
- [], MibView, Res, _LAVb) ->
+ [], MibView, Res, _LAVb, GbMaxVBs) ->
?vt("next_loop_varbinds(subagent) -> entry with"
"~n SAPid: ~p"
"~n SAOid: ~p", [SAPid, SAOid]),
case get_next_sa(SAPid, SAOid, SAVbs, MibView) of
{ok, SARes, SAEndOfMibViewVbs} ->
NewRes = lists:append(SARes, Res),
- next_loop_varbinds([], SAEndOfMibViewVbs, MibView, NewRes, []);
+ next_loop_varbinds([], SAEndOfMibViewVbs, MibView, NewRes, [],
+ GbMaxVBs);
{noSuchName, OrgIndex} ->
%% v1 reply, treat this Vb as endOfMibView, and try again for
%% the others.
@@ -3124,11 +3295,13 @@ next_loop_varbinds({subagent, SAPid, SAOid, SAVbs},
value = {endOfMibView, NextOid}},
case lists:delete(EVb, SAVbs) of
[] ->
- next_loop_varbinds([], [EndOfVb], MibView, Res, []);
+ next_loop_varbinds([], [EndOfVb], MibView, Res, [],
+ GbMaxVBs);
TryAgainVbs ->
next_loop_varbinds({subagent, SAPid, SAOid,
TryAgainVbs},
- [EndOfVb], MibView, Res, [])
+ [EndOfVb], MibView, Res, [],
+ GbMaxVBs)
end;
false ->
%% bad index from subagent
@@ -3141,12 +3314,15 @@ next_loop_varbinds({subagent, SAPid, SAOid, SAVbs},
[ErrorStatus,OrgIndex]),
{ErrorStatus, OrgIndex, []}
end;
-next_loop_varbinds([], [], _MibView, Res, _LAVb) ->
+next_loop_varbinds([], [], _MibView, Res, _LAVb, _GbMaxVBs) ->
?vt("next_loop_varbinds -> entry when done", []),
{noError, 0, Res}.
try_get_instance(_Vb, #me{mfa = {M, F, A}, asn1_type = ASN1Type}) ->
- ?vtrace("try get instance from <~p,~p,~p>",[M,F,A]),
+ ?vtrace("try_get_instance -> entry with"
+ "~n M: ~p"
+ "~n F: ~p"
+ "~n A: ~p", [M,F,A]),
Result = (catch dbg_apply(M, F, [get | A])),
% mib shall return {value, <a-nice-value-within-range>} |
% {noValue, noSuchName} (v1) |
@@ -3157,6 +3333,7 @@ try_get_instance(_Vb, #me{mfa = {M, F, A}, asn1_type = ASN1Type}) ->
tab_oid([]) -> [0];
tab_oid(X) -> X.
+
%%-----------------------------------------------------------------
%% Perform a next, using the varbinds Oid if value is simple
%% value. If value is {endOf<something>, NextOid}, use NextOid.
@@ -3403,22 +3580,30 @@ next_oid(Oid) ->
%%%-----------------------------------------------------------------
%%% 5. GET-BULK REQUEST
+%%%
+%%% In order to prevent excesses in reply sizes there are two
+%%% preventive methods in place. One is to check that the encode
+%%% size does not exceed Max PDU size (this is mentioned in the
+%%% standard). The other is a simple VBs limit. That is, the
+%%% resulting response cannot contain more then this number of VBs.
%%%-----------------------------------------------------------------
-do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds) ->
- ?vtrace("do get bulk: start with"
+
+do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds, GbMaxVBs) ->
+ ?vtrace("do_get_bulk -> entry with"
"~n MibView: ~p"
"~n NonRepeaters: ~p"
"~n MaxRepetitions: ~p"
"~n PduMS: ~p"
- "~n Varbinds: ~p",
- [MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds]),
+ "~n Varbinds: ~p"
+ "~n GbMaxVBs: ~p",
+ [MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds, GbMaxVBs]),
{NonRepVbs, RestVbs} = split_vbs(NonRepeaters, Varbinds, []),
- ?vt("do get bulk -> split: "
+ ?vt("do_get_bulk -> split: "
"~n NonRepVbs: ~p"
"~n RestVbs: ~p", [NonRepVbs, RestVbs]),
- case do_get_next(MibView, NonRepVbs) of
- {noError, 0, UResNonRepVbs} ->
- ?vt("do get bulk -> next: "
+ case do_get_next(MibView, NonRepVbs, GbMaxVBs) of
+ {noError, 0, UResNonRepVbs} ->
+ ?vt("do_get_bulk -> next noError: "
"~n UResNonRepVbs: ~p", [UResNonRepVbs]),
ResNonRepVbs = lists:keysort(#varbind.org_index, UResNonRepVbs),
%% Decode the first varbinds, produce a reversed list of
@@ -3428,11 +3613,12 @@ do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds) ->
user_err("failed encoding varbind ~w:~n~p", [Idx, Reason]),
{genErr, Idx, []};
{SizeLeft, Res} when is_integer(SizeLeft) and is_list(Res) ->
- ?vtrace("do get bulk -> encoded: "
+ ?vtrace("do_get_bulk -> encoded: "
"~n SizeLeft: ~p"
"~n Res: ~w", [SizeLeft, Res]),
case (catch do_get_rep(SizeLeft, MibView, MaxRepetitions,
- RestVbs, Res)) of
+ RestVbs, Res,
+ length(UResNonRepVbs), GbMaxVBs)) of
{error, Idx, Reason} ->
user_err("failed encoding varbind ~w:~n~p",
[Idx, Reason]),
@@ -3441,6 +3627,10 @@ do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds) ->
?vtrace("do get bulk -> Res: "
"~n ~w", [Res]),
{noError, 0, conv_res(Res)};
+ {noError, 0, Data} = OK ->
+ ?vtrace("do get bulk -> OK: "
+ "~n length(Data): ~w", [length(Data)]),
+ OK;
Else ->
?vtrace("do get bulk -> Else: "
"~n ~w", [Else]),
@@ -3449,6 +3639,7 @@ do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds) ->
Res when is_list(Res) ->
{noError, 0, conv_res(Res)}
end;
+
{ErrorStatus, Index, _} ->
?vdebug("do get bulk: "
"~n ErrorStatus: ~p"
@@ -3498,11 +3689,12 @@ enc_vbs(SizeLeft, Vbs) ->
end,
lists:foldl(Fun, {SizeLeft, []}, Vbs).
-do_get_rep(Sz, MibView, MaxRepetitions, Varbinds, Res)
+do_get_rep(Sz, MibView, MaxRepetitions, Varbinds, Res, GbNumVBs, GbMaxVBs)
when MaxRepetitions >= 0 ->
- do_get_rep(Sz, MibView, 0, MaxRepetitions, Varbinds, Res);
-do_get_rep(Sz, MibView, _MaxRepetitions, Varbinds, Res) ->
- do_get_rep(Sz, MibView, 0, 0, Varbinds, Res).
+ do_get_rep(Sz, MibView, 0, MaxRepetitions, Varbinds, Res,
+ GbNumVBs, GbMaxVBs);
+do_get_rep(Sz, MibView, _MaxRepetitions, Varbinds, Res, GbNumVBs, GbMaxVBs) ->
+ do_get_rep(Sz, MibView, 0, 0, Varbinds, Res, GbNumVBs, GbMaxVBs).
conv_res(ResVarbinds) ->
conv_res(ResVarbinds, []).
@@ -3511,22 +3703,30 @@ conv_res([VbListOfBytes | T], Bytes) ->
conv_res([], Bytes) ->
Bytes.
-do_get_rep(_Sz, _MibView, Max, Max, _, Res) ->
+%% The only other value, then a positive integer, is infinity.
+do_get_rep(_Sz, _MibView, Count, Max, _, _Res, GbNumVBs, GbMaxVBs)
+ when (is_integer(GbMaxVBs) andalso (GbNumVBs > GbMaxVBs)) ->
+ ?vinfo("Max Get-BULK VBs limit (~w) exceeded (~w) when:"
+ "~n Count: ~p"
+ "~n Max: ~p", [GbMaxVBs, GbNumVBs, Count, Max]),
+ {tooBig, 0, []};
+do_get_rep(_Sz, _MibView, Max, Max, _, Res, _GbNumVBs, _GbMaxVBs) ->
?vt("do_get_rep -> done when: "
"~n Res: ~p", [Res]),
{noError, 0, conv_res(Res)};
-do_get_rep(Sz, MibView, Count, Max, Varbinds, Res) ->
+do_get_rep(Sz, MibView, Count, Max, Varbinds, Res, GbNumVBs, GbMaxVBs) ->
?vt("do_get_rep -> entry when: "
"~n Sz: ~p"
"~n Count: ~p"
"~n Res: ~w", [Sz, Count, Res]),
- case try_get_bulk(Sz, MibView, Varbinds) of
+ case try_get_bulk(Sz, MibView, Varbinds, GbMaxVBs) of
{noError, NextVarbinds, SizeLeft, Res2} ->
?vt("do_get_rep -> noError: "
"~n SizeLeft: ~p"
"~n Res2: ~p", [SizeLeft, Res2]),
do_get_rep(SizeLeft, MibView, Count+1, Max, NextVarbinds,
- Res2 ++ Res);
+ Res2 ++ Res,
+ GbNumVBs + length(Varbinds), GbMaxVBs);
{endOfMibView, _NextVarbinds, _SizeLeft, Res2} ->
?vt("do_get_rep -> endOfMibView: "
"~n Res2: ~p", [Res2]),
@@ -3538,22 +3738,29 @@ do_get_rep(Sz, MibView, Count, Max, Varbinds, Res) ->
{ErrorStatus, Index, []}
end.
-try_get_bulk(Sz, MibView, Varbinds) ->
+org_index_sort_vbs(Vbs) ->
+ lists:keysort(#varbind.org_index, Vbs).
+
+try_get_bulk(Sz, MibView, Varbinds, GbMaxVBs) ->
?vt("try_get_bulk -> entry with"
- "~n Sz: ~w", [Sz]),
- case do_get_next(MibView, Varbinds) of
+ "~n Sz: ~w"
+ "~n MibView: ~w"
+ "~n Varbinds: ~w", [Sz, MibView, Varbinds]),
+ case do_get_next(MibView, Varbinds, GbMaxVBs) of
{noError, 0, UNextVarbinds} ->
- ?vt("try_get_bulk -> noError", []),
- NextVarbinds = lists:keysort(#varbind.org_index, UNextVarbinds),
+ ?vt("try_get_bulk -> noError: "
+ "~n UNextVarbinds: ~p", [UNextVarbinds]),
+ NextVarbinds = org_index_sort_vbs(UNextVarbinds),
case (catch enc_vbs(Sz, NextVarbinds)) of
{error, Idx, Reason} ->
user_err("failed encoding varbind ~w:~n~p", [Idx, Reason]),
- ?vtrace("try_get_bulk -> error: "
+ ?vtrace("try_get_bulk -> encode error: "
"~n Idx: ~p"
"~n Reason: ~p", [Idx, Reason]),
{genErr, Idx};
- {SizeLeft, Res} when is_integer(SizeLeft) andalso is_list(Res) ->
- ?vt("try get bulk -> "
+ {SizeLeft, Res} when is_integer(SizeLeft) andalso
+ is_list(Res) ->
+ ?vt("try get bulk -> encode ok: "
"~n SizeLeft: ~w"
"~n Res: ~w", [SizeLeft, Res]),
{check_end_of_mibview(NextVarbinds),
@@ -3564,9 +3771,9 @@ try_get_bulk(Sz, MibView, Varbinds) ->
{endOfMibView, [], 0, Res}
end;
{ErrorStatus, Index, _} ->
- ?vt("try get bulk: "
+ ?vt("try_get_bulk -> error: "
"~n ErrorStatus: ~p"
- "~n Index: ~p",[ErrorStatus, Index]),
+ "~n Index: ~p", [ErrorStatus, Index]),
{ErrorStatus, Index}
end.
@@ -3707,9 +3914,8 @@ get_err({ErrC, ErrI, Vbs}) ->
{get_err_i(ErrC), ErrI, Vbs}.
get_err_i(noError) -> noError;
-get_err_i(S) ->
- ?vtrace("convert '~p' to 'genErr'",[S]),
- genErr.
+get_err_i(tooBig) -> tooBig; % OTP-9700
+get_err_i(ES) -> ?vtrace("convert ErrorStatus '~p' to 'genErr'", [ES]), genErr.
v2err_to_v1err(noError) -> noError;
v2err_to_v1err(noAccess) -> noSuchName;
@@ -3935,6 +4141,7 @@ mapfoldl(F, Eas, Accu0, [Hd|Tail]) ->
{Accu2,[R|Rs]};
mapfoldl(_F, _Eas, Accu, []) -> {Accu,[]}.
+
%%-----------------------------------------------------------------
%% Runtime debugging of the agent.
%%-----------------------------------------------------------------
@@ -4001,6 +4208,18 @@ subagents_verbosity(_,_V) ->
%% ---------------------------------------------------------------------
+local_engine_id(#state{type = master_agent}) ->
+ ?DEFAULT_LOCAL_ENGINE_ID;
+local_engine_id(_) ->
+ %% subagent -
+ %% we don't need this now, eventually the trap send
+ %% request will reach the master-agent and then it
+ %% will look up the proper engine id.
+ ignore.
+
+
+%% ---------------------------------------------------------------------
+
handle_get_log_type(#state{net_if_mod = Mod})
when Mod =/= undefined ->
case (catch Mod:get_log_type(get(net_if))) of
@@ -4047,7 +4266,7 @@ handle_set_request_limit(_, _) ->
{error, not_supported}.
-agent_info(#state{worker = W, set_worker = SW}) ->
+agent_info(#state{worker = W, set_worker = SW}) ->
case (catch get_agent_info(W, SW)) of
Info when is_list(Info) ->
Info;
@@ -4206,6 +4425,9 @@ get_multi_threaded(Opts) ->
get_versions(Opts) ->
get_option(versions, Opts, [v1,v2,v3]).
+get_gb_max_vbs(Opts) ->
+ get_option(gb_max_vbs, Opts, infinity).
+
get_note_store_opt(Opts) ->
get_option(note_store, Opts, []).
diff --git a/lib/snmp/src/agent/snmpa_conf.erl b/lib/snmp/src/agent/snmpa_conf.erl
index 4b88eb69f7..c17a6abbd7 100644
--- a/lib/snmp/src/agent/snmpa_conf.erl
+++ b/lib/snmp/src/agent/snmpa_conf.erl
@@ -424,7 +424,8 @@ target_addr_entry(Name,
EngineId,
TMask) ->
target_addr_entry(Name, Ip, 162, TagList,
- ParamsName, EngineId, TMask, 2048).
+ ParamsName, EngineId,
+ TMask, 2048).
target_addr_entry(Name,
Ip,
@@ -435,7 +436,8 @@ target_addr_entry(Name,
TMask,
MaxMessageSize) ->
target_addr_entry(Name, Ip, Udp, 1500, 3, TagList,
- ParamsName, EngineId, TMask, MaxMessageSize).
+ ParamsName, EngineId,
+ TMask, MaxMessageSize).
target_addr_entry(Name,
Ip,
@@ -448,7 +450,8 @@ target_addr_entry(Name,
TMask,
MaxMessageSize) ->
target_addr_entry(Name, snmp_target_mib:default_domain(), Ip, Udp,
- Timeout, RetryCount, TagList, ParamsName,
+ Timeout, RetryCount, TagList,
+ ParamsName, EngineId,
TMask, MaxMessageSize).
target_addr_entry(Name,
diff --git a/lib/snmp/src/agent/snmpa_internal.hrl b/lib/snmp/src/agent/snmpa_internal.hrl
index a490a78f84..c435b519d9 100644
--- a/lib/snmp/src/agent/snmpa_internal.hrl
+++ b/lib/snmp/src/agent/snmpa_internal.hrl
@@ -22,9 +22,19 @@
-include_lib("snmp/src/app/snmp_internal.hrl").
--define(DEFAULT_LOCAL_ENGINE_ID, snmp_framework_mib:get_engine_id()).
+%% The DEFAULT_LOCAL_ENGINE_ID macro can only be used by the master_agent!!
+-define(DEFAULT_LOCAL_ENGINE_ID, snmp_framework_mib:get_engine_id()).
-define(DEFAULT_NOTIF_EXTRA_INFO, {snmpa_default_notification_extra_info}).
+%% -- Max number of VBs in a Get-BULK response --
+%% (( The default value, 1000, is *way* more ))
+%% (( then there is room for in a normal pdu ))
+%% (( (unless the max pdu size has been ))
+%% (( cranked way up), so this value should ))
+%% (( suffice as "infinity" without actually ))
+%% (( causing memory issues for the VM ... ))
+-define(DEFAULT_GB_MAX_VBS, 1000).
+
-define(snmpa_info(F, A), ?snmp_info("agent", F, A)).
-define(snmpa_warning(F, A), ?snmp_warning("agent", F, A)).
-define(snmpa_error(F, A), ?snmp_error("agent", F, A)).
diff --git a/lib/snmp/src/agent/snmpa_local_db.erl b/lib/snmp/src/agent/snmpa_local_db.erl
index d9d6e633de..ab277fc3e9 100644
--- a/lib/snmp/src/agent/snmpa_local_db.erl
+++ b/lib/snmp/src/agent/snmpa_local_db.erl
@@ -486,7 +486,11 @@ handle_call({match, Name, Db, Pattern}, _From, State) ->
L1 = match(Db, Name, Pattern, State),
{reply, lists:delete([undef], L1), State};
-handle_call({backup, BackupDir}, From, #state{dets = Dets} = State) ->
+%% This check (that there is no backup already in progress) is also
+%% done in the master agent process, but just in case a user issues
+%% a backup call to this process directly, we add a similar check here.
+handle_call({backup, BackupDir}, From,
+ #state{backup = undefined, dets = Dets} = State) ->
?vlog("backup: ~p",[BackupDir]),
Pid = self(),
V = get(verbosity),
@@ -511,6 +515,10 @@ handle_call({backup, BackupDir}, From, #state{dets = Dets} = State) ->
{reply, Error, State}
end;
+handle_call({backup, _BackupDir}, From, #state{backup = Backup} = S) ->
+ ?vinfo("backup already in progress: ~p", [Backup]),
+ {reply, {error, backup_in_progress}, S};
+
handle_call(dump, _From, #state{dets = Dets} = State) ->
?vlog("dump",[]),
dets_sync(Dets),
@@ -1110,7 +1118,7 @@ table_func(is_set_ok, RowIndex, Cols, NameDb) ->
table_func(set, RowIndex, Cols, NameDb) ->
snmp_generic:table_set_row(NameDb,
nofunc,
- {snmp_generic, table_try_make_consistent},
+ fun snmp_generic:table_try_make_consistent/3,
RowIndex,
Cols);
diff --git a/lib/snmp/src/agent/snmpa_mib.erl b/lib/snmp/src/agent/snmpa_mib.erl
index ce90db18b3..574467d38f 100644
--- a/lib/snmp/src/agent/snmpa_mib.erl
+++ b/lib/snmp/src/agent/snmpa_mib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -552,8 +552,12 @@ handle_call({dump, File}, _From, #state{data = Data} = State) ->
Reply = snmpa_mib_data:dump(Data, File),
{reply, Reply, State};
-handle_call({backup, BackupDir}, From, #state{data = Data} = State) ->
- ?vlog("backup to ~s",[BackupDir]),
+%% This check (that there is no backup already in progress) is also
+%% done in the master agent process, but just in case a user issues
+%% a backup call to this process directly, we add a similar check here.
+handle_call({backup, BackupDir}, From,
+ #state{backup = undefined, data = Data} = State) ->
+ ?vlog("backup to ~s", [BackupDir]),
Pid = self(),
V = get(verbosity),
case file:read_file_info(BackupDir) of
@@ -576,6 +580,10 @@ handle_call({backup, BackupDir}, From, #state{data = Data} = State) ->
{reply, Error, State}
end;
+handle_call({backup, _BackupDir}, From, #state{backup = Backup} = S) ->
+ ?vinfo("backup already in progress: ~p", [Backup]),
+ {reply, {error, backup_in_progress}, S};
+
handle_call(stop, _From, State) ->
?vlog("stop",[]),
{stop, normal, ok, State};
diff --git a/lib/snmp/src/agent/snmpa_mib_lib.erl b/lib/snmp/src/agent/snmpa_mib_lib.erl
index 078e681945..3c94cc8095 100644
--- a/lib/snmp/src/agent/snmpa_mib_lib.erl
+++ b/lib/snmp/src/agent/snmpa_mib_lib.erl
@@ -61,23 +61,23 @@ table_del_row({Tab, Db} = TabDb, Key) ->
get_table(NameDb, FOI) ->
(catch get_table(NameDb, FOI, [], [])).
-get_table(NameDb, FOI, Oid, Acc) ->
- case table_next(NameDb, Oid) of
+get_table(NameDb, FOI, Key, Acc) ->
+ case table_next(NameDb, Key) of
endOfTable ->
?vdebug("end of table",[]),
{ok, lists:reverse(Acc)};
- Oid ->
+ Key ->
%% Crap, circular ref
- ?vinfo("cyclic reference: ~w -> ~w", [Oid,Oid]),
- throw({error, {cyclic_db_reference, Oid, Acc}});
- NextOid ->
- ?vtrace("get row for oid ~w", [NextOid]),
- case table_get_row(NameDb, NextOid, FOI) of
+ ?vinfo("cyclic reference: ~w -> ~w", [Key, Key]),
+ throw({error, {cyclic_db_reference, Key, Acc}});
+ NextKey ->
+ ?vtrace("get row for key ~w", [NextKey]),
+ case table_get_row(NameDb, NextKey, FOI) of
undefined ->
- throw({error, {invalid_rowindex, NextOid, Acc}});
+ throw({error, {invalid_rowindex, NextKey, Acc}});
Row ->
?vtrace("row: ~w", [Row]),
- get_table(NameDb, FOI, NextOid, [{NextOid, Row}|Acc])
+ get_table(NameDb, FOI, NextKey, [{NextKey, Row}|Acc])
end
end.
diff --git a/lib/snmp/src/agent/snmpa_mpd.erl b/lib/snmp/src/agent/snmpa_mpd.erl
index 14f62b12f3..2d37ea56f0 100644
--- a/lib/snmp/src/agent/snmpa_mpd.erl
+++ b/lib/snmp/src/agent/snmpa_mpd.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -32,6 +32,7 @@
-include("SNMP-MPD-MIB.hrl").
-include("SNMPv2-TM.hrl").
-include("SNMP-FRAMEWORK-MIB.hrl").
+-include("TRANSPORT-ADDRESS-MIB.hrl").
-define(VMODULE,"MPD").
-include("snmp_verbosity.hrl").
@@ -467,15 +468,10 @@ v3_proc(NoteStore, Packet, LocalEngineID, V3Hdr, Data, Log) ->
_ ->
%% 4.2.2.1.2
NIsReportable = snmp_misc:is_reportable_pdu(Type),
- Val = inc(snmpUnknownPDUHandlers),
ErrorInfo =
- {#varbind{oid = ?snmpUnknownPDUHandlers,
- variabletype = 'Counter32',
- value = Val},
- SecName,
- [{securityLevel, SecLevel},
- {contextEngineID, ContextEngineID},
- {contextName, ContextName}]},
+ snmpUnknownPDUHandlers_ei(SecName, SecLevel,
+ ContextEngineID,
+ ContextName),
case generate_v3_report_msg(MsgID,
MsgSecurityModel,
Data, LocalEngineID,
@@ -506,6 +502,21 @@ v3_proc(NoteStore, Packet, LocalEngineID, V3Hdr, Data, Log) ->
end
end.
+make_error_info(Variable, Oid, SecName, Opts) ->
+ Val = inc(Variable),
+ VB = #varbind{oid = Oid,
+ variabletype = 'Counter32',
+ value = Val},
+ {VB, SecName, Opts}.
+
+snmpUnknownPDUHandlers_ei(SecName, SecLevel,
+ ContextEngineID, ContextName) ->
+ Opts = [{securityLevel, SecLevel},
+ {contextEngineID, ContextEngineID},
+ {contextName, ContextName}],
+ make_error_info(snmpUnknownPDUHandlers,
+ ?snmpUnknownPDUHandlers_instance,
+ SecName, Opts).
get_security_module(?SEC_USM) ->
snmpa_usm;
@@ -981,12 +992,15 @@ generate_discovery_msg2(NoteStore, Pdu,
discovery_note_timeout(Timeout) ->
(Timeout div 100) + 1.
-generate_discovery_msg(NoteStore, {?snmpUDPDomain, [A,B,C,D,U1,U2]},
+generate_discovery_msg(NoteStore, {TDomain, TAddress},
Pdu, ScopedPduBytes,
ContextEngineID, ManagerEngineID,
SecModel, SecName, SecLevelFlag,
InitialUserName,
ContextName, Timeout) ->
+
+ {ok, {_Domain, Address}} = transform_taddr(TDomain, TAddress),
+
%% 7.1.7
?vdebug("generate_discovery_msg -> 7.1.7 (~w)", [ManagerEngineID]),
MsgID = generate_msg_id(),
@@ -1027,7 +1041,7 @@ generate_discovery_msg(NoteStore, {?snmpUDPDomain, [A,B,C,D,U1,U2]},
%% Log(Packet),
inc_snmp_out_vars(Pdu),
?vdebug("generate_discovery_msg -> done", []),
- {Packet, {{A,B,C,D}, U1 bsl 8 + U2}};
+ {Packet, Address};
Error ->
throw(Error)
@@ -1057,6 +1071,34 @@ generate_sec_discovery_msg(Message, SecModule,
end.
+transform_taddr(?snmpUDPDomain, TAddress) ->
+ transform_taddr(?transportDomainUdpIpv4, TAddress);
+transform_taddr(?transportDomainUdpIpv4, [A, B, C, D, P1, P2]) ->
+ Domain = transportDomainUdpIpv4,
+ Addr = {A,B,C,D},
+ Port = P1 bsl 8 + P2,
+ Address = {Addr, Port},
+ {ok, {Domain, Address}};
+transform_taddr(?transportDomainUdpIpv4, BadAddr) ->
+ {error, {bad_transportDomainUdpIpv4_address, BadAddr}};
+transform_taddr(?transportDomainUdpIpv6,
+ [A1, A2, A3, A4, A5, A6, A7, A8, P1, P2]) ->
+ Domain = transportDomainUdpIpv6,
+ Addr = {A1, A2, A3, A4, A5, A6, A7, A8},
+ Port = P1 bsl 8 + P2,
+ Address = {Addr, Port},
+ {ok, {Domain, Address}};
+transform_taddr(?transportDomainUdpIpv6, BadAddr) ->
+ {error, {bad_transportDomainUdpIpv6_address, BadAddr}};
+transform_taddr(BadTDomain, TAddress) ->
+ case lists:member(BadTDomain, snmp_conf:all_tdomains()) of
+ true ->
+ {error, {unsupported_tdomain, BadTDomain, TAddress}};
+ false ->
+ {error, {unknown_tdomain, BadTDomain, TAddress}}
+ end.
+
+
process_taddrs(Dests) ->
?vtrace("process_taddrs -> entry with"
"~n Dests: ~p", [Dests]),
@@ -1066,46 +1108,44 @@ process_taddrs([], Acc) ->
?vtrace("process_taddrs -> entry when done with"
"~n Acc: ~p", [Acc]),
lists:reverse(Acc);
-
+
%% v3
-process_taddrs([{{?snmpUDPDomain, [A,B,C,D,U1,U2]}, SecData} | T], Acc) ->
+process_taddrs([{{TDomain, TAddress}, SecData} | T], Acc) ->
?vtrace("process_taddrs -> entry when v3 with"
- "~n A: ~p"
- "~n B: ~p"
- "~n C: ~p"
- "~n D: ~p"
- "~n U1: ~p"
- "~n U2: ~p"
- "~n SecData: ~p", [A, B, C, D, U1, U2, SecData]),
- Entry = {{snmpUDPDomain, {{A,B,C,D}, U1 bsl 8 + U2}}, SecData},
- process_taddrs(T, [Entry | Acc]);
-%% Bad v3
-process_taddrs([{{TDomain, TAddr}, _SecData} | T], Acc) ->
- ?vtrace("process_taddrs -> entry when bad v3 with"
- "~n TDomain: ~p"
- "~n TAddr: ~p", [TDomain, TAddr]),
- user_err("Bad TDomain/TAddr: ~w/~w", [TDomain, TAddr]),
- process_taddrs(T, Acc);
+ "~n TDomain: ~p"
+ "~n TAddress: ~p"
+ "~n SecData: ~p", [TDomain, TAddress, SecData]),
+ case transform_taddr(TDomain, TAddress) of
+ {ok, DestAddr} ->
+ ?vtrace("process_taddrs -> transformed: "
+ "~n DestAddr: ~p", [DestAddr]),
+ Entry = {DestAddr, SecData},
+ process_taddrs(T, [Entry | Acc]);
+ {error, Reason} ->
+ ?vinfo("Failed transforming v3 domain and address"
+ "~n Reason: ~p", [Reason]),
+ user_err("Bad TDomain/TAddress: ~w/~w", [TDomain, TAddress]),
+ process_taddrs(T, Acc)
+ end;
%% v1 & v2
-process_taddrs([{?snmpUDPDomain, [A,B,C,D,U1,U2]} | T], Acc) ->
+process_taddrs([{TDomain, TAddress} | T], Acc) ->
?vtrace("process_taddrs -> entry when v1/v2 with"
- "~n A: ~p"
- "~n B: ~p"
- "~n C: ~p"
- "~n D: ~p"
- "~n U1: ~p"
- "~n U2: ~p", [A, B, C, D, U1, U2]),
- Entry = {snmpUDPDomain, {{A,B,C,D}, U1 bsl 8 + U2}},
- process_taddrs(T, [Entry | Acc]);
-%% Bad v1 or v2
-process_taddrs([{TDomain, TAddr} | T], Acc) ->
- ?vtrace("process_taddrs -> entry when bad v1/v2 with"
- "~n TDomain: ~p"
- "~n TAddr: ~p", [TDomain, TAddr]),
- user_err("Bad TDomain/TAddr: ~w/~w", [TDomain, TAddr]),
- process_taddrs(T, Acc);
+ "~n TDomain: ~p"
+ "~n TAddress: ~p", [TDomain, TAddress]),
+ case transform_taddr(TDomain, TAddress) of
+ {ok, DestAddr} ->
+ ?vtrace("process_taddrs -> transformed: "
+ "~n DestAddr: ~p", [DestAddr]),
+ Entry = DestAddr,
+ process_taddrs(T, [Entry | Acc]);
+ {error, Reason} ->
+ ?vinfo("Failed transforming v1/v2 domain and address: "
+ "~n Reason: ~p", [Reason]),
+ user_err("Bad TDomain/TAddress: ~w/~w", [TDomain, TAddress]),
+ process_taddrs(T, Acc)
+ end;
process_taddrs(Crap, Acc) ->
- throw({error, {taddrs_crap, Crap, Acc}}).
+ throw({error, {bad_taddrs, Crap, Acc}}).
mk_v1_v2_packet_list(To, Packet, Len, Pdu) ->
diff --git a/lib/snmp/src/agent/snmpa_set_lib.erl b/lib/snmp/src/agent/snmpa_set_lib.erl
index 191029f6db..9f355855b4 100644
--- a/lib/snmp/src/agent/snmpa_set_lib.erl
+++ b/lib/snmp/src/agent/snmpa_set_lib.erl
@@ -143,8 +143,8 @@ consistency_check(Varbinds) ->
consistency_check(Varbinds, []).
consistency_check([{TableOid, TableVbs} | Varbinds], Done) ->
?vtrace("consistency_check -> entry with"
- "~n TableOid: ~p"
- "~n TableVbs: ~p",[TableOid,TableVbs]),
+ "~n TableOid: ~p"
+ "~n TableVbs: ~p", [TableOid, TableVbs]),
TableOpsWithShortOids = deletePrefixes(TableOid, TableVbs),
[#ivarbind{mibentry = MibEntry}|_] = TableVbs,
case is_set_ok_table(MibEntry, TableOpsWithShortOids) of
@@ -158,7 +158,7 @@ consistency_check([{TableOid, TableVbs} | Varbinds], Done) ->
end;
consistency_check([IVarbind | Varbinds], Done) ->
?vtrace("consistency_check -> entry with"
- "~n IVarbind: ~p",[IVarbind]),
+ "~n IVarbind: ~p", [IVarbind]),
#ivarbind{varbind = Varbind, mibentry = MibEntry} = IVarbind,
#varbind{value = Value, org_index = OrgIndex} = Varbind,
case is_set_ok_variable(MibEntry, Value) of
@@ -358,32 +358,39 @@ make_value_a_correct_value(Value, ASN1Type, Mfa) ->
%% Runtime debug support
%%-----------------------------------------------------------------
-% XXX: This function match on the exakt return codes from EXIT
-% messages. As of this writing it was not decided if this is
-% the right way so don't blindly do things this way.
-%
-% We fake a real EXIT signal as the return value because the
-% result is passed to the function snmpa_agent:validate_err()
-% that expect it.
+%% XYZ: This function match on the exakt return codes from EXIT
+%% messages. As of this writing it was not decided if this is
+%% the right way so don't blindly do things this way.
+%%
+%% We fake a real EXIT signal as the return value because the
+%% result is passed to the function snmpa_agent:validate_err()
+%% that expect it.
dbg_apply(M,F,A) ->
- Result =
- case get(verbosity) of
- false ->
- (catch apply(M,F,A));
- _ ->
- ?vlog("~n apply: ~w,~w,~p~n", [M,F,A]),
- Res = (catch apply(M,F,A)),
- ?vlog("~n returned: ~p", [Res]),
- Res
- end,
- case Result of
+ case maybe_verbose_apply(M, F, A) of
+ %% <Future proofing>
+ %% As of R15 we get extra info containing,
+ %% among other things, line numbers.
+ {'EXIT', {undef, [{M, F, A, _} | _]}} ->
+ {'EXIT', {hook_undef, {M, F, A}}};
+ {'EXIT', {function_clause, [{M, F, A, _} | _]}} ->
+ {'EXIT', {hook_function_clause, {M, F, A}}};
+
+ %% This is really overkill, but just to be on the safe side...
+ {'EXIT', {undef, {M, F, A, _}}} ->
+ {'EXIT', {hook_undef, {M, F, A}}};
+ {'EXIT', {function_clause, {M, F, A, _}}} ->
+ {'EXIT', {hook_function_clause, {M, F, A}}};
+ %% </Future proofing>
+
+
+ %% Old format format for compatibility
{'EXIT', {undef, [{M, F, A} | _]}} ->
{'EXIT', {hook_undef, {M, F, A}}};
{'EXIT', {function_clause, [{M, F, A} | _]}} ->
{'EXIT', {hook_function_clause, {M, F, A}}};
- % XXX: Old format for compatibility
+ % XYZ: Older format for compatibility
{'EXIT', {undef, {M, F, A}}} ->
{'EXIT', {hook_undef, {M, F, A}}};
{'EXIT', {function_clause, {M, F, A}}} ->
@@ -393,3 +400,15 @@ dbg_apply(M,F,A) ->
Result
end.
+
+maybe_verbose_apply(M, F, A) ->
+ case get(verbosity) of
+ false ->
+ (catch apply(M,F,A));
+ _ ->
+ ?vlog("~n apply: ~w,~w,~p~n", [M,F,A]),
+ Res = (catch apply(M,F,A)),
+ ?vlog("~n returned: ~p", [Res]),
+ Res
+ end.
+
diff --git a/lib/snmp/src/agent/snmpa_supervisor.erl b/lib/snmp/src/agent/snmpa_supervisor.erl
index 5ef5914e18..7a9c214e0d 100644
--- a/lib/snmp/src/agent/snmpa_supervisor.erl
+++ b/lib/snmp/src/agent/snmpa_supervisor.erl
@@ -176,8 +176,8 @@ init([AgentType, Opts]) ->
"~n AgentType: ~p"
"~n Opts: ~p", [AgentType, Opts]),
- put(sname, asup),
- put(verbosity,get_verbosity(Opts)),
+ put(sname, asup),
+ put(verbosity, get_verbosity(Opts)),
?vlog("starting",[]),
@@ -203,7 +203,12 @@ init([AgentType, Opts]) ->
Vsns = get_opt(versions, Opts, [v1,v2,v3]),
?vdebug("[agent table] store versions: ~p",[Vsns]),
ets:insert(snmp_agent_table, {versions, Vsns}),
-
+
+ %% -- Max number of VBs in a Get-BULK response --
+ GbMaxVBs = get_gb_max_vbs(Opts),
+ ?vdebug("[agent table] Get-BULK max VBs: ~p", [GbMaxVBs]),
+ ets:insert(snmp_agent_table, {gb_max_vbs, GbMaxVBs}),
+
%% -- DB-directory --
DbDir = get_opt(db_dir, Opts),
?vdebug("[agent table] store db_dir: ~n ~p",[DbDir]),
@@ -377,7 +382,8 @@ init([AgentType, Opts]) ->
{versions, Vsns},
{net_if, NiOpts},
{mib_server, MibsOpts},
- {note_store, NsOpts}|
+ {note_store, NsOpts},
+ {gb_max_vbs, GbMaxVBs} |
get_opt(master_agent_options, Opts, [])],
AgentSpec =
@@ -542,6 +548,32 @@ get_verbosity(Opts) ->
get_agent_type(Opts) ->
get_opt(agent_type, Opts, master).
+
+%% We validate this option! This should really be done for all
+%% options, but it is beyond the scope of this ticket, OTP-9700.
+
+get_gb_max_vbs(Opts) ->
+ Validate =
+ fun(GbMaxVBs)
+ when ((is_integer(GbMaxVBs) andalso (GbMaxVBs > 0)) orelse
+ (GbMaxVBs =:= infinity)) ->
+ ok;
+ (_) ->
+ error
+ end,
+ get_option(gb_max_vbs, ?DEFAULT_GB_MAX_VBS, Validate, Opts).
+
+get_option(Key, Default, Validate, Opts)
+ when is_list(Opts) andalso is_function(Validate) ->
+ Value = get_opt(Key, Opts, Default),
+ case Validate(Value) of
+ ok ->
+ Value;
+ error ->
+ exit({bad_option, Key, Value})
+ end.
+
+
get_opt(Key, Opts) ->
snmp_misc:get_option(Key, Opts).
diff --git a/lib/snmp/src/agent/snmpa_trap.erl b/lib/snmp/src/agent/snmpa_trap.erl
index 567de020c0..994d926224 100644
--- a/lib/snmp/src/agent/snmpa_trap.erl
+++ b/lib/snmp/src/agent/snmpa_trap.erl
@@ -352,11 +352,26 @@ send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, ExtraInfo, NetIf) ->
send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs,
LocalEngineID, ExtraInfo, NetIf).
+%% The agent normally does not care about the result,
+%% but since it can be usefull when debugging, add
+%% some info when we fail to send the trap(s).
send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID,
ExtraInfo, NetIf) ->
- (catch do_send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs,
- LocalEngineID, ExtraInfo, NetIf)).
-
+ try
+ begin
+ do_send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs,
+ LocalEngineID, ExtraInfo, NetIf)
+ end
+ catch
+ T:E ->
+ Info = [{args, [TrapRec, NotifyName, ContextName,
+ Recv, Vbs, LocalEngineID, ExtraInfo, NetIf]},
+ {tag, T},
+ {err, E},
+ {stacktrace, erlang:get_stacktrace()}],
+ {error, {failed_sending_trap, Info}}
+ end.
+
do_send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs,
LocalEngineID, ExtraInfo, NetIf) ->
VarbindList = make_varbind_list(Vbs),
@@ -379,8 +394,13 @@ send_discovery(TargetName, Record, ContextName, Vbs, NetIf, ExtraInfo) ->
get_values(VariablesWithType) ->
{Order, Varbinds} = extract_order(VariablesWithType, 1),
+ ?vtrace("get_values -> "
+ "~n Order: ~p"
+ "~n Varbinds: ~p", [Order, Varbinds]),
case snmpa_agent:do_get(snmpa_acm:get_root_mib_view(), Varbinds, true) of
{noError, _, NewVarbinds} ->
+ ?vtrace("get_values -> values retrieved"
+ "~n NewVarbinds: ~p", [NewVarbinds]),
%% NewVarbinds is the result of:
%% first a reverse, then a sort on the oid field and finally
%% a reverse during the get-processing so we need to re-sort
diff --git a/lib/snmp/src/agent/snmpa_vacm.erl b/lib/snmp/src/agent/snmpa_vacm.erl
index 892dc265f1..dadcf32543 100644
--- a/lib/snmp/src/agent/snmpa_vacm.erl
+++ b/lib/snmp/src/agent/snmpa_vacm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -62,6 +62,13 @@ get_mib_view(ViewType, SecModel, SecName, SecLevel, ContextName) ->
%% Follows the procedure in rfc2275
auth(ViewType, SecModel, SecName, SecLevel, ContextName) ->
+ ?vtrace("auth -> entry with"
+ "~n ViewType: ~p"
+ "~n SecModel: ~p"
+ "~n SecName: ~p"
+ "~n SecLevel: ~p"
+ "~n ContextName: ~p",
+ [ViewType, SecModel, SecName, SecLevel, ContextName]),
% 3.2.1 - Check that the context is known to us
?vdebug("check that the context (~p) is known to us",[ContextName]),
case snmp_view_based_acm_mib:vacmContextTable(get, ContextName,
@@ -74,7 +81,7 @@ auth(ViewType, SecModel, SecName, SecLevel, ContextName) ->
end,
% 3.2.2 - Check that the SecModel and SecName is valid
?vdebug("check that SecModel (~p) and SecName (~p) is valid",
- [SecModel,SecName]),
+ [SecModel, SecName]),
GroupName =
case snmp_view_based_acm_mib:get(vacmSecurityToGroupTable,
[SecModel, length(SecName) | SecName],
@@ -111,6 +118,8 @@ check_auth(Res) -> {ok, Res}.
%% key in the table >= ViewIndex.
%%-----------------------------------------------------------------
get_mib_view(ViewName) ->
+ ?vtrace("get_mib_view -> entry with"
+ "~n ViewName: ~p", [ViewName]),
ViewKey = [length(ViewName) | ViewName],
case snmp_view_based_acm_mib:table_next(vacmViewTreeFamilyTable,
ViewKey) of
@@ -202,6 +211,13 @@ backup(BackupDir) ->
%% Ret: {ok, ViewName} | {error, Reason}
get_view_name(ViewType, GroupName, ContextName, SecModel, SecLevel) ->
+ ?vtrace("get_view_name -> entry with"
+ "~n ViewType: ~p"
+ "~n GroupName: ~p"
+ "~n ContextName: ~p"
+ "~n SecModel: ~p"
+ "~n SecLevel: ~p",
+ [ViewType, GroupName, ContextName, SecModel, SecLevel]),
GroupKey = [length(GroupName) | GroupName],
case get_access_row(GroupKey, ContextName, SecModel, SecLevel) of
undefined ->
@@ -266,9 +282,10 @@ dump_table(true) ->
dump_table(_) ->
ok.
+
dump_table() ->
[{_, FName}] = ets:lookup(snmp_agent_table, snmpa_vacm_file),
- TmpName = FName ++ ".tmp",
+ TmpName = unique_table_name(FName),
case ets:tab2file(snmpa_vacm, TmpName) of
ok ->
case file:rename(TmpName, FName) of
@@ -283,6 +300,35 @@ dump_table() ->
[FName, Reason])
end.
+%% This little thing is an attempt to create a "unique" filename
+%% in order to minimize the risk of two processes at the same
+%% time dumping the table.
+unique_table_name(Pre) ->
+ %% We want something that is guaranteed to be unique,
+ %% therefor we use erlang:now() instead of os:timestamp()
+ unique_table_name(Pre, erlang:now()).
+
+unique_table_name(Pre, {_A, _B, C} = Now) ->
+ {Date, Time} = calendar:now_to_datetime(Now),
+ {YYYY, MM, DD} = Date,
+ {Hour, Min, Sec} = Time,
+ FormatDate =
+ io_lib:format("~.4w~.2.0w~.2.0w_~.2.0w~.2.0w~.2.0w_~w",
+ [YYYY, MM, DD, Hour, Min, Sec, round(C/1000)]),
+ unique_table_name2(Pre, FormatDate).
+
+unique_table_name2(Pre, FormatedDate) ->
+ PidPart = unique_table_name_pid(),
+ lists:flatten(io_lib:format("~s.~s~s.tmp", [Pre, PidPart, FormatedDate])).
+
+unique_table_name_pid() ->
+ case string:tokens(pid_to_list(self()), [$<,$.,$>]) of
+ [A, B, C] ->
+ A ++ B ++ C ++ ".";
+ _ ->
+ ""
+ end.
+
%%-----------------------------------------------------------------
%% Alg.