4
%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
4
%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
6
6
%% The contents of this file are subject to the Erlang Public License,
7
7
%% Version 1.1, (the "License"); you may not use this file except in
8
8
%% compliance with the License. You should have received a copy of the
9
9
%% Erlang Public License along with this software. If not, it can be
10
10
%% retrieved online at http://www.erlang.org/.
12
12
%% Software distributed under the License is distributed on an "AS IS"
13
13
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
14
14
%% the License for the specific language governing rights and limitations
15
15
%% under the License.
19
19
-module(snmpa_agent).
30
30
-export([subagent_set/2,
31
31
load_mibs/2, unload_mibs/2, which_mibs/1, whereis_mib/2, info/1,
32
32
register_subagent/3, unregister_subagent/2,
33
send_trap/6, send_trap/7,
34
34
register_notification_filter/5,
35
35
unregister_notification_filter/2,
36
36
which_notification_filter/1,
48
48
get/2, get/3, get_next/2, get_next/3]).
49
49
-export([mib_of/1, mib_of/2, me_of/1, me_of/2,
50
50
invalidate_mibs_cache/1,
51
which_mibs_cache_size/1,
51
52
enable_mibs_cache/1, disable_mibs_cache/1,
52
53
gc_mibs_cache/1, gc_mibs_cache/2, gc_mibs_cache/3,
53
54
enable_mibs_cache_autogc/1, disable_mibs_cache_autogc/1,
58
59
-export([get_log_type/1, set_log_type/2]).
59
60
-export([get_request_limit/1, set_request_limit/2]).
60
61
-export([invalidate_ca_cache/0]).
62
-export([increment_counter/3]).
61
63
-export([restart_worker/1, restart_set_worker/1]).
63
65
%% Internal exports
64
66
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
65
67
terminate/2, code_change/3, tr_var/2, tr_varbind/1,
66
handle_pdu/7, worker/2, worker_loop/1, do_send_trap/6]).
68
handle_pdu/7, worker/2, worker_loop/1, do_send_trap/7]).
68
70
-ifndef(default_verbosity).
69
71
-define(default_verbosity,silence).
259
265
call(Agent, {mibs_cache_request, {update_age, Age}}).
268
increment_counter(Counter, Initial, Max) ->
269
%% This is to make sure no one else increments our counter
270
Key = {Counter, self()},
277
UpdateOp = {Position, Increment, Threshold, SetValue},
279
%% And now for the actual increment
280
Tab = snmp_agent_table,
281
case (catch ets:update_counter(Tab, Key, UpdateOp)) of
282
{'EXIT', {badarg, _}} ->
284
ets:insert(Tab, {Key, Initial}),
286
Next when is_integer(Next) ->
262
291
init([Prio, Parent, Ref, Options]) ->
263
292
?d("init -> entry with"
501
530
send_trap(Agent, Trap, NotifyName, CtxName, Recv, Varbinds) ->
502
531
?d("send_trap -> entry with"
510
[self(), Agent, wis(Agent), Trap, NotifyName, CtxName, Recv, Varbinds]),
539
[self(), Agent, wis(Agent),
540
Trap, NotifyName, CtxName, Recv, Varbinds]),
511
541
Msg = {send_trap, Trap, NotifyName, CtxName, Recv, Varbinds},
512
542
case (wis(Agent) =:= self()) of
549
send_trap(Agent, Trap, NotifyName, CtxName, Recv, Varbinds, LocalEngineID) ->
550
?d("send_trap -> entry with"
558
"~n LocalEngineID: ~p",
559
[self(), Agent, wis(Agent),
560
Trap, NotifyName, CtxName, Recv, Varbinds, LocalEngineID]),
562
{send_trap, Trap, NotifyName, CtxName, Recv, Varbinds, LocalEngineID},
563
case (wis(Agent) =:= self()) of
520
571
%% -- Discovery functions --
696
748
handle_info({send_trap, Trap, NotifyName, ContextName, Recv, Varbinds}, S) ->
697
749
?vlog("[handle_info] send trap request:"
703
[Trap,NotifyName,ContextName,Recv,Varbinds]),
704
case catch handle_send_trap(S, Trap, NotifyName, ContextName,
709
?vinfo("Trap not sent:~n ~p", [R]),
715
handle_info({forward_trap, TrapRecord, NotifyName, ContextName,
716
Recv, Varbinds},S) ->
755
[Trap, NotifyName, ContextName, Recv, Varbinds]),
756
LocalEngineID = ?DEFAULT_LOCAL_ENGINE_ID,
757
case catch handle_send_trap(S, Trap, NotifyName, ContextName,
758
Recv, Varbinds, LocalEngineID) of
762
?vinfo("Trap not sent:~n ~p", [R]),
768
handle_info({send_trap, Trap, NotifyName, ContextName, Recv, Varbinds,
769
LocalEngineID}, S) ->
770
?vlog("[handle_info] send trap request:"
776
"~n LocalEngineID: ~p",
777
[Trap, NotifyName, ContextName, Recv, Varbinds, LocalEngineID]),
778
case catch handle_send_trap(S, Trap, NotifyName, ContextName,
779
Recv, Varbinds, LocalEngineID) of
783
?vinfo("Trap not sent:~n ~p", [R]),
789
handle_info({forward_trap, TrapRecord, NotifyName, ContextName,
790
Recv, Varbinds}, S) ->
717
791
?vlog("[handle_info] forward trap request:"
723
[TrapRecord,NotifyName,ContextName,Recv,Varbinds]),
797
[TrapRecord, NotifyName, ContextName, Recv, Varbinds]),
798
LocalEngineID = ?DEFAULT_LOCAL_ENGINE_ID,
724
799
case (catch maybe_send_trap(S, TrapRecord, NotifyName, ContextName,
800
Recv, Varbinds, LocalEngineID)) of
835
911
handle_call({send_trap, Trap, NotifyName, ContextName, Recv, Varbinds},
837
913
?vlog("[handle_call] send trap request:"
843
[Trap,NotifyName,ContextName,Recv,Varbinds]),
844
case (catch handle_send_trap(S, Trap, NotifyName, ContextName,
849
?vinfo("Trap not sent:~n ~p", [Reason]),
850
{reply, {error, {send_failed, Reason}}, S};
852
?vinfo("Trap not sent", []),
853
{reply, {error, send_failed}, S}
919
[Trap, NotifyName, ContextName, Recv, Varbinds]),
923
?DEFAULT_LOCAL_ENGINE_ID;
926
%% we don't need this, eventually the trap sent request
927
%% will reach the master-agent and then it will look up
928
%% the proper engine id.
931
case (catch handle_send_trap(S, Trap, NotifyName, ContextName,
932
Recv, Varbinds, LocalEngineID)) of
936
?vinfo("Trap not sent:~n ~p", [Reason]),
937
{reply, {error, {send_failed, Reason}}, S};
939
?vinfo("Trap not sent", []),
940
{reply, {error, send_failed}, S}
943
handle_call({send_trap, Trap, NotifyName,
944
ContextName, Recv, Varbinds, LocalEngineID},
946
?vlog("[handle_call] send trap request:"
952
"~n LocalEngineID: ~p",
953
[Trap, NotifyName, ContextName, Recv, Varbinds, LocalEngineID]),
954
case (catch handle_send_trap(S, Trap, NotifyName, ContextName,
955
Recv, Varbinds, LocalEngineID)) of
959
?vinfo("Trap not sent:~n ~p", [Reason]),
960
{reply, {error, {send_failed, Reason}}, S};
962
?vinfo("Trap not sent", []),
963
{reply, {error, send_failed}, S}
855
966
handle_call({discovery,
856
TargetName, Notification, ContextName, Vbs, DiscoHandler, ExtraInfo},
967
TargetName, Notification, ContextName, Vbs, DiscoHandler,
858
970
#state{disco = undefined} = S) ->
859
971
?vlog("[handle_call] initiate discovery process:"
1226
code_change({down, _Vsn}, S, downgrade_to_pre_4_13) ->
1227
S1 = workers_restart(S),
1228
case S1#state.disco of
1234
gen_server:reply(From, {error, {upgrade, Stage, Sender}}),
1241
S1#state.worker_state,
1242
S1#state.set_worker,
1243
S1#state.multi_threaded,
1247
S1#state.note_store,
1248
S1#state.mib_server,
1250
S1#state.net_if_mod,
1340
%% code_change({down, _Vsn}, S, downgrade_to_pre_4_13) ->
1257
code_change(_Vsn, S, upgrade_from_pre_4_13) ->
1269
MibServer, %% Currently unused
1270
NetIf, %% Currently unused
1273
S1 = #state{type = Type,
1276
worker_state = WorkerState,
1277
set_worker = SetWorker,
1278
multi_threaded = MultiThreaded,
1281
nfilters = NFilters,
1282
note_store = NoteStore,
1283
mib_server = MibServer,
1285
net_if_mod = NetIfMod,
1287
S2 = workers_restart(S1),
1345
%% code_change(_Vsn, S, upgrade_from_pre_4_13) ->
1290
1348
code_change(_Vsn, S, _Extra) ->
1294
workers_restart(#state{worker = W, set_worker = SW} = S) ->
1295
Worker = worker_restart(W),
1296
SetWorker = set_worker_restart(SW),
1297
S#state{worker = Worker,
1298
set_worker = SetWorker}.
1352
%% workers_restart(#state{worker = W, set_worker = SW} = S) ->
1353
%% Worker = worker_restart(W),
1354
%% SetWorker = set_worker_restart(SW),
1355
%% S#state{worker = Worker,
1356
%% set_worker = SetWorker}.
1301
1359
%%-----------------------------------------------------------------
1336
1394
worker_stop(_, _) ->
1339
set_worker_restart(Pid) ->
1340
worker_restart(Pid, [{master, self()} | get()]).
1342
worker_restart(Pid) ->
1343
worker_restart(Pid, get()).
1345
worker_restart(Pid, Dict) when is_pid(Pid) ->
1348
worker_restart(Any, _Dict) ->
1397
%% set_worker_restart(Pid) ->
1398
%% worker_restart(Pid, [{master, self()} | get()]).
1400
%% worker_restart(Pid) ->
1401
%% worker_restart(Pid, get()).
1403
%% worker_restart(Pid, Dict) when is_pid(Pid) ->
1404
%% worker_stop(Pid),
1405
%% worker_start(Dict);
1406
%% worker_restart(Any, _Dict) ->
1352
1410
%%-----------------------------------------------------------------
1464
1522
Args = [Vsn, Pdu, PduMS, ACMData, Address, Extra, Dict],
1465
1523
proc_lib:spawn_link(?MODULE, handle_pdu, Args).
1467
spawn_trap_thread(TrapRec, NotifyName, ContextName, Recv, V) ->
1525
spawn_trap_thread(TrapRec, NotifyName, ContextName, Recv, Vbs,
1469
1528
proc_lib:spawn_link(?MODULE, do_send_trap,
1470
[TrapRec, NotifyName, ContextName, Recv, V, Dict]).
1529
[TrapRec, NotifyName, ContextName,
1530
Recv, Vbs, LocalEngineID, Dict]).
1472
do_send_trap(TrapRec, NotifyName, ContextName, Recv, V, Dict) ->
1532
do_send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs,
1533
LocalEngineID, Dict) ->
1473
1534
lists:foreach(fun({Key, Val}) -> put(Key, Val) end, Dict),
1474
1535
put(sname,trap_sender_short_name(get(sname))),
1475
1536
?vlog("starting",[]),
1476
snmpa_trap:send_trap(TrapRec, NotifyName, ContextName, Recv, V,
1537
snmpa_trap:send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs,
1538
LocalEngineID, get(net_if)).
1479
1540
worker(Master, Dict) ->
1480
1541
lists:foreach(fun({Key, Val}) -> put(Key, Val) end, Dict),
1489
1550
handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra),
1490
1551
Master ! worker_available;
1492
%% Old style message
1493
{MibView, Vsn, Pdu, PduMS, ACMData, AgentData, Extra} ->
1494
?vtrace("worker_loop -> received (old) request", []),
1495
do_handle_pdu(MibView, Vsn, Pdu, PduMS, ACMData, AgentData, Extra),
1553
%% We don't trap exits!
1554
{TrapRec, NotifyName, ContextName, Recv, Vbs} ->
1555
?vtrace("worker_loop -> send trap:"
1556
"~n ~p", [TrapRec]),
1557
snmpa_trap:send_trap(TrapRec, NotifyName,
1558
ContextName, Recv, Vbs, get(net_if)),
1496
1559
Master ! worker_available;
1498
{TrapRec, NotifyName, ContextName, Recv, V} -> % We don't trap exits!
1561
%% We don't trap exits!
1563
TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID} ->
1499
1564
?vtrace("worker_loop -> send trap:"
1500
1565
"~n ~p", [TrapRec]),
1501
1566
snmpa_trap:send_trap(TrapRec, NotifyName,
1502
ContextName, Recv, V, get(net_if)),
1567
ContextName, Recv, Vbs, LocalEngineID,
1503
1569
Master ! worker_available;
1505
1571
{verbosity, Verbosity} ->
1651
handle_send_trap(S, TrapName, NotifyName, ContextName, Recv, Varbinds) ->
1717
handle_send_trap(S, TrapName, NotifyName, ContextName, Recv, Varbinds,
1652
1719
?vtrace("handle_send_trap -> entry with"
1653
"~n S#state.type: ~p"
1656
"~n ContextName: ~p",
1657
[S#state.type, TrapName, NotifyName, ContextName]),
1720
"~n S#state.type: ~p"
1723
"~n ContextName: ~p"
1724
"~n LocalEngineID: ~p",
1725
[S#state.type, TrapName, NotifyName, ContextName, LocalEngineID]),
1658
1726
case snmpa_trap:construct_trap(TrapName, Varbinds) of
1659
1727
{ok, TrapRecord, VarList} ->
1660
1728
?vtrace("handle_send_trap -> construction complete: "
1725
1795
?vtrace("maybe_send_trap -> send trap:"
1726
1796
"~n ~p", [TrapRec2]),
1727
1797
do_handle_send_trap(S, TrapRec2,
1728
NotifyName, ContextName, Recv, Varbinds);
1798
NotifyName, ContextName, Recv, Varbinds,
1730
1801
{send, Removed, TrapRec2} ->
1731
1802
?vtrace("maybe_send_trap -> send trap:"
1732
1803
"~n ~p", [TrapRec2]),
1733
1804
NFs2 = del_notification_filter(Removed, NFs),
1734
1805
do_handle_send_trap(S#state{nfilters = NFs2}, TrapRec2,
1735
NotifyName, ContextName, Recv, Varbinds)
1806
NotifyName, ContextName, Recv, Varbinds,
1738
do_handle_send_trap(S, TrapRec, NotifyName, ContextName, Recv, Varbinds) ->
1739
V = snmpa_trap:try_initialise_vars(get(mibserver), Varbinds),
1810
do_handle_send_trap(S, TrapRec, NotifyName, ContextName, Recv, Varbinds,
1812
Vbs = snmpa_trap:try_initialise_vars(get(mibserver), Varbinds),
1740
1813
case S#state.type of
1742
1815
forward_trap(S#state.parent, TrapRec, NotifyName, ContextName,
1745
1818
master_agent when S#state.multi_threaded =:= false ->
1746
1819
?vtrace("do_handle_send_trap -> send trap:"
1747
1820
"~n ~p", [TrapRec]),
1748
1821
snmpa_trap:send_trap(TrapRec, NotifyName, ContextName,
1749
Recv, V, get(net_if)),
1822
Recv, Vbs, LocalEngineID, get(net_if)),
1751
1824
master_agent when S#state.worker_state =:= busy ->
1752
1825
%% Main worker busy => create new worker
1753
1826
?vtrace("do_handle_send_trap -> main worker busy: "
1754
1827
"spawn a trap sender", []),
1755
spawn_trap_thread(TrapRec, NotifyName, ContextName, Recv, V),
1828
spawn_trap_thread(TrapRec, NotifyName, ContextName, Recv, Vbs,
1757
1831
master_agent ->
1758
1832
%% Send to main worker
1759
1833
?vtrace("do_handle_send_trap -> send to main worker",[]),
1760
S#state.worker ! {TrapRec, NotifyName, ContextName, Recv, V},
1834
S#state.worker ! {send_trap,
1835
TrapRec, NotifyName, ContextName, Recv, Vbs,
1761
1837
{ok, S#state{worker_state = busy}}