diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/snmp/doc/src/notes.xml | 12 | ||||
-rw-r--r-- | lib/snmp/doc/src/snmp_app.xml | 109 | ||||
-rw-r--r-- | lib/snmp/doc/src/snmp_config.xml | 108 | ||||
-rw-r--r-- | lib/snmp/src/agent/depend.mk | 2 | ||||
-rw-r--r-- | lib/snmp/src/agent/snmp_target_mib.erl | 16 | ||||
-rw-r--r-- | lib/snmp/src/agent/snmpa_agent.erl | 586 | ||||
-rw-r--r-- | lib/snmp/src/agent/snmpa_internal.hrl | 11 | ||||
-rw-r--r-- | lib/snmp/src/agent/snmpa_mib_lib.erl | 20 | ||||
-rw-r--r-- | lib/snmp/src/agent/snmpa_supervisor.erl | 40 | ||||
-rw-r--r-- | lib/snmp/src/agent/snmpa_trap.erl | 20 | ||||
-rw-r--r-- | lib/snmp/src/agent/snmpa_vacm.erl | 18 | ||||
-rw-r--r-- | lib/snmp/src/app/snmp.appup.src | 92 | ||||
-rw-r--r-- | lib/snmp/test/snmp_agent_test.erl | 34 | ||||
-rw-r--r-- | lib/snmp/test/snmp_agent_test_lib.erl | 181 | ||||
-rw-r--r-- | lib/snmp/vsn.mk | 2 |
15 files changed, 984 insertions, 267 deletions
diff --git a/lib/snmp/doc/src/notes.xml b/lib/snmp/doc/src/notes.xml index 9db372dbe1..9082868e39 100644 --- a/lib/snmp/doc/src/notes.xml +++ b/lib/snmp/doc/src/notes.xml @@ -46,6 +46,18 @@ <list type="bulleted"> <item> + <p>[agent] DoS attack using GET-BULK with large value of + MaxRepetitions. + A preventive method has been implementing by simply + limit the number of varbinds that can be included in + a Get-BULK response message. This is specified by the + new config option, + <seealso marker="snmp_app#agent_gb_max_vbs">gb_max_vbs</seealso>. + </p> + <p>Own Id: OTP-9700</p> + </item> + + <item> <p>[agent] Mib server cache gclimit update function incorrectly calls age update function. The gclimit update function, diff --git a/lib/snmp/doc/src/snmp_app.xml b/lib/snmp/doc/src/snmp_app.xml index 694e619da1..f6abe783b3 100644 --- a/lib/snmp/doc/src/snmp_app.xml +++ b/lib/snmp/doc/src/snmp_app.xml @@ -1,10 +1,10 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="iso-8859-1" ?> <!DOCTYPE appref SYSTEM "appref.dtd"> <appref> <header> <copyright> - <year>1997</year><year>2010</year> + <year>1997</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -78,7 +78,15 @@ ]. </pre> - <!-- The info below is also found in the snmp_config.xml file --> + + <!-- + ******************************************************** + + The info below is also found in the snmp_config.xml file + + ******************************************************** + --> + <p>Each snmp component has its own set of configuration parameters, even though some of the types are common to both components. </p> @@ -92,6 +100,7 @@ {agent_verbosity, verbosity()} | {discovery, agent_discovery()} | {versions, versions()} | + {gb_max_vbs, gb_max_vbs()} | {priority, priority()} | {multi_threaded, multi_threaded()} | {db_dir, db_dir()} | @@ -122,8 +131,10 @@ {def_user_data, def_user_data()} </pre> + <marker id="agent_opts_and_types"></marker> <p>Agent specific config options and types:</p> <taglist> + <marker id="agent_type"></marker> <tag><c><![CDATA[agent_type() = master | sub <optional>]]></c></tag> <item> <p>If <c>master</c>, one master agent is @@ -131,6 +142,7 @@ <p>Default is <c>master</c>.</p> </item> + <marker id="agent_disco"></marker> <tag><c><![CDATA[agent_discovery() = [agent_discovery_opt()] <optional>]]></c></tag> <item> <p><c>agent_discovery_opt() = @@ -143,6 +155,7 @@ <p>For defaults see the options in <c>agent_discovery_opt()</c>.</p> </item> + <marker id="agent_term_disco_opts"></marker> <tag><c><![CDATA[agent_terminating_discovery_opts() = [agent_terminating_discovery_opt()] <optional>]]></c></tag> <item> <p><c>agent_terminating_discovery_opt() = @@ -160,6 +173,7 @@ </list> </item> + <marker id="agent_orig_disco_opts"></marker> <tag><c><![CDATA[agent_originating_discovery_opts() = [agent_originating_discovery_opt()] <optional>]]></c></tag> <item> <p><c>agent_originating_discovery_opt() = @@ -173,6 +187,7 @@ </list> </item> + <marker id="agent_mt"></marker> <tag><c><![CDATA[multi_threaded() = bool() <optional>]]></c></tag> <item> <p>If <c>true</c>, the agent is multi-threaded, with one @@ -180,11 +195,21 @@ <p>Default is <c>false</c>.</p> </item> + <marker id="agent_data_dir"></marker> <tag><c><![CDATA[db_dir() = string() <mandatory>]]></c></tag> <item> <p>Defines where the SNMP agent internal db files are stored.</p> </item> + <marker id="agent_gb_max_vbs"></marker> + <tag><c><![CDATA[gb_max_vbs() = pos_integer() | infinity <optional>]]></c></tag> + <item> + <p>Defines the maximum number of varbinds allowed + in a Get-BULK response.</p> + <p>Default is <c>1000</c>.</p> + </item> + + <marker id="agent_local_db"></marker> <tag><c><![CDATA[local_db() = [local_db_opt()] <optional>]]></c></tag> <item> <p><c>local_db_opt() = {repair, agent_repair()} | {auto_save, agent_auto_save()} | {verbosity, verbosity()}</c></p> @@ -192,6 +217,7 @@ <p>For defaults see the options in <c>local_db_opt()</c>.</p> </item> + <marker id="agent_ldb_repair"></marker> <tag><c><![CDATA[agent_repair() = false | true | force <optional>]]></c></tag> <item> <p>When starting snmpa_local_db it always tries to open an @@ -202,6 +228,7 @@ <p>Default is <c>true</c>.</p> </item> + <marker id="agent_ldb_auto_save"></marker> <tag><c><![CDATA[agent_auto_save() = integer() | infinity <optional>]]></c></tag> <item> <p>The auto save interval. The table is flushed to disk @@ -209,6 +236,7 @@ <p>Default is <c>5000</c>.</p> </item> + <marker id="agent_net_if"></marker> <tag><c><![CDATA[agent_net_if() = [agent_net_if_opt()] <optional>]]></c></tag> <item> <p><c>agent_net_if_opt() = {module, agent_net_if_module()} | {verbosity, verbosity()} | {options, agent_net_if_options()}</c></p> @@ -217,6 +245,7 @@ <p>For defaults see the options in <c>agent_net_if_opt()</c>.</p> </item> + <marker id="agent_ni_module"></marker> <tag><c><![CDATA[agent_net_if_module() = atom() <optional>]]></c></tag> <item> <p>Module which handles the network interface part for the @@ -225,6 +254,7 @@ <p>Default is <c>snmpa_net_if</c>.</p> </item> + <marker id="agent_ni_opts"></marker> <tag><c><![CDATA[agent_net_if_options() = [agent_net_if_option()] <optional>]]></c></tag> <item> <p><c>agent_net_if_option() = {bind_to, bind_to()} | @@ -239,12 +269,14 @@ <p>For defaults see the options in <c>agent_net_if_option()</c>.</p> </item> + <marker id="agent_ni_req_limit"></marker> <tag><c><![CDATA[req_limit() = integer() | infinity <optional>]]></c></tag> <item> <p>Max number of simultaneous requests handled by the agent.</p> <p>Default is <c>infinity</c>.</p> </item> + <marker id="agent_ni_filter_opts"></marker> <tag><c><![CDATA[agent_net_if_filter_options() = [agent_net_if_filter_option()] <optional>]]></c></tag> <item> <p><c>agent_net_if_filter_option() = {module, agent_net_if_filter_module()}</c></p> @@ -255,6 +287,7 @@ <c>agent_net_if_filter_option()</c>.</p> </item> + <marker id="agent_ni_filter_module"></marker> <tag><c><![CDATA[agent_net_if_filter_module() = atom() <optional>]]></c></tag> <item> <p>Module which handles the network interface filter part for the @@ -263,6 +296,7 @@ <p>Default is <c>snmpa_net_if_filter</c>.</p> </item> + <marker id="agent_mibs"></marker> <tag><c><![CDATA[agent_mibs() = [string()] <optional>]]></c></tag> <item> <p>Specifies a list of MIBs (including path) that defines which MIBs @@ -277,6 +311,7 @@ <p>Default is <c>[]</c>.</p> </item> + <marker id="agent_mib_storage"></marker> <tag><c><![CDATA[mib_storage() = ets | {ets, Dir} | {ets, Dir, Action} | dets | {dets, Dir} | {dets, Dir, Action} | mnesia | {mnesia, Nodes} | {mnesia, Nodes, Action} <optional>]]></c></tag> <item> <p>Specifies how info retrieved from the mibs will be stored.</p> @@ -302,6 +337,7 @@ mnesia/dets table already exist.</p> </item> + <marker id="agent_mib_server"></marker> <tag><c><![CDATA[mib_server() = [mib_server_opt()] <optional>]]></c></tag> <item> <p><c>mib_server_opt() = {mibentry_override, mibentry_override()} | {trapentry_override, trapentry_override()} | {verbosity, verbosity()} | {cache, mibs_cache()}</c></p> @@ -309,6 +345,7 @@ <p>For defaults see the options in <c>mib_server_opt()</c>.</p> </item> + <marker id="agent_ms_meo"></marker> <tag><c><![CDATA[mibentry_override() = bool() <optional>]]></c></tag> <item> <p>If this value is false, then when loading a mib each mib- @@ -318,6 +355,7 @@ <p>Default is <c>false</c>.</p> </item> + <marker id="agent_ms_teo"></marker> <tag><c><![CDATA[trapentry_override() = bool() <optional>]]></c></tag> <item> <p>If this value is false, then when loading a mib each trap @@ -327,6 +365,7 @@ <p>Default is <c>false</c>.</p> </item> + <marker id="agent_ms_cache"></marker> <tag><c><![CDATA[mibs_cache() = bool() | mibs_cache_opts() <optional>]]></c></tag> <item> <p>Shall the agent utilize the mib server lookup cache or not.</p> @@ -334,6 +373,7 @@ default values apply).</p> </item> + <marker id="agent_ms_cache_opts"></marker> <tag><c><![CDATA[mibs_cache_opts() = [mibs_cache_opt()] <optional>]]></c></tag> <item> <p><c>mibs_cache_opt() = {autogc, mibs_cache_autogc()} | {gclimit, mibs_cache_gclimit()} | {age, mibs_cache_age()}</c></p> @@ -341,6 +381,7 @@ <p>For defaults see the options in <c>mibs_cache_opt()</c>.</p> </item> + <marker id="agent_ms_cache_autogc"></marker> <tag><c><![CDATA[mibs_cache_autogc() = bool() <optional>]]></c></tag> <item> <p>Defines if the mib server shall perform cache gc automatically or @@ -349,6 +390,7 @@ <p>Default is <c>true</c>.</p> </item> + <marker id="agent_ms_cache_age"></marker> <tag><c><![CDATA[mibs_cache_age() = integer() > 0 <optional>]]></c></tag> <item> <p>Defines how old the entries in the cache will be allowed before @@ -358,6 +400,7 @@ <p>Default is <c>10 timutes</c>.</p> </item> + <marker id="agent_ms_cache_gclimit"></marker> <tag><c><![CDATA[mibs_cache_gclimit() = integer() > 0 | infinity <optional>]]></c></tag> <item> <p>When performing a GC, this is the max number of cache entries @@ -368,6 +411,7 @@ <p>Default is <c>100</c>.</p> </item> + <marker id="agent_error_report_mod"></marker> <tag><c><![CDATA[error_report_mod() = atom() <optional>]]></c></tag> <item> <p>Defines an error report module, implementing the @@ -377,6 +421,7 @@ <p>Default is <c>snmpa_error_logger</c>.</p> </item> + <marker id="agent_symbolic_store"></marker> <tag><c>symbolic_store() = [symbolic_store_opt()]</c></tag> <item> <p><c>symbolic_store_opt() = {verbosity, verbosity()}</c></p> @@ -384,23 +429,29 @@ <p>For defaults see the options in <c>symbolic_store_opt()</c>.</p> </item> + <marker id="agent_target_cache"></marker> <tag><c>target_cache() = [target_cache_opt()]</c></tag> <item> <p><c>target_cache_opt() = {verbosity, verbosity()}</c></p> <p>Defines options specific for the SNMP agent target cache. </p> <p>For defaults see the options in <c>target_cache_opt()</c>.</p> </item> + + <marker id="agent_config"></marker> <tag><c><![CDATA[agent_config() = [agent_config_opt()] <mandatory>]]></c></tag> <item> <p><c>agent_config_opt() = {dir, agent_config_dir()} | {force_load, force_load()} | {verbosity, verbosity()}</c></p> <p>Defines specific config related options for the SNMP agent. </p> <p>For defaults see the options in <c>agent_config_opt()</c>.</p> </item> + + <marker id="agent_config_dir"></marker> <tag><c><![CDATA[agent_config_dir = dir() <mandatory>]]></c></tag> <item> <p>Defines where the SNMP agent configuration files are stored.</p> </item> + <marker id="agent_force_load"></marker> <tag><c><![CDATA[force_load() = bool() <optional>]]></c></tag> <item> <p>If <c>true</c> the configuration files are re-read @@ -412,14 +463,18 @@ </item> </taglist> + <marker id="manager_opts_and_types"></marker> <p>Manager specific config options and types:</p> <taglist> + <marker id="manager_server"></marker> <tag><c><![CDATA[server() = [server_opt()] <optional>]]></c></tag> <item> <p><c>server_opt() = {timeout, server_timeout()} | {verbosity, verbosity()}</c></p> <p>Specifies the options for the manager server process.</p> <p>Default is <c>silence</c>.</p> </item> + + <marker id="manager_server_timeout"></marker> <tag><c><![CDATA[server_timeout() = integer() <optional>]]></c></tag> <item> <p>Asynchroneous request cleanup time. For every requests, @@ -440,6 +495,7 @@ <p>Default is <c>30000</c>.</p> </item> + <marker id="manager_config"></marker> <tag><c><![CDATA[manager_config() = [manager_config_opt()] <mandatory>]]></c></tag> <item> <p><c>manager_config_opt() = {dir, manager_config_dir()} | {db_dir, manager_db_dir()} | {db_init_error, db_init_error()} | {repair, manager_repair()} | {auto_save, manager_auto_save()} | {verbosity, verbosity()}</c></p> @@ -447,16 +503,19 @@ <p>For defaults see the options in <c>manager_config_opt()</c>.</p> </item> + <marker id="manager_config_dir"></marker> <tag><c><![CDATA[manager_config_dir = dir() <mandatory>]]></c></tag> <item> <p>Defines where the SNMP manager configuration files are stored.</p> </item> + <marker id="manager_config_db_dir"></marker> <tag><c><![CDATA[manager_db_dir = dir() <mandatory>]]></c></tag> <item> <p>Defines where the SNMP manager store persistent data.</p> </item> + <marker id="manager_config_repair"></marker> <tag><c><![CDATA[manager_repair() = false | true | force <optional>]]></c></tag> <item> <p>Defines the repair option for the persistent database (if @@ -464,6 +523,7 @@ <p>Default is <c>true</c>.</p> </item> + <marker id="manager_config_auto_save"></marker> <tag><c><![CDATA[manager_auto_save() = integer() | infinity <optional>]]></c></tag> <item> <p>The auto save interval. The table is flushed to disk @@ -471,6 +531,7 @@ <p>Default is <c>5000</c>.</p> </item> + <marker id="manager_irb"></marker> <tag><c><![CDATA[manager_irb() = auto | user | {user, integer()} <optional>]]></c></tag> <item> <p>This option defines how the manager will handle the sending of @@ -500,6 +561,7 @@ <p>Default is <c>auto</c>.</p> </item> + <marker id="manager_mibs"></marker> <tag><c><![CDATA[manager_mibs() = [string()] <optional>]]></c></tag> <item> <p>Specifies a list of MIBs (including path) and defines which MIBs @@ -507,6 +569,7 @@ <p>Default is <c>[]</c>.</p> </item> + <marker id="manager_net_if"></marker> <tag><c><![CDATA[manager_net_if() = [manager_net_if_opt()] <optional>]]></c></tag> <item> <p><c>manager_net_if_opt() = {module, manager_net_if_module()} | @@ -517,6 +580,7 @@ <p>For defaults see the options in <c>manager_net_if_opt()</c>.</p> </item> + <marker id="manager_ni_opts"></marker> <tag><c><![CDATA[manager_net_if_options() = [manager_net_if_option()] <optional>]]></c></tag> <item> <p><c>manager_net_if_option() = {bind_to, bind_to()} | @@ -530,6 +594,7 @@ <p>For defaults see the options in <c>manager_net_if_option()</c>.</p> </item> + <marker id="manager_ni_module"></marker> <tag><c><![CDATA[manager_net_if_module() = atom() <optional>]]></c></tag> <item> <p>Module which handles the network interface part for the @@ -538,6 +603,7 @@ <p>Default is <c>snmpm_net_if</c>.</p> </item> + <marker id="manager_ni_filter_opts"></marker> <tag><c><![CDATA[manager_net_if_filter_options() = [manager_net_if_filter_option()] <optional>]]></c></tag> <item> <p><c>manager_net_if_filter_option() = {module, manager_net_if_filter_module()}</c></p> @@ -548,6 +614,7 @@ <c>manager_net_if_filter_option()</c>.</p> </item> + <marker id="manager_ni_filter_module"></marker> <tag><c><![CDATA[manager_net_if_filter_module() = atom() <optional>]]></c></tag> <item> <p>Module which handles the network interface filter part for the @@ -556,6 +623,7 @@ <p>Default is <c>snmpm_net_if_filter</c>.</p> </item> + <marker id="manager_def_user_module"></marker> <tag><c><![CDATA[def_user_module() = atom() <optional>]]></c></tag> <item> <p>The module implementing the default user. See the @@ -563,6 +631,7 @@ <p>Default is <c>snmpm_user_default</c>.</p> </item> + <marker id="manager_def_user_data"></marker> <tag><c><![CDATA[def_user_data() = term() <optional>]]></c></tag> <item> <p>Data for the default user. Passed to the user module when @@ -571,8 +640,10 @@ </item> </taglist> + <marker id="common_types"></marker> <p>Common config types:</p> <taglist> + <marker id="restart_type"></marker> <tag><c>restart_type() = permanent | transient | temporary</c></tag> <item> <p>See <seealso marker="stdlib:supervisor#child_spec">supervisor</seealso> @@ -580,6 +651,8 @@ <p>Default is <c>permanent</c> for the agent and <c>transient</c> for the manager.</p> </item> + + <marker id="db_init_error"></marker> <tag><c>db_init_error() = terminate | create</c></tag> <item> <p>Defines what to do if the agent or manager is unable to open an @@ -588,23 +661,31 @@ agent/manager will remove the faulty file(s) and create new ones.</p> <p>Default is <c>terminate</c>.</p> </item> + + <marker id="prio"></marker> <tag><c><![CDATA[priority() = atom() <optional>]]></c></tag> <item> <p>Defines the Erlang priority for all SNMP processes.</p> <p>Default is <c>normal</c>.</p> </item> + + <marker id="versions"></marker> <tag><c><![CDATA[versions() = [version()] <optional>]]></c></tag> <item> <p><c>version() = v1 | v2 | v3</c></p> <p>Which SNMP versions shall be accepted/used.</p> <p>Default is <c>[v1,v2,v3]</c>.</p> </item> + + <marker id="verbosity"></marker> <tag><c><![CDATA[verbosity() = silence | info | log | debug | trace <optional>]]></c></tag> <item> <p>Verbosity for a SNMP process. This specifies now much debug info is printed.</p> <p>Default is <c>silence</c>.</p> </item> + + <marker id="bind_to"></marker> <tag><c><![CDATA[bind_to() = bool() <optional>]]></c></tag> <item> <p>If <c>true</c>, net_if binds to the IP address. @@ -612,6 +693,8 @@ where it is running. </p> <p>Default is <c>false</c>.</p> </item> + + <marker id="no_reuse"></marker> <tag><c><![CDATA[no_reuse() = bool() <optional>]]></c></tag> <item> <p>If <c>true</c>, net_if does not specify that the IP @@ -619,22 +702,30 @@ the address is set to reusable. </p> <p>Default is <c>false</c>.</p> </item> + + <marker id="recbuf"></marker> <tag><c><![CDATA[recbuf() = integer() <optional>]]></c></tag> <item> <p>Receive buffer size. </p> <p>Default value is defined by <c>gen_udp</c>.</p> </item> + + <marker id="sndbuf"></marker> <tag><c><![CDATA[sndbuf() = integer() <optional>]]></c></tag> <item> <p>Send buffer size. </p> <p>Default value is defined by <c>gen_udp</c>.</p> </item> + + <marker id="note_store"></marker> <tag><c><![CDATA[note_store() = [note_store_opt()] <optional>]]></c></tag> <item> <p><c>note_store_opt() = {timeout, note_store_timeout()} | {verbosity, verbosity()}</c></p> <p>Specifies the start-up verbosity for the SNMP note store.</p> <p>For defaults see the options in <c>note_store_opt()</c>.</p> </item> + + <marker id="ns_timeout"></marker> <tag><c><![CDATA[note_store_timeout() = integer() <optional>]]></c></tag> <item> <p>Note cleanup time. When storing a note in the note store, @@ -643,9 +734,9 @@ milli-seconds.</p> <p>Default is <c>30000</c>.</p> - <marker id="audit_trail_log"></marker> </item> + <marker id="audit_trail_log"></marker> <tag><c><![CDATA[audit_trail_log() = [audit_trail_log_opt()] <optional>]]></c></tag> <item> <p><c>audit_trail_log_opt() = {type, atl_type()} | {dir, atl_dir()} | {size, atl_size()} | {repair, atl_repair()} | {seqno, atl_seqno()}</c></p> @@ -655,6 +746,8 @@ <c>size</c> options are mandatory.</p> <p>If not present, audit trail logging is not used.</p> </item> + + <marker id="atl_type"></marker> <tag><c><![CDATA[atl_type() = read | write | read_write <optional>]]></c></tag> <item> <p>Specifies what type of an audit trail log should be used. @@ -675,12 +768,16 @@ </list> <p>Default is <c>read_write</c>.</p> </item> + + <marker id="atl_dir"></marker> <tag><c><![CDATA[atl_dir = dir() <mandatory>]]></c></tag> <item> <p>Specifies where the audit trail log should be stored.</p> <p>If <c>audit_trail_log</c> specifies that logging should take place, this parameter <em>must</em> be defined.</p> </item> + + <marker id="atl_size"></marker> <tag><c><![CDATA[atl_size() = {integer(), integer()} <mandatory>]]></c></tag> <item> <p>Specifies the size of the audit @@ -688,6 +785,8 @@ <p>If <c>audit_trail_log</c> specifies that logging should take place, this parameter <em>must</em> be defined.</p> </item> + + <marker id="atl_repair"></marker> <tag><c><![CDATA[atl_repair() = true | false | truncate | snmp_repair <optional>]]></c></tag> <item> <p>Specifies if and how the audit trail log shall be repaired @@ -699,6 +798,8 @@ analysis.</p> <p>Default is <c>true</c>.</p> </item> + + <marker id="atl_seqno"></marker> <tag><c><![CDATA[atl_seqno() = true | false <optional>]]></c></tag> <item> <p>Specifies if the audit trail log entries will be (sequence) diff --git a/lib/snmp/doc/src/snmp_config.xml b/lib/snmp/doc/src/snmp_config.xml index 769b908adc..ab66a11387 100644 --- a/lib/snmp/doc/src/snmp_config.xml +++ b/lib/snmp/doc/src/snmp_config.xml @@ -1,10 +1,10 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="iso-8859-1" ?> <!DOCTYPE chapter SYSTEM "chapter.dtd"> <chapter> <header> <copyright> - <year>1997</year><year>2010</year> + <year>1997</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -40,6 +40,7 @@ <item>starting the application (agent and/or manager)</item> <item>debugging the application (agent and/or manager)</item> </list> + <p>Refer also to the chapter(s) <seealso marker="snmp_agent_config_files">Definition of Agent Configuration Files</seealso> and <seealso marker="snmp_manager_config_files">Definition of Manager Configuration Files</seealso> which contains more detailed information @@ -73,7 +74,14 @@ </item> </list> - <!-- The info below is also found in the snmp_app.xml file --> + + <!-- + ***************************************************** + + The info below is also found in the snmp_app.xml file + + ***************************************************** + --> <p>The agent and manager uses (application) configuration parameters to find out where these directories are located. The parameters should be @@ -87,6 +95,7 @@ {agent_verbosity, verbosity()} | {versions, versions()} | {discovery, agent_discovery()} | + {gb_max_vbs, gb_max_vbs()} | {priority, priority()} | {multi_threaded, multi_threaded()} | {db_dir, db_dir()} | @@ -117,8 +126,10 @@ {def_user_data, def_user_data()} </pre> + <marker id="agent_opts_and_types"></marker> <p>Agent specific config options and types:</p> <taglist> + <marker id="agent_type"></marker> <tag><c><![CDATA[agent_type() = master | sub <optional>]]></c></tag> <item> <p>If <c>master</c>, one master agent is @@ -126,6 +137,7 @@ <p>Default is <c>master</c>.</p> </item> + <marker id="agent_disco"></marker> <tag><c><![CDATA[agent_discovery() = [agent_discovery_opt()] <optional>]]></c></tag> <item> <p><c>agent_discovery_opt() = @@ -138,6 +150,7 @@ <p>For defaults see the options in <c>agent_discovery_opt()</c>.</p> </item> + <marker id="agent_term_disco_opts"></marker> <tag><c><![CDATA[agent_terminating_discovery_opts() = [agent_terminating_discovery_opt()] <optional>]]></c></tag> <item> <p><c>agent_terminating_discovery_opt() = @@ -155,6 +168,7 @@ </list> </item> + <marker id="agent_orig_disco_opts"></marker> <tag><c><![CDATA[agent_originating_discovery_opts() = [agent_originating_discovery_opt()] <optional>]]></c></tag> <item> <p><c>agent_originating_discovery_opt() = @@ -168,6 +182,7 @@ </list> </item> + <marker id="agent_mt"></marker> <tag><c><![CDATA[multi_threaded() = bool() <optional>]]></c></tag> <item> <p>If <c>true</c>, the agent is multi-threaded, with one @@ -175,11 +190,21 @@ <p>Default is <c>false</c>.</p> </item> + <marker id="agent_data_dir"></marker> <tag><c><![CDATA[db_dir() = string() <mandatory>]]></c></tag> <item> <p>Defines where the SNMP agent internal db files are stored.</p> </item> + <marker id="agent_gb_max_vbs"></marker> + <tag><c><![CDATA[gb_max_vbs() = pos_integer() | infinity <optional>]]></c></tag> + <item> + <p>Defines the maximum number of varbinds allowed + in a Get-BULK response.</p> + <p>Default is <c>1000</c>.</p> + </item> + + <marker id="agent_local_db"></marker> <tag><c><![CDATA[local_db() = [local_db_opt()] <optional>]]></c></tag> <item> <p><c>local_db_opt() = {repair, agent_repair()} | {auto_save, agent_auto_save()} | {verbosity, verbosity()}</c></p> @@ -187,6 +212,7 @@ <p>For defaults see the options in <c>local_db_opt()</c>.</p> </item> + <marker id="agent_ldb_repair"></marker> <tag><c><![CDATA[agent_repair() = false | true | force <optional>]]></c></tag> <item> <p>When starting snmpa_local_db it always tries to open an @@ -197,6 +223,7 @@ <p>Default is <c>true</c>.</p> </item> + <marker id="agent_ldb_auto_save"></marker> <tag><c><![CDATA[agent_auto_save() = integer() | infinity <optional>]]></c></tag> <item> <p>The auto save interval. The table is flushed to disk @@ -204,6 +231,7 @@ <p>Default is <c>5000</c>.</p> </item> + <marker id="agent_net_if"></marker> <tag><c><![CDATA[agent_net_if() = [agent_net_if_opt()] <optional>]]></c></tag> <item> <p><c>agent_net_if_option() = {module, agent_net_if_module()} | @@ -214,6 +242,7 @@ <p>For defaults see the options in <c>agent_net_if_opt()</c>.</p> </item> + <marker id="agent_ni_module"></marker> <tag><c><![CDATA[agent_net_if_module() = atom() <optional>]]></c></tag> <item> <p>Module which handles the network interface part for the @@ -222,6 +251,7 @@ <p>Default is <c>snmpa_net_if</c>.</p> </item> + <marker id="agent_ni_opts"></marker> <tag><c><![CDATA[agent_net_if_options() = [agent_net_if_option()] <optional>]]></c></tag> <item> <p><c>agent_net_if_option() = {bind_to, bind_to()} | @@ -236,6 +266,14 @@ <p>For defaults see the options in <c>agent_net_if_option()</c>.</p> </item> + <marker id="agent_ni_req_limit"></marker> + <tag><c><![CDATA[req_limit() = integer() | infinity <optional>]]></c></tag> + <item> + <p>Max number of simultaneous requests handled by the agent.</p> + <p>Default is <c>infinity</c>.</p> + </item> + + <marker id="agent_ni_filter_opts"></marker> <tag><c><![CDATA[agent_net_if_filter_options() = [agent_net_if_filter_option()] <optional>]]></c></tag> <item> <p><c><![CDATA[agent_net_if_filter_option() = {module, agent_net_if_filter_module()}]]></c></p> @@ -245,6 +283,7 @@ <p>For defaults see the options in <c>agent_net_if_filter_option()</c>.</p> </item> + <marker id="agent_ni_filter_module"></marker> <tag><c><![CDATA[agent_net_if_filter_module() = atom() <optional>]]></c></tag> <item> <p>Module which handles the network interface filter part for the @@ -254,12 +293,7 @@ <p>Default is <c>snmpa_net_if_filter</c>.</p> </item> - <tag><c><![CDATA[req_limit() = integer() | infinity <optional>]]></c></tag> - <item> - <p>Max number of simultaneous requests handled by the agent.</p> - <p>Default is <c>infinity</c>.</p> - </item> - + <marker id="agent_mibs"></marker> <tag><c><![CDATA[agent_mibs() = [string()] <optional>]]></c></tag> <item> <p>Specifies a list of MIBs (including path) that defines which MIBs @@ -274,6 +308,7 @@ <p>Default is <c>[]</c>.</p> </item> + <marker id="agent_mib_storage"></marker> <tag><c><![CDATA[mib_storage() = ets | {ets, Dir} | {ets, Dir, Action} | dets | {dets, Dir} | {dets, Dir, Action} | mnesia | {mnesia, Nodes} | {mnesia, Nodes, Action} <optional>]]></c></tag> <item> <p>Specifies how info retrieved from the mibs will be stored.</p> @@ -299,6 +334,7 @@ mnesia/dets table already exist.</p> </item> + <marker id="agent_mib_server"></marker> <tag><c><![CDATA[mib_server() = [mib_server_opt()] <optional>]]></c></tag> <item> <p><c>mib_server_opt() = {mibentry_override, mibentry_override()} | {trapentry_override, trapentry_override()} | {verbosity, verbosity()} | {cache, mibs_cache()}</c></p> @@ -306,6 +342,7 @@ <p>For defaults see the options in <c>mib_server_opt()</c>.</p> </item> + <marker id="agent_ms_meo"></marker> <tag><c><![CDATA[mibentry_override() = bool() <optional>]]></c></tag> <item> <p>If this value is false, then when loading a mib each mib- @@ -315,6 +352,7 @@ <p>Default is <c>false</c>.</p> </item> + <marker id="agent_ms_teo"></marker> <tag><c><![CDATA[trapentry_override() = bool() <optional>]]></c></tag> <item> <p>If this value is false, then when loading a mib each trap @@ -324,6 +362,7 @@ <p>Default is <c>false</c>.</p> </item> + <marker id="agent_ms_cache"></marker> <tag><c><![CDATA[mibs_cache() = bool() | mibs_cache_opts() <optional>]]></c></tag> <item> <p>Shall the agent utilize the mib server lookup cache or not.</p> @@ -331,6 +370,7 @@ default values apply).</p> </item> + <marker id="agent_ms_cache_opts"></marker> <tag><c><![CDATA[mibs_cache_opts() = [mibs_cache_opt()] <optional>]]></c></tag> <item> <p><c>mibs_cache_opt() = {autogc, mibs_cache_autogc()} | {gclimit, mibs_cache_gclimit()} | {age, mibs_cache_age()}</c></p> @@ -338,6 +378,7 @@ <p>For defaults see the options in <c>mibs_cache_opt()</c>.</p> </item> + <marker id="agent_ms_cache_autogc"></marker> <tag><c><![CDATA[mibs_cache_autogc() = bool() <optional>]]></c></tag> <item> <p>Defines if the mib server shall perform cache gc automatically or @@ -346,6 +387,7 @@ <p>Default is <c>true</c>.</p> </item> + <marker id="agent_ms_cache_age"></marker> <tag><c><![CDATA[mibs_cache_age() = integer() > 0 <optional>]]></c></tag> <item> <p>Defines how old the entries in the cache will be allowed before @@ -355,6 +397,7 @@ <p>Default is <c>10 timutes</c>.</p> </item> + <marker id="agent_ms_cache_gclimit"></marker> <tag><c><![CDATA[mibs_cache_gclimit() = integer() > 0 | infinity <optional>]]></c></tag> <item> <p>When performing a GC, this is the max number of cache entries @@ -365,6 +408,7 @@ <p>Default is <c>100</c>.</p> </item> + <marker id="agent_error_report_mod"></marker> <tag><c><![CDATA[error_report_mod() = atom() <optional>]]></c></tag> <item> <p>Defines an error report module, implementing the @@ -374,6 +418,7 @@ <p>Default is <c>snmpa_error_logger</c>.</p> </item> + <marker id="agent_symbolic_store"></marker> <tag><c>symbolic_store() = [symbolic_store_opt()]</c></tag> <item> <p><c>symbolic_store_opt() = {verbosity, verbosity()}</c></p> @@ -381,12 +426,15 @@ <p>For defaults see the options in <c>symbolic_store_opt()</c>.</p> </item> + <marker id="agent_target_cache"></marker> <tag><c>target_cache() = [target_cache_opt()]</c></tag> <item> <p><c>target_cache_opt() = {verbosity, verbosity()}</c></p> <p>Defines options specific for the SNMP agent target cache. </p> <p>For defaults see the options in <c>target_cache_opt()</c>.</p> </item> + + <marker id="agent_config"></marker> <tag><c><![CDATA[agent_config() = [agent_config_opt()] <mandatory>]]></c></tag> <item> <p><c>agent_config_opt() = {dir, agent_config_dir()} | {force_load, force_load()} | {verbosity, verbosity()}</c></p> @@ -394,11 +442,13 @@ <p>For defaults see the options in <c>agent_config_opt()</c>.</p> </item> + <marker id="agent_config_dir"></marker> <tag><c><![CDATA[agent_config_dir = dir() <mandatory>]]></c></tag> <item> <p>Defines where the SNMP agent configuration files are stored.</p> </item> + <marker id="agent_force_load"></marker> <tag><c><![CDATA[force_load() = bool() <optional>]]></c></tag> <item> <p>If <c>true</c> the configuration files are re-read @@ -410,14 +460,18 @@ </item> </taglist> + <marker id="manager_opts_and_types"></marker> <p>Manager specific config options and types:</p> <taglist> + <marker id="manager_server"></marker> <tag><c><![CDATA[server() = [server_opt()] <optional>]]></c></tag> <item> <p><c>server_opt() = {timeout, server_timeout()} | {verbosity, verbosity()}</c></p> <p>Specifies the options for the manager server process.</p> <p>Default is <c>silence</c>.</p> </item> + + <marker id="manager_server_timeout"></marker> <tag><c><![CDATA[server_timeout() = integer() <optional>]]></c></tag> <item> <p>Asynchroneous request cleanup time. For every requests, @@ -438,6 +492,7 @@ <p>Default is <c>30000</c>.</p> </item> + <marker id="manager_config"></marker> <tag><c><![CDATA[manager_config() = [manager_config_opt()] <mandatory>]]></c></tag> <item> <p><c>manager_config_opt() = {dir, manager_config_dir()} | {db_dir, manager_db_dir()} | {db_init_error, db_init_error()} | {repair, manager_repair()} | {auto_save, manager_auto_save()} | {verbosity, verbosity()}</c></p> @@ -445,16 +500,19 @@ <p>For defaults see the options in <c>manager_config_opt()</c>.</p> </item> + <marker id="manager_config_dir"></marker> <tag><c><![CDATA[manager_config_dir = dir() <mandatory>]]></c></tag> <item> <p>Defines where the SNMP manager configuration files are stored.</p> </item> + <marker id="manager_config_db_dir"></marker> <tag><c><![CDATA[manager_db_dir = dir() <mandatory>]]></c></tag> <item> <p>Defines where the SNMP manager store persistent data.</p> </item> + <marker id="manager_config_repair"></marker> <tag><c><![CDATA[manager_repair() = false | true | force <optional>]]></c></tag> <item> <p>Defines the repair option for the persistent database (if @@ -462,6 +520,7 @@ <p>Default is <c>true</c>.</p> </item> + <marker id="manager_config_auto_save"></marker> <tag><c><![CDATA[manager_auto_save() = integer() | infinity <optional>]]></c></tag> <item> <p>The auto save interval. The table is flushed to disk @@ -469,6 +528,7 @@ <p>Default is <c>5000</c>.</p> </item> + <marker id="manager_irb"></marker> <tag><c><![CDATA[manager_irb() = auto | user | {user, integer()} <optional>]]></c></tag> <item> <p>This option defines how the manager will handle the sending of @@ -498,6 +558,7 @@ <p>Default is <c>auto</c>.</p> </item> + <marker id="manager_mibs"></marker> <tag><c><![CDATA[manager_mibs() = [string()] <optional>]]></c></tag> <item> <p>Specifies a list of MIBs (including path) and defines which MIBs @@ -505,6 +566,7 @@ <p>Default is <c>[]</c>.</p> </item> + <marker id="manager_net_if"></marker> <tag><c><![CDATA[manager_net_if() = [manager_net_if_opt()] <optional>]]></c></tag> <item> <p><c>manager_net_if_opt() = {module, manager_net_if_module()} | @@ -515,6 +577,7 @@ <p>For defaults see the options in <c>manager_net_if_opt()</c>.</p> </item> + <marker id="manager_ni_opts"></marker> <tag><c><![CDATA[manager_net_if_options() = [manager_net_if_option()] <optional>]]></c></tag> <item> <p><c>manager_net_if_option() = {bind_to, bind_to()} | @@ -528,6 +591,7 @@ <p>For defaults see the options in <c>manager_net_if_option()</c>.</p> </item> + <marker id="manager_ni_module"></marker> <tag><c><![CDATA[manager_net_if_module() = atom() <optional>]]></c></tag> <item> <p>Module which handles the network interface part for the @@ -536,6 +600,7 @@ <p>Default is <c>snmpm_net_if</c>.</p> </item> + <marker id="manager_ni_filter_opts"></marker> <tag><c><![CDATA[manager_net_if_filter_options() = [manager_net_if_filter_option()] <optional>]]></c></tag> <item> <p><c>manager_net_if_filter_option() = {module, manager_net_if_filter_module()}</c></p> @@ -546,6 +611,7 @@ <c>manager_net_if_filter_option()</c>.</p> </item> + <marker id="manager_ni_filter_module"></marker> <tag><c><![CDATA[manager_net_if_filter_module() = atom() <optional>]]></c></tag> <item> <p>Module which handles the network interface filter part for the @@ -554,6 +620,7 @@ <p>Default is <c>snmpm_net_if_filter</c>.</p> </item> + <marker id="manager_def_user_module"></marker> <tag><c><![CDATA[def_user_module() = atom() <optional>]]></c></tag> <item> <p>The module implementing the default user. See the @@ -561,6 +628,7 @@ <p>Default is <c>snmpm_user_default</c>.</p> </item> + <marker id="manager_def_user_data"></marker> <tag><c><![CDATA[def_user_data() = term() <optional>]]></c></tag> <item> <p>Data for the default user. Passed to the user when calling @@ -569,8 +637,10 @@ </item> </taglist> + <marker id="common_types"></marker> <p>Common config types:</p> <taglist> + <marker id="restart_type"></marker> <tag><c>restart_type() = permanent | transient | temporary</c></tag> <item> <p>See <seealso marker="stdlib:supervisor#child_spec">supervisor</seealso> @@ -579,6 +649,7 @@ for the manager.</p> </item> + <marker id="db_init_error"></marker> <tag><c>db_init_error() = terminate | create</c></tag> <item> <p>Defines what to do if the agent is unable to open an @@ -588,12 +659,14 @@ <p>Default is <c>terminate</c>.</p> </item> + <marker id="prio"></marker> <tag><c><![CDATA[priority() = atom() <optional>]]></c></tag> <item> <p>Defines the Erlang priority for all SNMP processes.</p> <p>Default is <c>normal</c>.</p> </item> + <marker id="versions"></marker> <tag><c><![CDATA[versions() = [version()] <optional>]]></c></tag> <item> <p><c>version() = v1 | v2 | v3</c></p> @@ -601,6 +674,7 @@ <p>Default is <c>[v1,v2,v3]</c>.</p> </item> + <marker id="verbosity"></marker> <tag><c><![CDATA[verbosity() = silence | info | log | debug | trace <optional>]]></c></tag> <item> <p>Verbosity for a SNMP process. This specifies now much debug info @@ -608,6 +682,7 @@ <p>Default is <c>silence</c>.</p> </item> + <marker id="bind_to"></marker> <tag><c><![CDATA[bind_to() = bool() <optional>]]></c></tag> <item> <p>If <c>true</c>, net_if binds to the IP address. @@ -616,6 +691,7 @@ <p>Default is <c>false</c>.</p> </item> + <marker id="no_reuse"></marker> <tag><c><![CDATA[no_reuse() = bool() <optional>]]></c></tag> <item> <p>If <c>true</c>, net_if does not specify that the IP @@ -624,17 +700,21 @@ <p>Default is <c>false</c>.</p> </item> + <marker id="recbuf"></marker> <tag><c><![CDATA[recbuf() = integer() <optional>]]></c></tag> <item> <p>Receive buffer size. </p> <p>Default value is defined by <c>gen_udp</c>.</p> </item> + + <marker id="sndbuf"></marker> <tag><c><![CDATA[sndbuf() = integer() <optional>]]></c></tag> <item> <p>Send buffer size. </p> <p>Default value is defined by <c>gen_udp</c>.</p> </item> + <marker id="note_store"></marker> <tag><c><![CDATA[note_store() = [note_store_opt()] <optional>]]></c></tag> <item> <p><c>note_store_opt() = {timeout, note_store_timeout()} | {verbosity, verbosity()}</c></p> @@ -642,6 +722,7 @@ <p>For defaults see the options in <c>note_store_opt()</c>.</p> </item> + <marker id="ns_timeout"></marker> <tag><c><![CDATA[note_store_timeout() = integer() <optional>]]></c></tag> <item> <p>Note cleanup time. When storing a note in the note store, @@ -649,10 +730,9 @@ process performs a GC to remove the expired note's. Time in milli-seconds.</p> <p>Default is <c>30000</c>.</p> - - <marker id="audit_trail_log"></marker> </item> + <marker id="audit_trail_log"></marker> <tag><c><![CDATA[audit_trail_log() [audit_trail_log_opt()] <optional>]]></c></tag> <item> <p><c>audit_trail_log_opt() = {type, atl_type()} | {dir, atl_dir()} | {size, atl_size()} | {repair, atl_repair()} | {seqno, atl_seqno()}</c></p> @@ -663,6 +743,7 @@ <p>If not present, audit trail logging is not used.</p> </item> + <marker id="atl_type"></marker> <tag><c><![CDATA[atl_type() = read | write | read_write <optional>]]></c></tag> <item> <p>Specifies what type of an audit trail log should be used. @@ -684,6 +765,7 @@ <p>Default is <c>read_write</c>.</p> </item> + <marker id="atl_dir"></marker> <tag><c><![CDATA[atl_dir = dir() <mandatory>]]></c></tag> <item> <p>Specifies where the audit trail log should be stored.</p> @@ -691,6 +773,7 @@ place, this parameter <em>must</em> be defined.</p> </item> + <marker id="atl_size"></marker> <tag><c><![CDATA[atl_size() = {integer(), integer()} <mandatory>]]></c></tag> <item> <p>Specifies the size of the audit @@ -699,6 +782,7 @@ take place, this parameter <em>must</em> be defined.</p> </item> + <marker id="atl_repair"></marker> <tag><c><![CDATA[atl_repair() = true | false | truncate | snmp_repair <optional>]]></c></tag> <item> <p>Specifies if and how the audit trail log shall be repaired @@ -710,6 +794,8 @@ analysis.</p> <p>Default is <c>true</c>.</p> </item> + + <marker id="atl_seqno"></marker> <tag><c><![CDATA[atl_seqno() = true | false <optional>]]></c></tag> <item> <p>Specifies if the audit trail log entries will be (sequence) diff --git a/lib/snmp/src/agent/depend.mk b/lib/snmp/src/agent/depend.mk index bc39e1fa35..078ef15821 100644 --- a/lib/snmp/src/agent/depend.mk +++ b/lib/snmp/src/agent/depend.mk @@ -52,6 +52,7 @@ $(EBIN)/snmpa_acm.$(EMULATOR): \ $(EBIN)/snmpa_agent.$(EMULATOR): \ snmpa_agent.erl \ + snmpa_internal.hrl \ ../misc/snmp_debug.hrl \ ../misc/snmp_verbosity.hrl \ ../../include/snmp_types.hrl @@ -136,6 +137,7 @@ $(EBIN)/snmpa_set_lib.$(EMULATOR): \ $(EBIN)/snmpa_supervisor.$(EMULATOR): \ snmpa_supervisor.erl \ + snmpa_internal.hrl \ ../misc/snmp_debug.hrl \ ../misc/snmp_verbosity.hrl diff --git a/lib/snmp/src/agent/snmp_target_mib.erl b/lib/snmp/src/agent/snmp_target_mib.erl index a3ac67b533..d5c4ec2578 100644 --- a/lib/snmp/src/agent/snmp_target_mib.erl +++ b/lib/snmp/src/agent/snmp_target_mib.erl @@ -42,8 +42,14 @@ %% Column not accessible via SNMP - needed when the agent sends informs -define(snmpTargetAddrEngineId, 10). %% Extra comlumns for the augmented table snmpTargetAddrExtTable --define(snmpTargetAddrTMask, 11). --define(snmpTargetAddrMMS, 12). +-define(snmpTargetAddrTMask, 11). +-define(snmpTargetAddrMMS, 12). + +-ifdef(snmp_extended_verbosity). +-define(vt(F,A), ?vtrace(F, A)). +-else. +-define(vt(_F, _A), ok). +-endif. %%----------------------------------------------------------------- @@ -410,10 +416,16 @@ get_target_addrs() -> get_target_addrs(Key, {Tab, _} = TabDb, Acc) -> + ?vt("get_target_addrs -> entry with" + "~n Key: ~p", [Key]), case table_next(Tab, Key) of endOfTable -> + ?vt("get_target_addrs -> endOfTable when" + "~n Acc: ~p", [Acc]), Acc; NextKey -> + ?vt("get_target_addrs -> next ok: " + "~n NextKey: ~p", [NextKey]), case get_target_addr(TabDb, NextKey) of {ok, Targ} -> get_target_addrs(NextKey, TabDb, [Targ| Acc]); diff --git a/lib/snmp/src/agent/snmpa_agent.erl b/lib/snmp/src/agent/snmpa_agent.erl index f70885b2ec..00fe9be098 100644 --- a/lib/snmp/src/agent/snmpa_agent.erl +++ b/lib/snmp/src/agent/snmpa_agent.erl @@ -65,7 +65,10 @@ %% Internal exports -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3, tr_var/2, tr_varbind/1, - handle_pdu/7, worker/2, worker_loop/1, do_send_trap/7]). + handle_pdu/8, worker/2, worker_loop/1, do_send_trap/7]). +%% <BACKWARD-COMPAT> +-export([handle_pdu/7]). +%% </BACKWARD-COMPAT> -ifndef(default_verbosity). -define(default_verbosity,silence). @@ -81,7 +84,6 @@ -define(DISCO_TERMINATING_TRIGGER_USERNAME, ""). - -ifdef(snmp_debug). -define(GS_START_LINK3(Prio, Parent, Ref, Opts), gen_server:start_link(?MODULE, [Prio, Parent, Ref, Opts], @@ -97,13 +99,48 @@ gen_server:start_link({local, Name}, ?MODULE, [Prio, Parent, Ref, Opts],[])). -endif. - + +%% Increment this whenever a change is made to the worker interface +-define(WORKER_INTERFACE_VERSION, 1). + +%% -- Utility macros for creating worker commands -- +-define(mk_pdu_wreq(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra), + #wrequest{cmd = handle_pdu, + info = [{vsn, Vsn}, + {pdu, Pdu}, + {pdu_ms, PduMS}, + {acm_data, ACMData}, + {addr, Address}, + {gb_max_vbs, GbMaxVBs}, + {extra, Extra}]}). +-define(mk_send_trap_wreq(TrapRec, NotifyName, ContextName, + Recv, Vbs, LocalEngineID), + #wrequest{cmd = send_trap, + info = [{trap_rec, TrapRec}, + {notify_name, NotifyName}, + {context_name, ContextName}, + {receiver, Recv}, + {varbinds, Vbs}, + {local_engine_id, LocalEngineID}]}). +-define(mk_terminate_wreq(), #wrequest{cmd = terminate, info = []}). +-define(mk_verbosity_wreq(V), #wrequest{cmd = verbosity, + info = [{verbosity, V}]}). + -record(notification_filter, {id, mod, data}). -record(disco, {from, rec, sender, target, engine_id, sec_level, ctx, ivbs, stage, handler, extra}). +%% This record is used when sending requests to the worker processes +-record(wrequest, + { + version = ?WORKER_INTERFACE_VERSION, + cmd, + info + } + ). + %%----------------------------------------------------------------- %% The agent is multi-threaded, i.e. each request is handled @@ -136,7 +173,8 @@ net_if_mod, backup, disco, - mibs_cache_request}). + mibs_cache_request, + gb_max_vbs}). %%%----------------------------------------------------------------- @@ -324,6 +362,8 @@ do_init(Prio, Parent, Ref, Options) -> MultiT = get_multi_threaded(Options), Vsns = get_versions(Options), + GbMaxVbs = get_gb_max_vbs(Options), + NS = start_note_store(Prio, Ref, Options), {Type, NetIfPid, NetIfMod} = start_net_if(Parent, Prio, Ref, Vsns, NS, Options), @@ -342,7 +382,8 @@ do_init(Prio, Parent, Ref, Options) -> ref = Ref, vsns = Vsns, note_store = NS, - net_if_mod = NetIfMod}}. + net_if_mod = NetIfMod, + gb_max_vbs = GbMaxVbs}}. start_note_store(Prio, Ref, Options) -> @@ -404,7 +445,8 @@ start_net_if(Parent, _Prio, _Ref, _Vsns, _NoteStore, _Options) start_mib_server(Prio, Ref, Mibs, Options) -> ?vdebug("start_mib_server -> with Prio: ~p", [Prio]), MibStorage = get_mib_storage(Options), - MibsOpts = [{mib_storage, MibStorage}|get_option(mib_server, Options, [])], + MibsOpts = [{mib_storage, MibStorage} | + get_option(mib_server, Options, [])], ?vtrace("start_mib_server -> " "~n Mibs: ~p" @@ -734,7 +776,8 @@ handle_info({snmp_pdu, Vsn, Pdu, PduMS, ACMData, Address, Extra}, S) -> ?vdebug("handle_info(snmp_pdu) -> entry with" "~n Vsn: ~p" "~n Pdu: ~p" - "~n Address: ~p", [Vsn, Pdu, Address]), + "~n Address: ~p" + "~n Extra: ~p", [Vsn, Pdu, Address, Extra]), NewS = handle_snmp_pdu(is_valid_pdu_type(Pdu#pdu.type), Vsn, Pdu, PduMS, ACMData, Address, Extra, S), @@ -1005,7 +1048,7 @@ handle_call({subagent_get_next, MibView, Varbinds, PduData}, _From, S) -> "~n PduData: ~p", [MibView,Varbinds,PduData]), put_pdu_data(PduData), - {reply, do_get_next(MibView, Varbinds), S}; + {reply, do_get_next(MibView, Varbinds, infinity), S}; handle_call({subagent_set, Arguments, PduData}, _From, S) -> ?vlog("[handle_call] subagent set:" "~n Arguments: ~p" @@ -1046,7 +1089,7 @@ handle_call({get_next, Vars, Context}, _From, S) -> ?vdebug("Varbinds: ~p",[Varbinds]), MibView = snmpa_acm:get_root_mib_view(), Reply = - case do_get_next(MibView, Varbinds) of + case do_get_next(MibView, Varbinds, infinity) of {noError, 0, NewVarbinds} -> Vbs = lists:keysort(#varbind.org_index, NewVarbinds), [{Oid,Val} || #varbind{oid = Oid, value = Val} <- Vbs]; @@ -1242,15 +1285,15 @@ handle_call(Req, _From, S) -> Reply = {error, {unknown, Req}}, {reply, Reply, S}. -handle_cast({verbosity,Verbosity}, S) -> - ?vlog("verbosity: ~p -> ~p",[get(verbosity),Verbosity]), +handle_cast({verbosity, Verbosity}, S) -> + ?vlog("verbosity: ~p -> ~p",[get(verbosity), Verbosity]), put(verbosity,snmp_verbosity:validate(Verbosity)), case S#state.worker of - Pid when is_pid(Pid) -> Pid ! {verbosity,Verbosity}; + Pid when is_pid(Pid) -> Pid ! ?mk_verbosity_wreq(Verbosity); _ -> ok end, case S#state.set_worker of - Pid2 when is_pid(Pid2) -> Pid2 ! {verbosity,Verbosity}; + Pid2 when is_pid(Pid2) -> Pid2 ! ?mk_verbosity_wreq(Verbosity); _ -> ok end, {noreply, S}; @@ -1337,13 +1380,80 @@ handle_mibs_cache_request(MibServer, Req) -> %% Downgrade %% -%% code_change({down, _Vsn}, S, downgrade_to_pre_4_13) -> -%% {ok, S2}; +code_change({down, _Vsn}, S1, downgrade_to_pre_4_17_3) -> + #state{type = Type, + parent = Parent, + worker = Worker, + worker_state = WorkerState, + set_worker = SetWorker, + multi_threaded = MT, + ref = Ref, + vsns = Vsns, + nfilters = NF, + note_store = NoteStore, + mib_server = MS, + net_if = NetIf, + net_if_mod = NetIfMod, + backup = Backup, + disco = Disco, + mibs_cache_request = MCR} = S1, + S2 = {state, + type = Type, + parent = Parent, + worker = Worker, + worker_state = WorkerState, + set_worker = SetWorker, + multi_threaded = MT, + ref = Ref, + vsns = Vsns, + nfilters = NF, + note_store = NoteStore, + mib_server = MS, + net_if = NetIf, + net_if_mod = NetIfMod, + backup = Backup, + disco = Disco, + mibs_cache_request = MCR}, + {ok, S2}; %% Upgrade %% -%% code_change(_Vsn, S, upgrade_from_pre_4_13) -> -%% {ok, S2}; +code_change(_Vsn, S1, upgrade_from_pre_4_17_3) -> + {state, + type = Type, + parent = Parent, + worker = Worker, + worker_state = WorkerState, + set_worker = SetWorker, + multi_threaded = MT, + ref = Ref, + vsns = Vsns, + nfilters = NF, + note_store = NoteStore, + mib_server = MS, + net_if = NetIf, + net_if_mod = NetIfMod, + backup = Backup, + disco = Disco, + mibs_cache_request = MCR} = S1, + S2 = #state{type = Type, + parent = Parent, + worker = Worker, + worker_state = WorkerState, + set_worker = SetWorker, + multi_threaded = MT, + ref = Ref, + vsns = Vsns, + nfilters = NF, + note_store = NoteStore, + mib_server = MS, + net_if = NetIf, + net_if_mod = NetIfMod, + backup = Backup, + disco = Disco, + mibs_cache_request = MCR, + gb_max_vbs = ?DEFAULT_GB_MAX_VBS}, + {ok, S2}; code_change(_Vsn, S, _Extra) -> {ok, S}. @@ -1383,7 +1493,7 @@ worker_start(Dict) -> %% worker_stop(Pid, infinity). worker_stop(Pid, Timeout) when is_pid(Pid) -> - Pid ! terminate, + Pid ! ?mk_terminate_wreq(), receive {'EXIT', Pid, normal} -> ok @@ -1517,9 +1627,11 @@ invalidate_ca_cache() -> %% %%----------------------------------------------------------------- -spawn_thread(Vsn, Pdu, PduMS, ACMData, Address, Extra) -> +%% This functions spawns a temporary worker process, +%% that evaluates one request and then silently exits. +spawn_thread(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra) -> Dict = get(), - Args = [Vsn, Pdu, PduMS, ACMData, Address, Extra, Dict], + Args = [Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra, Dict], proc_lib:spawn_link(?MODULE, handle_pdu, Args). spawn_trap_thread(TrapRec, NotifyName, ContextName, Recv, Vbs, @@ -1532,7 +1644,7 @@ spawn_trap_thread(TrapRec, NotifyName, ContextName, Recv, Vbs, do_send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID, Dict) -> lists:foreach(fun({Key, Val}) -> put(Key, Val) end, Dict), - put(sname,trap_sender_short_name(get(sname))), + put(sname, trap_sender_short_name(get(sname))), ?vlog("starting",[]), snmpa_trap:send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID, get(net_if)). @@ -1544,45 +1656,119 @@ worker(Master, Dict) -> worker_loop(Master). worker_loop(Master) -> - receive - {Vsn, Pdu, PduMS, ACMData, Address, Extra} -> - ?vtrace("worker_loop -> received request", []), - handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra), - Master ! worker_available; - - %% We don't trap exits! - {TrapRec, NotifyName, ContextName, Recv, Vbs} -> - ?vtrace("worker_loop -> send trap:" - "~n ~p", [TrapRec]), - snmpa_trap:send_trap(TrapRec, NotifyName, - ContextName, Recv, Vbs, get(net_if)), - Master ! worker_available; - - %% We don't trap exits! - {send_trap, - TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID} -> - ?vtrace("worker_loop -> send trap:" - "~n ~p", [TrapRec]), - snmpa_trap:send_trap(TrapRec, NotifyName, - ContextName, Recv, Vbs, LocalEngineID, - get(net_if)), - Master ! worker_available; - - {verbosity, Verbosity} -> - put(verbosity,snmp_verbosity:validate(Verbosity)); - - terminate -> - exit(normal); - - _X -> - %% ignore - ok - - after 30000 -> - %% This is to assure that the worker process leaves a - %% possibly old version of this module. - ok - end, + Res = + receive + #wrequest{cmd = handle_pdu, + info = Info} = Req -> + ?vtrace("worker_loop -> received handle_pdu request with" + "~n Info: ~p", [Info]), + Vsn = proplists:get_value(vsn, Info), + Pdu = proplists:get_value(pdu, Info), + PduMS = proplists:get_value(pdu_ms, Info), + ACMData = proplists:get_value(acm_data, Info), + Address = proplists:get_value(addr, Info), + GbMaxVBs = proplists:get_value(gb_max_vbs, Info), + Extra = proplists:get_value(extra, Info), + HandlePduRes = + try + begin + handle_pdu2(Vsn, Pdu, PduMS, ACMData, Address, + GbMaxVBs, Extra) + end + catch + T:E -> + exit({worker_crash, Req, T, E, + erlang:get_stacktrace()}) + end, + Master ! worker_available, + HandlePduRes; % For debugging... + + + #wrequest{cmd = send_trap, + info = Info} = Req -> + ?vtrace("worker_loop -> received send_trap request with" + "~n Info: ~p", [Info]), + TrapRec = proplists:get_value(trap_rec, Info), + NotifyName = proplists:get_value(notify_name, Info), + ContextName = proplists:get_value(context_name, Info), + Recv = proplists:get_value(receiver, Info), + Vbs = proplists:get_value(varbinds, Info), + LocalEngineID = proplists:get_value(local_engine_id, Info), + SendTrapRes = + try + begin + snmpa_trap:send_trap(TrapRec, NotifyName, + ContextName, Recv, Vbs, + LocalEngineID, + get(net_if)) + end + catch + T:E -> + exit({worker_crash, Req, T, E, + erlang:get_stacktrace()}) + end, + Master ! worker_available, + SendTrapRes; % For debugging... + + + #wrequest{cmd = verbosity, + info = Info} -> + Verbosity = proplists:get_value(verbosity, Info), + put(verbosity, snmp_verbosity:validate(Verbosity)); + + + #wrequest{cmd = terminate} -> + ?vtrace("worker_loop -> received terminate request", []), + exit(normal); + + + %% ************************************************************* + %% + %% Kept for backward compatibillity reasons + %% + %% ************************************************************* + + {Vsn, Pdu, PduMS, ACMData, Address, Extra} -> + ?vtrace("worker_loop -> received request", []), + handle_pdu2(Vsn, Pdu, PduMS, ACMData, Address, + ?DEFAULT_GB_MAX_VBS, Extra), + Master ! worker_available; + + %% We don't trap exits! + {TrapRec, NotifyName, ContextName, Recv, Vbs} -> + ?vtrace("worker_loop -> send trap:" + "~n ~p", [TrapRec]), + snmpa_trap:send_trap(TrapRec, NotifyName, + ContextName, Recv, Vbs, get(net_if)), + Master ! worker_available; + + %% We don't trap exits! + {send_trap, + TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID} -> + ?vtrace("worker_loop -> send trap:" + "~n ~p", [TrapRec]), + snmpa_trap:send_trap(TrapRec, NotifyName, + ContextName, Recv, Vbs, LocalEngineID, + get(net_if)), + Master ! worker_available; + + {verbosity, Verbosity} -> + put(verbosity, snmp_verbosity:validate(Verbosity)); + + terminate -> + exit(normal); + + _X -> + %% ignore + ignore_unknown + + after 30000 -> + %% This is to assure that the worker process leaves a + %% possibly old version of this module. + ok + end, + ?vtrace("worker_loop -> wrap with" + "~n ~p", [Res]), ?MODULE:worker_loop(Master). @@ -1590,42 +1776,52 @@ worker_loop(Master) -> %%----------------------------------------------------------------- handle_snmp_pdu(true, Vsn, Pdu, PduMS, ACMData, Address, Extra, - #state{multi_threaded = false} = S) -> + #state{multi_threaded = false, + gb_max_vbs = GbMaxVBs} = S) -> ?vtrace("handle_snmp_pdu -> single-thread agent",[]), - handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra), + handle_pdu2(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra), S; handle_snmp_pdu(true, Vsn, #pdu{type = 'set-request'} = Pdu, PduMS, ACMData, Address, Extra, #state{set_worker = Worker} = S) -> ?vtrace("handle_snmp_pdu -> multi-thread agent: " "send set-request to main worker",[]), - Worker ! {Vsn, Pdu, PduMS, ACMData, Address, Extra}, + WRequest = ?mk_pdu_wreq(Vsn, Pdu, PduMS, ACMData, Address, infinity, Extra), + Worker ! WRequest, S#state{worker_state = busy}; handle_snmp_pdu(true, Vsn, Pdu, PduMS, ACMData, Address, Extra, - #state{worker_state = busy} = S) -> + #state{worker_state = busy, + gb_max_vbs = GbMaxVBs} = S) -> ?vtrace("handle_snmp_pdu -> multi-thread agent: " "main worker busy - create new worker",[]), - spawn_thread(Vsn, Pdu, PduMS, ACMData, Address, Extra), + spawn_thread(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra), S; handle_snmp_pdu(true, Vsn, Pdu, PduMS, ACMData, Address, Extra, - #state{worker = Worker} = S) -> + #state{worker = Worker, + gb_max_vbs = GbMaxVBs} = S) -> ?vtrace("handle_snmp_pdu -> multi-thread agent: " "send to main worker",[]), - Worker ! {Vsn, Pdu, PduMS, ACMData, Address, Extra}, + WRequest = ?mk_pdu_wreq(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra), + Worker ! WRequest, S#state{worker_state = busy}; handle_snmp_pdu(_, _Vsn, _Pdu, _PduMS, _ACMData, _Address, _Extra, S) -> S. %% Called via the spawn_thread function +%% <BACKWARD-COMPAT> handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra, Dict) -> + handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, ?DEFAULT_GB_MAX_VBS, Extra, + Dict). +%% </BACKWARD-COMPAT> +handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra, Dict) -> lists:foreach(fun({Key, Val}) -> put(Key, Val) end, Dict), put(sname, pdu_handler_short_name(get(sname))), ?vlog("new worker starting",[]), - handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra). + handle_pdu2(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra). -handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra) -> +handle_pdu2(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra) -> %% OTP-3324 AuthMod = get(auth_module), case AuthMod:init_check_access(Pdu, ACMData) of @@ -1634,7 +1830,8 @@ handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra) -> "~n MibView: ~p" "~n ContextName: ~p", [MibView, ContextName]), AgentData = cheat(ACMData, Address, ContextName), - do_handle_pdu(MibView, Vsn, Pdu, PduMS, ACMData, AgentData, Extra); + do_handle_pdu(MibView, Vsn, Pdu, PduMS, ACMData, AgentData, + GbMaxVBs, Extra); {error, Reason} -> ?vlog("handle_pdu -> error:" "~n Reason: ~p", [Reason]), @@ -1648,16 +1845,19 @@ handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra) -> end. do_handle_pdu(MibView, Vsn, Pdu, PduMS, - ACMData, {Community, Address, ContextName}, Extra) -> + ACMData, {Community, Address, ContextName}, + GbMaxVBs, Extra) -> put(net_if_data, Extra), + RePdu = process_msg(MibView, Vsn, Pdu, PduMS, Community, - Address, ContextName), + Address, ContextName, GbMaxVBs), ?vtrace("do_handle_pdu -> processed:" "~n RePdu: ~p", [RePdu]), - get(net_if) ! {snmp_response, Vsn, RePdu, - RePdu#pdu.type, ACMData, Address, Extra}. + NetIf = get(net_if), + NetIf ! {snmp_response, Vsn, RePdu, + RePdu#pdu.type, ACMData, Address, Extra}. handle_acm_error(Vsn, Reason, Pdu, ACMData, Address, Extra) -> @@ -1831,9 +2031,9 @@ do_handle_send_trap(S, TrapRec, NotifyName, ContextName, Recv, Varbinds, master_agent -> %% Send to main worker ?vtrace("do_handle_send_trap -> send to main worker",[]), - S#state.worker ! {send_trap, - TrapRec, NotifyName, ContextName, Recv, Vbs, - LocalEngineID}, + S#state.worker ! ?mk_send_trap_wreq(TrapRec, NotifyName, + ContextName, Recv, Vbs, + LocalEngineID), {ok, S#state{worker_state = busy}} end. @@ -2170,17 +2370,18 @@ handle_mib_of(MibServer, Oid) -> %% Func: process_msg/7 %% Returns: RePdu %%----------------------------------------------------------------- -process_msg(MibView, Vsn, Pdu, PduMS, Community, {Ip, Udp}, ContextName) -> +process_msg(MibView, Vsn, Pdu, PduMS, Community, {Ip, Udp}, ContextName, + GbMaxVBs) -> #pdu{request_id = ReqId} = Pdu, put(snmp_address, {tuple_to_list(Ip), Udp}), put(snmp_request_id, ReqId), put(snmp_community, Community), put(snmp_context, ContextName), ?vtrace("process ~p",[Pdu#pdu.type]), - process_pdu(Pdu, PduMS, Vsn, MibView). + process_pdu(Pdu, PduMS, Vsn, MibView, GbMaxVBs). process_pdu(#pdu{type='get-request', request_id = ReqId, varbinds=Vbs}, - _PduMS, Vsn, MibView) -> + _PduMS, Vsn, MibView, _GbMaxVBs) -> ?vtrace("get ~p",[ReqId]), Res = get_err(do_get(MibView, Vbs, false)), ?vtrace("get result: " @@ -2201,12 +2402,12 @@ process_pdu(#pdu{type='get-request', request_id = ReqId, varbinds=Vbs}, make_response_pdu(ReqId, ErrStatus, ErrIndex, Vbs, ResponseVarbinds); process_pdu(#pdu{type = 'get-next-request', request_id = ReqId, varbinds = Vbs}, - _PduMS, Vsn, MibView) -> + _PduMS, Vsn, MibView, _GbMaxVBs) -> ?vtrace("process get-next-request -> entry with" "~n ReqId: ~p" "~n Vbs: ~p" "~n MibView: ~p",[ReqId, Vbs, MibView]), - Res = get_err(do_get_next(MibView, Vbs)), + Res = get_err(do_get_next(MibView, Vbs, infinity)), ?vtrace("get-next result: " "~n ~p",[Res]), {ErrStatus, ErrIndex, ResVarbinds} = @@ -2223,11 +2424,15 @@ process_pdu(#pdu{type = 'get-next-request', request_id = ReqId, varbinds = Vbs}, "~n ~p",[ResponseVarbinds]), make_response_pdu(ReqId, ErrStatus, ErrIndex, Vbs, ResponseVarbinds); -process_pdu(#pdu{type = 'get-bulk-request',request_id = ReqId,varbinds = Vbs, - error_status = NonRepeaters, error_index = MaxRepetitions}, - PduMS, _Vsn, MibView)-> +process_pdu(#pdu{type = 'get-bulk-request', + request_id = ReqId, + varbinds = Vbs, + error_status = NonRepeaters, + error_index = MaxRepetitions}, + PduMS, _Vsn, MibView, GbMaxVBs) -> {ErrStatus, ErrIndex, ResponseVarbinds} = - get_err(do_get_bulk(MibView,NonRepeaters,MaxRepetitions,PduMS,Vbs)), + get_err(do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Vbs, + GbMaxVBs)), ?vtrace("get-bulk final result: " "~n Error status: ~p" "~n Error index: ~p" @@ -2236,7 +2441,7 @@ process_pdu(#pdu{type = 'get-bulk-request',request_id = ReqId,varbinds = Vbs, make_response_pdu(ReqId, ErrStatus, ErrIndex, Vbs, ResponseVarbinds); process_pdu(#pdu{type = 'set-request', request_id = ReqId, varbinds = Vbs}, - _PduMS, Vsn, MibView)-> + _PduMS, Vsn, MibView, _GbMaxVbs)-> Res = do_set(MibView, Vbs), ?vtrace("set result: " "~n ~p",[Res]), @@ -2293,7 +2498,8 @@ validate_next_v1_2([Vb | _Vbs], _MibView, _Res) {noSuchName, Vb#varbind.org_index}; validate_next_v1_2([Vb | Vbs], MibView, Res) when Vb#varbind.variabletype =:= 'Counter64' -> - case validate_next_v1(do_get_next(MibView, [mk_next_oid(Vb)]), MibView) of + case validate_next_v1( + do_get_next(MibView, [mk_next_oid(Vb)], infinity), MibView) of {noError, 0, [NVb]} -> validate_next_v1_2(Vbs, MibView, [NVb | Res]); {Error, Index, _OrgVb} -> @@ -2766,59 +2972,97 @@ validate_tab_res(_TooMany, [], Mfa, _Res, I) -> %% that this really matters, since many nexts across the same %% subagent must be considered to be very rare. %%----------------------------------------------------------------- -do_get_next(MibView, UnsortedVarbinds) -> - SortedVarbinds = oid_sort_varbindlist(UnsortedVarbinds), - next_loop_varbinds([], SortedVarbinds, MibView, [], []). -oid_sort_varbindlist(Vbs) -> +%% It may be a bit agressive to check this already, +%% but since it is a security measure, it makes sense. +do_get_next(_MibView, UnsortedVarbinds, GbMaxVBs) + when (is_integer(GbMaxVBs) andalso (length(UnsortedVarbinds) > GbMaxVBs)) -> + {tooBig, 0, []}; % What is the correct index in this case? +do_get_next(MibView, UnsortedVBs, GbMaxVBs) -> + ?vt("do_get_next -> entry when" + "~n MibView: ~p" + "~n UnsortedVBs: ~p", [MibView, UnsortedVBs]), + SortedVBs = oid_sort_vbs(UnsortedVBs), + ?vt("do_get_next -> " + "~n SortedVBs: ~p", [SortedVBs]), + next_loop_varbinds([], SortedVBs, MibView, [], [], GbMaxVBs). + +oid_sort_vbs(Vbs) -> lists:keysort(#varbind.oid, Vbs). +next_loop_varbinds(_, Vbs, _MibView, Res, _LAVb, GbMaxVBs) + when (is_integer(GbMaxVBs) andalso + ((length(Vbs) + length(Res)) > GbMaxVBs)) -> + {tooBig, 0, []}; % What is the correct index in this case? + %% LAVb is Last Accessible Vb -next_loop_varbinds([], [Vb | Vbs], MibView, Res, LAVb) -> +next_loop_varbinds([], [Vb | Vbs], MibView, Res, LAVb, GbMaxVBs) -> ?vt("next_loop_varbinds -> entry when" "~n Vb: ~p" "~n MibView: ~p", [Vb, MibView]), case varbind_next(Vb, MibView) of endOfMibView -> + ?vt("next_loop_varbind -> endOfMibView", []), RVb = if LAVb =:= [] -> Vb; true -> LAVb end, NewVb = RVb#varbind{variabletype = 'NULL', value = endOfMibView}, - next_loop_varbinds([], Vbs, MibView, [NewVb | Res], []); + next_loop_varbinds([], Vbs, MibView, [NewVb | Res], [], GbMaxVBs); + {variable, ME, VarOid} when ((ME#me.access =/= 'not-accessible') andalso (ME#me.access =/= 'write-only') andalso (ME#me.access =/= 'accessible-for-notify')) -> + ?vt("next_loop_varbind -> variable: " + "~n ME: ~p" + "~n VarOid: ~p", [ME, VarOid]), case try_get_instance(Vb, ME) of {value, noValue, _NoSuchSomething} -> + ?vt("next_loop_varbind -> noValue", []), %% Try next one - NewVb = Vb#varbind{oid = VarOid, value = 'NULL'}, - next_loop_varbinds([], [NewVb | Vbs], MibView, Res, []); + NewVb = Vb#varbind{oid = VarOid, + value = 'NULL'}, + next_loop_varbinds([], [NewVb | Vbs], MibView, Res, [], + GbMaxVBs); {value, Type, Value} -> - NewVb = Vb#varbind{oid = VarOid, variabletype = Type, - value = Value}, - next_loop_varbinds([], Vbs, MibView, [NewVb | Res], []); + ?vt("next_loop_varbind -> value" + "~n Type: ~p" + "~n Value: ~p", [Type, Value]), + NewVb = Vb#varbind{oid = VarOid, + variabletype = Type, + value = Value}, + next_loop_varbinds([], Vbs, MibView, [NewVb | Res], [], + GbMaxVBs); {error, ErrorStatus} -> ?vdebug("next loop varbinds:" "~n ErrorStatus: ~p",[ErrorStatus]), {ErrorStatus, Vb#varbind.org_index, []} end; {variable, _ME, VarOid} -> + ?vt("next_loop_varbind -> variable: " + "~n VarOid: ~p", [VarOid]), RVb = if LAVb =:= [] -> Vb; true -> LAVb end, NewVb = Vb#varbind{oid = VarOid, value = 'NULL'}, - next_loop_varbinds([], [NewVb | Vbs], MibView, Res, RVb); + next_loop_varbinds([], [NewVb | Vbs], MibView, Res, RVb, GbMaxVBs); {table, TableOid, TableRestOid, ME} -> + ?vt("next_loop_varbind -> table: " + "~n TableOid: ~p" + "~n TableRestOid: ~p" + "~n ME: ~p", [TableOid, TableRestOid, ME]), next_loop_varbinds({table, TableOid, ME, [{tab_oid(TableRestOid), Vb}]}, - Vbs, MibView, Res, []); + Vbs, MibView, Res, [], GbMaxVBs); {subagent, SubAgentPid, SAOid} -> + ?vt("next_loop_varbind -> subagent: " + "~n SubAgentPid: ~p" + "~n SAOid: ~p", [SubAgentPid, SAOid]), NewVb = Vb#varbind{variabletype = 'NULL', value = 'NULL'}, next_loop_varbinds({subagent, SubAgentPid, SAOid, [NewVb]}, - Vbs, MibView, Res, []) + Vbs, MibView, Res, [], GbMaxVBs) end; next_loop_varbinds({table, TableOid, ME, TabOids}, - [Vb | Vbs], MibView, Res, _LAVb) -> + [Vb | Vbs], MibView, Res, _LAVb, GbMaxVBs) -> ?vt("next_loop_varbinds(table) -> entry with" "~n TableOid: ~p" "~n Vb: ~p", [TableOid, Vb]), @@ -2826,13 +3070,14 @@ next_loop_varbinds({table, TableOid, ME, TabOids}, {table, TableOid, TableRestOid, _ME} -> next_loop_varbinds({table, TableOid, ME, [{tab_oid(TableRestOid), Vb} | TabOids]}, - Vbs, MibView, Res, []); + Vbs, MibView, Res, [], GbMaxVBs); _ -> case get_next_table(ME, TableOid, TabOids, MibView) of {ok, TabRes, TabEndOfTabVbs} -> NewVbs = lists:append(TabEndOfTabVbs, [Vb | Vbs]), NewRes = lists:append(TabRes, Res), - next_loop_varbinds([], NewVbs, MibView, NewRes, []); + next_loop_varbinds([], NewVbs, MibView, NewRes, [], + GbMaxVBs); {ErrorStatus, OrgIndex} -> ?vdebug("next loop varbinds: next varbind" "~n ErrorStatus: ~p" @@ -2842,7 +3087,7 @@ next_loop_varbinds({table, TableOid, ME, TabOids}, end end; next_loop_varbinds({table, TableOid, ME, TabOids}, - [], MibView, Res, _LAVb) -> + [], MibView, Res, _LAVb, GbMaxVBs) -> ?vt("next_loop_varbinds(table) -> entry with" "~n TableOid: ~p", [TableOid]), case get_next_table(ME, TableOid, TabOids, MibView) of @@ -2851,7 +3096,8 @@ next_loop_varbinds({table, TableOid, ME, TabOids}, "~n TabRes: ~p" "~n TabEndOfTabVbs: ~p", [TabRes, TabEndOfTabVbs]), NewRes = lists:append(TabRes, Res), - next_loop_varbinds([], TabEndOfTabVbs, MibView, NewRes, []); + next_loop_varbinds([], TabEndOfTabVbs, MibView, NewRes, [], + GbMaxVBs); {ErrorStatus, OrgIndex} -> ?vdebug("next loop varbinds: next table" "~n ErrorStatus: ~p" @@ -2860,7 +3106,7 @@ next_loop_varbinds({table, TableOid, ME, TabOids}, {ErrorStatus, OrgIndex, []} end; next_loop_varbinds({subagent, SAPid, SAOid, SAVbs}, - [Vb | Vbs], MibView, Res, _LAVb) -> + [Vb | Vbs], MibView, Res, _LAVb, GbMaxVBs) -> ?vt("next_loop_varbinds(subagent) -> entry with" "~n SAPid: ~p" "~n SAOid: ~p" @@ -2869,13 +3115,14 @@ next_loop_varbinds({subagent, SAPid, SAOid, SAVbs}, {subagent, _SubAgentPid, SAOid} -> next_loop_varbinds({subagent, SAPid, SAOid, [Vb | SAVbs]}, - Vbs, MibView, Res, []); + Vbs, MibView, Res, [], GbMaxVBs); _ -> case get_next_sa(SAPid, SAOid, SAVbs, MibView) of {ok, SARes, SAEndOfMibViewVbs} -> NewVbs = lists:append(SAEndOfMibViewVbs, [Vb | Vbs]), NewRes = lists:append(SARes, Res), - next_loop_varbinds([], NewVbs, MibView, NewRes, []); + next_loop_varbinds([], NewVbs, MibView, NewRes, [], + GbMaxVBs); {noSuchName, OrgIndex} -> %% v1 reply, treat this Vb as endOfMibView, and try again %% for the others. @@ -2888,12 +3135,14 @@ next_loop_varbinds({subagent, SAPid, SAOid, SAVbs}, case lists:delete(EVb, SAVbs) of [] -> next_loop_varbinds([], [EndOfVb, Vb | Vbs], - MibView, Res, []); + MibView, Res, [], + GbMaxVBs); TryAgainVbs -> next_loop_varbinds({subagent, SAPid, SAOid, TryAgainVbs}, [EndOfVb, Vb | Vbs], - MibView, Res, []) + MibView, Res, [], + GbMaxVBs) end; false -> %% bad index from subagent @@ -2909,14 +3158,15 @@ next_loop_varbinds({subagent, SAPid, SAOid, SAVbs}, end end; next_loop_varbinds({subagent, SAPid, SAOid, SAVbs}, - [], MibView, Res, _LAVb) -> + [], MibView, Res, _LAVb, GbMaxVBs) -> ?vt("next_loop_varbinds(subagent) -> entry with" "~n SAPid: ~p" "~n SAOid: ~p", [SAPid, SAOid]), case get_next_sa(SAPid, SAOid, SAVbs, MibView) of {ok, SARes, SAEndOfMibViewVbs} -> NewRes = lists:append(SARes, Res), - next_loop_varbinds([], SAEndOfMibViewVbs, MibView, NewRes, []); + next_loop_varbinds([], SAEndOfMibViewVbs, MibView, NewRes, [], + GbMaxVBs); {noSuchName, OrgIndex} -> %% v1 reply, treat this Vb as endOfMibView, and try again for %% the others. @@ -2927,11 +3177,13 @@ next_loop_varbinds({subagent, SAPid, SAOid, SAVbs}, value = {endOfMibView, NextOid}}, case lists:delete(EVb, SAVbs) of [] -> - next_loop_varbinds([], [EndOfVb], MibView, Res, []); + next_loop_varbinds([], [EndOfVb], MibView, Res, [], + GbMaxVBs); TryAgainVbs -> next_loop_varbinds({subagent, SAPid, SAOid, TryAgainVbs}, - [EndOfVb], MibView, Res, []) + [EndOfVb], MibView, Res, [], + GbMaxVBs) end; false -> %% bad index from subagent @@ -2944,12 +3196,15 @@ next_loop_varbinds({subagent, SAPid, SAOid, SAVbs}, [ErrorStatus,OrgIndex]), {ErrorStatus, OrgIndex, []} end; -next_loop_varbinds([], [], _MibView, Res, _LAVb) -> +next_loop_varbinds([], [], _MibView, Res, _LAVb, _GbMaxVBs) -> ?vt("next_loop_varbinds -> entry when done", []), {noError, 0, Res}. try_get_instance(_Vb, #me{mfa = {M, F, A}, asn1_type = ASN1Type}) -> - ?vtrace("try get instance from <~p,~p,~p>",[M,F,A]), + ?vtrace("try_get_instance -> entry with" + "~n M: ~p" + "~n F: ~p" + "~n A: ~p", [M,F,A]), Result = (catch dbg_apply(M, F, [get | A])), % mib shall return {value, <a-nice-value-within-range>} | % {noValue, noSuchName} (v1) | @@ -2960,6 +3215,7 @@ try_get_instance(_Vb, #me{mfa = {M, F, A}, asn1_type = ASN1Type}) -> tab_oid([]) -> [0]; tab_oid(X) -> X. + %%----------------------------------------------------------------- %% Perform a next, using the varbinds Oid if value is simple %% value. If value is {endOf<something>, NextOid}, use NextOid. @@ -3206,22 +3462,30 @@ next_oid(Oid) -> %%%----------------------------------------------------------------- %%% 5. GET-BULK REQUEST +%%% +%%% In order to prevent excesses in reply sizes there are two +%%% preventive methods in place. One is to check that the encode +%%% size does not exceed Max PDU size (this is mentioned in the +%%% standard). The other is a simple VBs limit. That is, the +%%% resulting response cannot contain more then this number of VBs. %%%----------------------------------------------------------------- -do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds) -> - ?vtrace("do get bulk: start with" + +do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds, GbMaxVBs) -> + ?vtrace("do_get_bulk -> entry with" "~n MibView: ~p" "~n NonRepeaters: ~p" "~n MaxRepetitions: ~p" "~n PduMS: ~p" - "~n Varbinds: ~p", - [MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds]), + "~n Varbinds: ~p" + "~n GbMaxVBs: ~p", + [MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds, GbMaxVBs]), {NonRepVbs, RestVbs} = split_vbs(NonRepeaters, Varbinds, []), - ?vt("do get bulk -> split: " + ?vt("do_get_bulk -> split: " "~n NonRepVbs: ~p" "~n RestVbs: ~p", [NonRepVbs, RestVbs]), - case do_get_next(MibView, NonRepVbs) of - {noError, 0, UResNonRepVbs} -> - ?vt("do get bulk -> next: " + case do_get_next(MibView, NonRepVbs, GbMaxVBs) of + {noError, 0, UResNonRepVbs} -> + ?vt("do_get_bulk -> next noError: " "~n UResNonRepVbs: ~p", [UResNonRepVbs]), ResNonRepVbs = lists:keysort(#varbind.org_index, UResNonRepVbs), %% Decode the first varbinds, produce a reversed list of @@ -3231,11 +3495,12 @@ do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds) -> user_err("failed encoding varbind ~w:~n~p", [Idx, Reason]), {genErr, Idx, []}; {SizeLeft, Res} when is_integer(SizeLeft) and is_list(Res) -> - ?vtrace("do get bulk -> encoded: " + ?vtrace("do_get_bulk -> encoded: " "~n SizeLeft: ~p" "~n Res: ~w", [SizeLeft, Res]), case (catch do_get_rep(SizeLeft, MibView, MaxRepetitions, - RestVbs, Res)) of + RestVbs, Res, + length(UResNonRepVbs), GbMaxVBs)) of {error, Idx, Reason} -> user_err("failed encoding varbind ~w:~n~p", [Idx, Reason]), @@ -3244,6 +3509,10 @@ do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds) -> ?vtrace("do get bulk -> Res: " "~n ~w", [Res]), {noError, 0, conv_res(Res)}; + {noError, 0, Data} = OK -> + ?vtrace("do get bulk -> OK: " + "~n length(Data): ~w", [length(Data)]), + OK; Else -> ?vtrace("do get bulk -> Else: " "~n ~w", [Else]), @@ -3252,6 +3521,7 @@ do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds) -> Res when is_list(Res) -> {noError, 0, conv_res(Res)} end; + {ErrorStatus, Index, _} -> ?vdebug("do get bulk: " "~n ErrorStatus: ~p" @@ -3301,11 +3571,12 @@ enc_vbs(SizeLeft, Vbs) -> end, lists:foldl(Fun, {SizeLeft, []}, Vbs). -do_get_rep(Sz, MibView, MaxRepetitions, Varbinds, Res) +do_get_rep(Sz, MibView, MaxRepetitions, Varbinds, Res, GbNumVBs, GbMaxVBs) when MaxRepetitions >= 0 -> - do_get_rep(Sz, MibView, 0, MaxRepetitions, Varbinds, Res); -do_get_rep(Sz, MibView, _MaxRepetitions, Varbinds, Res) -> - do_get_rep(Sz, MibView, 0, 0, Varbinds, Res). + do_get_rep(Sz, MibView, 0, MaxRepetitions, Varbinds, Res, + GbNumVBs, GbMaxVBs); +do_get_rep(Sz, MibView, _MaxRepetitions, Varbinds, Res, GbNumVBs, GbMaxVBs) -> + do_get_rep(Sz, MibView, 0, 0, Varbinds, Res, GbNumVBs, GbMaxVBs). conv_res(ResVarbinds) -> conv_res(ResVarbinds, []). @@ -3314,22 +3585,30 @@ conv_res([VbListOfBytes | T], Bytes) -> conv_res([], Bytes) -> Bytes. -do_get_rep(_Sz, _MibView, Max, Max, _, Res) -> +%% The only other value, then a positive integer, is infinity. +do_get_rep(_Sz, _MibView, Count, Max, _, _Res, GbNumVBs, GbMaxVBs) + when (is_integer(GbMaxVBs) andalso (GbNumVBs > GbMaxVBs)) -> + ?vinfo("Max Get-BULK VBs limit (~w) exceeded (~w) when:" + "~n Count: ~p" + "~n Max: ~p", [GbMaxVBs, GbNumVBs, Count, Max]), + {tooBig, 0, []}; +do_get_rep(_Sz, _MibView, Max, Max, _, Res, _GbNumVBs, _GbMaxVBs) -> ?vt("do_get_rep -> done when: " "~n Res: ~p", [Res]), {noError, 0, conv_res(Res)}; -do_get_rep(Sz, MibView, Count, Max, Varbinds, Res) -> +do_get_rep(Sz, MibView, Count, Max, Varbinds, Res, GbNumVBs, GbMaxVBs) -> ?vt("do_get_rep -> entry when: " "~n Sz: ~p" "~n Count: ~p" "~n Res: ~w", [Sz, Count, Res]), - case try_get_bulk(Sz, MibView, Varbinds) of + case try_get_bulk(Sz, MibView, Varbinds, GbMaxVBs) of {noError, NextVarbinds, SizeLeft, Res2} -> ?vt("do_get_rep -> noError: " "~n SizeLeft: ~p" "~n Res2: ~p", [SizeLeft, Res2]), do_get_rep(SizeLeft, MibView, Count+1, Max, NextVarbinds, - Res2 ++ Res); + Res2 ++ Res, + GbNumVBs + length(Varbinds), GbMaxVBs); {endOfMibView, _NextVarbinds, _SizeLeft, Res2} -> ?vt("do_get_rep -> endOfMibView: " "~n Res2: ~p", [Res2]), @@ -3341,22 +3620,29 @@ do_get_rep(Sz, MibView, Count, Max, Varbinds, Res) -> {ErrorStatus, Index, []} end. -try_get_bulk(Sz, MibView, Varbinds) -> +org_index_sort_vbs(Vbs) -> + lists:keysort(#varbind.org_index, Vbs). + +try_get_bulk(Sz, MibView, Varbinds, GbMaxVBs) -> ?vt("try_get_bulk -> entry with" - "~n Sz: ~w", [Sz]), - case do_get_next(MibView, Varbinds) of + "~n Sz: ~w" + "~n MibView: ~w" + "~n Varbinds: ~w", [Sz, MibView, Varbinds]), + case do_get_next(MibView, Varbinds, GbMaxVBs) of {noError, 0, UNextVarbinds} -> - ?vt("try_get_bulk -> noError", []), - NextVarbinds = lists:keysort(#varbind.org_index, UNextVarbinds), + ?vt("try_get_bulk -> noError: " + "~n UNextVarbinds: ~p", [UNextVarbinds]), + NextVarbinds = org_index_sort_vbs(UNextVarbinds), case (catch enc_vbs(Sz, NextVarbinds)) of {error, Idx, Reason} -> user_err("failed encoding varbind ~w:~n~p", [Idx, Reason]), - ?vtrace("try_get_bulk -> error: " + ?vtrace("try_get_bulk -> encode error: " "~n Idx: ~p" "~n Reason: ~p", [Idx, Reason]), {genErr, Idx}; - {SizeLeft, Res} when is_integer(SizeLeft) andalso is_list(Res) -> - ?vt("try get bulk -> " + {SizeLeft, Res} when is_integer(SizeLeft) andalso + is_list(Res) -> + ?vt("try get bulk -> encode ok: " "~n SizeLeft: ~w" "~n Res: ~w", [SizeLeft, Res]), {check_end_of_mibview(NextVarbinds), @@ -3367,9 +3653,9 @@ try_get_bulk(Sz, MibView, Varbinds) -> {endOfMibView, [], 0, Res} end; {ErrorStatus, Index, _} -> - ?vt("try get bulk: " + ?vt("try_get_bulk -> error: " "~n ErrorStatus: ~p" - "~n Index: ~p",[ErrorStatus, Index]), + "~n Index: ~p", [ErrorStatus, Index]), {ErrorStatus, Index} end. @@ -3510,9 +3796,8 @@ get_err({ErrC, ErrI, Vbs}) -> {get_err_i(ErrC), ErrI, Vbs}. get_err_i(noError) -> noError; -get_err_i(S) -> - ?vtrace("convert '~p' to 'genErr'",[S]), - genErr. +get_err_i(tooBig) -> tooBig; % OTP-9700 +get_err_i(ES) -> ?vtrace("convert ErrorStatus '~p' to 'genErr'", [ES]), genErr. v2err_to_v1err(noError) -> noError; v2err_to_v1err(noAccess) -> noSuchName; @@ -4001,6 +4286,9 @@ get_multi_threaded(Opts) -> get_versions(Opts) -> get_option(versions, Opts, [v1,v2,v3]). +get_gb_max_vbs(Opts) -> + get_option(gb_max_vbs, Opts, infinity). + get_note_store_opt(Opts) -> get_option(note_store, Opts, []). diff --git a/lib/snmp/src/agent/snmpa_internal.hrl b/lib/snmp/src/agent/snmpa_internal.hrl index 9fa874f119..671a3e4aaf 100644 --- a/lib/snmp/src/agent/snmpa_internal.hrl +++ b/lib/snmp/src/agent/snmpa_internal.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2010. All Rights Reserved. +%% Copyright Ericsson AB 2006-2011. 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 @@ -24,6 +24,15 @@ -define(DEFAULT_LOCAL_ENGINE_ID, snmp_framework_mib:get_engine_id()). +%% -- Max number of VBs in a Get-BULK response -- +%% (( The default value, 1000, is *way* more )) +%% (( then there is room for in a normal pdu )) +%% (( (unless the max pdu size has been )) +%% (( cranked way up), so this value should )) +%% (( suffice as "infinity" without actually )) +%% (( causing memory issues for the VM ... )) +-define(DEFAULT_GB_MAX_VBS, 1000). + -define(snmpa_info(F, A), ?snmp_info("agent", F, A)). -define(snmpa_warning(F, A), ?snmp_warning("agent", F, A)). -define(snmpa_error(F, A), ?snmp_error("agent", F, A)). diff --git a/lib/snmp/src/agent/snmpa_mib_lib.erl b/lib/snmp/src/agent/snmpa_mib_lib.erl index 441228b9ee..ae94aca6d8 100644 --- a/lib/snmp/src/agent/snmpa_mib_lib.erl +++ b/lib/snmp/src/agent/snmpa_mib_lib.erl @@ -60,23 +60,23 @@ table_del_row({Tab, Db} = TabDb, Key) -> get_table(NameDb, FOI) -> (catch get_table(NameDb, FOI, [], [])). -get_table(NameDb, FOI, Oid, Acc) -> - case table_next(NameDb, Oid) of +get_table(NameDb, FOI, Key, Acc) -> + case table_next(NameDb, Key) of endOfTable -> ?vdebug("end of table",[]), {ok, lists:reverse(Acc)}; - Oid -> + Key -> %% Crap, circular ref - ?vinfo("cyclic reference: ~w -> ~w", [Oid,Oid]), - throw({error, {cyclic_db_reference, Oid, Acc}}); - NextOid -> - ?vtrace("get row for oid ~w", [NextOid]), - case table_get_row(NameDb, NextOid, FOI) of + ?vinfo("cyclic reference: ~w -> ~w", [Key, Key]), + throw({error, {cyclic_db_reference, Key, Acc}}); + NextKey -> + ?vtrace("get row for key ~w", [NextKey]), + case table_get_row(NameDb, NextKey, FOI) of undefined -> - throw({error, {invalid_rowindex, NextOid, Acc}}); + throw({error, {invalid_rowindex, NextKey, Acc}}); Row -> ?vtrace("row: ~w", [Row]), - get_table(NameDb, FOI, NextOid, [{NextOid, Row}|Acc]) + get_table(NameDb, FOI, NextKey, [{NextKey, Row}|Acc]) end end. diff --git a/lib/snmp/src/agent/snmpa_supervisor.erl b/lib/snmp/src/agent/snmpa_supervisor.erl index 5ef5914e18..7a9c214e0d 100644 --- a/lib/snmp/src/agent/snmpa_supervisor.erl +++ b/lib/snmp/src/agent/snmpa_supervisor.erl @@ -176,8 +176,8 @@ init([AgentType, Opts]) -> "~n AgentType: ~p" "~n Opts: ~p", [AgentType, Opts]), - put(sname, asup), - put(verbosity,get_verbosity(Opts)), + put(sname, asup), + put(verbosity, get_verbosity(Opts)), ?vlog("starting",[]), @@ -203,7 +203,12 @@ init([AgentType, Opts]) -> Vsns = get_opt(versions, Opts, [v1,v2,v3]), ?vdebug("[agent table] store versions: ~p",[Vsns]), ets:insert(snmp_agent_table, {versions, Vsns}), - + + %% -- Max number of VBs in a Get-BULK response -- + GbMaxVBs = get_gb_max_vbs(Opts), + ?vdebug("[agent table] Get-BULK max VBs: ~p", [GbMaxVBs]), + ets:insert(snmp_agent_table, {gb_max_vbs, GbMaxVBs}), + %% -- DB-directory -- DbDir = get_opt(db_dir, Opts), ?vdebug("[agent table] store db_dir: ~n ~p",[DbDir]), @@ -377,7 +382,8 @@ init([AgentType, Opts]) -> {versions, Vsns}, {net_if, NiOpts}, {mib_server, MibsOpts}, - {note_store, NsOpts}| + {note_store, NsOpts}, + {gb_max_vbs, GbMaxVBs} | get_opt(master_agent_options, Opts, [])], AgentSpec = @@ -542,6 +548,32 @@ get_verbosity(Opts) -> get_agent_type(Opts) -> get_opt(agent_type, Opts, master). + +%% We validate this option! This should really be done for all +%% options, but it is beyond the scope of this ticket, OTP-9700. + +get_gb_max_vbs(Opts) -> + Validate = + fun(GbMaxVBs) + when ((is_integer(GbMaxVBs) andalso (GbMaxVBs > 0)) orelse + (GbMaxVBs =:= infinity)) -> + ok; + (_) -> + error + end, + get_option(gb_max_vbs, ?DEFAULT_GB_MAX_VBS, Validate, Opts). + +get_option(Key, Default, Validate, Opts) + when is_list(Opts) andalso is_function(Validate) -> + Value = get_opt(Key, Opts, Default), + case Validate(Value) of + ok -> + Value; + error -> + exit({bad_option, Key, Value}) + end. + + get_opt(Key, Opts) -> snmp_misc:get_option(Key, Opts). diff --git a/lib/snmp/src/agent/snmpa_trap.erl b/lib/snmp/src/agent/snmpa_trap.erl index 450cb2e9f4..3b31c8d909 100644 --- a/lib/snmp/src/agent/snmpa_trap.erl +++ b/lib/snmp/src/agent/snmpa_trap.erl @@ -339,9 +339,25 @@ send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, NetIf) -> send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID, NetIf). +%% The agent normally does not care about the result, +%% but since it can be usefull when debugging, add +%% some info when we fail to send the trap(s). send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID, NetIf) -> - (catch do_send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, - LocalEngineID, NetIf)). + try + begin + do_send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, + LocalEngineID, NetIf) + end + catch + T:E -> + Info = [{args, [TrapRec, NotifyName, ContextName, + Recv, Vbs, LocalEngineID, NetIf]}, + {tag, T}, + {err, E}, + {stacktrace, erlang:get_stacktrace()}], + {error, {failed_sending_trap, Info}} + end. + do_send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID, NetIf) -> diff --git a/lib/snmp/src/agent/snmpa_vacm.erl b/lib/snmp/src/agent/snmpa_vacm.erl index 2eacea4301..d17ed73ab7 100644 --- a/lib/snmp/src/agent/snmpa_vacm.erl +++ b/lib/snmp/src/agent/snmpa_vacm.erl @@ -62,6 +62,13 @@ get_mib_view(ViewType, SecModel, SecName, SecLevel, ContextName) -> %% Follows the procedure in rfc2275 auth(ViewType, SecModel, SecName, SecLevel, ContextName) -> + ?vtrace("auth -> entry with" + "~n ViewType: ~p" + "~n SecModel: ~p" + "~n SecName: ~p" + "~n SecLevel: ~p" + "~n ContextName: ~p", + [ViewType, SecModel, SecName, SecLevel, ContextName]), % 3.2.1 - Check that the context is known to us ?vdebug("check that the context (~p) is known to us",[ContextName]), case snmp_view_based_acm_mib:vacmContextTable(get, ContextName, @@ -74,7 +81,7 @@ auth(ViewType, SecModel, SecName, SecLevel, ContextName) -> end, % 3.2.2 - Check that the SecModel and SecName is valid ?vdebug("check that SecModel (~p) and SecName (~p) is valid", - [SecModel,SecName]), + [SecModel, SecName]), GroupName = case snmp_view_based_acm_mib:get(vacmSecurityToGroupTable, [SecModel, length(SecName) | SecName], @@ -111,6 +118,8 @@ check_auth(Res) -> {ok, Res}. %% key in the table >= ViewIndex. %%----------------------------------------------------------------- get_mib_view(ViewName) -> + ?vtrace("get_mib_view -> entry with" + "~n ViewName: ~p", [ViewName]), ViewKey = [length(ViewName) | ViewName], case snmp_view_based_acm_mib:table_next(vacmViewTreeFamilyTable, ViewKey) of @@ -202,6 +211,13 @@ backup(BackupDir) -> %% Ret: {ok, ViewName} | {error, Reason} get_view_name(ViewType, GroupName, ContextName, SecModel, SecLevel) -> + ?vtrace("get_view_name -> entry with" + "~n ViewType: ~p" + "~n GroupName: ~p" + "~n ContextName: ~p" + "~n SecModel: ~p" + "~n SecLevel: ~p", + [ViewType, GroupName, ContextName, SecModel, SecLevel]), GroupKey = [length(GroupName) | GroupName], case get_access_row(GroupKey, ContextName, SecModel, SecLevel) of undefined -> diff --git a/lib/snmp/src/app/snmp.appup.src b/lib/snmp/src/app/snmp.appup.src index 30f2075bc0..4ac6daf579 100644 --- a/lib/snmp/src/app/snmp.appup.src +++ b/lib/snmp/src/app/snmp.appup.src @@ -24,40 +24,69 @@ [ {"4.17.2", [ - {load_module, snmpa, soft_purge, soft_purge, []} + {load_module, snmpa, soft_purge, soft_purge, []}, + {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]}, + {load_module, snmpa_mib_lib, soft_purge, soft_purge, []}, + {load_module, snmpa_trap, soft_purge, soft_purge, []}, + {load_module, snmpa_vacm, soft_purge, soft_purge, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []} ] }, {"4.17.1", [ {load_module, snmpa, soft_purge, soft_purge, []}, + {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]}, + {load_module, snmpa_mib_lib, soft_purge, soft_purge, []}, + {load_module, snmpa_trap, soft_purge, soft_purge, []}, + {load_module, snmpa_vacm, soft_purge, soft_purge, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []}, {load_module, snmpm, soft_purge, soft_purge, [snmpm_server]}, - {update, snmpm_server, soft, soft_purge, soft_purge, []} + {update, snmpm_server, soft, soft_purge, soft_purge, []} ] }, {"4.17", [ {load_module, snmpa, soft_purge, soft_purge, []}, + {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]}, + {load_module, snmpa_mib_lib, soft_purge, soft_purge, []}, + {load_module, snmpa_trap, soft_purge, soft_purge, []}, + {load_module, snmpa_vacm, soft_purge, soft_purge, []}, {load_module, snmpa_net_if, soft_purge, soft_purge, []}, {load_module, snmpm, soft_purge, soft_purge, [snmpm_server]}, - {update, snmpm_server, soft, soft_purge, soft_purge, []} + {update, snmpm_server, soft, soft_purge, soft_purge, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []} ] }, {"4.16.2", [ + {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]}, + {load_module, snmpa_mib_lib, soft_purge, soft_purge, []}, + {load_module, snmpa_trap, soft_purge, soft_purge, []}, + {load_module, snmpa_vacm, soft_purge, soft_purge, []}, + {load_module, snmp_log, soft_purge, soft_purge, []}, {load_module, snmpa, soft_purge, soft_purge, [snmpa_agent]}, {load_module, snmpa_mpd, soft_purge, soft_purge, [snmpa_usm]}, {load_module, snmpa_usm, soft_purge, soft_purge, []}, - {update, snmpa_agent, soft, soft_purge, soft_purge, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []}, {load_module, snmpa_net_if, soft_purge, soft_purge, []}, {load_module, snmpm, soft_purge, soft_purge, [snmpm_server]}, {load_module, snmpm_mpd, soft_purge, soft_purge, []}, - {update, snmpm_server, soft, soft_purge, soft_purge, []} + {update, snmpm_server, soft, soft_purge, soft_purge, []} ] }, {"4.16.1", [ + {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]}, + {load_module, snmpa_mib_lib, soft_purge, soft_purge, []}, + {load_module, snmpa_trap, soft_purge, soft_purge, []}, + {load_module, snmpa_vacm, soft_purge, soft_purge, []}, + {load_module, snmp_log, soft_purge, soft_purge, []}, {load_module, snmp_pdus, soft_purge, soft_purge, []}, {load_module, snmp_usm, soft_purge, soft_purge, []}, @@ -66,6 +95,7 @@ {load_module, snmpa_mpd, soft_purge, soft_purge, [snmpa_usm]}, {load_module, snmpa_usm, soft_purge, soft_purge, [snmp_usm]}, {update, snmpa_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mib]}, {load_module, snmpa_net_if, soft_purge, soft_purge, []}, @@ -76,6 +106,11 @@ }, {"4.16", [ + {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]}, + {load_module, snmpa_mib_lib, soft_purge, soft_purge, []}, + {load_module, snmpa_trap, soft_purge, soft_purge, []}, + {load_module, snmpa_vacm, soft_purge, soft_purge, []}, + {load_module, snmp_log, soft_purge, soft_purge, []}, {load_module, snmp_pdus, soft_purge, soft_purge, []}, {load_module, snmp_usm, soft_purge, soft_purge, []}, @@ -85,6 +120,7 @@ {load_module, snmpa_mpd, soft_purge, soft_purge, [snmpa_usm]}, {load_module, snmpa_usm, soft_purge, soft_purge, [snmp_usm]}, {update, snmpa_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mib]}, {load_module, snmpa_net_if, soft_purge, soft_purge, []}, @@ -101,41 +137,70 @@ [ {"4.17.2", [ - {load_module, snmpa, soft_purge, soft_purge, []} + {load_module, snmpa, soft_purge, soft_purge, []}, + {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]}, + {load_module, snmpa_mib_lib, soft_purge, soft_purge, []}, + {load_module, snmpa_trap, soft_purge, soft_purge, []}, + {load_module, snmpa_vacm, soft_purge, soft_purge, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []} ] }, {"4.17.1", [ {load_module, snmpa, soft_purge, soft_purge, []}, + {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]}, + {load_module, snmpa_mib_lib, soft_purge, soft_purge, []}, + {load_module, snmpa_trap, soft_purge, soft_purge, []}, + {load_module, snmpa_vacm, soft_purge, soft_purge, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []}, {load_module, snmpm, soft_purge, soft_purge, [snmpm_server]}, - {update, snmpm_server, soft, soft_purge, soft_purge, []} + {update, snmpm_server, soft, soft_purge, soft_purge, []} ] }, {"4.17", [ {load_module, snmpa, soft_purge, soft_purge, []}, + {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]}, + {load_module, snmpa_mib_lib, soft_purge, soft_purge, []}, + {load_module, snmpa_trap, soft_purge, soft_purge, []}, + {load_module, snmpa_vacm, soft_purge, soft_purge, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []}, {load_module, snmpa_net_if, soft_purge, soft_purge, []}, {load_module, snmpm, soft_purge, soft_purge, [snmpm_server]}, - {update, snmpm_server, soft, soft_purge, soft_purge, []} + {update, snmpm_server, soft, soft_purge, soft_purge, []} ] }, {"4.16.2", [ + {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]}, + {load_module, snmpa_mib_lib, soft_purge, soft_purge, []}, + {load_module, snmpa_trap, soft_purge, soft_purge, []}, + {load_module, snmpa_vacm, soft_purge, soft_purge, []}, + {load_module, snmp_log, soft_purge, soft_purge, []}, {load_module, snmpa, soft_purge, soft_purge, [snmpa_agent]}, {load_module, snmpa_mpd, soft_purge, soft_purge, [snmpa_usm]}, {load_module, snmpa_usm, soft_purge, soft_purge, []}, - {update, snmpa_agent, soft, soft_purge, soft_purge, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []}, {load_module, snmpa_net_if, soft_purge, soft_purge, []}, {load_module, snmpm, soft_purge, soft_purge, [snmpm_server]}, {load_module, snmpm_mpd, soft_purge, soft_purge, []}, - {update, snmpm_server, soft, soft_purge, soft_purge, []} + {update, snmpm_server, soft, soft_purge, soft_purge, []} ] }, {"4.16.1", [ + {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]}, + {load_module, snmpa_mib_lib, soft_purge, soft_purge, []}, + {load_module, snmpa_trap, soft_purge, soft_purge, []}, + {load_module, snmpa_vacm, soft_purge, soft_purge, []}, + {load_module, snmp_log, soft_purge, soft_purge, []}, {load_module, snmp_pdus, soft_purge, soft_purge, []}, {load_module, snmp_usm, soft_purge, soft_purge, []}, @@ -144,6 +209,7 @@ {load_module, snmpa_mpd, soft_purge, soft_purge, [snmpa_usm]}, {load_module, snmpa_usm, soft_purge, soft_purge, [snmp_usm]}, {update, snmpa_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mib]}, {load_module, snmpa_net_if, soft_purge, soft_purge, []}, @@ -154,6 +220,11 @@ }, {"4.16", [ + {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]}, + {load_module, snmpa_mib_lib, soft_purge, soft_purge, []}, + {load_module, snmpa_trap, soft_purge, soft_purge, []}, + {load_module, snmpa_vacm, soft_purge, soft_purge, []}, + {load_module, snmp_log, soft_purge, soft_purge, []}, {load_module, snmp_pdus, soft_purge, soft_purge, []}, {load_module, snmp_usm, soft_purge, soft_purge, []}, @@ -163,6 +234,7 @@ {load_module, snmpa_mpd, soft_purge, soft_purge, [snmpa_usm]}, {load_module, snmpa_usm, soft_purge, soft_purge, [snmp_usm]}, {update, snmpa_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mib]}, {load_module, snmpa_net_if, soft_purge, soft_purge, []}, diff --git a/lib/snmp/test/snmp_agent_test.erl b/lib/snmp/test/snmp_agent_test.erl index 9d2e9969c4..3af55bc002 100644 --- a/lib/snmp/test/snmp_agent_test.erl +++ b/lib/snmp/test/snmp_agent_test.erl @@ -1200,7 +1200,10 @@ test_multi_threaded(suite) -> {req, [], {conf, init_mt, mt_cases(), finish_mt}}. mt_cases() -> - [multi_threaded, mt_trap]. + [ + multi_threaded, + mt_trap + ]. init_mt(Config) when is_list(Config) -> SaNode = ?config(snmp_sa, Config), @@ -3024,8 +3027,9 @@ mt_trap_test(MA) -> ?DBG("mt_trap_test(01) -> issue testTrapv22 (standard trap)", []), snmpa:send_trap(MA, testTrapv22, "standard trap"), ?DBG("mt_trap_test(02) -> await v2trap", []), - ?line expect(1, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}]), + ?line expect(mt_trap_test_1, v2trap, + [{[sysUpTime, 0], any}, + {[snmpTrapOID, 0], ?system ++ [0,1]}]), ?DBG("mt_trap_test(03) -> issue mtTrap (standard trap)", []), snmpa:send_trap(MA, mtTrap, "standard trap"), @@ -3033,28 +3037,22 @@ mt_trap_test(MA) -> ?DBG("mt_trap_test(04) -> multi pid: ~p. Now request sysUpTime...", [Pid]), g([[sysUpTime,0]]), - %% Previously (before OTP-6784) this was done at 09 below - %% when the test1:multiStr was actually executed by the - %% worker-process, but as of 4.9.4, this is now executed - %% my the master_agent-process... - ?DBG("mt_trap_test(05) -> send continue to multi-pid", []), - Pid ! continue, - ?DBG("mt_trap_test(06) -> await sysUpTime", []), - ?line expect(2, [{[sysUpTime,0], any}]), + ?line expect(mt_trap_test_2, [{[sysUpTime,0], any}]), ?DBG("mt_trap_test(07) -> issue testTrapv22 (standard trap)", []), snmpa:send_trap(MA, testTrapv22, "standard trap"), ?DBG("mt_trap_test(08) -> await v2trap", []), - ?line expect(3, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}]), + ?line expect(mt_trap_test_3, v2trap, + [{[sysUpTime, 0], any}, + {[snmpTrapOID, 0], ?system ++ [0,1]}]), - %% ?DBG("mt_trap_test(09) -> send continue to multi-pid", []), - %% Pid ! continue, + ?DBG("mt_trap_test(09) -> send continue to multi-pid", []), + Pid ! continue, ?DBG("mt_trap_test(10) -> await v2trap", []), - ?line expect(4, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?testTrap ++ [2]}, - {[multiStr,0], "ok"}]), + ?line expect(mt_trap_test_4, v2trap, [{[sysUpTime, 0], any}, + {[snmpTrapOID, 0], ?testTrap ++ [2]}, + {[multiStr,0], "ok"}]), ?DBG("mt_trap_test(11) -> done", []), ok. diff --git a/lib/snmp/test/snmp_agent_test_lib.erl b/lib/snmp/test/snmp_agent_test_lib.erl index 9e89aa889c..084b3ee8da 100644 --- a/lib/snmp/test/snmp_agent_test_lib.erl +++ b/lib/snmp/test/snmp_agent_test_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2010. All Rights Reserved. +%% Copyright Ericsson AB 2005-2011. 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 @@ -296,7 +296,12 @@ call(N,M,F,A) -> ?DBG("call -> done:" "~n Ret: ~p" "~n Zed: ~p", [Ret, Zed]), - Ret + case Ret of + {error, Reason} -> + exit(Reason); + OK -> + OK + end end. wait(From, Env, M, F, A) -> @@ -724,17 +729,13 @@ expect(Id, A, B, C, D, E) -> expect2(Id, Fun). expect2(Id, F) -> - io:format("~w:expect2 -> entry with" - "~n Id: ~w" - "~n", [?MODULE, Id]), + io:format("EXPECT for ~w~n", [Id]), case F() of {error, Reason} -> - {error, Id, Reason}; + io:format("EXPECT failed for ~w: ~n~p~n", [Id, Reason]), + throw({error, {expect, Id, Reason}}); Else -> - io:format("~w:expect2 -> " - "~n Id: ~w" - "~n Else: ~p" - "~n", [?MODULE, Id, Else]), + io:format("EXPECT result for ~w: ~n~p~n", [Id, Else]), Else end. @@ -769,21 +770,15 @@ do_expect(Expect) when is_atom(Expect) -> do_expect({any_pdu, To}) when is_integer(To) orelse (To =:= infinity) -> - io:format("~w:do_expect(any_pdu) -> entry with" - "~n To: ~w" - "~n", [?MODULE, To]), + io:format("EXPECT any PDU~n", []), receive_pdu(To); do_expect({any_trap, To}) -> - io:format("~w:do_expect(any_trap) -> entry with" - "~n To: ~w" - "~n", [?MODULE, To]), + io:format("EXPECT any TRAP within ~w~n", [To]), receive_trap(To); do_expect({timeout, To}) -> - io:format("~w:do_expect(timeout) -> entry with" - "~n To: ~w" - "~n", [?MODULE, To]), + io:format("EXPECT nothing within ~w~n", [To]), receive X -> {error, {unexpected, X}} @@ -794,13 +789,16 @@ do_expect({timeout, To}) -> do_expect({Err, To}) when is_atom(Err) andalso (is_integer(To) orelse (To =:= infinity)) -> + io:format("EXPECT error ~w within ~w~n", [Err, To]), do_expect({{error, Err}, To}); do_expect({error, Err}) when is_atom(Err) -> Check = fun(_, R) -> R end, + io:format("EXPECT error ~w~n", [Err]), do_expect2(Check, any, Err, any, any, get_timeout()); do_expect({{error, Err}, To}) -> Check = fun(_, R) -> R end, + io:format("EXPECT error ~w within ~w~n", [Err, To]), do_expect2(Check, any, Err, any, any, To); %% exp_varbinds() -> [exp_varbind()] @@ -810,16 +808,25 @@ do_expect({{error, Err}, To}) -> %% ExpVBs -> exp_varbinds() | {VbsCondition, exp_varbinds()} do_expect(ExpVBs) -> Check = fun(_, R) -> R end, + io:format("EXPECT 'get-response'" + "~n with" + "~n Varbinds: ~p~n", [ExpVBs]), do_expect2(Check, 'get-response', noError, 0, ExpVBs, get_timeout()). do_expect(v2trap, ExpVBs) -> Check = fun(_, R) -> R end, + io:format("EXPECT 'snmpv2-trap'" + "~n with" + "~n Varbinds: ~p~n", [ExpVBs]), do_expect2(Check, 'snmpv2-trap', noError, 0, ExpVBs, get_timeout()); do_expect(report, ExpVBs) -> Check = fun(_, R) -> R end, + io:format("EXPECT 'report'" + "~n with" + "~n Varbinds: ~p~n", [ExpVBs]), do_expect2(Check, 'report', noError, 0, ExpVBs, get_timeout()); @@ -827,16 +834,13 @@ do_expect(inform, ExpVBs) -> do_expect({inform, true}, ExpVBs); do_expect({inform, false}, ExpVBs) -> - io:format("~w:do_expect(inform, false) -> entry with" - "~n ExpVBs: ~p" - "~n", [?MODULE, ExpVBs]), Check = fun(_, R) -> R end, + io:format("EXPECT 'inform-request' (false)" + "~n with" + "~n Varbinds: ~p~n", [ExpVBs]), do_expect2(Check, 'inform-request', noError, 0, ExpVBs, get_timeout()); do_expect({inform, true}, ExpVBs) -> - io:format("~w:do_expect(inform, true) -> entry with" - "~n ExpVBs: ~p" - "~n", [?MODULE, ExpVBs]), Check = fun(PDU, ok) -> RespPDU = PDU#pdu{type = 'get-response', @@ -847,6 +851,9 @@ do_expect({inform, true}, ExpVBs) -> (_, Err) -> Err end, + io:format("EXPECT 'inform-request' (true)" + "~n with" + "~n Varbinds: ~p~n", [ExpVBs]), do_expect2(Check, 'inform-request', noError, 0, ExpVBs, get_timeout()); do_expect({inform, {error, EStat, EIdx}}, ExpVBs) @@ -861,6 +868,11 @@ do_expect({inform, {error, EStat, EIdx}}, ExpVBs) (_, Err) -> Err end, + io:format("EXPECT 'inform-request' (error)" + "~n with" + "~n Error Status: ~p" + "~n Error Index: ~p" + "~n Varbinds: ~p~n", [EStat, EIdx, ExpVBs]), do_expect2(Check, 'inform-request', noError, 0, ExpVBs, get_timeout()). @@ -871,6 +883,12 @@ do_expect(Err, Idx, ExpVBs, To) when is_atom(Err) andalso (is_integer(Idx) orelse is_list(Idx) orelse (Idx == any)) -> Check = fun(_, R) -> R end, + io:format("EXPECT 'get-response'" + "~n with" + "~n Error: ~p" + "~n Index: ~p" + "~n Varbinds: ~p" + "~n within ~w~n", [Err, Idx, ExpVBs, To]), do_expect2(Check, 'get-response', Err, Idx, ExpVBs, To). @@ -878,15 +896,13 @@ do_expect(Type, Enterp, Generic, Specific, ExpVBs) -> do_expect(Type, Enterp, Generic, Specific, ExpVBs, 3500). do_expect(trap, Enterp, Generic, Specific, ExpVBs, To) -> - io:format("~w:do_expect(trap) -> entry with" - "~n Enterp: ~w" - "~n Generic: ~w" - "~n Specific: ~w" - "~n ExpVBs: ~w" - "~n To: ~w" - "~nwhen" - "~n Time: ~w" - "~n", [?MODULE, Enterp, Generic, Specific, ExpVBs, To, t()]), + io:format("EXPECT trap" + "~n with" + "~n Enterp: ~w" + "~n Generic: ~w" + "~n Specific: ~w" + "~n Varbinds: ~w" + "~n within ~w~n", [Enterp, Generic, Specific, ExpVBs, To]), PureE = purify_oid(Enterp), case receive_trap(To) of #trappdu{enterprise = PureE, @@ -916,49 +932,51 @@ do_expect2(Check, Type, Err, Idx, ExpVBs, To) (is_list(ExpVBs) orelse (ExpVBs =:= any)) andalso (is_integer(To) orelse (To =:= infinity)) -> - io:format("~w:do_expect2 -> entry with" - "~n Type: ~w" - "~n Err: ~w" - "~n Idx: ~w" - "~n ExpVBs: ~w" - "~n To: ~w" - "~nwhen" - "~n Time: ~w" - "~n", [?MODULE, Type, Err, Idx, ExpVBs, To, t()]), - case receive_pdu(To) of #pdu{type = Type, error_status = Err, error_index = Idx} when ExpVBs =:= any -> + io:format("EXPECT received expected pdu (1)~n", []), ok; #pdu{type = Type, request_id = ReqId, error_status = Err2, error_index = Idx} when ExpVBs =:= any -> + io:format("EXPECT received expected pdu with " + "unexpected error status (2): " + "~n Error Status: ~p~n", [Err2]), {error, {unexpected_error_status, Err, Err2, ReqId}}; #pdu{error_status = Err} when (Type =:= any) andalso (Idx =:= any) andalso (ExpVBs =:= any) -> + io:format("EXPECT received expected pdu (3)~n", []), ok; #pdu{request_id = ReqId, error_status = Err2} when (Type =:= any) andalso (Idx =:= any) andalso (ExpVBs =:= any) -> + io:format("EXPECT received expected pdu with " + "unexpected error status (4): " + "~n Error Status: ~p~n", [Err2]), {error, {unexpected_error_status, Err, Err2, ReqId}}; #pdu{type = Type, error_status = Err} when (Idx =:= any) andalso (ExpVBs =:= any) -> + io:format("EXPECT received expected pdu (5)~n", []), ok; #pdu{type = Type, request_id = ReqId, error_status = Err2} when (Idx =:= any) andalso (ExpVBs =:= any) -> + io:format("EXPECT received expected pdu with " + "unexpected error status (6): " + "~n Error Status: ~p~n", [Err2]), {error, {unexpected_error_status, Err, Err2, ReqId}}; #pdu{type = Type, @@ -967,8 +985,13 @@ do_expect2(Check, Type, Err, Idx, ExpVBs, To) error_index = EI} when is_list(Idx) andalso (ExpVBs =:= any) -> case lists:member(EI, Idx) of true -> + io:format("EXPECT received expected pdu with " + "expected error index (7)~n", []), ok; false -> + io:format("EXPECT received expected pdu with " + "unexpected error index (8): " + "~n Error Index: ~p~n", [EI]), {error, {unexpected_error_index, EI, Idx, ReqId}} end; @@ -978,8 +1001,15 @@ do_expect2(Check, Type, Err, Idx, ExpVBs, To) error_index = EI} when is_list(Idx) andalso (ExpVBs =:= any) -> case lists:member(EI, Idx) of true -> + io:format("EXPECT received expected pdu with " + "unexpected error status (9): " + "~n Error Status: ~p~n", [Err2]), {error, {unexpected_error_status, Err, Err2, ReqId}}; false -> + io:format("EXPECT received expected pdu with " + "unexpected error (10): " + "~n Error Status: ~p" + "~n Error index: ~p~n", [Err2, EI]), {error, {unexpected_error, {Err, Idx}, {Err2, EI}, ReqId}} end; @@ -987,6 +1017,12 @@ do_expect2(Check, Type, Err, Idx, ExpVBs, To) request_id = ReqId, error_status = Err2, error_index = Idx2} when ExpVBs =:= any -> + io:format("EXPECT received unexpected pdu with (11) " + "~n Type: ~p" + "~n ReqId: ~p" + "~n Errot status: ~p" + "~n Error index: ~p" + "~n", [Type2, ReqId, Err2, Idx2]), {error, {unexpected_pdu, {Type, Err, Idx}, {Type2, Err2, Idx2}, ReqId}}; @@ -995,11 +1031,26 @@ do_expect2(Check, Type, Err, Idx, ExpVBs, To) error_status = Err, error_index = Idx, varbinds = VBs} = PDU -> + io:format("EXPECT received pdu (12): " + "~n [exp] Type: ~p" + "~n [exp] Error Status: ~p" + "~n [exp] Error Index: ~p" + "~n VBs: ~p" + "~nwhen" + "~n ExpVBs: ~p" + "~n", [Type, Err, Idx, VBs, ExpVBs]), Check(PDU, check_vbs(purify_oids(ExpVBs), VBs)); #pdu{type = Type, error_status = Err, varbinds = VBs} = PDU when Idx =:= any -> + io:format("EXPECT received pdu (13): " + "~n [exp] Type: ~p" + "~n [exp] Error Status: ~p" + "~n VBs: ~p" + "~nwhen" + "~n ExpVBs: ~p" + "~n", [Type, Err, VBs, ExpVBs]), Check(PDU, check_vbs(purify_oids(ExpVBs), VBs)); #pdu{type = Type, @@ -1007,6 +1058,15 @@ do_expect2(Check, Type, Err, Idx, ExpVBs, To) error_status = Err, error_index = EI, varbinds = VBs} = PDU when is_list(Idx) -> + io:format("EXPECT received pdu (14): " + "~n [exp] Type: ~p" + "~n ReqId: ~p" + "~n [exp] Error Status: ~p" + "~n [exp] Error Index: ~p" + "~n VBs: ~p" + "~nwhen" + "~n ExpVBs: ~p" + "~n", [Type, ReqId, Err, EI, VBs, ExpVBs]), PureVBs = purify_oids(ExpVBs), case lists:member(EI, Idx) of true -> @@ -1020,6 +1080,13 @@ do_expect2(Check, Type, Err, Idx, ExpVBs, To) error_status = Err2, error_index = Idx2, varbinds = VBs2} -> + io:format("EXPECT received unexpected pdu with (15) " + "~n Type: ~p" + "~n ReqId: ~p" + "~n Errot status: ~p" + "~n Error index: ~p" + "~n Varbinds: ~p" + "~n", [Type2, ReqId, Err2, Idx2, VBs2]), {error, {unexpected_pdu, {Type, Err, Idx, purify_oids(ExpVBs)}, @@ -1027,6 +1094,9 @@ do_expect2(Check, Type, Err, Idx, ExpVBs, To) ReqId}}; Error -> + io:format("EXPECT received error (16): " + "~n Error: ~p" + "~n", [Error]), Error end. @@ -1311,10 +1381,12 @@ rewrite_target_addr_conf(Dir, NewPort) -> "~n NewPort: ~p", [NewPort]), TAFile = filename:join(Dir, "target_addr.conf"), case file:read_file_info(TAFile) of - {ok, _} -> ok; - {error, R} -> ?ERR("failure reading file info of " - "target address config file: ~p",[R]), - ok + {ok, _} -> + ok; + {error, R} -> + ?ERR("failure reading file info of " + "target address config file: ~p",[R]), + ok end, ?line [TrapAddr|Addrs] = @@ -1335,8 +1407,9 @@ rewrite_target_addr_conf(Dir, NewPort) -> rewrite_target_addr_conf_check(O) -> {ok,O}. -rewrite_target_addr_conf2(NewPort,{Name,Ip,_Port,Timeout,Retry, - "std_trap",EngineId}) -> +rewrite_target_addr_conf2(NewPort, + {Name, Ip, _Port, Timeout, Retry, + "std_trap", EngineId}) -> ?LOG("rewrite_target_addr_conf2 -> entry with std_trap",[]), {Name,Ip,NewPort,Timeout,Retry,"std_trap",EngineId}; rewrite_target_addr_conf2(_NewPort,O) -> @@ -1463,7 +1536,7 @@ rpc(Node, F, A) -> %% %% %% t() -> -%% {A,B,C} = erlang:now(), +%% {A,B,C} = os:timestamp(), %% A*1000000000+B*1000+(C div 1000). %% %% @@ -1475,6 +1548,6 @@ rpc(Node, F, A) -> %% Time in milli seconds -t() -> - {A,B,C} = erlang:now(), - A*1000000000+B*1000+(C div 1000). +%% t() -> +%% {A,B,C} = os:timestamp(), +%% A*1000000000+B*1000+(C div 1000). diff --git a/lib/snmp/vsn.mk b/lib/snmp/vsn.mk index 9dd47a741c..3ab08eca58 100644 --- a/lib/snmp/vsn.mk +++ b/lib/snmp/vsn.mk @@ -21,7 +21,7 @@ SNMP_VSN = 4.17.3 PRE_VSN = APP_VSN = "snmp-$(SNMP_VSN)$(PRE_VSN)" -TICKETS = OTP-9868 +TICKETS = OTP-9700 OTP-9868 TICKETS_4_17_2 = OTP-9236 |