From 76e9c68368dfd9ec20181939511e2baf93fc73d9 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 3 Feb 2010 18:00:01 +0000 Subject: OTP-8395: Sequence number in Audit Trail Logs. --- lib/snmp/doc/src/notes.xml | 59 +++- lib/snmp/doc/src/snmp_app.xml | 22 +- lib/snmp/doc/src/snmp_config.xml | 21 +- lib/snmp/doc/src/snmpa_conf.xml | 6 +- lib/snmp/src/agent/snmpa.erl | 17 +- lib/snmp/src/agent/snmpa_agent.erl | 130 +++----- lib/snmp/src/agent/snmpa_net_if.erl | 112 +++---- lib/snmp/src/agent/snmpa_usm.erl | 18 +- lib/snmp/src/app/snmp.appup.src | 52 ++- lib/snmp/src/manager/snmpm_config.erl | 62 +++- lib/snmp/src/manager/snmpm_net_if.erl | 66 ++-- lib/snmp/src/misc/snmp_config.erl | 144 ++++++++- lib/snmp/src/misc/snmp_log.erl | 495 ++++++++++++++++++++++++----- lib/snmp/src/misc/snmp_usm.erl | 26 +- lib/snmp/test/snmp_agent_test.erl | 475 +++++++++++++++++++++++++-- lib/snmp/test/snmp_log_test.erl | 299 +++++++++++++---- lib/snmp/test/snmp_manager_config_test.erl | 184 ++++++++++- lib/snmp/test/snmp_manager_test.erl | 96 ++++-- lib/snmp/test/snmp_test_mgr.erl | 10 +- lib/snmp/vsn.mk | 18 +- 20 files changed, 1853 insertions(+), 459 deletions(-) diff --git a/lib/snmp/doc/src/notes.xml b/lib/snmp/doc/src/notes.xml index 96a444227d..7984f2a536 100644 --- a/lib/snmp/doc/src/notes.xml +++ b/lib/snmp/doc/src/notes.xml @@ -4,7 +4,7 @@
- 19962009 + 19962010 Ericsson AB. All Rights Reserved. @@ -13,12 +13,12 @@ compliance with the License. You should have received a copy of the Erlang Public License along with this software. If not, it can be retrieved online at http://www.erlang.org/. - + Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. - + SNMP Release Notes @@ -32,6 +32,59 @@ notes.xml
+
+ SNMP Development Toolkit 4.16 +

Version 4.16 supports code replacement in runtime from/to + version 4.15, 4.14 and 4.13.5.

+ +
+ Improvements and new features + + + +

[agent|manager] Entries in the audit trail log can now be + augmented by a sequence number.

+

This is enabled by the seqno option, which is part of the + Audit Trail Log + config option.

+

See the + reference manual + or the + Configuring the application + chapter of the User's Guide for further info.

+ +

Own Id: OTP-8395

+
+ +
+ +
+ +
+ Reported Fixed Bugs and Malfunctions +

-

+ + + +
+ +
+ Incompatibilities +

-

+
+
+ +
SNMP Development Toolkit 4.15 diff --git a/lib/snmp/doc/src/snmp_app.xml b/lib/snmp/doc/src/snmp_app.xml index 460f0b8018..e5a725d720 100644 --- a/lib/snmp/doc/src/snmp_app.xml +++ b/lib/snmp/doc/src/snmp_app.xml @@ -4,7 +4,7 @@
- 19972009 + 19972010 Ericsson AB. All Rights Reserved. @@ -13,12 +13,12 @@ compliance with the License. You should have received a copy of the Erlang Public License along with this software. If not, it can be retrieved online at http://www.erlang.org/. - + Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. - + snmp @@ -78,11 +78,11 @@ ]. + +

Each snmp component has it's own set of configuration parameters, even though some of the types are common to both components.

- -
       snmp_components_config() -> [snmp_component_config()]
       snmp_component_config() -> {agent, agent_options()} | {manager, manager_options()}
@@ -642,10 +642,13 @@
           process performs a GC to remove the expired note's. Time in
           milli-seconds.

Default is 30000.

+ + + ]]> -

audit_trail_log_opt() = {type, atl_type()} | {dir, atl_dir()} | {size, atl_size()} | {repair, atl_repair()}

+

audit_trail_log_opt() = {type, atl_type()} | {dir, atl_dir()} | {size, atl_size()} | {repair, atl_repair()} | {seqno, atl_seqno()}

If present, this option specifies the options for the audit trail logging. The disk_log module is used to maintain a wrap log. If present, the dir and @@ -696,6 +699,13 @@ analysis.

Default is true.

+ ]]> + +

Specifies if the audit trail log entries will be (sequence) + numbered or not. The range of the sequence numbers are according + to RFC 5424, i.e. 1 through 2147483647.

+

Default is false.

+
diff --git a/lib/snmp/doc/src/snmp_config.xml b/lib/snmp/doc/src/snmp_config.xml index 073cdde308..6fc9cc49f2 100644 --- a/lib/snmp/doc/src/snmp_config.xml +++ b/lib/snmp/doc/src/snmp_config.xml @@ -4,7 +4,7 @@
- 19972009 + 19972010 Ericsson AB. All Rights Reserved. @@ -13,12 +13,12 @@ compliance with the License. You should have received a copy of the Erlang Public License along with this software. If not, it can be retrieved online at http://www.erlang.org/. - + Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. - + Running the application @@ -73,13 +73,13 @@ + +

The agent and manager uses (application) configuration parameters to find out where these directories are located. The parameters should be defined in an Erlang system configuration file. The following configuration parameters are defined for the SNMP application:

- -
       agent_options() = [agent_option()]
       agent_option() = {restart_type,     restart_type()}     | 
@@ -649,11 +649,13 @@
           process performs a GC to remove the expired note's. Time in
           milli-seconds.

Default is 30000.

+ + ]]> -

audit_trail_log_opt() = {type, atl_type()} | {dir, atl_dir()} | {size, atl_size()} | {repair, atl_repair()}

+

audit_trail_log_opt() = {type, atl_type()} | {dir, atl_dir()} | {size, atl_size()} | {repair, atl_repair()} | {seqno, atl_seqno()}

If present, this option specifies the options for the audit trail logging. The disk_log module is used to maintain a wrap log. If present, the dir and @@ -708,6 +710,13 @@ analysis.

Default is true.

+ ]]> + +

Specifies if the audit trail log entries will be (sequence) + numbered or not. The range of the sequence numbers are according + to RFC 5424, i.e. 1 through 2147483647.

+

Default is false.

+
diff --git a/lib/snmp/doc/src/snmpa_conf.xml b/lib/snmp/doc/src/snmpa_conf.xml index f383394b7a..d873574c6e 100644 --- a/lib/snmp/doc/src/snmpa_conf.xml +++ b/lib/snmp/doc/src/snmpa_conf.xml @@ -4,7 +4,7 @@
- 20062009 + 20062010 Ericsson AB. All Rights Reserved. @@ -13,12 +13,12 @@ compliance with the License. You should have received a copy of the Erlang Public License along with this software. If not, it can be retrieved online at http://www.erlang.org/. - + Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. - + snmpa_conf diff --git a/lib/snmp/src/agent/snmpa.erl b/lib/snmp/src/agent/snmpa.erl index 79493bd892..a113bba3a7 100644 --- a/lib/snmp/src/agent/snmpa.erl +++ b/lib/snmp/src/agent/snmpa.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2004-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2004-2010. 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 %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% -module(snmpa). @@ -83,6 +83,7 @@ %% Audit Trail Log functions -export([log_to_txt/2, log_to_txt/3, log_to_txt/4, log_to_txt/5, log_to_txt/6, log_to_txt/7, + log_info/0, change_log_size/1, get_log_type/0, get_log_type/1, change_log_type/1, change_log_type/2, @@ -535,6 +536,7 @@ get_agent_caps() -> %%%----------------------------------------------------------------- %%% Audit Trail Log functions %%%----------------------------------------------------------------- + log_to_txt(LogDir, Mibs) -> OutFile = "snmpa_log.txt", LogName = ?audit_trail_log_name, @@ -555,6 +557,11 @@ log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) -> snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop). +log_info() -> + LogName = ?audit_trail_log_name, + snmp_log:info(LogName). + + change_log_size(NewSize) -> LogName = ?audit_trail_log_name, % The old (agent) default snmp:change_log_size(LogName, NewSize). diff --git a/lib/snmp/src/agent/snmpa_agent.erl b/lib/snmp/src/agent/snmpa_agent.erl index 508a1da514..fb04fca632 100644 --- a/lib/snmp/src/agent/snmpa_agent.erl +++ b/lib/snmp/src/agent/snmpa_agent.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1996-2010. 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 %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% -module(snmpa_agent). @@ -58,6 +58,7 @@ -export([get_log_type/1, set_log_type/2]). -export([get_request_limit/1, set_request_limit/2]). -export([invalidate_ca_cache/0]). +-export([increment_counter/3]). -export([restart_worker/1, restart_set_worker/1]). %% Internal exports @@ -259,6 +260,29 @@ update_mibs_cache_age(Agent, Age) -> call(Agent, {mibs_cache_request, {update_age, Age}}). +increment_counter(Counter, Initial, Max) -> + %% This is to make sure no one else increments our counter + Key = {Counter, self()}, + + %% Counter data + Position = 2, + Increment = 1, + Threshold = Max, + SetValue = Initial, + UpdateOp = {Position, Increment, Threshold, SetValue}, + + %% And now for the actual increment + Tab = snmp_agent_table, + case (catch ets:update_counter(Tab, Key, UpdateOp)) of + {'EXIT', {badarg, _}} -> + %% Oups, first time + ets:insert(Tab, {Key, Initial}), + Initial; + Next when is_integer(Next) -> + Next + end. + + init([Prio, Parent, Ref, Options]) -> ?d("init -> entry with" "~n Prio: ~p" @@ -1223,79 +1247,23 @@ handle_mibs_cache_request(MibServer, Req) -> %% Downgrade %% -code_change({down, _Vsn}, S, downgrade_to_pre_4_13) -> - S1 = workers_restart(S), - case S1#state.disco of - undefined -> - ok; - #disco{from = From, - sender = Sender, - stage = Stage} -> - gen_server:reply(From, {error, {upgrade, Stage, Sender}}), - exit(Sender, kill) - end, - S2 = {state, - S1#state.type, - S1#state.parent, - S1#state.worker, - S1#state.worker_state, - S1#state.set_worker, - S1#state.multi_threaded, - S1#state.ref, - S1#state.vsns, - S1#state.nfilters, - S1#state.note_store, - S1#state.mib_server, - S1#state.net_if, - S1#state.net_if_mod, - S1#state.backup, - S1#state.disco}, - {ok, S2}; +%% code_change({down, _Vsn}, S, downgrade_to_pre_4_13) -> +%% {ok, S2}; %% Upgrade %% -code_change(_Vsn, S, upgrade_from_pre_4_13) -> - {state, - Type, - Parent, - Worker, - WorkerState, - SetWorker, - MultiThreaded, - Ref, - Vsns, - NFilters = [], - NoteStore, - MibServer, %% Currently unused - NetIf, %% Currently unused - NetIfMod, - Backup} = S, - S1 = #state{type = Type, - parent = Parent, - worker = Worker, - worker_state = WorkerState, - set_worker = SetWorker, - multi_threaded = MultiThreaded, - ref = Ref, - vsns = Vsns, - nfilters = NFilters, - note_store = NoteStore, - mib_server = MibServer, - net_if = NetIf, - net_if_mod = NetIfMod, - backup = Backup}, - S2 = workers_restart(S1), - {ok, S2}; +%% code_change(_Vsn, S, upgrade_from_pre_4_13) -> +%% {ok, S2}; code_change(_Vsn, S, _Extra) -> {ok, S}. -workers_restart(#state{worker = W, set_worker = SW} = S) -> - Worker = worker_restart(W), - SetWorker = set_worker_restart(SW), - S#state{worker = Worker, - set_worker = SetWorker}. +%% workers_restart(#state{worker = W, set_worker = SW} = S) -> +%% Worker = worker_restart(W), +%% SetWorker = set_worker_restart(SW), +%% S#state{worker = Worker, +%% set_worker = SetWorker}. %%----------------------------------------------------------------- @@ -1321,8 +1289,8 @@ set_worker_start() -> worker_start(Dict) -> proc_lib:spawn_link(?MODULE, worker, [self(), Dict]). -worker_stop(Pid) -> - worker_stop(Pid, infinity). +%% worker_stop(Pid) -> +%% worker_stop(Pid, infinity). worker_stop(Pid, Timeout) when is_pid(Pid) -> Pid ! terminate, @@ -1336,17 +1304,17 @@ worker_stop(Pid, Timeout) when is_pid(Pid) -> worker_stop(_, _) -> ok. -set_worker_restart(Pid) -> - worker_restart(Pid, [{master, self()} | get()]). +%% set_worker_restart(Pid) -> +%% worker_restart(Pid, [{master, self()} | get()]). -worker_restart(Pid) -> - worker_restart(Pid, get()). +%% worker_restart(Pid) -> +%% worker_restart(Pid, get()). -worker_restart(Pid, Dict) when is_pid(Pid) -> - worker_stop(Pid), - worker_start(Dict); -worker_restart(Any, _Dict) -> - Any. +%% worker_restart(Pid, Dict) when is_pid(Pid) -> +%% worker_stop(Pid), +%% worker_start(Dict); +%% worker_restart(Any, _Dict) -> +%% Any. %%----------------------------------------------------------------- diff --git a/lib/snmp/src/agent/snmpa_net_if.erl b/lib/snmp/src/agent/snmpa_net_if.erl index d703e5ac55..bc0777a7dd 100644 --- a/lib/snmp/src/agent/snmpa_net_if.erl +++ b/lib/snmp/src/agent/snmpa_net_if.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2004-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2004-2010. 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 %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% -module(snmpa_net_if). @@ -55,6 +55,9 @@ -define(DEFAULT_FILTER_MODULE, snmpa_net_if_filter). -define(DEFAULT_FILTER_OPTS, [{module, ?DEFAULT_FILTER_MODULE}]). +-define(ATL_SEQNO_INITIAL, 1). +-define(ATL_SEQNO_MAX, 2147483647). + %%%----------------------------------------------------------------- %%% This module implements the default Network Interface part @@ -194,24 +197,43 @@ do_init(Prio, NoteStore, MasterAgent, Parent, Opts) -> {error, {udp_open, UDPPort, Reason}} end. + create_log() -> case ets:lookup(snmp_agent_table, audit_trail_log) of [] -> {undefined, []}; [{audit_trail_log, AtlOpts}] -> - ?vtrace("AtlOpts: ~p",[AtlOpts]), + ?vtrace("AtlOpts: ~p", [AtlOpts]), Type = get_atl_type(AtlOpts), Dir = get_atl_dir(AtlOpts), Size = get_atl_size(AtlOpts), Repair = get_atl_repair(AtlOpts), Name = ?audit_trail_log_name, File = filename:absname(?audit_trail_log_file, Dir), - case snmp_log:create(Name, File, Size, Repair, true) of - {ok, Log} -> - ?vdebug("log created: ~w",[Log]), - {Log, Type}; - {error, Reason} -> - throw({error, {create_log, Reason}}) + case get_atl_seqno(AtlOpts) of + true -> + Initial = ?ATL_SEQNO_INITIAL, + Max = ?ATL_SEQNO_MAX, + Module = snmpa_agent, + Function = increment_counter, + Args = [atl_seqno, Initial, Max], + SeqNoGen = {Module, Function, Args}, + case snmp_log:create(Name, File, + SeqNoGen, Size, Repair, true) of + {ok, Log} -> + ?vdebug("log created: ~w", [Log]), + {Log, Type}; + {error, Reason} -> + throw({error, {create_log, Reason}}) + end; + _ -> + case snmp_log:create(Name, File, Size, Repair, true) of + {ok, Log} -> + ?vdebug("log created: ~w", [Log]), + {Log, Type}; + {error, Reason} -> + throw({error, {create_log, Reason}}) + end end end. @@ -918,60 +940,23 @@ system_continue(_Parent, _Dbg, S) -> loop(S). system_terminate(Reason, _Parent, _Dbg, #state{log = Log}) -> + ?vlog("system-terminate -> entry with" + "~n Reason: ~p", [Reason]), do_close_log(Log), exit(Reason). -system_code_change(OldState, _Module, _OldVsn, upgrade_from_pre_4_10) -> - {state, - parent = Parent, - note_store = NS, - master_agent = MA, - usock = Sock, - usock_opts = SockOpts, - mpd_state = MpdState, - log = Log, - reqs = Reqs, - debug = Dbg, - limit = Limit, - rcnt = RCNT} = OldState, - NewState = #state{parent = Parent, - note_store = NS, - master_agent = MA, - usock = Sock, - usock_opts = SockOpts, - mpd_state = MpdState, - log = Log, - reqs = Reqs, - debug = Dbg, - limit = Limit, - rcnt = RCNT, - filter = create_filter(?DEFAULT_FILTER_OPTS)}, +system_code_change(OldState, _Module, _OldVsn, upgrade_from_pre_4_16) -> + Initial = ?ATL_SEQNO_INITIAL, + Max = ?ATL_SEQNO_MAX, + Module = snmpa_agent, + Function = increment_counter, + Args = [atl_seqno, Initial, Max], + SeqNoGen = {Module, Function, Args}, + NewLog = snmp_log:upgrade(OldState#state.log, SeqNoGen), + NewState = OldState#state{log = NewLog}, {ok, NewState}; -system_code_change(OldState, _Module, _OldVsn, downgrade_to_pre_4_10) -> - #state{parent = Parent, - note_store = NS, - master_agent = MA, - usock = Sock, - usock_opts = SockOpts, - mpd_state = MpdState, - log = Log, - reqs = Reqs, - debug = Dbg, - limit = Limit, - rcnt = RCNT} = OldState, - NewState = - {state, - parent = Parent, - note_store = NS, - master_agent = MA, - usock = Sock, - usock_opts = SockOpts, - mpd_state = MpdState, - log = Log, - reqs = Reqs, - debug = Dbg, - limit = Limit, - rcnt = RCNT}, +system_code_change(OldState, _Module, _OldVsn, downgrade_to_pre_4_16) -> + NewState = OldState#state{log = snmp_log:downgrade(OldState#state.log)}, {ok, NewState}; system_code_change(S, _Module, _OldVsn, _Extra) -> {ok, S}. @@ -1111,6 +1096,9 @@ get_atl_size(Opts) -> get_atl_repair(Opts) -> snmp_misc:get_option(repair, Opts, true). +get_atl_seqno(Opts) -> + snmp_misc:get_option(seqno, Opts, false). + get_verbosity(Opts) -> snmp_misc:get_option(verbosity, Opts, ?default_verbosity). diff --git a/lib/snmp/src/agent/snmpa_usm.erl b/lib/snmp/src/agent/snmpa_usm.erl index a8c395534f..12a6b996ff 100644 --- a/lib/snmp/src/agent/snmpa_usm.erl +++ b/lib/snmp/src/agent/snmpa_usm.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1999-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1999-2010. 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 %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% -module(snmpa_usm). @@ -396,7 +396,9 @@ try_decrypt(?usmDESPrivProtocol, case (catch des_decrypt(PrivKey, UsmSecParams, EncryptedPDU)) of {ok, DecryptedData} -> DecryptedData; - _ -> + Error -> + ?vlog("try_decrypt -> failed DES decrypt" + "~n Error: ~p", [Error]), error(usmStatsDecryptionErrors, ?usmStatsDecryptionErrors_instance, % OTP-5464 SecName) @@ -406,7 +408,9 @@ try_decrypt(?usmAesCfb128Protocol, case (catch aes_decrypt(PrivKey, UsmSecParams, EncryptedPDU)) of {ok, DecryptedData} -> DecryptedData; - _ -> + Error -> + ?vlog("try_decrypt -> failed AES decrypt" + "~n Error: ~p", [Error]), error(usmStatsDecryptionErrors, ?usmStatsDecryptionErrors_instance, % OTP-5464 SecName) diff --git a/lib/snmp/src/app/snmp.appup.src b/lib/snmp/src/app/snmp.appup.src index 0b8f0bbddd..74747b2e59 100644 --- a/lib/snmp/src/app/snmp.appup.src +++ b/lib/snmp/src/app/snmp.appup.src @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1999-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1999-2010. 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 %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% @@ -24,10 +24,21 @@ [ {"4.15", [ + {load_module, snmpa, soft_purge, soft_purge, [snmp_log]}, + {load_module, snmp_log, soft_purge, soft_purge, []}, + {update, snmpa_net_if, {advanced, upgrade_from_pre_4_16}, + soft_purge, soft_purge, [snmpa_agent, snmp_log]}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []} ] }, {"4.14", [ + {load_module, snmpa, soft_purge, soft_purge, [snmp_log]}, + {load_module, snmp_log, soft_purge, soft_purge, []}, + {update, snmpa_net_if, {advanced, upgrade_from_pre_4_16}, + soft_purge, soft_purge, [snmpa_agent, snmp_log]}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []}, + {load_module, snmpm_user, soft_purge, soft_purge, []}, {load_module, snmpm_user_default, soft_purge, soft_purge, [snmpm_user]}, {update, snmpm_server, soft, soft_purge, soft_purge, @@ -36,11 +47,15 @@ }, {"4.13.5", [ - {load_module, snmpm_user, soft_purge, soft_purge, []}, - {load_module, snmpm_user_default, soft_purge, soft_purge, [snmpm_user]}, {load_module, snmpa_mib_data, soft_purge, soft_purge, []}, + {load_module, snmpa, soft_purge, soft_purge, [snmp_log]}, + {load_module, snmp_log, soft_purge, soft_purge, []}, + {update, snmpa_net_if, {advanced, upgrade_from_pre_4_16}, + soft_purge, soft_purge, [snmpa_agent, snmp_log]}, {update, snmpa_agent, soft, soft_purge, soft_purge, []}, - {update, snmpa_net_if, soft, soft_purge, soft_purge, []}, + + {load_module, snmpm_user, soft_purge, soft_purge, []}, + {load_module, snmpm_user_default, soft_purge, soft_purge, [snmpm_user]}, {update, snmpm_config, soft, soft_purge, soft_purge, []}, {update, snmpm_server, soft, soft_purge, soft_purge, [snmpm_user_default]}, {add_module, snmpm_net_if_filter}, @@ -54,10 +69,21 @@ [ {"4.15", [ + {load_module, snmpa, soft_purge, soft_purge, [snmp_log]}, + {load_module, snmp_log, soft_purge, soft_purge, []}, + {update, snmpa_net_if, {advanced, downgrade_to_pre_4_16}, + soft_purge, soft_purge, [snmpa_agent, snmp_log]}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []} ] }, {"4.14", [ + {load_module, snmpa, soft_purge, soft_purge, [snmp_log]}, + {load_module, snmp_log, soft_purge, soft_purge, []}, + {update, snmpa_net_if, {advanced, downgrade_to_pre_4_16}, + soft_purge, soft_purge, [snmpa_agent, snmp_log]}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []}, + {load_module, snmpm_user, soft_purge, soft_purge, []}, {load_module, snmpm_user_default, soft_purge, soft_purge, [snmpm_user]}, {update, snmpm_server, soft, soft_purge, soft_purge, [snmpm_user_default]} @@ -65,11 +91,15 @@ }, {"4.13.5", [ - {load_module, snmpm_user, soft_purge, soft_purge, []}, - {load_module, snmpm_user_default, soft_purge, soft_purge, [snmpm_user]}, {load_module, snmpa_mib_data, soft_purge, soft_purge, []}, + {load_module, snmpa, soft_purge, soft_purge, [snmp_log]}, + {load_module, snmp_log, soft_purge, soft_purge, []}, + {update, snmpa_net_if, {advanced, downgrade_to_pre_4_16}, + soft_purge, soft_purge, [snmpa_agent, snmp_log]}, {update, snmpa_agent, soft, soft_purge, soft_purge, []}, - {update, snmpa_net_if, soft, soft_purge, soft_purge, []}, + + {load_module, snmpm_user, soft_purge, soft_purge, []}, + {load_module, snmpm_user_default, soft_purge, soft_purge, [snmpm_user]}, {update, snmpm_config, soft, soft_purge, soft_purge, []}, {update, snmpm_server, soft, soft_purge, soft_purge, [snmpm_user_default]}, {remove, {snmpm_net_if_filter, soft_purge, brutal_purge}}, diff --git a/lib/snmp/src/manager/snmpm_config.erl b/lib/snmp/src/manager/snmpm_config.erl index 1a5400bf8e..e4069485ad 100644 --- a/lib/snmp/src/manager/snmpm_config.erl +++ b/lib/snmp/src/manager/snmpm_config.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2004-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2004-2010. 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 %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% ------------------------------------------------------------------------- @@ -63,6 +63,7 @@ cre_counter/2, incr_counter/2, + increment_counter/3, increment_counter/4, cre_stats_counter/2, maybe_cre_stats_counter/2, @@ -792,6 +793,34 @@ incr_counter(Counter, Incr, Wrap) -> end. +%% +increment_counter(Counter, Initial, Max) -> + Increment = 1, + increment_counter(Counter, Initial, Increment, Max). + +increment_counter(Counter, Initial, Increment, Max) -> + %% This is to make sure no one else increments our counter + Key = {Counter, self()}, + + %% Counter data + Position = 2, + Threshold = Max, + SetValue = Initial, + UpdateOp = {Position, Increment, Threshold, SetValue}, + + %% And now for the actual increment + Tab = snmpm_counter_table, + case (catch ets:update_counter(Tab, Key, UpdateOp)) of + {'EXIT', {badarg, _}} -> + %% Oups, first time + ets:insert(Tab, {Key, Initial}), + Initial; + Next when is_integer(Next) -> + Next + end. +%% + + maybe_cre_stats_counter(Counter, Initial) -> case ets:lookup(snmpm_stats_table, Counter) of [_] -> @@ -1013,14 +1042,16 @@ do_init(Opts) -> AuditTrailLogOpts -> ?vtrace("ATL options: ~p", [AuditTrailLogOpts]), ets:insert(snmpm_config_table, {audit_trail_log, true}), - LogDir = get_atl_dir(AuditTrailLogOpts), - LogType = get_atl_type(AuditTrailLogOpts), - LogSize = get_atl_size(AuditTrailLogOpts), - LogRep = get_atl_repair(AuditTrailLogOpts), + LogDir = get_atl_dir(AuditTrailLogOpts), + LogType = get_atl_type(AuditTrailLogOpts), + LogSize = get_atl_size(AuditTrailLogOpts), + LogRep = get_atl_repair(AuditTrailLogOpts), + LogSeqNo = get_atl_seqno(AuditTrailLogOpts), ets:insert(snmpm_config_table, {audit_trail_log_dir, LogDir}), ets:insert(snmpm_config_table, {audit_trail_log_type, LogType}), ets:insert(snmpm_config_table, {audit_trail_log_size, LogSize}), - ets:insert(snmpm_config_table, {audit_trail_log_repair, LogRep}) + ets:insert(snmpm_config_table, {audit_trail_log_repair, LogRep}), + ets:insert(snmpm_config_table, {audit_trail_log_seqno, LogSeqNo}) end, %% -- System default agent config -- @@ -1398,6 +1429,9 @@ verify_audit_trail_log_opts([{size, Size}|Opts]) -> verify_audit_trail_log_opts([{repair, Repair}|Opts]) -> verify_log_repair(Repair), verify_audit_trail_log_opts(Opts); +verify_audit_trail_log_opts([{seqno, SeqNo}|Opts]) -> + verify_log_seqno(SeqNo), + verify_audit_trail_log_opts(Opts); verify_audit_trail_log_opts([Opt|_Opts]) -> error({invalid_audit_trail_log_option, Opt}). @@ -1440,6 +1474,11 @@ verify_log_repair(truncate) -> ok; verify_log_repair(Repair) -> error({invalid_audit_trail_log_repair, Repair}). +verify_log_seqno(true) -> ok; +verify_log_seqno(false) -> ok; +verify_log_seqno(SeqNo) -> + error({invalid_audit_trail_log_seqno, SeqNo}). + verify_module(_, Mod) when is_atom(Mod) -> ok; @@ -3040,6 +3079,9 @@ get_atl_size(Opts) -> get_atl_repair(Opts) -> get_opt(repair, Opts, truncate). +get_atl_seqno(Opts) -> + get_opt(seqno, Opts, false). + %%---------------------------------------------------------------------- diff --git a/lib/snmp/src/manager/snmpm_net_if.erl b/lib/snmp/src/manager/snmpm_net_if.erl index 14d39933dc..4ec24af7f3 100644 --- a/lib/snmp/src/manager/snmpm_net_if.erl +++ b/lib/snmp/src/manager/snmpm_net_if.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2004-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2004-2010. 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 %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% @@ -81,6 +81,9 @@ -define(IRGC_TIMEOUT, timer:minutes(5)). +-define(ATL_SEQNO_INITIAL, 1). +-define(ATL_SEQNO_MAX, 2147483647). + %%%------------------------------------------------------------------- %%% API @@ -297,11 +300,29 @@ do_init_log(true) -> {ok, Repair} = snmpm_config:system_info(audit_trail_log_repair), Name = ?audit_trail_log_name, File = filename:absname(?audit_trail_log_file, Dir), - case snmp_log:create(Name, File, Size, Repair, true) of - {ok, Log} -> - {Log, Type}; - {error, Reason} -> - throw({error, {failed_create_audit_log, Reason}}) + case snmpm_config:system_info(audit_trail_log_seqno) of + {ok, true} -> + Initial = ?ATL_SEQNO_INITIAL, + Max = ?ATL_SEQNO_MAX, + Module = snmpm_config, + Function = increment_counter, + Args = [atl_seqno, Initial, Max], + SeqNoGen = {Module, Function, Args}, + case snmp_log:create(Name, File, + SeqNoGen, Size, Repair, true) of + {ok, Log} -> + ?vdebug("log created: ~w", [Log]), + {Log, Type}; + {error, Reason} -> + throw({error, {failed_create_audit_log, Reason}}) + end; + _ -> + case snmp_log:create(Name, File, Size, Repair, true) of + {ok, Log} -> + {Log, Type}; + {error, Reason} -> + throw({error, {failed_create_audit_log, Reason}}) + end end. @@ -441,32 +462,15 @@ do_close_log(_) -> %% Returns: {ok, NewState} %%---------------------------------------------------------------------- -code_change({down, _Vsn}, OldState, downgrade_to_pre45) -> +code_change({down, _Vsn}, OldState, downgrade_to_pre_4_16) -> ?d("code_change(down) -> entry", []), - #state{server = Server, - note_store = NoteStore, - sock = Sock, - mpd_state = MpdState, - log = Log, - irgc = IrGcRef} = OldState, - irgc_stop(IrGcRef), - (catch ets:delete(snmpm_inform_request_table)), - State = {state, Server, NoteStore, Sock, MpdState, Log}, + State = OldState#state{log = snmp_log:downgrade(OldState#state.log)}, {ok, State}; % upgrade -code_change(_Vsn, OldState, upgrade_from_pre45) -> +code_change(_Vsn, OldState, upgrade_from_pre_4_16) -> ?d("code_change(up) -> entry", []), - {state, Server, NoteStore, Sock, MpdState, Log} = OldState, - State = #state{server = Server, - note_store = NoteStore, - sock = Sock, - mpd_state = MpdState, - log = Log, - irb = auto, - irgc = undefined}, - ets:new(snmpm_inform_request_table, - [set, protected, named_table, {keypos, 1}]), + State = OldState#state{log = snmp_log:upgrade(OldState#state.log)}, {ok, State}; code_change(_Vsn, State, _Extra) -> diff --git a/lib/snmp/src/misc/snmp_config.erl b/lib/snmp/src/misc/snmp_config.erl index ad41eaf160..0ee373a4d4 100644 --- a/lib/snmp/src/misc/snmp_config.erl +++ b/lib/snmp/src/misc/snmp_config.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1996-2010. 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 %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% @@ -327,10 +327,15 @@ config_agent_sys() -> ATLRepair = ask("23f. Audit trail log repair " "(true/false/truncate/snmp_repair)?", "true", fun verify_atl_repair/1), + ATLSeqNo = ask("23g. Audit trail log " + "sequence-numbering (true/false)?", + "false", + fun verify_atl_seqno/1), [{audit_trail_log, [{type, ATLType}, {dir, ATLDir}, {size, ATLSize}, - {repair, ATLRepair}]}]; + {repair, ATLRepair}, + {seqno, ATLSeqNo}]}]; no -> [] end, @@ -400,8 +405,39 @@ config_agent_sys() -> NetIf = [{module, NetIfMod}, {verbosity, NetIfVerb}, {options, NetIfOpts}], + TermDiscoEnable = ask("26a. Allow terminating discovery " + "(true/false)?", "true", + fun verify_bool/1), + TermDiscoConf = + case TermDiscoEnable of + true -> + TermDiscoStage2 = + ask("26b. Second stage behaviour " + "(discovery/plain)?", "discovery", + fun verify_term_disco_behaviour/1), + TermDiscoTrigger = + ask("26c. Trigger username " + "(default/a string)?", "default", + fun verify_term_disco_trigger_username/1), + [{enable, TermDiscoEnable}, + {stage2, TermDiscoStage2}, + {trigger_username, TermDiscoTrigger}]; + false -> + [{enable, TermDiscoEnable}, + {stage2, discovery}, + {trigger_username, ""}] + end, + OrigDiscoEnable = ask("27a. Allow originating discovery " + "(true/false)?", "true", + fun verify_bool/1), + OrigDiscoConf = + [{enable, OrigDiscoEnable}], + DiscoveryConfig = + [{terminating, TermDiscoConf}, + {originating, OrigDiscoConf}], [{agent_type, master}, {agent_verbosity, MasterAgentVerb}, + {discovery, DiscoveryConfig}, {config, [{dir, ConfigDir}, {force_load, ForceLoad}, {verbosity, ConfigVerb}]}, @@ -644,23 +680,31 @@ config_manager_sys() -> "(y/n)?", "n", fun verify_yes_or_no/1) of yes -> - ATLDir = ask("19b. Where to store the " + ATLType = ask("19b. Audit trail log type " + "(write/read_write)?", + "read_write", fun verify_atl_type/1), + ATLDir = ask("19c. Where to store the " "audit trail log?", DefDir, fun verify_dir/1), - ATLMaxFiles = ask("19c. Max number of files?", + ATLMaxFiles = ask("19d. Max number of files?", "10", fun verify_pos_integer/1), - ATLMaxBytes = ask("19d. Max size (in bytes) " + ATLMaxBytes = ask("19e. Max size (in bytes) " "of each file?", "10240", fun verify_pos_integer/1), ATLSize = {ATLMaxBytes, ATLMaxFiles}, - ATLRepair = ask("19e. Audit trail log repair " + ATLRepair = ask("19f. Audit trail log repair " "(true/false/truncate/snmp_repair)?", "true", fun verify_atl_repair/1), - [{audit_trail_log, [{dir, ATLDir}, + ATLSeqNo = ask("19g. Audit trail log sequence-numbering " + "(true/false)?", "false", + fun verify_atl_seqno/1), + [{audit_trail_log, [{type, ATLType}, + {dir, ATLDir}, {size, ATLSize}, - {repair, ATLRepair}]}]; + {repair, ATLRepair}, + {seqno, ATLSeqNo}]}]; no -> [] end, @@ -1180,6 +1224,13 @@ verify_atl_repair("snmp_repair") -> verify_atl_repair(R) -> {error, "invalid audit trail log repair: " ++ R}. +verify_atl_seqno("true") -> + {ok, true}; +verify_atl_seqno("false") -> + {ok, false}; +verify_atl_seqno(SN) -> + {error, "invalid audit trail log seqno: " ++ SN}. + verify_pos_integer(I0) -> case (catch list_to_integer(I0)) of @@ -1237,6 +1288,18 @@ verify_irb_user(TO) -> end. +verify_term_disco_behaviour("discovery") -> + {ok, discovery}; +verify_term_disco_behaviour("plain") -> + {ok, plain}; +verify_term_disco_behaviour(B) -> + {error, "invalid terminating discovery behaviour: " ++ B}. + +verify_term_disco_trigger_username("default") -> + {ok, ""}; +verify_term_disco_trigger_username(Trigger) -> + {ok, Trigger}. + verify_user_id(UserId) when is_list(UserId) -> case (catch list_to_atom(UserId)) of @@ -2096,6 +2159,10 @@ write_sys_config_file_agent_opt(Fid, {audit_trail_log, Opts}) -> ok = io:format(Fid, " {audit_trail_log, [", []), write_sys_config_file_agent_atl_opts(Fid, Opts), ok = io:format(Fid, "}", []); +write_sys_config_file_agent_opt(Fid, {discovery, Opts}) -> + ok = io:format(Fid, " {discovery, [", []), + write_sys_config_file_agent_disco_opts(Fid, Opts), + ok = io:format(Fid, "}", []); write_sys_config_file_agent_opt(Fid, {net_if, Opts}) -> ok = io:format(Fid, " {net_if, ~w}", [Opts]); write_sys_config_file_agent_opt(Fid, {mib_server, Opts}) -> @@ -2139,7 +2206,58 @@ write_sys_config_file_agent_atl_opt(Fid, {type, Type}) -> write_sys_config_file_agent_atl_opt(Fid, {size, Size}) -> ok = io:format(Fid, "{size, ~w}", [Size]); write_sys_config_file_agent_atl_opt(Fid, {repair, Rep}) -> - ok = io:format(Fid, "{repair, ~w}", [Rep]). + ok = io:format(Fid, "{repair, ~w}", [Rep]); +write_sys_config_file_agent_atl_opt(Fid, {seqno, SeqNo}) -> + ok = io:format(Fid, "{seqno, ~w}", [SeqNo]). + + +%% These options are allways there +write_sys_config_file_agent_disco_opts(Fid, [Opt]) -> + write_sys_config_file_agent_disco_opt(Fid, Opt), + ok = io:format(Fid, "]", []), + ok; +write_sys_config_file_agent_disco_opts(Fid, [Opt|Opts]) -> + write_sys_config_file_agent_disco_opt(Fid, Opt), + ok = io:format(Fid, ", ", []), + write_sys_config_file_agent_disco_opts(Fid, Opts). + +write_sys_config_file_agent_disco_opt(Fid, {terminating, Opts}) -> + ok = io:format(Fid, "{terminating, [", []), + write_sys_config_file_agent_term_disco_opts(Fid, Opts), + ok = io:format(Fid, "}", []); +write_sys_config_file_agent_disco_opt(Fid, {originating, Opts}) -> + ok = io:format(Fid, "{originating, [", []), + write_sys_config_file_agent_orig_disco_opts(Fid, Opts), + ok = io:format(Fid, "}", []). + +write_sys_config_file_agent_term_disco_opts(Fid, [Opt]) -> + write_sys_config_file_agent_term_disco_opt(Fid, Opt), + ok = io:format(Fid, "]", []), + ok; +write_sys_config_file_agent_term_disco_opts(Fid, [Opt|Opts]) -> + write_sys_config_file_agent_term_disco_opt(Fid, Opt), + ok = io:format(Fid, ", ", []), + write_sys_config_file_agent_term_disco_opts(Fid, Opts). + +write_sys_config_file_agent_term_disco_opt(Fid, {enable, Enable}) -> + ok = io:format(Fid, "{enable, ~w}", [Enable]); +write_sys_config_file_agent_term_disco_opt(Fid, {stage2, Stage2}) -> + ok = io:format(Fid, "{stage2, ~w}", [Stage2]); +write_sys_config_file_agent_term_disco_opt(Fid, {trigger_username, Trigger}) -> + ok = io:format(Fid, "{trigger_username, \"~s\"}", [Trigger]). + +write_sys_config_file_agent_orig_disco_opts(Fid, [Opt]) -> + write_sys_config_file_agent_orig_disco_opt(Fid, Opt), + ok = io:format(Fid, "]", []), + ok; +write_sys_config_file_agent_orig_disco_opts(Fid, [Opt|Opts]) -> + write_sys_config_file_agent_orig_disco_opt(Fid, Opt), + ok = io:format(Fid, ", ", []), + write_sys_config_file_agent_orig_disco_opts(Fid, Opts). + +write_sys_config_file_agent_orig_disco_opt(Fid, {enable, Enable}) -> + ok = io:format(Fid, "{enable, ~w}", [Enable]). + write_sys_config_file_manager_opts(Fid, [Opt]) -> diff --git a/lib/snmp/src/misc/snmp_log.erl b/lib/snmp/src/misc/snmp_log.erl index c3932ccc08..9f4fdf97ca 100644 --- a/lib/snmp/src/misc/snmp_log.erl +++ b/lib/snmp/src/misc/snmp_log.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1997-2010. 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 %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% @@ -21,12 +21,19 @@ -export([ - create/4, create/5, + create/4, create/5, create/6, change_size/2, close/1, sync/1, info/1, log/4, log_to_txt/5, log_to_txt/6, log_to_txt/7, log_to_io/4, log_to_io/5, log_to_io/6 ]). +-export([ + upgrade/1, upgrade/2, + downgrade/1 + ]). +-export([ + validate/1, validate/2 + ]). -define(SNMP_USE_V3, true). @@ -38,30 +45,74 @@ -define(LOG_FORMAT, internal). -define(LOG_TYPE, wrap). +-record(snmp_log, {id, seqno}). + %% -------------------------------------------------------------------- %% Exported functions %% -------------------------------------------------------------------- +upgrade(Log) when is_record(Log, snmp_log) -> + Log; +upgrade(Log) -> + upgrade(Log, disabled). + +upgrade(Log, _SeqNoGen) when is_record(Log, snmp_log) -> + Log; +upgrade(Log, {M, F, A} = SeqNoGen) + when (is_atom(M) andalso is_atom(F) andalso is_list(A)) -> + #snmp_log{id = Log, seqno = SeqNoGen}; +upgrade(Log, SeqNoGen) + when is_function(SeqNoGen, 0) -> + #snmp_log{id = Log, seqno = SeqNoGen}; +upgrade(Log, disabled = SeqNoGen) -> + #snmp_log{id = Log, seqno = SeqNoGen}. + +downgrade(#snmp_log{id = Log}) -> + Log; +downgrade(Log) -> + Log. + %% -- create --- create(Name, File, Size, Repair) -> - create(Name, File, Size, Repair, false). - -create(Name, File, Size, Repair, Notify) -> + create(Name, File, disabled, Size, Repair, false). + +create(Name, File, Size, Repair, Notify) + when (((Repair =:= true) orelse + (Repair =:= false) orelse + (Repair =:= truncate) orelse + (Repair =:= snmp_repair)) andalso + ((Notify =:= true) orelse + (Notify =:= false))) -> + create(Name, File, disabled, Size, Repair, Notify); +create(Name, File, SeqNoGen, Size, Repair) -> + create(Name, File, SeqNoGen, Size, Repair, false). + +create(Name, File, SeqNoGen, Size, Repair, Notify) + when (((Repair =:= true) orelse + (Repair =:= false) orelse + (Repair =:= truncate) orelse + (Repair =:= snmp_repair)) andalso + ((Notify =:= true) orelse + (Notify =:= false))) -> ?vtrace("create -> entry with" - "~n Name: ~p" - "~n File: ~p" - "~n Size: ~p" - "~n Repair: ~p" - "~n Notify: ~p", [Name, File, Size, Repair, Notify]), - log_open(Name, File, Size, Repair, Notify). + "~n Name: ~p" + "~n File: ~p" + "~n SeqNoGen: ~p" + "~n Size: ~p" + "~n Repair: ~p" + "~n Notify: ~p", [Name, File, SeqNoGen, Size, Repair, Notify]), + log_open(Name, File, SeqNoGen, Size, Repair, Notify); +create(Name, File, SeqNoGen, Size, Repair, Notify) -> + {error, {bad_args, Name, File, SeqNoGen, Size, Repair, Notify}}. + %% -- close --- -close(Log) -> +close(#snmp_log{id = Log}) -> ?vtrace("close -> entry with" "~n Log: ~p", [Log]), disk_log:close(Log). @@ -69,14 +120,25 @@ close(Log) -> %% -- close --- +sync(#snmp_log{id = Log}) -> + do_sync(Log); sync(Log) -> + do_sync(Log). + +do_sync(Log) -> ?vtrace("sync -> entry with" "~n Log: ~p", [Log]), disk_log:sync(Log). + %% -- info --- +info(#snmp_log{id = Log}) -> + do_info(Log); info(Log) -> + do_info(Log). + +do_info(Log) -> case disk_log:info(Log) of Info when is_list(Info) -> Items = [no_current_bytes, no_current_items, @@ -97,6 +159,138 @@ info_filter([Item|Items], Info, Acc) -> end. +%% -- validate -- + +%% This function is used to "validate" a log. +%% At present this means making sure all entries +%% are in the proper order, and if sequence numbering +%% is used that no entries are missing. +%% It is intended to be used for testing. + +validate(Log) -> + validate(Log, false). + +validate(#snmp_log{id = Log}, SeqNoReq) -> + validate(Log, SeqNoReq); +validate(Log, SeqNoReq) + when ((SeqNoReq =:= true) orelse (SeqNoReq =:= false)) -> + Validator = + fun({Timestamp, SeqNo, _Packet, _Addr, _Port}, {PrevTS, PrevSN}) -> + ?vtrace("validating log entry when" + "~n Timestamp: ~p" + "~n SeqNo: ~p" + "~n PrevTS: ~p" + "~n PrevSN: ~p", + [Timestamp, SeqNo, PrevTS, PrevSN]), + validate_timestamp(PrevTS, Timestamp), + validate_seqno(PrevSN, SeqNo), + {Timestamp, SeqNo}; + + ({Timestamp, _Packet, _Addr, _Port}, {PrevTS, _PrevSN}) when SeqNoReq =:= true -> + ?vtrace("validating log entry when" + "~n Timestamp: ~p" + "~n PrevTS: ~p", + [Timestamp, PrevTS]), + throw({error, {missing_seqno, Timestamp}}); + + ({Timestamp, _Packet, _Addr, _Port}, {PrevTS, PrevSN}) -> + ?vtrace("validating log entry when" + "~n Timestamp: ~p" + "~n PrevTS: ~p", + [Timestamp, PrevTS]), + validate_timestamp(PrevTS, Timestamp), + {Timestamp, PrevSN}; + + (E, Acc) -> + ?vtrace("validating bad log entry when" + "~n E: ~p" + "~n Acc: ~p", + [E, Acc]), + throw({error, {bad_entry, E, Acc}}) + end, + try + begin + validate_loop(disk_log:chunk(Log, start), + Log, Validator, first, first) + end + catch + throw:Error -> + Error + end. + +%% We shall check that TS2 >= TS1 +validate_timestamp(first, _TS2) -> + ok; +validate_timestamp({LT1, UT1} = TS1, {LT2, UT2} = TS2) -> + LT1_Secs = calendar:datetime_to_gregorian_seconds(LT1), + UT1_Secs = calendar:datetime_to_gregorian_seconds(UT1), + LT2_Secs = calendar:datetime_to_gregorian_seconds(LT2), + UT2_Secs = calendar:datetime_to_gregorian_seconds(UT2), + case ((LT2_Secs >= LT1_Secs) andalso (UT2_Secs >= UT1_Secs)) of + true -> + ok; + false -> + throw({error, {invalid_timestamp, TS1, TS2}}) + end; +validate_timestamp(TS1, TS2) -> + throw({error, {bad_timestamp, TS1, TS2}}). + + +%% The usual case when SN2 = SN1 + 1 +validate_seqno(first, SN2) + when is_integer(SN2) >= 1 -> + ok; + +%% The usual case when SN2 = SN1 + 1 +validate_seqno(SN1, SN2) + when is_integer(SN1) andalso is_integer(SN2) andalso + (SN2 =:= (SN1 + 1)) andalso (SN1 >= 1) -> + ok; + +%% The case when we have a wrap +validate_seqno(SN1, SN2) + when is_integer(SN1) andalso is_integer(SN2) andalso + (SN2 < SN1) andalso (SN2 >= 1) -> + ok; + +%% And everything else must be an error... +validate_seqno(SN1, SN2) -> + throw({error, {bad_seqno, SN1, SN2}}). + +validate_loop(eof, _Log, _Validatior, _PrevTS, _PrevSN) -> + ok; +validate_loop({error, _} = Error, _Log, _Validator, _PrevTS, _PrevSN) -> + Error; +validate_loop({corrupt_log_file, _} = Reason, + _Log, _Validator, _PrevTS, _PrevSN) -> + {error, Reason}; +validate_loop({Cont, Terms}, Log, Validator, PrevTS, PrevSN) -> + ?vtrace("validate_loop -> entry with" + "~n Terms: ~p" + "~n PrevTS: ~p" + "~n PrevSN: ~p", [Terms, PrevTS, PrevSN]), + {NextTS, NextSN} = lists:foldl(Validator, {PrevTS, PrevSN}, Terms), + ?vtrace("validate_loop -> " + "~n NextTS: ~p" + "~n NextSN: ~p", [NextTS, NextSN]), + validate_loop(disk_log:chunk(Log, Cont), Log, Validator, NextTS, NextSN); +validate_loop({Cont, Terms, BadBytes}, Log, Validator, PrevTS, PrevSN) -> + ?vtrace("validate_loop -> entry with" + "~n Terms: ~p" + "~n BadBytes: ~p" + "~n PrevTS: ~p" + "~n PrevSN: ~p", [Terms, BadBytes, PrevTS, PrevSN]), + error_logger:error_msg("Skipping ~w bytes while validating ~p~n~n", + [BadBytes, Log]), + {NextTS, NextSN} = lists:foldl(Validator, {PrevTS, PrevSN}, Terms), + ?vtrace("validate_loop -> " + "~n NextTS: ~p" + "~n NextSN: ~p", [NextTS, NextSN]), + validate_loop(disk_log:chunk(Log, Cont), Log, Validator, NextTS, NextSN); +validate_loop(Error, _Log, _Write, _PrevTS, _PrevSN) -> + Error. + + %% -- log --- %%----------------------------------------------------------------- @@ -109,19 +303,48 @@ info_filter([Item|Items], Info, Acc) -> %%----------------------------------------------------------------- -log(Log, Packet, Addr, Port) -> +log(#snmp_log{id = Log, seqno = SeqNo}, Packet, Addr, Port) -> ?vtrace("log -> entry with" "~n Log: ~p" "~n Addr: ~p" "~n Port: ~p", [Log, Addr, Port]), - Entry = {timestamp(), Packet, Addr, Port}, - disk_log:alog(Log, Entry). + Entry = make_entry(SeqNo, Packet, Addr, Port), +%% io:format("log -> " +%% "~n Entry: ~p" +%% "~n Info: ~p" +%% "~n", [Entry, disk_log:info(Log)]), + Res = disk_log:alog(Log, Entry), +%% io:format("log -> " +%% "~n Res: ~p" +%% "~n Info: ~p" +%% "~n", [Res, disk_log:info(Log)]), + %% disk_log:sync(Log), + Res. + + + +make_entry(SeqNoGen, Packet, Addr, Port) -> + try next_seqno(SeqNoGen) of + disabled -> + {timestamp(), Packet, Addr, Port}; + {ok, NextSeqNo} -> + {timestamp(), NextSeqNo, Packet, Addr, Port} + catch + _:_ -> + {timestamp(), Packet, Addr, Port} + end. +next_seqno({M, F, A}) -> + {ok, apply(M, F, A)}; +next_seqno(F) when is_function(F) -> + {ok, F()}; +next_seqno(_) -> + disabled. %% -- change_size --- -change_size(Log, NewSize) -> +change_size(#snmp_log{id = Log}, NewSize) -> ?vtrace("change_size -> entry with" "~n Log: ~p" "~n NewSize: ~p", [Log, NewSize]), @@ -171,6 +394,23 @@ log_to_io(Log, FileName, Dir, Mibs, Start, Stop) log_convert(Log, File, Converter). +%% -- log_to_plain --- + +%% log_to_plain(Log, FileName, Dir) -> +%% log_to_plain(Log, FileName, Dir, null, null). + +%% log_to_plain(Log, FileName, Dir, Start) -> +%% log_to_plain(Log, FileName, Dir, Start, null). + +%% log_to_plain(Log, FileName, Dir, Start, Stop) +%% when is_list(Mibs) -> +%% File = filename:join(Dir, FileName), +%% Converter = fun(L) -> +%% do_log_to_plain(L, Start, Stop) +%% end, +%% log_convert(Log, File, Converter). + + %% -------------------------------------------------------------------- %% Internal functions %% -------------------------------------------------------------------- @@ -178,7 +418,12 @@ log_to_io(Log, FileName, Dir, Mibs, Start, Stop) %% -- log_convert --- +log_convert(#snmp_log{id = Log}, File, Converter) -> + do_log_convert(Log, File, Converter); log_convert(Log, File, Converter) -> + do_log_convert(Log, File, Converter). + +do_log_convert(Log, File, Converter) -> %% First check if the caller process has already opened the %% log, because if we close an already open log we will cause %% a runtime error. @@ -274,86 +519,151 @@ loop({Cont, Terms, BadBytes}, Log, Write) -> loop(Error, _Log, _Write) -> Error. -format_msg({TimeStamp, {V3Hdr, ScopedPdu}, {Addr, Port}}, - Mib, Start, Stop) -> - format_msg({TimeStamp, {V3Hdr, ScopedPdu}, Addr, Port}, - Mib, Start, Stop); -format_msg({TimeStamp, {V3Hdr, ScopedPdu}, Addr, Port}, - Mib, Start, Stop) -> -% io:format("format_msg -> entry with" -% "~n TimeStamp: ~p" -% "~n Start: ~p" -% "~n Stop: ~p", [TimeStamp, Start, Stop]), - case timestamp_filter(TimeStamp, Start, Stop) of - true -> - case (catch snmp_pdus:dec_scoped_pdu(ScopedPdu)) of - ScopedPDU when is_record(ScopedPDU, scopedPdu) -> - Msg = #message{version = 'version-3', - vsn_hdr = V3Hdr, - data = ScopedPDU}, - f(ts2str(TimeStamp), Msg, Addr, Port, Mib); - {'EXIT', Reason} -> - format_tab("** error in log file at ~s from ~p:~w ~p\n\n", - [ts2str(TimeStamp), ip(Addr), Port, Reason]) - end; - false -> - ignore - end; -format_msg({TimeStamp, Packet, {Addr, Port}}, Mib, Start, Stop) -> - format_msg({TimeStamp, Packet, Addr, Port}, Mib, Start, Stop); -format_msg({TimeStamp, Packet, Addr, Port}, Mib, Start, Stop) -> + +format_msg(Entry, Mib, Start, Stop) -> + TimeStamp = element(1, Entry), case timestamp_filter(TimeStamp, Start, Stop) of true -> - case (catch snmp_pdus:dec_message(binary_to_list(Packet))) of - Msg when is_record(Msg, message) -> - f(ts2str(TimeStamp), Msg, Addr, Port, Mib); - {'EXIT', Reason} -> - format_tab("** error in log file ~p\n\n", [Reason]) - end; - false -> - ignore - end; -format_msg(_, _Mib, _Start, _Stop) -> + do_format_msg(Entry, Mib); + false -> + ignore + end. + +%% This is an old-style entry, that never had the sequence-number +do_format_msg({Timestamp, Packet, {Addr, Port}}, Mib) -> + do_format_msg(Timestamp, Packet, Addr, Port, Mib); + +%% This is the format without sequence-number +do_format_msg({Timestamp, Packet, Addr, Port}, Mib) -> + do_format_msg(Timestamp, Packet, Addr, Port, Mib); + +%% This is the format with sequence-number +do_format_msg({Timestamp, SeqNo, Packet, Addr, Port}, Mib) -> + do_format_msg(Timestamp, SeqNo, Packet, Addr, Port, Mib); + +%% This is crap... +do_format_msg(_, _) -> format_tab("** unknown entry in log file\n\n", []). -f(TimeStamp, #message{version = Vsn, vsn_hdr = VsnHdr, data = Data}, +do_format_msg(TimeStamp, {V3Hdr, ScopedPdu}, Addr, Port, Mib) -> + case (catch snmp_pdus:dec_scoped_pdu(ScopedPdu)) of + ScopedPDU when is_record(ScopedPDU, scopedPdu) -> + Msg = #message{version = 'version-3', + vsn_hdr = V3Hdr, + data = ScopedPDU}, + f(ts2str(TimeStamp), "", Msg, Addr, Port, Mib); + {'EXIT', Reason} -> + format_tab("** error in log file at ~s from ~p:~w ~p\n\n", + [ts2str(TimeStamp), ip(Addr), Port, Reason]) + end; +do_format_msg(TimeStamp, Packet, Addr, Port, Mib) -> + case (catch snmp_pdus:dec_message(binary_to_list(Packet))) of + Msg when is_record(Msg, message) -> + f(ts2str(TimeStamp), "", Msg, Addr, Port, Mib); + {'EXIT', Reason} -> + format_tab("** error in log file ~p\n\n", [Reason]) + end. + +do_format_msg(TimeStamp, SeqNo, {V3Hdr, ScopedPdu}, Addr, Port, Mib) -> + case (catch snmp_pdus:dec_scoped_pdu(ScopedPdu)) of + ScopedPDU when is_record(ScopedPDU, scopedPdu) -> + Msg = #message{version = 'version-3', + vsn_hdr = V3Hdr, + data = ScopedPDU}, + f(ts2str(TimeStamp), sn2str(SeqNo), Msg, Addr, Port, Mib); + {'EXIT', Reason} -> + format_tab("** error in log file at ~s from ~p:~w ~p\n\n", + [ts2str(TimeStamp), sn2str(SeqNo), + ip(Addr), Port, Reason]) + end; +do_format_msg(TimeStamp, SeqNo, Packet, Addr, Port, Mib) -> + case (catch snmp_pdus:dec_message(binary_to_list(Packet))) of + Msg when is_record(Msg, message) -> + f(ts2str(TimeStamp), sn2str(SeqNo), Msg, Addr, Port, Mib); + {'EXIT', Reason} -> + format_tab("** error in log file ~s from ~p:~w ~p\n\n", + [ts2str(TimeStamp), sn2str(SeqNo), + ip(Addr), Port, Reason]) + end. + + +%% format_msg({TimeStamp, {V3Hdr, ScopedPdu}, {Addr, Port}}, +%% Mib, Start, Stop) -> +%% format_msg({TimeStamp, {V3Hdr, ScopedPdu}, Addr, Port}, +%% Mib, Start, Stop); +%% format_msg({TimeStamp, {V3Hdr, ScopedPdu}, Addr, Port}, +%% Mib, Start, Stop) -> +%% case timestamp_filter(TimeStamp, Start, Stop) of +%% true -> +%% case (catch snmp_pdus:dec_scoped_pdu(ScopedPdu)) of +%% ScopedPDU when record(ScopedPDU, scopedPdu) -> +%% Msg = #message{version = 'version-3', +%% vsn_hdr = V3Hdr, +%% data = ScopedPDU}, +%% f(ts2str(TimeStamp), Msg, Addr, Port, Mib); +%% {'EXIT', Reason} -> +%% format_tab("** error in log file at ~s from ~p:~w ~p\n\n", +%% [ts2str(TimeStamp), ip(Addr), Port, Reason]) +%% end; +%% false -> +%% ignore +%% end; +%% format_msg({TimeStamp, Packet, {Addr, Port}}, Mib, Start, Stop) -> +%% format_msg({TimeStamp, Packet, Addr, Port}, Mib, Start, Stop); +%% format_msg({TimeStamp, Packet, Addr, Port}, Mib, Start, Stop) -> +%% case timestamp_filter(TimeStamp, Start, Stop) of +%% true -> +%% case (catch snmp_pdus:dec_message(binary_to_list(Packet))) of +%% Msg when record(Msg, message) -> +%% f(ts2str(TimeStamp), Msg, Addr, Port, Mib); +%% {'EXIT', Reason} -> +%% format_tab("** error in log file ~p\n\n", [Reason]) +%% end; +%% false -> +%% ignore +%% end; +%% format_msg(_, _Mib, _Start, _Stop) -> +%% format_tab("** unknown entry in log file\n\n", []). + +f(TimeStamp, SeqNo, + #message{version = Vsn, vsn_hdr = VsnHdr, data = Data}, Addr, Port, Mib) -> Str = format_pdu(Data, Mib), HdrStr = format_header(Vsn, VsnHdr), case get_type(Data) of trappdu -> - f_trap(TimeStamp, Vsn, HdrStr, Str, Addr, Port); + f_trap(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port); 'snmpv2-trap' -> - f_trap(TimeStamp, Vsn, HdrStr, Str, Addr, Port); + f_trap(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port); 'inform-request' -> - f_inform(TimeStamp, Vsn, HdrStr, Str, Addr, Port); + f_inform(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port); 'get-response' -> - f_response(TimeStamp, Vsn, HdrStr, Str, Addr, Port); + f_response(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port); report -> - f_report(TimeStamp, Vsn, HdrStr, Str, Addr, Port); + f_report(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port); _ -> - f_request(TimeStamp, Vsn, HdrStr, Str, Addr, Port) + f_request(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port) end. -f_request(TimeStamp, Vsn, HdrStr, Str, Addr, Port) -> - format_tab("request ~s:~w - ~s [~s] ~w\n~s", - [ip(Addr), Port, HdrStr, TimeStamp, Vsn, Str]). +f_request(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port) -> + format_tab("request ~s:~w - ~s [~s]~s ~w\n~s", + [ip(Addr), Port, HdrStr, TimeStamp, SeqNo, Vsn, Str]). -f_response(TimeStamp, Vsn, HdrStr, Str, Addr, Port) -> - format_tab("response ~s:~w - ~s [~s] ~w\n~s", - [ip(Addr), Port, HdrStr, TimeStamp, Vsn, Str]). +f_response(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port) -> + format_tab("response ~s:~w - ~s [~s]~s ~w\n~s", + [ip(Addr), Port, HdrStr, TimeStamp, SeqNo, Vsn, Str]). -f_report(TimeStamp, Vsn, HdrStr, Str, Addr, Port) -> - format_tab("report ~s:~w - ~s [~s] ~w\n~s", - [ip(Addr), Port, HdrStr, TimeStamp, Vsn, Str]). +f_report(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port) -> + format_tab("report ~s:~w - ~s [~s]~s ~w\n~s", + [ip(Addr), Port, HdrStr, TimeStamp, SeqNo, Vsn, Str]). -f_trap(TimeStamp, Vsn, HdrStr, Str, Addr, Port) -> - format_tab("trap ~s:~w - ~s [~s] ~w\n~s", - [ip(Addr), Port, HdrStr, TimeStamp, Vsn, Str]). +f_trap(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port) -> + format_tab("trap ~s:~w - ~s [~s]~s ~w\n~s", + [ip(Addr), Port, HdrStr, TimeStamp, SeqNo, Vsn, Str]). -f_inform(TimeStamp, Vsn, HdrStr, Str, Addr, Port) -> - format_tab("inform ~s:~w - ~s [~s] ~w\n~s", - [ip(Addr), Port, HdrStr, TimeStamp, Vsn, Str]). +f_inform(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port) -> + format_tab("inform ~s:~w - ~s [~s]~s ~w\n~s", + [ip(Addr), Port, HdrStr, TimeStamp, SeqNo, Vsn, Str]). %% Convert a timestamp 2-tupple to a printable string @@ -363,6 +673,13 @@ ts2str({Local,Universal}) -> ts2str(_) -> "". +%% Convert a sequence number integer to a printable string +%% +sn2str(SeqNo) when is_integer(SeqNo) -> + " [" ++ integer_to_list(SeqNo) ++ "]"; +sn2str(_) -> + "". + %% Convert a datetime 2-tupple to a printable string %% dat2str({{Y,M,D},{H,Min,S}}) -> @@ -457,19 +774,31 @@ ip({A,B,C,D}) -> %% Various utility functions %% ------------------------------------------------------------------- -log_open(Name, File, Size, Repair, Notify) -> +log_open(Name, File, {M, F, A} = SeqNoGen, Size, Repair, Notify) + when (is_atom(M) andalso is_atom(F) andalso is_list(A)) -> + log_open2(Name, File, SeqNoGen, Size, Repair, Notify); +log_open(Name, File, SeqNoGen, Size, Repair, Notify) + when is_function(SeqNoGen, 0) -> + log_open2(Name, File, SeqNoGen, Size, Repair, Notify); +log_open(Name, File, disabled = SeqNoGen, Size, Repair, Notify) -> + log_open2(Name, File, SeqNoGen, Size, Repair, Notify); +log_open(_, _File, BadSeqNoGen, _Size, _Repair, _Notify) -> + {error, {bad_seqno, BadSeqNoGen}}. + +log_open2(Name, File, SeqNoGen, Size, Repair, Notify) -> case do_log_open(Name, File, Size, Repair, Notify) of {ok, Log} -> - {ok, Log}; + {ok, #snmp_log{id = Log, seqno = SeqNoGen}}; {repaired, Log, Rec, Bad} -> ?vlog("log_open -> repaired: " "~n Rec: ~p" "~n Bad: ~p", [Rec, Bad]), - {ok, Log}; + {ok, #snmp_log{id = Log, seqno = SeqNoGen}}; Error -> Error end. + %% We need to make sure we do not end up in an infinit loop %% Take the number of files of the wrap log and add 2 (for %% the index and size files). diff --git a/lib/snmp/src/misc/snmp_usm.erl b/lib/snmp/src/misc/snmp_usm.erl index 6d216e65d6..19be564a8e 100644 --- a/lib/snmp/src/misc/snmp_usm.erl +++ b/lib/snmp/src/misc/snmp_usm.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2004-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2004-2010. 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 %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% @@ -206,6 +206,10 @@ des_encrypt(PrivKey, Data, SaltFun) -> des_decrypt(PrivKey, MsgPrivParams, EncData) when length(MsgPrivParams) =:= 8 -> + ?vtrace("des_decrypt -> entry with" + "~n PrivKey: ~p" + "~n MsgPrivParams: ~p" + "~n EncData: ~p", [PrivKey, MsgPrivParams, EncData]), [A,B,C,D,E,F,G,H | PreIV] = PrivKey, DesKey = [A,B,C,D,E,F,G,H], Salt = MsgPrivParams, @@ -213,7 +217,15 @@ des_decrypt(PrivKey, MsgPrivParams, EncData) %% Whatabout errors here??? E.g. not a mulitple of 8! Data = binary_to_list(crypto:des_cbc_decrypt(DesKey, IV, EncData)), Data2 = snmp_pdus:strip_encrypted_scoped_pdu_data(Data), - {ok, Data2}. + {ok, Data2}; +des_decrypt(PrivKey, BadMsgPrivParams, EncData) -> + ?vtrace("des_decrypt -> entry with when bad MsgPrivParams" + "~n PrivKey: ~p" + "~n BadMsgPrivParams: ~p" + "~n EncData: ~p", + [PrivKey, BadMsgPrivParams, EncData]), + throw({error, {bad_msgPrivParams, PrivKey, BadMsgPrivParams, EncData}}). + aes_encrypt(PrivKey, Data, SaltFun) -> AesKey = PrivKey, @@ -225,7 +237,7 @@ aes_encrypt(PrivKey, Data, SaltFun) -> {ok, binary_to_list(EncData), Salt}. aes_decrypt(PrivKey, MsgPrivParams, EncData, EngineBoots, EngineTime) - when length(MsgPrivParams) == 8 -> + when length(MsgPrivParams) =:= 8 -> AesKey = PrivKey, Salt = MsgPrivParams, IV = [?i32(EngineBoots), ?i32(EngineTime) | Salt], diff --git a/lib/snmp/test/snmp_agent_test.erl b/lib/snmp/test/snmp_agent_test.erl index 53b35058e1..af0581150a 100644 --- a/lib/snmp/test/snmp_agent_test.erl +++ b/lib/snmp/test/snmp_agent_test.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2003-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2003-2010. 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 %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% @@ -32,6 +32,8 @@ -include("snmp_test_lib.hrl"). -define(SNMP_USE_V3, true). -include_lib("snmp/include/snmp_types.hrl"). +-include_lib("snmp/src/agent/snmpa_atl.hrl"). + %% -include_lib("snmp/include/SNMP-COMMUNITY-MIB.hrl"). %% -include_lib("snmp/include/SNMP-VIEW-BASED-ACM-MIB.hrl"). %% -include_lib("snmp/include/SNMP-USER-BASED-SM-MIB.hrl"). @@ -84,16 +86,18 @@ all(suite) -> - {req, - [ - mnesia, - distribution, - {local_slave_nodes, 2}, - {time, 360} - ], - [{conf, init_all, cases(), finish_all}]}. + Reqs = [mnesia, distribution, {local_slave_nodes, 2}, {time, 360}], + Conf1 = [{conf, init_all, cases(), finish_all}], + Conf2 = [tickets2], + {req, Reqs, Conf1 ++ Conf2}. +init_per_testcase(otp8395 = Case, Config) when is_list(Config) -> + ?DBG("init_per_testcase -> entry with" + "~n Case: ~p" + "~n Config: ~p", [Case, Config]), + Config2 = init_per_testcase2(Case, init_suite(Config)), + otp8395({init, Config2}); init_per_testcase(otp_7157_test = _Case, Config) when is_list(Config) -> ?DBG("init_per_testcase -> entry with" "~n Case: ~p" @@ -119,6 +123,8 @@ init_per_testcase(_Case, Config) when is_list(Config) -> Dog = ?WD_START(?MINS(6)), [{watchdog, Dog}|Config]. +fin_per_testcase(otp8395, Config) when is_list(Config) -> + otp8395({fin, Config}); fin_per_testcase(_Case, Config) when is_list(Config) -> ?DBG("fin_per_testcase -> entry with" "~n Case: ~p" @@ -127,6 +133,97 @@ fin_per_testcase(_Case, Config) when is_list(Config) -> ?WD_STOP(Dog), Config. + +init_suite(Config) -> + ?DBG("init_suite -> entry with" + "~n Config: ~p", [Config]), + + %% Suite root dir for test suite + PrivDir = ?config(priv_dir, Config), + + %% Create top-directory for this sub-suite + SuiteTopDir = filename:join([PrivDir, ?MODULE]), + case file:make_dir(SuiteTopDir) of + ok -> + ok; + {error, eexist} -> + %% This can happen since this is not really a + %% suite-init function. + ok; + {error, Reason} -> + ?FAIL({failed_creating_suite_top_dir, SuiteTopDir, Reason}) + end, + + + %% -- + %% Fix config (data-dir is not correct): + %% + + Config1 = fix_data_dir(Config), + %% Config1 = Config, + + %% Mib-dirs + MibDir = ?config(data_dir, Config1), + StdMibDir = filename:join([code:priv_dir(snmp), "mibs"]), + + Config2 = [{suite_top_dir, SuiteTopDir}, + {mib_dir, MibDir}, + {std_mib_dir, StdMibDir} | Config1], + + ?DBG("init_suite -> done when" + "~n Config2: ~p", [Config2]), + Config2. + +%% end_per_suite(Config) -> +end_suite(Config) -> + Config. + +fix_data_dir(Config) -> + DataDir0 = ?config(data_dir, Config), + DataDir1 = filename:split(filename:absname(DataDir0)), + [_|DataDir2] = lists:reverse(DataDir1), + DataDir = filename:join(lists:reverse(DataDir2) ++ [?snmp_test_data]), + Config1 = lists:keydelete(data_dir, 1, Config), + [{data_dir, DataDir} | Config1]. + + +init_per_testcase2(Case, Config) -> + SuiteToDir = ?config(suite_top_dir, Config), + + %% Create top-directory for this test-case + CaseTopDir = filename:join([SuiteToDir, Case]), + ok = file:make_dir(CaseTopDir), + + %% Create agent top-dir(s) + AgentTopDir = filename:join([CaseTopDir, agent]), + ok = file:make_dir(AgentTopDir), + AgentConfDir = filename:join([AgentTopDir, config]), + ok = file:make_dir(AgentConfDir), + AgentDbDir = filename:join([AgentTopDir, db]), + ok = file:make_dir(AgentDbDir), + AgentLogDir = filename:join([AgentTopDir, log]), + ok = file:make_dir(AgentLogDir), + + %% Create sub-agent top-dir(s) + SubAgentTopDir = filename:join([CaseTopDir, sub_agent]), + ok = file:make_dir(SubAgentTopDir), + + %% Create manager top-dir(s) + ManagerTopDir = filename:join([CaseTopDir, manager]), + ok = file:make_dir(ManagerTopDir), + + [{case_top_dir, CaseTopDir}, + {agent_top_dir, AgentTopDir}, + {agent_conf_dir, AgentConfDir}, + {agent_db_dir, AgentDbDir}, + {agent_log_dir, AgentLogDir}, + {sub_agent_top_dir, SubAgentTopDir}, + {manager_top_dir, ManagerTopDir} | Config]. + +fin_per_testcase2(_Case, Config) -> + Config. + + cases() -> case ?OSTYPE() of vxworks -> @@ -138,7 +235,7 @@ cases() -> test_v1_v2, test_multi_threaded, mib_storage, - tickets + tickets1 ]; _Else -> [ @@ -149,7 +246,7 @@ cases() -> test_v3, test_multi_threaded, mib_storage, - tickets + tickets1 ] end. @@ -5071,12 +5168,20 @@ reported_bugs_3(suite) -> %% These are (ticket) test cases where the initiation has to be done %% individually. -tickets(suite) -> +tickets1(suite) -> [ otp_4394, otp_7157 ]. + +tickets2(suite) -> + [ + otp8395 + ]. + + + %%----------------------------------------------------------------- %% Ticket: OTP-1128 %% Slogan: Bug in handling of createAndWait set-requests. @@ -5624,10 +5729,9 @@ otp_4394_test1() -> otp_7157(suite) -> - {req, [], {conf, - init_otp_7157, - [otp_7157_test], - finish_otp_7157}}. + Reqs = [], + Conf = [{conf, init_otp_7157, [otp_7157_test], finish_otp_7157}], + {req, Reqs, Conf}. init_otp_7157(Config) when is_list(Config) -> %% @@ -5690,6 +5794,337 @@ otp_7157_test1(MA) -> +%%----------------------------------------------------------------- +%% Extra test cases +%% These cases are started in the new way +%%----------------------------------------------------------------- + +otp8395({init, Config}) when is_list(Config) -> + ?DBG("otp8395(init) -> entry with" + "~n Config: ~p", [Config]), + + %% -- + %% Start nodes + %% + + {ok, AgentNode} = start_node(agent), + %% {ok, SubAgentNode} = start_node(sub_agent), + {ok, ManagerNode} = start_node(manager), + + %% -- + %% Mnesia init + %% + + AgentDbDir = ?config(agent_db_dir, Config), + AgentMnesiaDir = filename:join([AgentDbDir, "mnesia"]), + mnesia_init(AgentNode, AgentMnesiaDir), + +%% SubAgentDir = ?config(sub_agent_dir, Config), +%% SubAgentMnesiaDir = filename:join([SubAgentDir, "mnesia"]), +%% mnesia_init(SubAgentNode, SubAgentMnesiaDir), + + %% ok = mnesia_create_schema(AgentNode, [AgentNode, SubAgentNode]), + %% ok = mnesia:create_schema([AgentNode, SubAgentNode]), + mnesia_create_schema(AgentNode, [AgentNode]), + + mnesia_start(AgentNode), + %% mnesia_start(SubAgentNode), + + %% -- + %% Host & IP + %% + + AgentHost = ?HOSTNAME(AgentNode), + %% SubAgentHost = ?HPSTNAME(SubAgentNode), + ManagerHost = ?HOSTNAME(ManagerNode), + + Host = snmp_test_lib:hostname(), + Ip = ?LOCALHOST(), + {ok, AgentIP0} = snmp_misc:ip(AgentHost), + AgentIP = tuple_to_list(AgentIP0), + %% {ok, SubAgentIP0} = snmp_misc:ip(SubAgentHost), + %% SubAgentIP = tuple_to_list(SubAgentIP0), + {ok, ManagerIP0} = snmp_misc:ip(ManagerHost), + ManagerIP = tuple_to_list(ManagerIP0), + + + %% -- + %% Write agent config + %% + + Vsns = [v1], + AgentConfDir = ?config(agent_conf_dir, Config), + ManagerConfDir = ?config(manager_top_dir, Config), + snmp_agent_test_lib:config(Vsns, + ManagerConfDir, AgentConfDir, + ManagerIP, AgentIP), + + + %% -- + %% Start the agent + %% + + Config2 = start_agent([{host, Host}, + {ip, Ip}, + {agent_node, AgentNode}, + {agent_host, AgentHost}, + {agent_ip, AgentIP}, + %% {sub_agent_node, SubAgentNode}, + %% {sub_agent_host, SubAgentHost}, + %% {sub_agent_ip, SubAgentIP}, + {manager_node, ManagerNode}, + {manager_host, ManagerHost}, + {manager_ip, ManagerIP}|Config]), + + %% -- + %% Create watchdog + %% + + Dog = ?WD_START(?MINS(1)), + + [{watchdog, Dog} | Config2]; + +otp8395({fin, Config}) when is_list(Config) -> + ?DBG("otp8395(fin) -> entry with" + "~n Config: ~p", [Config]), + + AgentNode = ?config(agent_node, Config), + ManagerNode = ?config(manager_node, Config), + + %% - + %% Stop agent (this is the nice way to do it, + %% so logs and files can be closed in the proper way). + %% + + AgentSup = ?config(agent_sup, Config), + ?DBG("otp8395(fin) -> stop (stand-alone) agent: ~p", [AgentSup]), + stop_stdalone_agent(AgentSup), + + %% - + %% Stop mnesia + %% + ?DBG("otp8395(fin) -> stop mnesia", []), + mnesia_stop(AgentNode), + + + %% - + %% Stop the agent node + %% + + ?DBG("otp8395(fin) -> stop agent node", []), + stop_node(AgentNode), + + +%% SubAgentNode = ?config(sub_agent_node, Config), +%% stop_node(SubAgentNode), + + + %% - + %% Stop the manager node + %% + + ?DBG("otp8395(fin) -> stop manager node", []), + stop_node(ManagerNode), + + Dog = ?config(watchdog, Config), + ?WD_STOP(Dog), + lists:keydelete(watchdog, 1, Config); + +otp8395(doc) -> + "OTP-8395 - ATL with sequence numbering. "; + +otp8395(Config) when is_list(Config) -> + ?DBG("otp8395 -> entry with" + "~n Config: ~p", [Config]), + + ?SLEEP(1000), + + %% This is just to dirty trick for the ***old*** test-code + put(mgr_node, ?config(manager_node, Config)), + put(mgr_dir, ?config(manager_top_dir, Config)), + put(mib_dir, ?config(mib_dir, Config)), + put(vsn, v1), + put(master_host, ?config(agent_host, Config)), + try_test(simple_standard_test), + + ?SLEEP(1000), + AgentNode = ?config(agent_node, Config), + AgentLogDir = ?config(agent_log_dir, Config), + OutFile = filename:join([AgentLogDir, "otp8395.txt"]), + {ok, LogInfo} = rpc:call(AgentNode, snmpa, log_info, []), + ?DBG("otp8395 -> LogInfo: ~p", [LogInfo]), + +%% SyncRes = rpc:call(AgentNode, snmp, log_sync, [?audit_trail_log_name]), +%% ?DBG("otp8395 -> SyncRes: ~p", [SyncRes]), + + ok = agent_log_validation(AgentNode), + LTTRes = + rpc:call(AgentNode, snmpa, log_to_txt, [AgentLogDir, [], OutFile]), + ?DBG("otp8395 -> LTTRes: ~p", [LTTRes]), + + ?SLEEP(1000), + ?DBG("otp8395 -> done", []), + ok. + + +agent_log_validation(Node) -> + rpc:call(Node, ?MODULE, agent_log_validation, []). + +agent_log_validation() -> + put(sname, otp8308), + put(verbosity, trace), + snmp_log:validate(?audit_trail_log_name, true). + +mnesia_init(Node, Dir) -> + rpc:call(Node, ?MODULE, mnesia_init, [Dir]). + +mnesia_init(Dir) -> + ok = application:load(mnesia), + application_controller:set_env(mnesia, dir, Dir). + +mnesia_create_schema(Node, Nodes) -> + rpc:call(Node, mnesia, create_schema, [Nodes]). + +mnesia_start(Node) -> + rpc:call(Node, application, start, [mnesia]). + +mnesia_start() -> + application:start(mnesia). + +mnesia_stop(Node) -> + rpc:call(Node, application, stop, [mnesia]). + +mnesia_stop() -> + application:start(mnesia). + + +start_agent(Config) -> + start_agent(Config, []). + +start_agent(Config, Opts) -> + + %% Directories + ConfDir = ?config(agent_conf_dir, Config), + DbDir = ?config(agent_db_dir, Config), + LogDir = ?config(agent_log_dir, Config), + + Vsns = [v1], + + AgentConfig = process_agent_options(ConfDir, DbDir, LogDir, Vsns, Opts), + + %% Nodes + AgentNode = ?config(agent_node, Config), + %% ManagerNode = ?config(manager_node, Config), + + process_flag(trap_exit,true), + + AgentTopSup = start_stdalone_agent(AgentNode, AgentConfig), + + [{agent_sup, AgentTopSup} | Config]. + + +process_agent_options(ConfDir, DbDir, LogDir, Vsns, Opts) -> + Defaults = + [{agent_type, master}, + {agent_verbosity, trace}, + {priority, normal}, + {versions, Vsns}, + {db_dir, DbDir}, + {mib_storage, ets}, + {local_db, [{repair, true}, + {auto_save, 5000}, + {verbosity, log}]}, + {error_report_module, snmpa_error_logger}, + {config, [{dir, ConfDir}, + {force_load, true}, + {verbosity, trace}]}, + {multi_threaded, true}, + {mib_server, [{mibentry_override, false}, + {trapentry_override, false}, + {verbosity, info}]}, + {target_cache, [{verbosity,info}]}, + {symbolic_store, [{verbosity,log}]}, + {note_store, [{timeout,30000}, {verbosity,log}]}, + {net_if, [{module, snmpa_net_if}, + {verbosity, trace}, + {options, [{bind_to, false}, + {no_reuse, false}, + {req_limit, infinity}]}]}, + {audit_trail_log, [{type, read_write}, + {dir, LogDir}, + {size, {10240,20}}, + {repair, true}, + {seqno, true}]}], + + process_options(Defaults, Opts). + +process_options(Defaults, _Opts) -> + %% process_options(Defaults, Opts, []). + Defaults. + +%% process_options([], _Opts, Acc) -> +%% lists:reverse(Acc); +%% process_options([{Key, DefaultValue}|Defaults], Opts, Acc) -> +%% case lists:keysearch(Key, 1, Opts) of +%% {value, {Key, Value}} when is_list-> + + +snmp_app_env_init(Node, Entity, Conf) -> + rpc:call(Node, snmp_app_env_init, [Entity, Conf]). + +snmp_app_env_init(Entity, Conf) -> + application:unload(snmp), + application:load(snmp), + application:set_env(snmp, Entity, Conf). + +start_stdalone_agent(Node, Config) -> + rpc:call(Node, ?MODULE, start_stdalone_agent, [Config]). + +start_stdalone_agent(Config) -> + case snmpa_supervisor:start_link(normal, Config) of + {ok, AgentTopSup} -> + unlink(AgentTopSup), + AgentTopSup; + {error, {already_started, AgentTopSup}} -> + AgentTopSup + end. + +stop_stdalone_agent(Pid) when (node(Pid) =/= node()) -> + MRef = erlang:monitor(process, Pid), + rpc:call(node(Pid), ?MODULE, stop_stdalone_agent, [Pid]), + receive + {'DOWN', MRef, process, Pid, Info} -> + ?DBG("received expected DOWN message " + "regarding snmp agent supervisor: " + "~n Info: ~p", [Info]), + ok + after 5000 -> + ?DBG("no DOWN message " + "regarding snmp agent supervisor within time", []), + ok + end; +stop_stdalone_agent(Pid) -> + ?DBG("attempting to terminate agent top-supervisor: ~p", [Pid]), + nkill(Pid, kill). + + +nkill(Pid, Reason) -> + nkill(Pid, Reason, 10). + +nkill(Pid, Reason, N) when N > 0 -> + case (catch erlang:process_info(Pid)) of + Info when is_list(Info) -> + ?DBG("Info for process to kill: " + "~n Info: ~p", [Info]), + exit(Pid, Reason), + ?SLEEP(1000), + nkill(Pid, Reason, N-1); + _ -> + ?DBG("No process info => already dead?", []), + ok + end. + + %%----------------------------------------------------------------- %% Slogan: info test %%----------------------------------------------------------------- diff --git a/lib/snmp/test/snmp_log_test.erl b/lib/snmp/test/snmp_log_test.erl index b4694fd9ab..91bdc3e849 100644 --- a/lib/snmp/test/snmp_log_test.erl +++ b/lib/snmp/test/snmp_log_test.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2003-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2003-2010. 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 %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% @@ -45,20 +45,30 @@ all/1, open_and_close/1, open_write_and_close/1, + open_write_and_close1/1, + open_write_and_close2/1, + open_write_and_close3/1, + open_write_and_close4/1, + log_to_io/1, log_to_io1/1, log_to_io2/1, + log_to_txt/1, log_to_txt1/1, - log_to_txt2/1 + log_to_txt2/1, + log_to_txt3/1 ]). + %%---------------------------------------------------------------------- %% Internal exports %%---------------------------------------------------------------------- -export([ log_writer_main/5, - log_reader_main/1 + log_reader_main/1, + next_seqno/2 ]). + %%---------------------------------------------------------------------- %% Macros %%---------------------------------------------------------------------- @@ -102,10 +112,32 @@ all(suite) -> [ open_and_close, open_write_and_close, + log_to_io, + log_to_txt + ]. + + +open_write_and_close(suite) -> + [ + open_write_and_close1, + open_write_and_close2, + open_write_and_close3, + open_write_and_close4 + ]. + + +log_to_io(suite) -> + [ log_to_io1, - log_to_io2, + log_to_io2 + ]. + + +log_to_txt(suite) -> + [ log_to_txt1, - log_to_txt2 + log_to_txt2, + log_to_txt3 ]. @@ -132,24 +164,129 @@ open_and_close(Config) when is_list(Config) -> %%====================================================================== -open_write_and_close(suite) -> []; -open_write_and_close(Config) when is_list(Config) -> - p(open_write_and_close), - put(sname,open_write_and_close), +open_write_and_close1(suite) -> + []; +open_write_and_close1(doc) -> + "Open a plain (no sequence-numbering) log file"; +open_write_and_close1(Config) when is_list(Config) -> + p(open_write_and_close1), + put(sname,open_write_and_close1), + put(verbosity,trace), + ?DBG("open_write_and_close1 -> start", []), + + SeqNoGen = none, + ?line ok = open_write_and_close(SeqNoGen, Config), + + ?DBG("open_write_and_close1 -> done", []), + ok. + + +%%====================================================================== + +open_write_and_close2(suite) -> + []; +open_write_and_close2(doc) -> + "Open a log file with sequence-numbering explicitly disabled"; +open_write_and_close2(Config) when is_list(Config) -> + p(open_write_and_close2), + put(sname,open_write_and_close2), + put(verbosity,trace), + ?DBG("open_write_and_close2 -> start", []), + + SeqNoGen = disabled, + ?line ok = open_write_and_close(SeqNoGen, Config), + + ?DBG("open_write_and_close2 -> done", []), + ok. + + +%%====================================================================== + +open_write_and_close3(suite) -> + []; +open_write_and_close3(doc) -> + "Open a log file with sequence-numbering using MFA"; +open_write_and_close3(Config) when is_list(Config) -> + p(open_write_and_close3), + put(sname,open_write_and_close3), + put(verbosity,trace), + ?DBG("open_write_and_close2 -> start", []), + + seqno_init(), + SeqNoGen = {?MODULE, next_seqno, [10, 100]}, + ?line ok = open_write_and_close(SeqNoGen, Config), + seqno_finish(), + + ?DBG("open_write_and_close2 -> done", []), + ok. + + +%%====================================================================== + +open_write_and_close4(suite) -> + []; +open_write_and_close4(doc) -> + "Open a log file with sequence-numbering using fun"; +open_write_and_close4(Config) when is_list(Config) -> + p(open_write_and_close4), + put(sname,open_write_and_close4), put(verbosity,trace), - ?DBG("open_write_and_close -> start", []), + ?DBG("open_write_and_close2 -> start", []), + + seqno_init(), + SeqNoGen = fun() -> next_seqno(10, 100) end, + ?line ok = open_write_and_close(SeqNoGen, Config), + seqno_finish(), + + ?DBG("open_write_and_close2 -> done", []), + ok. + + +%%====================================================================== + +seqno_init() -> + ets:new(snmp_log_test_seqno_tab, [named_table, set, protected]). + +seqno_finish() -> + ets:delete(snmp_log_test_seqno_tab). + +next_seqno(Initial, Max) -> + Key = seqno, + Position = 2, + Increment = 1, + Threshold = Max, + SetValue = Initial, + UpdateOp = {Position, Increment, Threshold, SetValue}, + Tab = snmp_log_test_seqno_tab, + case (catch ets:update_counter(Tab, Key, UpdateOp)) of + {'EXIT', {badarg, _}} -> + ets:insert(Tab, {seqno, Initial}), + Initial; + Next when is_integer(Next) -> + Next + end. + +open_write_and_close(SeqNoGen, Config) -> + ?DBG("open_write_and_close1 -> start", []), Dir = ?config(log_dir, Config), Name = "snmp_test", File = join(Dir, "snmp_test.log"), Size = {1024, 10}, Repair = true, ?DBG("open_write_and_close -> create log", []), - ?line {ok, Log} = snmp_log:create(Name, File, Size, Repair), + + ?line {ok, Log} = + case SeqNoGen of + none -> + snmp_log:create(Name, File, Size, Repair); + _ -> + snmp_log:create(Name, File, SeqNoGen, Size, Repair) + end, Vsn = 'version-2', Community = "all-rights", - ?DBG("open_write_and_close -> create messages to log", []), + ?DBG("open_write_and_close1 -> create messages to log", []), %% A request ?line Req = get_next_request(Vsn, Community, [1,1], 1, 235779012), @@ -162,7 +299,7 @@ open_write_and_close(Config) when is_list(Config) -> Msgs = lists:flatten(lists:duplicate(1002,[Req,Rep])), %% And now log them: - ?DBG("open_write_and_close -> log ~p messages, ~p bytes", + ?DBG("open_write_and_close1 -> log ~p messages, ~p bytes", [length(Msgs), size(list_to_binary(Msgs))]), Addr = ?LOCALHOST(), Port = 162, @@ -172,11 +309,11 @@ open_write_and_close(Config) when is_list(Config) -> lists:foreach(Logger, Msgs), check_notify(), - ?DBG("open_write_and_close -> display info", []), + ?DBG("open_write_and_close1 -> display info", []), ?line {ok, Info} = snmp_log:info(Log), display_info(Info), - ?DBG("open_write_and_close -> close log", []), + ?DBG("open_write_and_close1 -> close log", []), ?line ok = snmp_log:close(Log), ?DBG("open_write_and_close -> done", []), @@ -308,18 +445,58 @@ log_to_txt1(Config) when is_list(Config) -> put(sname,l2t1), put(verbosity,trace), ?DBG("log_to_txt1 -> start", []), + + Name = "snmp_test_l2t1", + SeqNoGen = disabled, + ?line ok = log_to_txt(Name, SeqNoGen, Config), + + ?DBG("log_to_txt1 -> done", []), + ok. + + + +%%====================================================================== + +log_to_txt2(suite) -> []; +log_to_txt2(Config) when is_list(Config) -> + p(log_to_txt2), + put(sname,l2t2), + put(verbosity,trace), + ?DBG("log_to_txt2 -> start", []), + + Name = "snmp_test_l2t2", + seqno_init(), + SeqNoGen = {?MODULE, next_seqno, [1, 100]}, + ?line ok = log_to_txt(Name, SeqNoGen, Config), + seqno_finish(), + + ?DBG("log_to_txt2 -> done", []), + ok. + + + +%%====================================================================== + +log_to_txt(Name, SeqNoGen, Config) when is_list(Config) -> + ?DBG("log_to_txt -> entry", []), Dir = ?config(log_dir, Config), - Name = "snmp_test_l2t1", - File = join(Dir, "snmp_test_l2t1.log"), + File = join(Dir, Name ++ ".log"), Size = {10240, 10}, Repair = true, - ?DBG("log_to_txt1 -> create log", []), - ?line {ok, Log} = snmp_log:create(Name, File, Size, Repair), - ?DBG("log_to_txt1 -> create messages to log", []), + ?DBG("log_to_txt -> create log", []), + ?line {ok, Log} = + case SeqNoGen of + none -> + snmp_log:create(Name, File, Size, Repair); + _ -> + snmp_log:create(Name, File, SeqNoGen, Size, Repair) + end, + + ?DBG("log_to_txt -> create messages to log", []), Msgs = messages(), - ?DBG("log_to_txt1 -> create logger funs", []), + ?DBG("log_to_txt -> create logger funs", []), Addr = ?LOCALHOST(), Port = 162, Logger = fun(Packet) -> @@ -332,42 +509,42 @@ log_to_txt1(Config) when is_list(Config) -> end, To = lists:duplicate(20, 5000), - ?DBG("log_to_txt1 -> log the messages", []), + ?DBG("log_to_txt -> log the messages", []), Start = calendar:local_time(), lists:foreach(BatchLogger, To), Stop = calendar:local_time(), - ?DBG("log_to_txt1 -> display info", []), + ?DBG("log_to_txt -> display info", []), ?line {ok, Info} = snmp_log:info(Log), display_info(Info), Out1 = join(Dir, "snmp_text-1.txt"), - ?DBG("log_to_txt1 -> do the convert to a text file when" + ?DBG("log_to_txt -> do the convert to a text file when" "~n Out1: ~p", [Out1]), ?line ok = snmp:log_to_txt(Dir, [], Out1, Log, File), ?line {ok, #file_info{size = Size1}} = file:read_file_info(Out1), - ?DBG("log_to_txt1 -> text file size: ~p", [Size1]), + ?DBG("log_to_txt -> text file size: ~p", [Size1]), validate_size(Size1), Out2 = join(Dir, "snmp_text-2.txt"), - ?DBG("log_to_txt1 -> do the convert to a text file when" + ?DBG("log_to_txt -> do the convert to a text file when" "~n Start: ~p" "~n Stop: ~p" "~n Out2: ~p", [Start, Stop, Out2]), ?line ok = snmp:log_to_txt(Dir, [], Out2, Log, File, Start, Stop), ?line {ok, #file_info{size = Size2}} = file:read_file_info(Out2), - ?DBG("log_to_txt1 -> text file size: ~p", [Size2]), + ?DBG("log_to_txt -> text file size: ~p", [Size2]), validate_size(Size2, {le, Size1}), %% Calculate new start / stop times... GStart = calendar:datetime_to_gregorian_seconds(Start), - ?DBG("log_to_txt1 -> GStart: ~p", [GStart]), + ?DBG("log_to_txt -> GStart: ~p", [GStart]), GStop = calendar:datetime_to_gregorian_seconds(Stop), - ?DBG("log_to_txt1 -> GStop: ~p", [GStop]), + ?DBG("log_to_txt -> GStop: ~p", [GStop]), Diff4 = (GStop - GStart) div 4, - ?DBG("log_to_txt1 -> Diff4: ~p", [Diff4]), + ?DBG("log_to_txt -> Diff4: ~p", [Diff4]), GStart2 = GStart + Diff4, GStop2 = GStop - Diff4, if @@ -381,20 +558,20 @@ log_to_txt1(Config) when is_list(Config) -> Stop2 = calendar:gregorian_seconds_to_datetime(GStop2), Out3 = join(Dir, "snmp_text-3.txt"), - ?DBG("log_to_txt1 -> do the convert to a text file when" + ?DBG("log_to_txt -> do the convert to a text file when" "~n Start2: ~p" "~n Stop2: ~p" "~n Out3: ~p", [Start2, Stop2, Out3]), ?line ok = snmp:log_to_txt(Dir, [], Out3, Log, File, Start2, Stop2), ?line {ok, #file_info{size = Size3}} = file:read_file_info(Out3), - ?DBG("log_to_txt1 -> text file size: ~p", [Size3]), + ?DBG("log_to_txt -> text file size: ~p", [Size3]), validate_size(Size3, {l, Size1}), - ?DBG("log_to_txt1 -> close log", []), + ?DBG("log_to_txt -> close log", []), ?line ok = snmp_log:close(Log), - ?DBG("log_to_txt1 -> done", []), + ?DBG("log_to_txt -> done", []), ok. @@ -405,19 +582,21 @@ log_to_txt1(Config) when is_list(Config) -> %% %% Test: ts:run(snmp, snmp_log_test, log_to_txt2, [batch]). -log_to_txt2(suite) -> []; -log_to_txt2(doc) -> "Log to txt file from a different process than which " - "opened and wrote the log"; -log_to_txt2(Config) when is_list(Config) -> +log_to_txt3(suite) -> + []; +log_to_txt3(doc) -> + "Log to txt file from a different process than which " + "opened and wrote the log"; +log_to_txt3(Config) when is_list(Config) -> process_flag(trap_exit, true), - p(log_to_txt2), - put(sname,l2t2), + p(log_to_txt3), + put(sname,l2t3), put(verbosity,trace), - ?DBG("log_to_txt2 -> start", []), + ?DBG("log_to_txt3 -> start", []), Dir = ?config(log_dir, Config), - Name = "snmp_test_l2t2", - LogFile = join(Dir, "snmp_test_l2t2.log"), - TxtFile = join(Dir, "snmp_test_l2t2.txt"), + Name = "snmp_test_l2t3", + LogFile = join(Dir, "snmp_test_l2t3.log"), + TxtFile = join(Dir, "snmp_test_l2t3.txt"), Meg = 1024*1024, Size = {10*Meg, 10}, Repair = true, @@ -425,22 +604,22 @@ log_to_txt2(Config) when is_list(Config) -> StdMibDir = filename:join(code:priv_dir(snmp), "mibs") ++ "/", Mibs = [join(StdMibDir, "SNMPv2-MIB")], - ?DBG("log_to_txt2 -> create log writer process", []), + ?DBG("log_to_txt3 -> create log writer process", []), ?line {ok, Log, Logger} = log_writer_start(Name, LogFile, Size, Repair), - ?DBG("log_to_txt2 -> create log reader process", []), + ?DBG("log_to_txt3 -> create log reader process", []), ?line {ok, Reader} = log_reader_start(), - ?DBG("log_to_txt2 -> wait some time", []), + ?DBG("log_to_txt3 -> wait some time", []), ?SLEEP(5000), - ?DBG("log_to_txt2 -> display log info", []), + ?DBG("log_to_txt3 -> display log info", []), ?line log_writer_info(Logger), - ?DBG("log_to_txt2 -> instruct the log writer to sleep some", []), + ?DBG("log_to_txt3 -> instruct the log writer to sleep some", []), ?line ok = log_writer_sleep(Logger, 5000), - ?DBG("log_to_txt2 -> instruct the log reader to log to txt", []), + ?DBG("log_to_txt3 -> instruct the log reader to log to txt", []), Res = log_reader_log_to(Reader, fun() -> @@ -457,25 +636,25 @@ log_to_txt2(Config) when is_list(Config) -> case Res of {ok, Info} -> - ?DBG("log_to_txt2 -> ~n Info: ~p", [Info]), + ?DBG("log_to_txt3 -> ~n Info: ~p", [Info]), ?line {ok, #file_info{size = FileSize}} = file:read_file_info(TxtFile), - ?DBG("log_to_txt2 -> text file size: ~p", [FileSize]), + ?DBG("log_to_txt3 -> text file size: ~p", [FileSize]), validate_size(FileSize); {Error, Info} -> - ?DBG("log_to_txt2 -> log to txt failed: " + ?DBG("log_to_txt3 -> log to txt failed: " "~n Error: ~p" "~n Info: ~p", [Error, Info]), ?line ?FAIL({log_lo_txt_failed, Error, Info}) end, - ?DBG("log_to_txt2 -> instruct the log writer to stop", []), + ?DBG("log_to_txt3 -> instruct the log writer to stop", []), ?line log_writer_stop(Logger), - ?DBG("log_to_txt2 -> instruct the log reader to stop", []), + ?DBG("log_to_txt3 -> instruct the log reader to stop", []), ?line log_reader_stop(Reader), - ?DBG("log_to_txt2 -> done", []), + ?DBG("log_to_txt3 -> done", []), ok. diff --git a/lib/snmp/test/snmp_manager_config_test.erl b/lib/snmp/test/snmp_manager_config_test.erl index 51325996e6..fcb3d7e30c 100644 --- a/lib/snmp/test/snmp_manager_config_test.erl +++ b/lib/snmp/test/snmp_manager_config_test.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2004-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2004-2010. 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 %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% @@ -86,7 +86,12 @@ stats_create_and_increment/1, tickets/1, - otp_7219/1 + otp_7219/1, + otp_8395/1, + otp_8395_1/1, + otp_8395_2/1, + otp_8395_3/1, + otp_8395_4/1 ]). @@ -2295,7 +2300,8 @@ loop(N, _, F) when (N > 0) andalso is_function(F) -> tickets(suite) -> [ - otp_7219 + otp_7219, + otp_8395 ]. @@ -2347,6 +2353,170 @@ otp_7219(Config) when is_list(Config) -> ok. + +otp_8395(suite) -> + [ + otp_8395_1, + otp_8395_2, + otp_8395_3, + otp_8395_4 + ]. + +otp_8395_1(suite) -> []; +otp_8395_1(doc) -> + "OTP-8395(1)"; +otp_8395_1(Conf) when is_list(Conf) -> + put(tname, otp_8395_1), + p("start"), + process_flag(trap_exit, true), + otp8395(Conf, false, ok), + ok. + +otp_8395_2(suite) -> []; +otp_8395_2(doc) -> + "OTP-8395(2)"; +otp_8395_2(Conf) when is_list(Conf) -> + put(tname, otp_8395_2), + p("start"), + process_flag(trap_exit, true), + otp8395(Conf, true, ok), + ok. + +otp_8395_3(suite) -> []; +otp_8395_3(doc) -> + "OTP-8395(3)"; +otp_8395_3(Conf) when is_list(Conf) -> + put(tname, otp_8395_3), + p("start"), + process_flag(trap_exit, true), + otp8395(Conf, gurka, error), + ok. + +otp8395(Conf, SeqNoVal, Expect) -> + ConfDir = ?config(manager_conf_dir, Conf), + DbDir = ?config(manager_db_dir, Conf), + LogDir = ?config(manager_log_dir, Conf), + StdMibDir = filename:join(code:priv_dir(snmp), "mibs") ++ "/", + + write_manager_conf(ConfDir), + + %% Third set of options (no versions): + p("all options"), + NetIfOpts = [{module, snmpm_net_if}, + {verbosity, trace}, + {options, [{recbuf, 30000}, + {bind_to, false}, + {no_reuse, false}]}], + ServerOpts = [{timeout, 10000}, {verbosity, trace}], + NoteStoreOpts = [{timeout, 20000}, {verbosity, trace}], + ConfigOpts = [{dir, ConfDir}, {verbosity, trace}, {db_dir, DbDir}], + Mibs = [join(StdMibDir, "SNMP-NOTIFICATION-MIB"), + join(StdMibDir, "SNMP-USER-BASED-SM-MIB")], + Prio = normal, + ATL = [{type, read_write}, + {dir, LogDir}, + {size, {10,10240}}, + {repair, true}, + {seqno, SeqNoVal}], + Vsns = [v1,v2,v3], + Opts = [{config, ConfigOpts}, + {net_if, NetIfOpts}, + {server, ServerOpts}, + {note_store, NoteStoreOpts}, + {audit_trail_log, ATL}, + {priority, Prio}, + {mibs, Mibs}, + {versions, Vsns}], + + case config_start(Opts) of + {ok, _Pid} when (Expect =:= ok) -> + ?line ok = config_stop(), + ok; + {ok, _Pid} when (Expect =/= ok) -> + config_stop(), + exit({unexpected_started_config, SeqNoVal}); + _Error when (Expect =/= ok) -> + ok; + Error when (Expect =:= ok) -> + exit({unexpected_failed_starting_config, SeqNoVal, Error}) + end, + p("done"), + ok. + + +otp_8395_4(suite) -> []; +otp_8395_4(doc) -> + "OTP-8395(4)"; +otp_8395_4(Conf) when is_list(Conf) -> + put(tname, otp_8395_4), + p("start"), + process_flag(trap_exit, true), + + snmp:print_version_info(), + + ConfDir = ?config(manager_conf_dir, Conf), + DbDir = ?config(manager_db_dir, Conf), + LogDir = ?config(manager_log_dir, Conf), + StdMibDir = filename:join(code:priv_dir(snmp), "mibs") ++ "/", + + write_manager_conf(ConfDir), + + %% Third set of options (no versions): + p("all options"), + NetIfOpts = [{module, snmpm_net_if}, + {verbosity, trace}, + {options, [{recbuf, 30000}, + {bind_to, false}, + {no_reuse, false}]}], + ServerOpts = [{timeout, 10000}, {verbosity, trace}], + NoteStoreOpts = [{timeout, 20000}, {verbosity, trace}], + ConfigOpts = [{dir, ConfDir}, {verbosity, trace}, {db_dir, DbDir}], + Mibs = [join(StdMibDir, "SNMP-NOTIFICATION-MIB"), + join(StdMibDir, "SNMP-USER-BASED-SM-MIB")], + Prio = normal, + ATL = [{type, read_write}, + {dir, LogDir}, + {size, {10,10240}}, + {repair, true}, + {seqno, true}], + Vsns = [v1,v2,v3], + Opts = [{config, ConfigOpts}, + {net_if, NetIfOpts}, + {server, ServerOpts}, + {note_store, NoteStoreOpts}, + {audit_trail_log, ATL}, + {priority, Prio}, + {mibs, Mibs}, + {versions, Vsns}], + + ?line {ok, _Pid} = config_start(Opts), + + Counter = otp_8395_4, + Initial = 10, + Increment = 2, + Max = 20, + + %% At this call the counter does *not* exist. The call creates + %% it with the initial value! + + Val1 = Initial, + Val1 = otp8395_incr_counter(Counter, Initial, Increment, Max), + + %% Now it exist, make sure another call does the expected increment + + Val2 = Initial + Increment, + Val2 = otp8395_incr_counter(Counter, Initial, Increment, Max), + + ?line ok = config_stop(), + + p("done"), + ok. + + +otp8395_incr_counter(Counter, Initial, Increment, Max) -> + snmpm_config:increment_counter(Counter, Initial, Increment, Max). + + %%====================================================================== %% Internal functions %%====================================================================== diff --git a/lib/snmp/test/snmp_manager_test.erl b/lib/snmp/test/snmp_manager_test.erl index 31cc095349..518b8b34de 100644 --- a/lib/snmp/test/snmp_manager_test.erl +++ b/lib/snmp/test/snmp_manager_test.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2003-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2003-2010. 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 %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% @@ -111,7 +111,9 @@ tickets/1, otp8015/1, - otp8015_1/1 + otp8015_1/1, + otp8395/1, + otp8395_1/1 ]). @@ -240,18 +242,22 @@ init_per_testcase3(Case, Config) -> simple_async_set2, simple_sync_get_bulk2, simple_async_get_bulk2, - misc_async2 + misc_async2, + otp8395_1 ], - Cases = [ - trap1, - trap2, - inform1, - inform2, - inform3, - inform4, - inform_swarm, - report - ] ++ OldApiCases ++ NewApiCases, + Cases = + [ + trap1, + trap2, + inform1, + inform2, + inform3, + inform4, + inform_swarm, + report + ] ++ + OldApiCases ++ + NewApiCases, case lists:member(Case, Cases) of true -> NoAutoInformCases = [inform1, inform2, inform3, inform_swarm], @@ -265,6 +271,8 @@ init_per_testcase3(Case, Config) -> {agent_verbosity, info}, {agent_net_if_verbosity, info}], Verb ++ Config; + Case =:= otp8395_1 -> + [{manager_atl_seqno, true} | Config]; true -> Config end, @@ -315,18 +323,22 @@ fin_per_testcase2(Case, Config) -> simple_async_set2, simple_sync_get_bulk2, simple_async_get_bulk2, - misc_async2 + misc_async2, + otp8395_1 ], - Cases = [ - trap1, - trap2, - inform1, - inform2, - inform3, - inform4, - inform_swarm, - report - ] ++ OldApiCases ++ NewApiCases, + Cases = + [ + trap1, + trap2, + inform1, + inform2, + inform3, + inform4, + inform_swarm, + report + ] ++ + OldApiCases ++ + NewApiCases, case lists:member(Case, Cases) of true -> Conf1 = case lists:member(Case, NewApiCases) of @@ -446,7 +458,8 @@ event_tests(suite) -> tickets(suite) -> [ - otp8015 + otp8015, + otp8395 ]. otp8015(suite) -> @@ -454,6 +467,11 @@ otp8015(suite) -> otp8015_1 ]. +otp8395(suite) -> + [ + otp8395_1 + ]. + %%====================================================================== %% Test functions @@ -1372,6 +1390,9 @@ simple_sync_get2(suite) -> []; simple_sync_get2(Config) when is_list(Config) -> process_flag(trap_exit, true), put(tname, ssg2), + do_simple_get(Config). + +do_simple_get(Config) -> p("starting with Config: ~p~n", [Config]), Node = ?config(manager_node, Config), @@ -1386,7 +1407,7 @@ simple_sync_get2(Config) when is_list(Config) -> Oids2 = [[sysObjectID, 0], [sysDescr, 0], [sysUpTime, 0]], ?line ok = do_simple_get(Node, TargetName, Oids2), ok. - + do_simple_get(Node, TargetName, Oids) -> ?line {ok, Reply, Rem} = mgr_user_sync_get(Node, TargetName, Oids), @@ -4437,6 +4458,16 @@ otp8015_1(Config) when is_list(Config) -> ok. +%%====================================================================== + +otp8395_1(doc) -> ["OTP-8395:1 - simple get with ATL sequence numbering."]; +otp8395_1(suite) -> []; +otp8395_1(Config) when is_list(Config) -> + process_flag(trap_exit, true), + put(tname, otp8395_1), + do_simple_get(Config). + + %%====================================================================== %% async snmp utility functions %%====================================================================== @@ -5063,12 +5094,15 @@ start_manager(Node, Vsns, Conf0, Opts) -> ServerVerbosity = get_opt(manager_server_verbosity, Conf0, trace), NetIfVerbosity = get_opt(manager_net_if_verbosity, Conf0, trace), + AtlSeqNo = get_opt(manager_atl_seqno, Conf0, false), + Env = [{versions, Vsns}, {inform_request_behaviour, IRB}, {audit_trail_log, [{type, read_write}, {dir, AtlDir}, {size, {10240, 10}}, - {repair, true}]}, + {repair, true}, + {seqno, AtlSeqNo}]}, {config, [{dir, ConfDir}, {db_dir, DbDir}, {verbosity, ConfigVerbosity}]}, diff --git a/lib/snmp/test/snmp_test_mgr.erl b/lib/snmp/test/snmp_test_mgr.erl index 085dc8600f..84bdc6b04f 100644 --- a/lib/snmp/test/snmp_test_mgr.erl +++ b/lib/snmp/test/snmp_test_mgr.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1996-2010. 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 %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% diff --git a/lib/snmp/vsn.mk b/lib/snmp/vsn.mk index 9931bb90f4..d78a2cec7a 100644 --- a/lib/snmp/vsn.mk +++ b/lib/snmp/vsn.mk @@ -1,27 +1,29 @@ #-*-makefile-*- ; force emacs to enter makefile-mode # %CopyrightBegin% -# -# Copyright Ericsson AB 1997-2009. All Rights Reserved. -# +# +# Copyright Ericsson AB 1997-2010. 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 # compliance with the License. You should have received a copy of the # Erlang Public License along with this software. If not, it can be # retrieved online at http://www.erlang.org/. -# +# # Software distributed under the License is distributed on an "AS IS" # basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See # the License for the specific language governing rights and limitations # under the License. -# +# # %CopyrightEnd% -SNMP_VSN = 4.15.0.1 -PRE_VSN = +SNMP_VSN = 4.16 +PRE_VSN =-p01 APP_VSN = "snmp-$(SNMP_VSN)$(PRE_VSN)" -TICKETS = OTP-8229 OTP-8249 +TICKETS = OTP-8395 + +TICKETS_4_15 = OTP-8229 OTP-8249 TICKETS_4_14 = OTP-8223 OTP-8228 OTP-8237 -- cgit v1.2.3