aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorMicael Karlberg <[email protected]>2013-05-28 17:23:06 +0200
committerMicael Karlberg <[email protected]>2013-05-28 17:23:06 +0200
commita6c76247fa67e86c12773e2d997c66c9f794b002 (patch)
tree152b2eb5983ae14bf4947a997428a1ebf36e6f1c /lib
parent1fadb8a6744b282659cecba754b9678ef9761d8c (diff)
parent8f541e4959d4f58480beac053cc76613cd208837 (diff)
downloadotp-a6c76247fa67e86c12773e2d997c66c9f794b002.tar.gz
otp-a6c76247fa67e86c12773e2d997c66c9f794b002.tar.bz2
otp-a6c76247fa67e86c12773e2d997c66c9f794b002.zip
Merge branch 'bmk/snmp/agent/mib_storage_behaviour/OTP-11107' into bmk/snmp/snmp424_integration/r16
Conflicts: lib/snmp/doc/src/notes.xml
Diffstat (limited to 'lib')
-rw-r--r--lib/snmp/doc/src/files.mk1
-rw-r--r--lib/snmp/doc/src/notes.xml13
-rw-r--r--lib/snmp/doc/src/ref_man.xml1
-rw-r--r--lib/snmp/doc/src/snmp_app.xml137
-rw-r--r--lib/snmp/doc/src/snmp_config.xml121
-rw-r--r--lib/snmp/doc/src/snmpa_mib_data.xml2
-rw-r--r--lib/snmp/doc/src/snmpa_mib_storage.xml292
-rw-r--r--lib/snmp/src/agent/depend.mk16
-rw-r--r--lib/snmp/src/agent/modules.mk5
-rw-r--r--lib/snmp/src/agent/snmpa.erl1
-rw-r--r--lib/snmp/src/agent/snmpa_agent.erl185
-rw-r--r--lib/snmp/src/agent/snmpa_agent_sup.erl10
-rw-r--r--lib/snmp/src/agent/snmpa_mib.erl13
-rw-r--r--lib/snmp/src/agent/snmpa_mib_data_tttn.erl293
-rw-r--r--lib/snmp/src/agent/snmpa_mib_storage.erl181
-rw-r--r--lib/snmp/src/agent/snmpa_mib_storage_dets.erl309
-rw-r--r--lib/snmp/src/agent/snmpa_mib_storage_ets.erl341
-rw-r--r--lib/snmp/src/agent/snmpa_mib_storage_mnesia.erl302
-rw-r--r--lib/snmp/src/agent/snmpa_supervisor.erl107
-rw-r--r--lib/snmp/src/agent/snmpa_symbolic_store.erl283
-rw-r--r--lib/snmp/src/app/snmp.app.src5
-rw-r--r--lib/snmp/src/app/snmp_app.erl14
-rw-r--r--lib/snmp/src/misc/snmp_config.erl22
-rw-r--r--lib/snmp/test/snmp_agent_mibs_test.erl263
-rw-r--r--lib/snmp/test/snmp_agent_test.erl462
-rw-r--r--lib/snmp/test/snmp_agent_test_lib.erl278
-rw-r--r--lib/stdlib/src/otp_internal.erl4
27 files changed, 2936 insertions, 725 deletions
diff --git a/lib/snmp/doc/src/files.mk b/lib/snmp/doc/src/files.mk
index e215143b03..494c550fff 100644
--- a/lib/snmp/doc/src/files.mk
+++ b/lib/snmp/doc/src/files.mk
@@ -42,6 +42,7 @@ XML_AGENT_REF3_FILES = \
snmpa_error_logger.xml \
snmpa_local_db.xml \
snmpa_mib_data.xml \
+ snmpa_mib_storage.xml \
snmpa_mpd.xml \
snmpa_network_interface.xml \
snmpa_network_interface_filter.xml \
diff --git a/lib/snmp/doc/src/notes.xml b/lib/snmp/doc/src/notes.xml
index bf4710aa2c..80de9738f1 100644
--- a/lib/snmp/doc/src/notes.xml
+++ b/lib/snmp/doc/src/notes.xml
@@ -62,6 +62,19 @@
<p>Own Id: OTP-11101</p>
</item>
+ <item>
+ <p>[agent] Introduced a documented behaviour for the
+ <seealso marker="snmpa_mib_storage">mib storage</seealso>.
+ At present there are three simple modules
+ (<c>snmpa_mib_storage_ets</c>, <c>snmpa_mib_storage_dets</c> and
+ <c>snmpa_mib_storage_mnesia</c>) implement�ng this behaviour,
+ provided with the app. </p>
+ <p>A config option for the (agent)
+ <seealso marker="snmp_config#agent_mib_storage">mib storage</seealso>
+ has been added to the agent config options. </p>
+ <p>Own Id: OTP-11107</p>
+ </item>
+
</list>
</section>
diff --git a/lib/snmp/doc/src/ref_man.xml b/lib/snmp/doc/src/ref_man.xml
index 2c12ac665a..628b30b11a 100644
--- a/lib/snmp/doc/src/ref_man.xml
+++ b/lib/snmp/doc/src/ref_man.xml
@@ -45,6 +45,7 @@
<xi:include href="snmpa_error_logger.xml"/>
<xi:include href="snmpa_local_db.xml"/>
<xi:include href="snmpa_mib_data.xml"/>
+ <xi:include href="snmpa_mib_storage.xml"/>
<xi:include href="snmpa_mpd.xml"/>
<xi:include href="snmpa_network_interface.xml"/>
<xi:include href="snmpa_network_interface_filter.xml"/>
diff --git a/lib/snmp/doc/src/snmp_app.xml b/lib/snmp/doc/src/snmp_app.xml
index c7a74f0ca6..e5a05342c1 100644
--- a/lib/snmp/doc/src/snmp_app.xml
+++ b/lib/snmp/doc/src/snmp_app.xml
@@ -311,30 +311,119 @@
<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>
- <p>If <c>mib_storage</c> is <c>{ets, Dir}</c>, the table will also be
- stored on file. If <c>Dir</c> is <c>default</c>, then <c>db_dir</c>
- will be used.</p>
- <p>If <c>mib_storage</c> is <c>dets</c> or if <c>Dir</c> is
- <c>default</c>, then <c>db_dir</c> will be used for <c>Dir</c>.</p>
- <p>If <c>mib_storage</c> is <c>mnesia</c> then <c>erlang:nodes()</c>
- will be used for <c>Nodes</c>.</p>
- <p>Default is <c>ets</c>. </p>
- <p><c>Dir = default | string()</c>. Dir is the directory where the
- files will be stored. If <c>default</c>, then <c>db_dir</c> will be
- used.</p>
- <p><c>Nodes = visible | connected | [node()]</c>.
- <c>Nodes = visible</c> is translated to
- <c>erlang:nodes(visible)</c>.
- <c>Nodes = connected</c> is translated to
- <c>erlang:nodes(connected)</c>.
- If <c>Nodes = []</c> then the own node is assumed.</p>
- <p><c>Action = clear | keep</c>. Default is <c>keep</c>.
- <c>Action</c> is used to specify what shall be done if the
- mnesia/dets table already exist.</p>
+ <marker id="agent_mib_storage"></marker>
+ <tag><c><![CDATA[mib_storage() = [mib_storage_opt()] <optional>]]></c></tag>
+ <item>
+ <p><c>mib_storage_opt() = {module, mib_storage_module()} | {options, mib_storage_options()}</c></p>
+ <p>This option specifies how basic mib data is stored.
+ This option is used by two parts of the snmp agent:
+ The mib-server and the symbolic-store. </p>
+ <p>Default is <c>[{module, snmpa_mib_storage_ets}]</c>. </p>
+ </item>
+
+ <marker id="agent_mst_module"></marker>
+ <tag><c><![CDATA[mib_storage_module() = snmpa_mib_data_ets | snmpa_mib_data_dets | snmpa_mib_data_mnesia | module()]]></c></tag>
+ <item>
+ <p>Defines the mib storage module of the SNMP agent as defined by the
+ <seealso marker="snmpa_mib_storage">snmpa_mib_storage</seealso>
+ behaviour. </p>
+ <p>Several entities (<c>mib-server</c> via the its data module and
+ the <c>symbolic-store</c>) of the snmp agent uses this for storage
+ of miscelaneous mib related data retrieved while loading a mib. </p>
+ <p>There are several implementations provided with the agent:
+ <c>snmpa_mib_storage_ets</c>, <c>snmpa_mib_storage_dets</c> and
+ <c>snmpa_mib_storage_mnesia</c>. </p>
+ <p>Default module is <c>snmpa_mib_storage_ets</c>. </p>
+ </item>
+
+ <marker id="agent_mst_options"></marker>
+ <tag><c><![CDATA[mib_storage_options() = list() <optional>]]></c></tag>
+ <item>
+ <p>This is implementattion depended. That is, it depends on the
+ module. For each module a specific set of options are valid.
+ For the module provided with the app, these options are supported: </p>
+ <list type="bulleted">
+ <item>
+ <p><c>snmpa_mib_storage_ets</c>: <c>{dir, filename()} | {action, keep | clear}, {checksum, boolean()}</c></p>
+ <list>
+ <item>
+ <p><c>dir</c> - If present, points to a directory where a file
+ to which all data in the ets table is "synced". </p>
+ <p>Also, when a table is opened this file is read,
+ if it exists. </p>
+ <p>By default, this will <em>not</em> be used. </p>
+ </item>
+ <item>
+ <p><c>action</c> - Specifies the behaviour when a non-empty
+ file is found: Keep its content or clear it out. </p>
+ <p>Default is <c>keep</c>. </p>
+ </item>
+ <item>
+ <p><c>checksum</c> - Defines if the file is checksummed
+ or not. </p>
+ <p>Default is <c>false</c>. </p>
+ </item>
+ </list>
+ </item>
+ <item>
+ <p><c>snmpa_mib_storage_dets</c>: <c>{dir, filename()} | {action, keep | clear}, {auto_save, default | pos_integer()} | {repair, force | boolean()}</c></p>
+ <list>
+ <item>
+ <p><c>dir</c> - This <em>mandatory</em> option points to a
+ directory where to place the file of a dets table. </p>
+ </item>
+ <item>
+ <p><c>action</c> - Specifies the behaviour when a non-empty
+ file is found: Keep its content or clear it out. </p>
+ <p>Default is <c>keep</c>. </p>
+ </item>
+ <item>
+ <p><c>auto_save</c> - Defines the dets auto-save frequency. </p>
+ <p>Default is <c>default</c>. </p>
+ </item>
+ <item>
+ <p><c>repair</c> - Defines the dets repair behaviour. </p>
+ <p>Default is <c>false</c>. </p>
+ </item>
+ </list>
+ </item>
+ <item>
+ <p><c>snmpa_mib_storage_mnesia</c>: <c>{action, keep | clear}, {nodes, [node()]}</c></p>
+ <list>
+ <item>
+ <p><c>action</c> - Specifies the behaviour when a non-empty,
+ already existing, table: Keep its content or clear it out. </p>
+ <p>Default is <c>keep</c>. </p>
+ </item>
+ <item>
+ <p><c>nodes</c> - A list of node names (or an atom
+ describing a list of nodes) defining where to open the table.
+ Its up to the user to ensure that mnesia is actually running
+ on the specified nodes. </p>
+ <p>The following distinct values are recognised: </p>
+ <list>
+ <item>
+ <p><c>[]</c> - Translated into a list of the own node: <c>[node()]</c></p>
+ </item>
+ <item>
+ <p><c>all</c> - <c>erlang:nodes()</c></p>
+ </item>
+ <item>
+ <p><c>visible</c> - <c>erlang:nodes(visible)</c></p>
+ </item>
+ <item>
+ <p><c>connected</c> - <c>erlang:nodes(connected)</c></p>
+ </item>
+ <item>
+ <p><c>db_nodes</c> - <c>mnesia:system_info(db_nodes)</c></p>
+ </item>
+ </list>
+
+ <p>Default is the result of the call: <c>erlang:nodes()</c>. </p>
+ </item>
+ </list>
+ </item>
+ </list>
</item>
<marker id="agent_mib_server"></marker>
diff --git a/lib/snmp/doc/src/snmp_config.xml b/lib/snmp/doc/src/snmp_config.xml
index 28bfcbb3de..61ee7f00ee 100644
--- a/lib/snmp/doc/src/snmp_config.xml
+++ b/lib/snmp/doc/src/snmp_config.xml
@@ -308,6 +308,126 @@
<p>Default is <c>[]</c>.</p>
</item>
+ <marker id="agent_mib_storage"></marker>
+ <tag><c><![CDATA[mib_storage() = [mib_storage_opt()] <optional>]]></c></tag>
+ <item>
+ <p><c>mib_storage_opt() = {module, mib_storage_module()} | {options, mib_storage_options()}</c></p>
+ <p>This option specifies how basic mib data is stored.
+ This option is used by two parts of the snmp agent:
+ The mib-server and the symbolic-store. </p>
+ <p>Default is <c>[{module, snmpa_mib_storage_ets}]</c>. </p>
+ </item>
+
+ <marker id="agent_mst_module"></marker>
+ <tag><c><![CDATA[mib_storage_module() = snmpa_mib_data_ets | snmpa_mib_data_dets | snmpa_mib_data_mnesia | module()]]></c></tag>
+ <item>
+ <p>Defines the mib storage module of the SNMP agent as defined by the
+ <seealso marker="snmpa_mib_storage">snmpa_mib_storage</seealso>
+ behaviour. </p>
+ <p>Several entities (<c>mib-server</c> via the its data module and
+ the <c>symbolic-store</c>) of the snmp agent uses this for storage
+ of miscelaneous mib related data dataretrieved while loading a mib. </p>
+ <p>There are several implementations provided with the agent:
+ <c>snmpa_mib_storage_ets</c>, <c>snmpa_mib_storage_dets</c> and
+ <c>snmpa_mib_storage_mnesia</c>. </p>
+ <p>Default module is <c>snmpa_mib_storage_ets</c>. </p>
+ </item>
+
+ <marker id="agent_mst_options"></marker>
+ <tag><c><![CDATA[mib_storage_options() = list() <optional>]]></c></tag>
+ <item>
+ <p>This is implementattion depended. That is, it depends on the
+ module. For each module a specific set of options are valid.
+ For the module provided with the app, these options are supported: </p>
+ <list type="bulleted">
+ <item>
+ <p><c>snmpa_mib_storage_ets</c>: <c>{dir, filename()} | {action, keep | clear}, {checksum, boolean()}</c></p>
+ <list>
+ <item>
+ <p><c>dir</c> - If present, points to a directory where a file
+ to which all data in the ets table is "synced". </p>
+ <p>Also, when a table is opened this file is read,
+ if it exists. </p>
+ <p>By default, this will <em>not</em> be used. </p>
+ </item>
+ <item>
+ <p><c>action</c> - Specifies the behaviour when a non-empty
+ file is found: Keep its content or clear it out. </p>
+ <p>Default is <c>keep</c>. </p>
+ </item>
+ <item>
+ <p><c>checksum</c> - Defines if the file is checksummed
+ or not. </p>
+ <p>Default is <c>false</c>. </p>
+ </item>
+ </list>
+ </item>
+ <item>
+ <p><c>snmpa_mib_storage_dets</c>: <c>{dir, filename()} | {action, keep | clear}, {auto_save, default | pos_integer()} | {repair, force | boolean()}</c></p>
+ <list>
+ <item>
+ <p><c>dir</c> - This <em>mandatory</em> option points to a
+ directory where to place the file of a dets table. </p>
+ </item>
+ <item>
+ <p><c>action</c> - Specifies the behaviour when a non-empty
+ file is found: Keep its content or clear it out. </p>
+ <p>Default is <c>keep</c>. </p>
+ </item>
+ <item>
+ <p><c>auto_save</c> - Defines the dets auto-save frequency. </p>
+ <p>Default is <c>default</c>. </p>
+ </item>
+ <item>
+ <p><c>repair</c> - Defines the dets repair behaviour. </p>
+ <p>Default is <c>false</c>. </p>
+ </item>
+ </list>
+ </item>
+ <item>
+ <p><c>snmpa_mib_storage_mnesia</c>: <c>{action, keep | clear}, {nodes, [node()]}</c></p>
+ <list>
+ <item>
+ <p><c>action</c> - Specifies the behaviour when a non-empty,
+ already existing, table: Keep its content or clear it out. </p>
+ <p>Default is <c>keep</c>. </p>
+ </item>
+ <item>
+ <p><c>nodes</c> - A list of node names (or an atom
+ describing a list of nodes) defining where to open the table.
+ Its up to the user to ensure that mnesia is actually running
+ on the specified nodes. </p>
+ <p>The following distinct values are recognised: </p>
+ <list>
+ <item>
+ <p><c>[]</c> - Translated into a list of the own node: <c>[node()]</c></p>
+ </item>
+ <item>
+ <p><c>all</c> - <c>erlang:nodes()</c></p>
+ </item>
+ <item>
+ <p><c>visible</c> - <c>erlang:nodes(visible)</c></p>
+ </item>
+ <item>
+ <p><c>connected</c> - <c>erlang:nodes(connected)</c></p>
+ </item>
+ <item>
+ <p><c>db_nodes</c> - <c>mnesia:system_info(db_nodes)</c></p>
+ </item>
+ </list>
+
+ <p>Default is the result of the call: <c>erlang:nodes()</c>. </p>
+ </item>
+ </list>
+ </item>
+ </list>
+ </item>
+
+<!--
+
+This is the old format which is "supported", but not documented,
+in so far as it will be converted to the new format if found.
+
<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>
@@ -333,6 +453,7 @@
<c>Action</c> is used to specify what shall be done if the
mnesia/dets table already exist.</p>
</item>
+-->
<marker id="agent_mib_server"></marker>
<tag><c><![CDATA[mib_server() = [mib_server_opt()] <optional>]]></c></tag>
diff --git a/lib/snmp/doc/src/snmpa_mib_data.xml b/lib/snmp/doc/src/snmpa_mib_data.xml
index 4c971ec5d9..ff07a03b98 100644
--- a/lib/snmp/doc/src/snmpa_mib_data.xml
+++ b/lib/snmp/doc/src/snmpa_mib_data.xml
@@ -122,7 +122,7 @@
<func>
<name>Module:close(State) -> void()</name>
- <fsummary>Close the mib-storage</fsummary>
+ <fsummary>Close the mib-server data instance</fsummary>
<type>
<v>State = term()</v>
</type>
diff --git a/lib/snmp/doc/src/snmpa_mib_storage.xml b/lib/snmp/doc/src/snmpa_mib_storage.xml
new file mode 100644
index 0000000000..a857ce79e8
--- /dev/null
+++ b/lib/snmp/doc/src/snmpa_mib_storage.xml
@@ -0,0 +1,292 @@
+<?xml version="1.0" encoding="iso-8859-1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2013</year><year>2013</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>snmpa_mib_storage</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ <file>snmpa_mib_storage.xml</file>
+ </header>
+
+ <module>snmpa_mib_storage</module>
+ <modulesummary>
+ Behaviour module for the SNMP agent mib storage.
+ </modulesummary>
+ <description>
+ <p>This module defines the behaviour of the SNMP agent mib storage. </p>
+ <p>The mib storage is used by the agent to store internal mib-
+ related information. The mib storage module is used by several entities,
+ not just the mib-server. </p>
+
+ <p>A <c>snmpa_mib_storage</c> compliant module
+ must export the following functions: </p>
+ <list type="bulleted">
+ <item>
+ <seealso marker="#open">open/5</seealso>
+ </item>
+ <item>
+ <seealso marker="#close">close/1</seealso>
+ </item>
+ <item>
+ <seealso marker="#read">read/2</seealso>
+ </item>
+ <item>
+ <seealso marker="#write">write/2</seealso>
+ </item>
+ <item>
+ <seealso marker="#delete1">delete/1</seealso>
+ </item>
+ <item>
+ <seealso marker="#delete2">delete/2</seealso>
+ </item>
+ <item>
+ <seealso marker="#match_object">match_object/2</seealso>
+ </item>
+ <item>
+ <seealso marker="#match_delete">match_delete/2</seealso>
+ </item>
+ <item>
+ <seealso marker="#tab2list">tab2list/1</seealso>
+ </item>
+ <item>
+ <seealso marker="#info">info/1</seealso>
+ </item>
+ <item>
+ <seealso marker="#sync">sync/1</seealso>
+ </item>
+ <item>
+ <seealso marker="#backup">backup/2</seealso>
+ </item>
+ </list>
+
+ <p>The semantics of them and their exact signatures are
+ explained below. </p>
+
+ </description>
+
+ <section>
+ <title>CALLBACK FUNCTIONS</title>
+ <p>The following functions must be exported from a
+ <c>mib-server</c> data callback module: </p>
+
+ <marker id="open"></marker>
+ </section>
+
+ <funcs>
+ <func>
+ <name>Module:open(Name, RecordName, Fields, Type, Options) -> {ok, TabId} | {error, Reason}</name>
+ <fsummary>Create new (mib-server) data instance</fsummary>
+ <type>
+ <v>Name = atom()</v>
+ <v>RecordName = atom()</v>
+ <v>Fields = [atom()]</v>
+ <v>Type = set | bag()</v>
+ <v>Options = list()</v>
+ <v>TabId = term()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Create or open a mib storage table. </p>
+ <p>Note that the <c>RecordName</c> and <c>Fields</c> arguments
+ my not be used in all implementations (they are actually only
+ needed for mnesia-based implementations). </p>
+
+ <p>Note also that the <c>Options</c> argument comes from
+ the <c>options</c> config option of the mib-storage config option,
+ and is passed on as is. </p>
+
+ <marker id="close"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:close(TabId) -> void()</name>
+ <fsummary>Close the mib-storage table</fsummary>
+ <type>
+ <v>State = term()</v>
+ </type>
+ <desc>
+ <p>Close the mib-storage table.</p>
+
+ <marker id="read"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:read(TabId, Key) -> false | {value, Record}</name>
+ <fsummary>Read a record from the mib-storage table</fsummary>
+ <type>
+ <v>TabId = term()</v>
+ <v>Key = term()</v>
+ <v>Record = tuple()</v>
+ </type>
+ <desc>
+ <p>Read a record from the mib-storage table. </p>
+
+ <marker id="write"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:write(TabId, Record) -> ok | {error, Reason}</name>
+ <fsummary>Write a record to the mib-storage table</fsummary>
+ <type>
+ <v>TabId = term()</v>
+ <v>Record = tuple()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Write a record to the mib-storage table. </p>
+
+ <marker id="delete1"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:delete(TabId) -> void()</name>
+ <fsummary>Delete an entire mib-storage table</fsummary>
+ <type>
+ <v>TabId = term()</v>
+ </type>
+ <desc>
+ <p>Delete an entire mib-storage table. </p>
+
+ <marker id="delete2"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:delete(TabId, Key) -> ok | {error, Reason}</name>
+ <fsummary>Delete a record from the mib-storage table</fsummary>
+ <type>
+ <v>TabId = term()</v>
+ <v>Key = term()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Delete a record from the mib-storage table. </p>
+
+ <marker id="match_object"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:match_object(TabId, Pattern) -> {ok, Recs} | {error, Reason}</name>
+ <fsummary>Search the mib-storage table for record matching pattern</fsummary>
+ <type>
+ <v>TabId = term()</v>
+ <v>Pattern = match_pattern()</v>
+ <v>Recs = [tuple()]</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Search the mib-storage table for record that match the
+ specified pattern. </p>
+
+ <marker id="match_delete"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:match_delete(TabId, Pattern) -> {ok, Recs} | {error, Reason}</name>
+ <fsummary>Delete records in the mib-storage table matching pattern</fsummary>
+ <type>
+ <v>TabId = term()</v>
+ <v>Pattern = match_pattern()</v>
+ <v>Recs = [tuple()]</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Search the mib-storage table for record that match the
+ specified pattern and then delete them. The records deleted are
+ also returned. </p>
+
+ <marker id="tab2list"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:tab2list(TabId) -> Recs</name>
+ <fsummary>Return all records of the mib-storage table</fsummary>
+ <type>
+ <v>TabId = term()</v>
+ <v>Recs = [tuple()]</v>
+ </type>
+ <desc>
+ <p>Return all records in the mib-storage table in the form
+ of a list. </p>
+
+ <marker id="info"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:info(TabId) -> {ok, Info} | {error, Reason}</name>
+ <fsummary>Returns information about the mib-storage table. </fsummary>
+ <type>
+ <v>TabId = term()</v>
+ <v>Info = term()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Retrieve implementation dependent mib-storage table
+ information. </p>
+
+ <marker id="sync"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:sync(TabId) -> void()</name>
+ <fsummary>Synchronize mib-storage table</fsummary>
+ <type>
+ <v>TabId = term()</v>
+ </type>
+ <desc>
+ <p>Synchronize the mib-storage table. </p>
+ <p>What this means, if anything, is implementation dependent. </p>
+
+ <marker id="backup"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:backup(TabId, BackupDir) -> ok | {error, Reason}</name>
+ <fsummary>Perform a backup of the mib-storage table</fsummary>
+ <type>
+ <v>TabId = term()</v>
+ <v>BackupDir = string()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Perform a backup of the mib-storage table. </p>
+ <p>What this means, if anything, is implementation dependent. </p>
+
+ </desc>
+ </func>
+
+ </funcs>
+
+</erlref>
+
diff --git a/lib/snmp/src/agent/depend.mk b/lib/snmp/src/agent/depend.mk
index 096182a626..4b12b66e3b 100644
--- a/lib/snmp/src/agent/depend.mk
+++ b/lib/snmp/src/agent/depend.mk
@@ -77,10 +77,6 @@ $(EBIN)/snmpa_error_logger.$(EMULATOR): \
snmpa_error_report.erl \
snmpa_error_logger.erl
-$(EBIN)/snmpa_general_db.$(EMULATOR): \
- snmpa_general_db.erl \
- ../misc/snmp_verbosity.hrl
-
$(EBIN)/snmpa_local_db.$(EMULATOR): \
snmpa_local_db.erl \
../misc/snmp_debug.hrl \
@@ -88,6 +84,18 @@ $(EBIN)/snmpa_local_db.$(EMULATOR): \
../../include/snmp_types.hrl \
../../include/STANDARD-MIB.hrl
+$(EBIN)/snmpa_mib_storage.$(EMULATOR): \
+ snmpa_mib_storage.erl
+
+$(EBIN)/snmpa_mib_storage_ets.$(EMULATOR): \
+ snmpa_mib_storage_ets.erl
+
+$(EBIN)/snmpa_mib_storage_dets.$(EMULATOR): \
+ snmpa_mib_storage_dets.erl
+
+$(EBIN)/snmpa_mib_storage_mnesia.$(EMULATOR): \
+ snmpa_mib_storage_mnesia.erl
+
$(EBIN)/snmpa_mib.$(EMULATOR): \
snmpa_mib.erl \
../misc/snmp_debug.hrl \
diff --git a/lib/snmp/src/agent/modules.mk b/lib/snmp/src/agent/modules.mk
index da9f6d6b4c..ea43904f4a 100644
--- a/lib/snmp/src/agent/modules.mk
+++ b/lib/snmp/src/agent/modules.mk
@@ -21,6 +21,7 @@ BEHAVIOUR_MODULES = \
snmpa_authentication_service \
snmpa_discovery_handler \
snmpa_error_report \
+ snmpa_mib_storage \
snmpa_mib_data \
snmpa_network_interface \
snmpa_network_interface_filter \
@@ -43,8 +44,10 @@ MODULES = \
snmpa_error \
snmpa_error_io \
snmpa_error_logger \
- snmpa_general_db \
snmpa_local_db \
+ snmpa_mib_storage_ets \
+ snmpa_mib_storage_dets \
+ snmpa_mib_storage_mnesia \
snmpa_mib \
snmpa_mib_data_tttn \
snmpa_mib_lib \
diff --git a/lib/snmp/src/agent/snmpa.erl b/lib/snmp/src/agent/snmpa.erl
index 785276c73d..0ce1f611b2 100644
--- a/lib/snmp/src/agent/snmpa.erl
+++ b/lib/snmp/src/agent/snmpa.erl
@@ -115,6 +115,7 @@
me/0
]).
+-deprecated([{old_info_format, 1, next_major_release}]).
-include("snmpa_atl.hrl").
diff --git a/lib/snmp/src/agent/snmpa_agent.erl b/lib/snmp/src/agent/snmpa_agent.erl
index 57846db13b..c267ce5a70 100644
--- a/lib/snmp/src/agent/snmpa_agent.erl
+++ b/lib/snmp/src/agent/snmpa_agent.erl
@@ -159,12 +159,15 @@
%% it is sent to the worker, and the worker is marked as busy.
%% If a request is received when the worker is busy, a new temporary
%% worker is spawned.
+%%
%% Code change
%% ===========
%% Note that the worker(s) execute the same module as the master
%% agent. For code change we have two options - ignore the workers,
%% or send them a code change message.
+%%
%%-----------------------------------------------------------------
+
-record(state, {type,
parent,
worker,
@@ -219,22 +222,19 @@
%%-----------------------------------------------------------------
start_link(Prio, Parent, Ref, Options) ->
?d("start_link -> entry with"
- "~n Prio: ~p"
- "~n Parent: ~p"
- "~n Ref: ~p"
- "~n Options: ~p", [Prio, Parent, Ref, Options]),
- %% gen_server:start_link(?MODULE, [Prio, Parent, Ref, Options], []).
+ "~n Prio: ~p"
+ "~n Parent: ~p"
+ "~n Ref: ~p"
+ "~n Options: ~p", [Prio, Parent, Ref, Options]),
?GS_START_LINK3(Prio, Parent, Ref, Options).
start_link(Prio, Name, Parent, Ref, Options) ->
?d("start_link -> entry with"
- "~n Prio: ~p"
- "~n Name: ~p"
- "~n Parent: ~p"
- "~n Ref: ~p"
- "~n Options: ~p", [Prio, Name, Parent, Ref, Options]),
-% gen_server:start_link({local, Name}, ?MODULE,
-% [Prio, Parent, Ref, Options], []).
+ "~n Prio: ~p"
+ "~n Name: ~p"
+ "~n Parent: ~p"
+ "~n Ref: ~p"
+ "~n Options: ~p", [Prio, Name, Parent, Ref, Options]),
?GS_START_LINK4(Prio, Name, Parent, Ref, Options).
stop(Agent) -> call(Agent, stop).
@@ -335,10 +335,10 @@ increment_counter(Counter, Initial, Max) ->
init([Prio, Parent, Ref, Options]) ->
?d("init -> entry with"
- "~n Prio: ~p"
- "~n Parent: ~p"
- "~n Ref: ~p"
- "~n Options: ~p", [Prio, Parent, Ref, Options]),
+ "~n Prio: ~p"
+ "~n Parent: ~p"
+ "~n Ref: ~p"
+ "~n Options: ~p", [Prio, Parent, Ref, Options]),
case (catch do_init(Prio, Parent, Ref, Options)) of
{ok, State} ->
?vdebug("started",[]),
@@ -1457,80 +1457,80 @@ handle_mibs_cache_request(MibServer, Req) ->
%% Downgrade
%%
-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, 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({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, 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}.
@@ -4411,7 +4411,7 @@ get_mibs(Opts) ->
get_option(mibs, Opts, []).
get_mib_storage(Opts) ->
- get_option(mib_storage, Opts, ets).
+ get_option(mib_storage, Opts).
get_set_mechanism(Opts) ->
get_option(set_mechanism, Opts, snmpa_set).
@@ -4450,6 +4450,9 @@ net_if_verbosity(_Pid,_Verbosity) ->
ok.
+get_option(Key, Opts) ->
+ snmp_misc:get_option(Key, Opts).
+
get_option(Key, Opts, Default) ->
snmp_misc:get_option(Key, Opts, Default).
diff --git a/lib/snmp/src/agent/snmpa_agent_sup.erl b/lib/snmp/src/agent/snmpa_agent_sup.erl
index 9b8c4d12a6..2805e2dc0d 100644
--- a/lib/snmp/src/agent/snmpa_agent_sup.erl
+++ b/lib/snmp/src/agent/snmpa_agent_sup.erl
@@ -29,10 +29,12 @@
-export([init/1]).
-define(SERVER, ?MODULE).
+%% Always use plain ets for sub-agents
-ifdef(snmp_debug).
--define(DEFAULT_OPTS, [{verbosity, trace}]).
+-define(DEFAULT_SA_OPTS, [{mib_storage, [{module, snmpa_mib_storage_ets}]},
+ {verbosity, trace}]).
-else.
--define(DEFAULT_OPTS, []).
+-define(DEFAULT_SA_OPTS, [{mib_storage, [{module, snmpa_mib_storage_ets}]}]).
-endif.
@@ -63,8 +65,8 @@ start_subagent(ParentAgent, Subtree, Mibs) ->
Ref = make_ref(),
?d("start_subagent -> Ref: ~p", [Ref]),
Options = [{priority, Prio},
- {mibs, Mibs},
- {misc_sup, snmpa_misc_sup} | ?DEFAULT_OPTS],
+ {mibs, Mibs},
+ {misc_sup, snmpa_misc_sup} | ?DEFAULT_SA_OPTS],
Agent = {{sub_agent, Max},
{snmpa_agent, start_link,
[Prio, ParentAgent, Ref, Options]},
diff --git a/lib/snmp/src/agent/snmpa_mib.erl b/lib/snmp/src/agent/snmpa_mib.erl
index 1bd7398a69..031309b990 100644
--- a/lib/snmp/src/agent/snmpa_mib.erl
+++ b/lib/snmp/src/agent/snmpa_mib.erl
@@ -257,7 +257,7 @@ init([Prio, Mibs, Opts]) ->
do_init(Prio, Mibs, Opts) ->
process_flag(priority, Prio),
process_flag(trap_exit, true),
- put(sname,ms),
+ put(sname, ms),
put(verbosity, ?vvalidate(get_verbosity(Opts))),
?vlog("starting",[]),
@@ -291,8 +291,12 @@ do_init(Prio, Mibs, Opts) ->
TeOverride = get_te_override(Opts),
MibStorage = get_mib_storage(Opts),
MibDataMod = get_data_mod(Opts),
+ ?vtrace("init -> try create mib data with"
+ "~n MeOverride: ~p"
+ "~n TeOverride: ~p"
+ "~n MibStorage: ~p", [MeOverride, TeOverride, MibStorage]),
Data = MibDataMod:new(MibStorage),
- ?vtrace("init -> mib data created",[]),
+ ?vdebug("init -> mib data created", []),
case (catch mib_operations(MibDataMod,
load_mib, Mibs, Data,
MeOverride, TeOverride, true)) of
@@ -704,7 +708,7 @@ get_te_override(Options) ->
get_opt(trapentry_override, Options, false).
get_mib_storage(Options) ->
- get_opt(mib_storage, Options, ets).
+ get_opt(mib_storage, Options).
get_data_mod(Options) ->
get_opt(data_module, Options, snmpa_mib_data_tttn).
@@ -894,6 +898,9 @@ timestamp() ->
%% ----------------------------------------------------------------
+get_opt(Key, Options) ->
+ snmp_misc:get_option(Key, Options).
+
get_opt(Key, Options, Default) ->
snmp_misc:get_option(Key, Options, Default).
diff --git a/lib/snmp/src/agent/snmpa_mib_data_tttn.erl b/lib/snmp/src/agent/snmpa_mib_data_tttn.erl
index c24cff43e5..f0bd5dabfd 100644
--- a/lib/snmp/src/agent/snmpa_mib_data_tttn.erl
+++ b/lib/snmp/src/agent/snmpa_mib_data_tttn.erl
@@ -18,6 +18,7 @@
%%
-module(snmpa_mib_data_tttn).
+
%%%-----------------------------------------------------------------
%%%
%%% TTTN - TupleTreeTupleNodes
@@ -33,7 +34,9 @@
%%%
%%% When a mib is loaded, the tree is built from the plain list
%%% in the binary file.
+%%%
%%%-----------------------------------------------------------------
+
-include("snmp_types.hrl").
-include("snmp_debug.hrl").
@@ -73,11 +76,15 @@
%% subagents is a list of {SAPid, Oid}
%%----------------------------------------------------------------------
--record(mib_data, {mib_db, % table of #mib_info
- node_db, % table of #node_info
- tree_db, % table of #tree
- tree, % The actual tree
- subagents = []}).
+-record(mib_data,
+ {
+ module, % Mib storage module
+ mib_db, % table of #mib_info
+ node_db, % table of #node_info
+ tree_db, % table of #tree
+ tree, % The actual tree
+ subagents = []
+ }).
-record(mib_info, {name, symbolic, file_name}).
-record(node_info, {oid, mib_name, me}).
@@ -121,7 +128,7 @@
%% This record is what is stored in the database. The 'tree' part
%% is described above...
--record(tree,{generation = ?DUMMY_TREE_GENERATION, root = ?DEFAULT_TREE}).
+-record(tree, {generation = ?DUMMY_TREE_GENERATION, root = ?DEFAULT_TREE}).
%%%======================================================================
@@ -134,32 +141,54 @@
%%-----------------------------------------------------------------
%% Where -> A list of nodes where the tables will be created
-new(Storage) ->
+new(MibStorage) ->
+ Mod = snmp_misc:get_option(module, MibStorage),
+ Opts = snmp_misc:get_option(options, MibStorage, []),
+
%% First we must check if there is already something to read
%% If a database already exists, then the tree structure has to be read
?vtrace("open (mib) database",[]),
- MibDb = snmpa_general_db:open(Storage, ?MIB_DATA,
- mib_info,
- record_info(fields,mib_info), set),
+ MibDb =
+ case Mod:open(?MIB_DATA, mib_info, record_info(fields, mib_info),
+ set, Opts) of
+ {ok, T1} ->
+ T1;
+ {error, Reason1} ->
+ throw({error, {open, mib_data, Reason1}})
+ end,
+
?vtrace("open (mib) node database",[]),
- NodeDb = snmpa_general_db:open(Storage, ?MIB_NODE,
- node_info,
- record_info(fields,node_info), set),
+ NodeDb =
+ case Mod:open(?MIB_NODE, node_info, record_info(fields, node_info),
+ set, Opts) of
+ {ok, T2} ->
+ T2;
+ {error, Reason2} ->
+ throw({error, {open, mib_node, Reason2}})
+ end,
+
?vtrace("open (mib) tree database",[]),
- TreeDb = snmpa_general_db:open(Storage, ?MIB_TREE,
- tree,
- record_info(fields,tree), set),
+ TreeDb =
+ case Mod:open(?MIB_TREE, tree, record_info(fields, tree),
+ set, Opts) of
+ {ok, T3} ->
+ T3;
+ {error, Reason3} ->
+ throw({error, {open, mib_tree, Reason3}})
+ end,
+
Tree =
- case snmpa_general_db:read(TreeDb, ?DUMMY_TREE_GENERATION) of
+ case Mod:read(TreeDb, ?DUMMY_TREE_GENERATION) of
false ->
T = #tree{},
- snmpa_general_db:write(TreeDb, T),
+ Mod:write(TreeDb, T),
T;
{value, T} ->
T
end,
- install_mibs(MibDb, NodeDb),
- #mib_data{mib_db = MibDb,
+ install_mibs(Mod, MibDb, NodeDb),
+ #mib_data{module = Mod,
+ mib_db = MibDb,
node_db = NodeDb,
tree_db = TreeDb,
tree = Tree}.
@@ -168,7 +197,7 @@ new(Storage) ->
%%----------------------------------------------------------------------
%% Returns: new mib data | {error, Reason}
%%----------------------------------------------------------------------
-load_mib(MibData,FileName,MeOverride,TeOverride)
+load_mib(MibData, FileName, MeOverride, TeOverride)
when is_record(MibData,mib_data) andalso is_list(FileName) ->
?vlog("load mib file: ~p",[FileName]),
ActualFileName = filename:rootname(FileName, ".bin") ++ ".bin",
@@ -180,13 +209,14 @@ do_load_mib(MibData, ActualFileName, MibName, MeOverride, TeOverride) ->
?vtrace("do_load_mib -> entry with"
"~n ActualFileName: ~s"
"~n MibName: ~p",[ActualFileName, MibName]),
- #mib_data{mib_db = MibDb,
+ #mib_data{module = Mod,
+ mib_db = MibDb,
node_db = NodeDb,
%% tree_db = TreeDb,
tree = Tree} = MibData,
- verify_not_loaded(MibDb, MibName),
+ verify_not_loaded(Mod, MibDb, MibName),
?vtrace("do_load_mib -> already loaded mibs:"
- "~n ~p",[loaded(MibDb)]),
+ "~n ~p", [loaded(Mod, MibDb)]),
Mib = do_read_mib(ActualFileName),
?vtrace("do_load_mib -> read mib ~s",[Mib#mib.name]),
NonInternalMes =
@@ -208,12 +238,12 @@ do_load_mib(MibData, ActualFileName, MibName, MeOverride, TeOverride) ->
case (catch check_notif_and_mes(TeOverride, MeOverride, Symbolic,
Mib#mib.traps, NonInternalMes)) of
true ->
- install_mes(NodeDb, MibName, NonInternalMes),
- install_mib(MibDb, Symbolic, Mib,
+ install_mes(Mod, NodeDb, MibName, NonInternalMes),
+ install_mib(Mod,
+ MibDb, Symbolic, Mib,
MibName, ActualFileName, NonInternalMes),
?vtrace("installed mib ~s", [Mib#mib.name]),
Tree2 = Tree#tree{root = NewRoot},
- %% snmpa_general_db:write(TreeDb, Tree2), %% Store later?
{ok, MibData#mib_data{tree = Tree2}};
Else ->
Else
@@ -221,10 +251,10 @@ do_load_mib(MibData, ActualFileName, MibName, MeOverride, TeOverride) ->
end.
-verify_not_loaded(Db, Name) ->
- case snmpa_general_db:read(Db, Name) of
+verify_not_loaded(Mod, Tab, Name) ->
+ case Mod:read(Tab, Name) of
{value, #mib_info{name = Name}} ->
- throw({error, 'already loaded'});
+ throw({error, already_loaded});
false ->
ok
end.
@@ -233,26 +263,28 @@ do_read_mib(ActualFileName) ->
case snmp_misc:read_mib(ActualFileName) of
{error, Reason} ->
?vlog("Failed reading mib file ~p with reason: ~p",
- [ActualFileName,Reason]),
+ [ActualFileName, Reason]),
throw({error, Reason});
{ok, Mib} ->
Mib
end.
%% The Tree DB is handled in a special way since it can be very large.
-sync(#mib_data{mib_db = M,
+sync(#mib_data{module = Mod,
+ mib_db = M,
node_db = N,
tree_db = T, tree = Tree, subagents = []}) ->
- snmpa_general_db:sync(M),
- snmpa_general_db:sync(N),
- snmpa_general_db:write(T, Tree),
- snmpa_general_db:sync(T);
-sync(#mib_data{mib_db = M,
+ Mod:sync(M),
+ Mod:sync(N),
+ Mod:write(T, Tree),
+ Mod:sync(T);
+sync(#mib_data{module = Mod,
+ mib_db = M,
node_db = N,
tree_db = T, tree = Tree, subagents = SAs}) ->
- snmpa_general_db:sync(M),
- snmpa_general_db:sync(N),
+ Mod:sync(M),
+ Mod:sync(N),
%% Ouch. Since the subagent info is dynamic we do not
%% want to store the tree containing subagent info. So, we
@@ -260,8 +292,8 @@ sync(#mib_data{mib_db = M,
case delete_subagents(Tree, SAs) of
{ok, TreeWithoutSAs} ->
- snmpa_general_db:write(T, TreeWithoutSAs),
- snmpa_general_db:sync(T);
+ Mod:write(T, TreeWithoutSAs),
+ Mod:sync(T);
Error ->
Error
end.
@@ -350,30 +382,34 @@ unload_mib(MibData, FileName, _, _) when is_list(FileName) ->
do_unload_mib(MibData, MibName) ->
?vtrace("do_unload_mib -> entry with"
"~n MibName: ~p", [MibName]),
- #mib_data{mib_db = MibDb,
+ #mib_data{module = Mod,
+ mib_db = MibDb,
node_db = NodeDb,
%% tree_db = TreeDb,
tree = Tree} = MibData,
- #mib_info{symbolic = Symbolic} = verify_loaded(MibDb, MibName),
+ #mib_info{symbolic = Symbolic} = verify_loaded(Mod, MibDb, MibName),
NewRoot = delete_mib_from_tree(MibName, Tree#tree.root),
- MEs = uninstall_mes(NodeDb, MibName),
- uninstall_mib(MibDb, Symbolic, MibName, MEs),
+ MEs = uninstall_mes(Mod, NodeDb, MibName),
+ uninstall_mib(Mod, MibDb, Symbolic, MibName, MEs),
NewMibData = MibData#mib_data{tree = Tree#tree{root = NewRoot}},
{ok, NewMibData}.
-verify_loaded(Db, Name) ->
- case snmpa_general_db:read(Db, Name) of
+verify_loaded(Mod, Tab, Name) ->
+ case Mod:read(Tab, Name) of
{value, MibInfo} ->
MibInfo;
false ->
- throw({error, 'not loaded'})
+ throw({error, not_loaded})
end.
-close(#mib_data{mib_db = MibDb, node_db = NodeDb, tree_db = TreeDb}) ->
- snmpa_general_db:close(MibDb),
- snmpa_general_db:close(NodeDb),
- snmpa_general_db:close(TreeDb),
+close(#mib_data{module = Mod,
+ mib_db = MibDb,
+ node_db = NodeDb,
+ tree_db = TreeDb}) ->
+ Mod:close(MibDb),
+ Mod:close(NodeDb),
+ Mod:close(TreeDb),
ok.
register_subagent(#mib_data{tree = T} = MibData, Oid, Pid) ->
@@ -392,8 +428,8 @@ register_subagent(#mib_data{tree = T} = MibData, Oid, Pid) ->
%% Returns: [{Name, File}]
%%----------------------------------------------------------------------
-which_mibs(#mib_data{mib_db = Db}) ->
- Mibs = snmpa_general_db:tab2list(Db),
+which_mibs(#mib_data{module = Mod, mib_db = Db}) ->
+ Mibs = Mod:tab2list(Db),
[{Name, File} || #mib_info{name = Name, file_name = File} <- Mibs].
@@ -402,8 +438,8 @@ which_mibs(#mib_data{mib_db = Db}) ->
%% Returns: [{Name, File}]
%%----------------------------------------------------------------------
-whereis_mib(#mib_data{mib_db = Db}, Name) ->
- case snmpa_general_db:read(Db, Name) of
+whereis_mib(#mib_data{module = Mod, mib_db = Db}, Name) ->
+ case Mod:read(Db, Name) of
{value, #mib_info{file_name = File}} ->
{ok, File};
false ->
@@ -451,32 +487,39 @@ unregister_subagent(#mib_data{tree = T} = MibData, Oid) when is_list(Oid) ->
%%----------------------------------------------------------------------
info(MibData) ->
?vtrace("retrieve info",[]),
- #mib_data{mib_db = MibDb, node_db = NodeDb, tree_db = TreeDb,
- tree = Tree, subagents = SAs} = MibData,
- LoadedMibs = old_format(snmpa_general_db:tab2list(MibDb)),
+ #mib_data{module = Mod,
+ mib_db = MibDb,
+ node_db = NodeDb,
+ tree_db = TreeDb,
+ tree = Tree,
+ subagents = SAs} = MibData,
+ LoadedMibs = old_format(Mod:tab2list(MibDb)),
TreeSize = snmp_misc:mem_size(Tree),
- {memory, ProcSize} = erlang:process_info(self(),memory),
- MibDbSize = snmpa_general_db:info(MibDb, memory),
- NodeDbSize = snmpa_general_db:info(NodeDb, memory),
- TreeDbSize = snmpa_general_db:info(TreeDb, memory),
+ {memory, ProcSize} = erlang:process_info(self(), memory),
+ MibDbSize = Mod:info(MibDb, memory),
+ NodeDbSize = Mod:info(NodeDb, memory),
+ TreeDbSize = Mod:info(TreeDb, memory),
[{loaded_mibs, LoadedMibs}, {subagents, SAs}, {tree_size_bytes, TreeSize},
{process_memory, ProcSize},
{db_memory, [{mib,MibDbSize},{node,NodeDbSize},{tree,TreeDbSize}]}].
-info(#mib_data{mib_db = MibDb}, loaded_mibs) ->
- Mibs = snmpa_general_db:tab2list(MibDb),
+info(#mib_data{module = Mod, mib_db = MibDb}, loaded_mibs) ->
+ Mibs = Mod:tab2list(MibDb),
[filename:rootname(FN, ".bin") || #mib_info{file_name = FN} <- Mibs];
info(#mib_data{tree = Tree}, tree_size_bytes) ->
snmp_misc:mem_size(Tree);
info(_, process_memory) ->
{memory, ProcSize} = erlang:process_info(self(),memory),
ProcSize;
-info(#mib_data{mib_db = MibDb, node_db = NodeDb, tree_db = TreeDb},
+info(#mib_data{module = Mod,
+ mib_db = MibDb,
+ node_db = NodeDb,
+ tree_db = TreeDb},
db_memory) ->
- MibDbSize = snmpa_general_db:info(MibDb, memory),
- NodeDbSize = snmpa_general_db:info(NodeDb, memory),
- TreeDbSize = snmpa_general_db:info(TreeDb, memory),
- [{mib,MibDbSize},{node,NodeDbSize},{tree,TreeDbSize}];
+ MibDbSize = Mod:info(MibDb, memory),
+ NodeDbSize = Mod:info(NodeDb, memory),
+ TreeDbSize = Mod:info(TreeDb, memory),
+ [{mib, MibDbSize}, {node, NodeDbSize}, {tree, TreeDbSize}];
info(#mib_data{subagents = SAs}, subagents) ->
SAs.
@@ -489,17 +532,19 @@ old_format(LoadedMibs) ->
%% A total dump for debugging.
%%----------------------------------------------------------------------
-dump(#mib_data{mib_db = MibDb,
+dump(#mib_data{module = Mod,
+ mib_db = MibDb,
node_db = NodeDb,
tree = Tree}, io) ->
(catch io:format("MIB-tables:~n~p~n~n",
- [snmpa_general_db:tab2list(MibDb)])),
+ [Mod:tab2list(MibDb)])),
(catch io:format("MIB-entries:~n~p~n~n",
- [snmpa_general_db:tab2list(NodeDb)])),
+ [Mod:tab2list(NodeDb)])),
(catch io:format("Tree:~n~p~n", [Tree])), % good luck reading it!
ok;
-dump(#mib_data{mib_db = MibDb,
+dump(#mib_data{module = Mod,
+ mib_db = MibDb,
node_db = NodeDb,
tree = Tree}, File) ->
case file:open(File, [write]) of
@@ -507,9 +552,9 @@ dump(#mib_data{mib_db = MibDb,
io:format(Fd,"~s~n",
[snmp:date_and_time_to_string(snmp:date_and_time())]),
(catch io:format(Fd,"MIB-tables:~n~p~n~n",
- [snmpa_general_db:tab2list(MibDb)])),
+ [Mod:tab2list(MibDb)])),
(catch io:format(Fd, "MIB-entries:~n~p~n~n",
- [snmpa_general_db:tab2list(NodeDb)])),
+ [Mod:tab2list(NodeDb)])),
io:format(Fd,"Tree:~n~p~n", [Tree]), % good luck reading it!
file:close(Fd),
ok;
@@ -520,10 +565,13 @@ dump(#mib_data{mib_db = MibDb,
end.
-backup(#mib_data{mib_db = M, node_db = N, tree_db = T}, BackupDir) ->
- MRes = snmpa_general_db:backup(M, BackupDir),
- NRes = snmpa_general_db:backup(N, BackupDir),
- TRes = snmpa_general_db:backup(T, BackupDir),
+backup(#mib_data{module = Mod,
+ mib_db = M,
+ node_db = N,
+ tree_db = T}, BackupDir) ->
+ MRes = Mod:backup(M, BackupDir),
+ NRes = Mod:backup(N, BackupDir),
+ TRes = Mod:backup(T, BackupDir),
handle_backup_res([{mib_db, MRes}, {node_db, NRes}, {tree_db, TRes}]).
handle_backup_res(Res) ->
@@ -632,9 +680,9 @@ find_node(D, {tree, Tree, {table_entry, _}}, RestOfOid, RevOid) ->
?vtrace("find_node(tree,table_entry) -> entry with"
"~n RestOfOid: ~p"
"~n RevOid: ~p",[RestOfOid, RevOid]),
- #mib_data{node_db = Db} = D,
+ #mib_data{module = Mod, node_db = Db} = D,
Oid = lists:reverse(RevOid),
- case snmpa_general_db:read(Db, Oid) of
+ case Mod:read(Db, Oid) of
{value, #node_info{me = ME, mib_name = Mib}} ->
case find_node(D, {tree, Tree, internal}, RestOfOid, RevOid) of
{false, ErrorCode} -> {false, ErrorCode};
@@ -659,13 +707,13 @@ find_node(D, {node, {table_column, _}}, RestOfOid, [ColInt | RevOid]) ->
"~n RestOfOid: ~p"
"~n ColInt: ~p"
"~n RevOid: ~p",[RestOfOid, ColInt, RevOid]),
- #mib_data{node_db = Db} = D,
+ #mib_data{module = Mod, node_db = Db} = D,
Oid = lists:reverse([ColInt | RevOid]),
- case snmpa_general_db:read(Db, Oid) of
+ case Mod:read(Db, Oid) of
{value, #node_info{me = ME}} ->
{ME, lists:reverse(RevOid)};
false ->
- X = snmpa_general_db:read(Db, lists:reverse([ColInt | RevOid])),
+ X = Mod:read(Db, lists:reverse([ColInt | RevOid])),
?vinfo("find_node -> could not find table_column ME with"
"~n RevOid: ~p"
"~n trying [~p|~p]"
@@ -676,10 +724,9 @@ find_node(D, {node, {table_column, _}}, RestOfOid, [ColInt | RevOid]) ->
find_node(D, {node, {variable, _MibName}}, [0], RevOid) ->
?vtrace("find_node(tree,variable,[0]) -> entry with"
"~n RevOid: ~p",[RevOid]),
- #mib_data{node_db = Db} = D,
+ #mib_data{module = Mod, node_db = Db} = D,
Oid = lists:reverse(RevOid),
- %% {value, #node_info{me = ME}} = snmpa_general_db:read(Db, Oid),
- case snmpa_general_db:read(Db, Oid) of
+ case Mod:read(Db, Oid) of
{value, #node_info{me = ME, mib_name = Mib}} ->
{variable, ME, Mib};
false ->
@@ -761,8 +808,8 @@ next_node(D, {tree, Tree, {table_entry, _MibName}},
?vdebug("next_node(tree,table_entry) -> not in mib view",[]),
false;
_ ->
- #mib_data{node_db = Db} = D,
- case snmpa_general_db:read(Db, OidSoFar) of
+ #mib_data{module = Mod, node_db = Db} = D,
+ case Mod:read(Db, OidSoFar) of
false ->
?vinfo("next_node -> could not find table_entry with"
"~n OidSoFar: ~p", [OidSoFar]),
@@ -834,8 +881,8 @@ next_node(D, {node, {variable, _MibName}}, [], RevOidSoFar, MibView) ->
OidSoFar = lists:reverse([0 | RevOidSoFar]),
case snmpa_acm:validate_mib_view(OidSoFar, MibView) of
true ->
- #mib_data{node_db = Db} = D,
- case snmpa_general_db:read(Db, lists:reverse(RevOidSoFar)) of
+ #mib_data{module = Mod, node_db = Db} = D,
+ case Mod:read(Db, lists:reverse(RevOidSoFar)) of
false ->
?vinfo("next_node -> could not find variable with"
"~n RevOidSoFar: ~p", [RevOidSoFar]),
@@ -851,6 +898,7 @@ next_node(_D, {node, {variable, _MibName}}, _Oid, _RevOidSoFar, _MibView) ->
?vtrace("next_node(node,variable) -> entry", []),
false.
+
%%-----------------------------------------------------------------
%% This function is used to find the first leaf from where we
%% are.
@@ -882,8 +930,8 @@ find_next(D, {tree, _Tree, {table_entry, _MibName}}, _Index,
true ->
false;
_ ->
- #mib_data{node_db = Db} = D,
- case snmpa_general_db:read(Db, OidSoFar) of
+ #mib_data{module = Mod, node_db = Db} = D,
+ case Mod:read(Db, OidSoFar) of
false ->
?vinfo("find_next -> could not find table_entry ME with"
"~n OidSoFar: ~p", [OidSoFar]),
@@ -896,8 +944,8 @@ find_next(D, {node, {variable, _MibName}}, _Idx, RevOidSoFar, MibView) ->
OidSoFar = lists:reverse([0 | RevOidSoFar]),
case snmpa_acm:validate_mib_view(OidSoFar, MibView) of
true ->
- #mib_data{node_db = Db} = D,
- case snmpa_general_db:read(Db, lists:reverse(RevOidSoFar)) of
+ #mib_data{module = Mod, node_db = Db} = D,
+ case Mod:read(Db, lists:reverse(RevOidSoFar)) of
false ->
?vinfo("find_next -> could not find variable with"
"~n RevOidSoFar: ~p", [RevOidSoFar]),
@@ -1213,9 +1261,11 @@ build_tree_for_subagent([Index]) ->
build_tree_for_subagent([Index | T]) ->
[{Index, {tree, build_tree_for_subagent(T), internal}}].
+
%%----------------------------------------------------------------------
%% Returns: A new tree where the subagent at Oid (2nd arg) has been deleted.
%%----------------------------------------------------------------------
+
delete_subagent({tree, Tree, Info}, [Index]) ->
{node, subagent} = element(Index+1, Tree),
{tree, setelement(Index+1, Tree, undefined_node), Info};
@@ -1223,6 +1273,7 @@ delete_subagent({tree, Tree, Info}, [Index | TI]) ->
{tree, setelement(Index+1, Tree,
delete_subagent(element(Index+1, Tree), TI)), Info}.
+
%%%======================================================================
%%% 7. Misc functions
%%%======================================================================
@@ -1232,35 +1283,35 @@ delete_subagent({tree, Tree, Info}, [Index | TI]) ->
%% Basically calls the instrumentation functions for all non-internal
%% mib-entries
%%----------------------------------------------------------------------
-install_mibs(MibDb, NodeDb) ->
- MibNames = loaded(MibDb),
+install_mibs(Mod, MibDb, NodeDb) ->
+ MibNames = loaded(Mod, MibDb),
?vtrace("install_mibs -> found following mibs in database: ~n"
"~p", [MibNames]),
- install_mibs2(NodeDb, MibNames).
+ install_mibs2(Mod, NodeDb, MibNames).
-install_mibs2(_, []) ->
+install_mibs2(_, _, []) ->
ok;
-install_mibs2(NodeDb, [MibName|MibNames]) ->
+install_mibs2(Mod, NodeDb, [MibName|MibNames]) ->
Pattern = #node_info{oid = '_', mib_name = MibName, me = '_'},
- Nodes = snmpa_general_db:match_object(NodeDb, Pattern),
+ Nodes = Mod:match_object(NodeDb, Pattern),
MEs = [ME || #node_info{me = ME} <- Nodes],
?vtrace("install_mibs2 -> installing ~p MEs for mib ~p",
- [length(MEs),MibName]),
+ [length(MEs), MibName]),
NewF = fun(ME) -> call_instrumentation(ME, new) end,
lists:foreach(NewF, MEs),
- install_mibs2(NodeDb, MibNames).
+ install_mibs2(Mod, NodeDb, MibNames).
%%----------------------------------------------------------------------
%% Does all side effect stuff during load_mib.
%%----------------------------------------------------------------------
-install_mib(Db, Symbolic, Mib, MibName, FileName, NonInternalMes) ->
+install_mib(Mod, Db, Symbolic, Mib, MibName, FileName, NonInternalMes) ->
?vdebug("install_mib -> entry with"
"~n Symbolic: ~p"
"~n MibName: ~p"
"~n FileName: ~p", [Symbolic, MibName, FileName]),
Rec = #mib_info{name = MibName, symbolic = Symbolic, file_name = FileName},
- snmpa_general_db:write(Db, Rec),
+ Mod:write(Db, Rec),
install_mib2(Symbolic, MibName, Mib),
NewF = fun(ME) -> call_instrumentation(ME, new) end,
lists:foreach(NewF, NonInternalMes).
@@ -1282,23 +1333,31 @@ install_mib2(true, MibName, Mib) ->
install_mib2(_, _, _) ->
ok.
-install_mes(_Db, _MibName, []) ->
+install_mes(Mod, Db, MibName, MEs) ->
+ Write = fun(#me{oid = Oid} = ME) ->
+ Node = #node_info{oid = Oid,
+ mib_name = MibName,
+ me = ME},
+ Mod:write(Db, Node)
+ end,
+ install_mes(Write, MEs).
+
+install_mes(_Write, []) ->
ok;
-install_mes(Db, MibName, [ME|MEs]) ->
- Node = #node_info{oid = ME#me.oid, mib_name = MibName, me = ME},
- snmpa_general_db:write(Db, Node),
- install_mes(Db, MibName, MEs).
+install_mes(Write, [ME|MEs]) ->
+ Write(ME),
+ install_mes(Write, MEs).
%%----------------------------------------------------------------------
%% Does all side effect stuff during unload_mib.
%%----------------------------------------------------------------------
-uninstall_mib(Db, Symbolic, MibName, MEs) ->
+uninstall_mib(Mod, Db, Symbolic, MibName, MEs) ->
?vtrace("uninstall_mib -> entry with"
"~n Db: ~p"
"~n Symbolic: ~p"
"~n MibName: ~p", [Db, Symbolic, MibName]),
- Res = snmpa_general_db:delete(Db, MibName),
+ Res = Mod:delete(Db, MibName),
?vtrace("uninstall_mib -> (mib) db delete result: ~p", [Res]),
uninstall_mib2(Symbolic, MibName),
DelF = fun(ME) -> call_instrumentation(ME, delete) end,
@@ -1313,16 +1372,16 @@ uninstall_mib2(true, MibName) ->
uninstall_mib2(_, _) ->
ok.
-uninstall_mes(Db, MibName) ->
+uninstall_mes(Mod, Db, MibName) ->
Pattern = #node_info{oid = '_', mib_name = MibName, me = '_'},
- snmpa_general_db:match_delete(Db, Pattern).
+ Mod:match_delete(Db, Pattern).
%%----------------------------------------------------------------------
%% Create a list of the names of all the loaded mibs
%%----------------------------------------------------------------------
-loaded(Db) ->
- [N || #mib_info{name = N} <- snmpa_general_db:tab2list(Db)].
+loaded(Mod, Db) ->
+ [N || #mib_info{name = N} <- Mod:tab2list(Db)].
%%----------------------------------------------------------------------
diff --git a/lib/snmp/src/agent/snmpa_mib_storage.erl b/lib/snmp/src/agent/snmpa_mib_storage.erl
new file mode 100644
index 0000000000..5c3f76d89b
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_mib_storage.erl
@@ -0,0 +1,181 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013-2013. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(snmpa_mib_storage).
+
+-export_type([
+ mib_storage_fields/0,
+ mib_storage_table_type/0,
+ mib_storage_table_id/0
+ ]).
+
+
+%%% ----------------------------------------------------------------
+%%% This behaviour module defines the API for the mib-storage.
+%%% This is how the agent stores its internal mib-data
+%%% (symbolic-store and mib-server).
+%%%-----------------------------------------------------------------
+
+-type mib_storage_fields() :: [atom()].
+-type mib_storage_table_type() :: set | bag.
+-type mib_storage_table_id() :: term().
+
+
+%% ---------------------------------------------------------------
+%% open
+%%
+%% Open or create a mib-storage table.
+%% If any extra info needs to be communicated to the implementor
+%% (of the behaviour), this is done using the *Options* argument.
+%% ---------------------------------------------------------------
+
+%% Options is callback module dependant
+
+-callback open(Name :: atom(),
+ RecName :: atom(),
+ Fields :: mib_storage_fields(),
+ Type :: mib_storage_table_type(),
+ Options :: list()) ->
+ {ok, TabId :: mib_storage_table_id()} | {error, Reason :: term()}.
+
+
+%% ---------------------------------------------------------------
+%% close
+%%
+%% Close the mib-storage table. What this does is up to the
+%% implementor (when using mnesia it may be a no-op but for ets
+%% it may actually delete the table).
+%% ---------------------------------------------------------------
+
+-callback close(TabId :: mib_storage_table_id()) ->
+ term().
+
+
+%% ---------------------------------------------------------------
+%% read/2
+%%
+%% Retrieve a record from the mib-storage table.
+%% ---------------------------------------------------------------
+
+-callback read(TabId :: mib_storage_table_id(),
+ Key :: term()) ->
+ false | {value, Record :: tuple()}.
+
+
+%% ---------------------------------------------------------------
+%% write/2
+%%
+%% Write a record to the mib-storage table.
+%% ---------------------------------------------------------------
+
+-callback write(TabId :: mib_storage_table_id(),
+ Record :: tuple()) ->
+ ok | {error, Reason :: term()}.
+
+
+%% ---------------------------------------------------------------
+%% delete/1
+%%
+%% Delete the mib-storage table.
+%% ---------------------------------------------------------------
+
+-callback delete(TabId :: mib_storage_table_id()) ->
+ snmp:void().
+
+
+%% ---------------------------------------------------------------
+%% delete/2
+%%
+%% Delete a record from the mib-storage table.
+%% ---------------------------------------------------------------
+
+-callback delete(TabId :: mib_storage_table_id(),
+ Key :: term()) ->
+ ok | {error, Reason :: term()}.
+
+
+%% ---------------------------------------------------------------
+%% match_object
+%%
+%% Search the mib-storage table for records which matches
+%% the pattern.
+%% ---------------------------------------------------------------
+
+-callback match_object(TabId :: mib_storage_table_id(),
+ Pattern :: ets:match_pattern()) ->
+ {ok, Recs :: [tuple()]} | {error, Reason :: term()}.
+
+
+%% ---------------------------------------------------------------
+%% match_delete
+%%
+%% Search the mib-storage table for records which matches the
+%% pattern and deletes them from the database and return the
+%5 deleted records.
+%% ---------------------------------------------------------------
+
+-callback match_delete(TabId :: mib_storage_table_id(),
+ Pattern :: ets:match_pattern()) ->
+ {ok, Recs :: [tuple()]} | {error, Reason :: term()}.
+
+
+%% ---------------------------------------------------------------
+%% tab2list
+%%
+%% Return all records in the table in the form of a list.
+%% ---------------------------------------------------------------
+
+-callback tab2list(TabId :: mib_storage_table_id()) ->
+ [tuple()].
+
+
+%% ---------------------------------------------------------------
+%% info/1,2
+%%
+%% Retrieve implementation dependent mib-storage table
+%% information.
+%% ---------------------------------------------------------------
+
+-callback info(TabId :: mib_storage_table_id()) ->
+ Info :: term().
+
+-callback info(TabId :: mib_storage_table_id(), Item :: atom()) ->
+ Info :: term().
+
+
+%% ---------------------------------------------------------------
+%% sync
+%%
+%% Dump mib-storage table to disc (if it has a disk component).
+%% ---------------------------------------------------------------
+
+-callback sync(TabId :: mib_storage_table_id()) ->
+ snmp:void().
+
+
+%% ---------------------------------------------------------------
+%% backup
+%%
+%% Make a backup copy of the mib-storage table.
+%% ---------------------------------------------------------------
+
+-callback backup(TabId :: mib_storage_table_id(),
+ Dir :: file:filename()) ->
+ ok | {error, Reason :: term()}.
+
diff --git a/lib/snmp/src/agent/snmpa_mib_storage_dets.erl b/lib/snmp/src/agent/snmpa_mib_storage_dets.erl
new file mode 100644
index 0000000000..e84e18e7ea
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_mib_storage_dets.erl
@@ -0,0 +1,309 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013-2013. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(snmpa_mib_storage_dets).
+
+-behaviour(snmpa_mib_storage).
+
+
+%%%-----------------------------------------------------------------
+%%% This module implements the snmpa_mib_storage behaviour.
+%%% It uses dets for storage.
+%%%-----------------------------------------------------------------
+
+-export([
+ open/5,
+ close/1,
+ read/2,
+ write/2,
+ delete/1,
+ delete/2,
+ match_object/2,
+ match_delete/2,
+ tab2list/1,
+ info/1, info/2,
+ sync/1,
+ backup/2
+ ]).
+
+
+-define(VMODULE, "MS-DETS").
+-include("snmp_verbosity.hrl").
+
+-record(tab, {id, rec_name}).
+
+
+%% ---------------------------------------------------------------
+%% open
+%%
+%% Open or create a mib-storage (dets) table.
+%%
+%% Opts - A list of implementation dependent options
+%% dets_open_options() = [dets_open_option()]
+%% dets_open_option() = {dir, filename()} |
+%% {action, keep | clear} |
+%% {auto_save, default | pos_integer()} |
+%% {repair, force | boolean()}
+%%
+%% ---------------------------------------------------------------
+
+open(Name, RecName, _Fields, Type, Opts) ->
+ Dir = snmp_misc:get_option(dir, Opts),
+ Action = snmp_misc:get_option(action, Opts, keep),
+ AutoSave = snmp_misc:get_option(auto_save, Opts, default),
+ Repair = snmp_misc:get_option(repair, Opts, false),
+ File = dets_filename(Name, Dir),
+ OpenOpts = [{file, File},
+ {type, Type},
+ {keypos, 2},
+ {repair, Repair}] ++
+ case AutoSave of
+ default ->
+ [];
+ _ ->
+ [{auto_save, AutoSave}]
+ end,
+ case dets:open_file(Name, OpenOpts) of
+ {ok, ID} when (Action =:= keep) ->
+ {ok, #tab{id = ID, rec_name = RecName}};
+ {ok, ID} when (Action =:= clear) ->
+ dets:match_delete(ID, '_'),
+ {ok, #tab{id = ID, rec_name = RecName}};
+ {error, Reason} ->
+ {error, {dets_open, Reason}}
+ end.
+
+dets_filename(Name, Dir) ->
+ Dir1 = dets_filename1(Dir),
+ Dir2 = string:strip(Dir1, right, $/),
+ io_lib:format("~s/~p.dat", [Dir2, Name]).
+
+dets_filename1([]) -> ".";
+dets_filename1(Dir) -> Dir.
+
+
+%% ---------------------------------------------------------------
+%% close
+%%
+%% Close the table.
+%% ---------------------------------------------------------------
+
+close(#tab{id = ID}) ->
+ ?vtrace("close database ~p", [ID]),
+ dets:close(ID).
+
+
+%% ---------------------------------------------------------------
+%% read
+%%
+%% Retrieve a record from the database table.
+%% ---------------------------------------------------------------
+
+read(#tab{id = ID}, Key) ->
+ ?vtrace("read from table ~p: ~p", [ID, Key]),
+ case dets:lookup(ID, Key) of
+ [Rec|_] -> {value, Rec};
+ _ -> false
+ end.
+
+
+%% ---------------------------------------------------------------
+%% write
+%%
+%% Write a record to the database table.
+%% ---------------------------------------------------------------
+
+write(#tab{id = ID, rec_name = RecName}, Rec)
+ when (is_tuple(Rec) andalso (element(1, Rec) =:= RecName)) ->
+ ?vtrace("write to table ~p", [ID]),
+ dets:insert(ID, Rec).
+
+
+%% ---------------------------------------------------------------
+%% delete
+%%
+%% Delete the database table.
+%% ---------------------------------------------------------------
+
+delete(#tab{id = ID}) ->
+ ?vtrace("delete database ~p", [ID]),
+ File = dets:info(ID, filename),
+ case dets:close(ID) of
+ ok ->
+ file:delete(File);
+ Error ->
+ Error
+ end.
+
+
+%% ---------------------------------------------------------------
+%% delete
+%%
+%% Delete a record from the database table.
+%% ---------------------------------------------------------------
+
+delete(#tab{id = ID}, Key) ->
+ ?vtrace("delete from table ~p: ~p", [ID, Key]),
+ dets:delete(ID, Key).
+
+
+%% ---------------------------------------------------------------
+%% match_object
+%%
+%% Search the database table for records witch matches the pattern.
+%% ---------------------------------------------------------------
+
+match_object(#tab{id = ID}, Pattern) ->
+ ?vtrace("match_object in ~p of ~p", [ID, Pattern]),
+ dets:match_object(ID, Pattern).
+
+
+%% ---------------------------------------------------------------
+%% match_delete
+%%
+%% Search the database table for records witch matches the
+%% pattern and deletes them from the database table.
+%% ---------------------------------------------------------------
+
+match_delete(#tab{id = ID}, Pattern) ->
+ ?vtrace("match_delete in ~p with pattern ~p", [ID, Pattern]),
+ Recs = dets:match_object(ID, Pattern),
+ dets:match_delete(ID, Pattern),
+ Recs.
+
+
+%% ---------------------------------------------------------------
+%% tab2list
+%%
+%% Return all records in the table in the form of a list.
+%% ---------------------------------------------------------------
+
+tab2list(#tab{id = ID} = Tab) ->
+ ?vtrace("tab2list -> list of ~p", [ID]),
+ match_object(Tab, '_').
+
+
+%% ---------------------------------------------------------------
+%% info
+%%
+%% Retrieve implementation dependent mib-storage table
+%% information.
+%% ---------------------------------------------------------------
+
+info(#tab{id = ID}) ->
+ ?vtrace("info -> info of ~p", [ID]),
+ dets:info(ID).
+
+
+info(TabId, all = _Item) ->
+ info(TabId);
+info(#tab{id = ID}, memory = _Item) ->
+ ?vtrace("info on ~p (~w)", [ID, _Item]),
+ dets:info(ID, file_size);
+info(#tab{id = ID}, Item) ->
+ ?vtrace("info on ~p (~w)", [ID, Item]),
+ dets:info(ID, Item).
+
+
+%% ---------------------------------------------------------------
+%% sync
+%%
+%% Dump mib-storage table to disc (if it has a disk component)
+%% ---------------------------------------------------------------
+
+sync(#tab{id = ID}) ->
+ ?vtrace("sync -> sync ~p", [ID]),
+ dets:sync(ID).
+
+
+%% ---------------------------------------------------------------
+%% backup
+%%
+%% Make a backup copy of the mib-storage table.
+%% ---------------------------------------------------------------
+
+backup(#tab{id = ID}, BackupDir) ->
+ ?vtrace("backup -> backup of ~p to ~p", [ID, BackupDir]),
+ case dets:info(ID, filename) of
+ undefined ->
+ {error, no_file};
+ Filename ->
+ case filename:dirname(Filename) of
+ BackupDir ->
+ {error, db_dir};
+ _ ->
+ Type = dets:info(ID, type),
+ KP = dets:info(ID, keypos),
+ dets_backup(ID,
+ filename:basename(Filename),
+ BackupDir, Type, KP)
+ end
+ end.
+
+
+dets_backup(ID, Filename, BackupDir, Type, KP) ->
+ ?vtrace("dets_backup -> entry with"
+ "~n ID: ~p"
+ "~n Filename: ~p"
+ "~n BackupDir: ~p"
+ "~n Type: ~p"
+ "~n KP: ~p", [ID, Filename, BackupDir, Type, KP]),
+ BackupFile = filename:join(BackupDir, Filename),
+ ?vtrace("dets_backup -> "
+ "~n BackupFile: ~p", [BackupFile]),
+ Backup = list_to_atom(atom_to_list(ID) ++ "_backup"),
+ Opts = [{file, BackupFile}, {type, Type}, {keypos, KP}],
+ case dets:open_file(Backup, Opts) of
+ {ok, B} ->
+ ?vtrace("dets_backup -> create fun", []),
+ F = fun(Arg) ->
+ dets_backup(Arg, start, ID, B)
+ end,
+ dets:safe_fixtable(ID, true),
+ Res = dets:init_table(Backup, F, [{format, bchunk}]),
+ dets:safe_fixtable(ID, false),
+ ?vtrace("dets_backup -> Res: ~p", [Res]),
+ Res;
+ Error ->
+ ?vinfo("dets_backup -> open_file failed: "
+ "~n ~p", [Error]),
+ Error
+ end.
+
+dets_backup(close, _Cont, _ID, B) ->
+ dets:close(B),
+ ok;
+dets_backup(read, Cont1, ID, B) ->
+ case dets:bchunk(ID, Cont1) of
+ {Cont2, Data} ->
+ F = fun(Arg) ->
+ dets_backup(Arg, Cont2, ID, B)
+ end,
+ {Data, F};
+ '$end_of_table' ->
+ dets:close(B),
+ end_of_input;
+ Error ->
+ Error
+ end.
+
+
+%%----------------------------------------------------------------------
+
+%% user_err(F, A) ->
+%% snmpa_error:user_err(F, A).
diff --git a/lib/snmp/src/agent/snmpa_mib_storage_ets.erl b/lib/snmp/src/agent/snmpa_mib_storage_ets.erl
new file mode 100644
index 0000000000..04faf46864
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_mib_storage_ets.erl
@@ -0,0 +1,341 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013-2013. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(snmpa_mib_storage_ets).
+
+-behaviour(snmpa_mib_storage).
+
+%%%-----------------------------------------------------------------
+%%% This module implements the snmpa_mib_storage behaviour.
+%%% It uses ets for storage.
+%%%-----------------------------------------------------------------
+
+-export([
+ open/5,
+ close/1,
+ read/2,
+ write/2,
+ delete/1,
+ delete/2,
+ match_object/2,
+ match_delete/2,
+ tab2list/1,
+ info/1, info/2,
+ sync/1,
+ backup/2
+ ]).
+
+
+-define(VMODULE,"MS-ETS").
+-include("snmp_verbosity.hrl").
+
+-record(tab, {id, rec_name, file, checksum = false}).
+
+
+%% ---------------------------------------------------------------
+%% open
+%%
+%% Open or create an ets table.
+%% Possibly also read data from a (specified) file (mirror) and
+%% populate the table from that (the dir option).
+%%
+%% Opts - A list of implementation dependent options
+%% ets_open_options() = [ets_open_option()]
+%% ets_open_option() = {dir, filename()} |
+%% {action, keep | clear} |
+%% {checksum, boolean()}
+%%
+%% The RecName and Fields arguments are not used in this
+%% implementation.
+%%
+%% ---------------------------------------------------------------
+
+%% This function creates the ets table
+open(Name, RecName, _Fields, Type, Opts) ->
+ ?vtrace("open table ~p", [Name]),
+ case lists:keysearch(dir, 1, Opts) of
+ {value, {dir, Dir}} ->
+ Action = snmp_misc:get_option(action, Opts, keep),
+ Checksum = snmp_misc:get_option(checksum, Opts, false),
+ ?vtrace("open ~p database ~p - check if file exist", [Type, Name]),
+ File = filename:join(Dir, atom_to_list(Name) ++ ".db"),
+ case file:read_file_info(File) of
+ {ok, _} ->
+ ?vdebug("open ~p database ~p - file exist - try reading",
+ [Type, Name]),
+ case ets:file2tab(File, [{verify, Checksum}]) of
+ {ok, ID} ->
+ ?vtrace("open ~p database ~p - "
+ "data read from file", [Type, Name]),
+ {ok, #tab{id = ID,
+ rec_name = RecName,
+ file = File,
+ checksum = Checksum}};
+ {error, Reason} when (Action =:= keep) ->
+ ?vinfo("open ~p database ~p - "
+ "failed reading from file (keep): "
+ "~n ~p",
+ [Type, Name, Reason]),
+ {error, {file2tab, Reason}};
+ {error, Reason} ->
+ ?vlog("open ~p database ~p - "
+ "failed reading from file (clear): "
+ "~n ~p", [Type, Name, Reason]),
+ user_err("Warning: could not read file - "
+ "create new (empty): "
+ "~n File: ~p"
+ "~n Reason: ~p", [File, Reason]),
+ ID = ets:new(Name, [Type, protected, {keypos, 2}]),
+ write_ets_file(ID, File, Checksum),
+ {ok, #tab{id = ID,
+ rec_name = RecName,
+ file = File,
+ checksum = Checksum}}
+ end;
+ {error, enoent} ->
+ %% No such file - create it
+ ?vdebug("open ~p database ~p - "
+ "file does *not* exist - create",
+ [Type, Name]),
+ ID = ets:new(Name, [Type, protected, {keypos, 2}]),
+ write_ets_file(ID, File, Checksum),
+ {ok, #tab{id = ID,
+ rec_name = RecName,
+ file = File,
+ checksum = Checksum}};
+ {error, Reason} when (Action =:= keep) ->
+ ?vinfo("open ~p database ~p - "
+ "failed reading file info (keep): "
+ "~n ~p",
+ [Type, Name, Reason]),
+ {error, {read_file_info, Reason}};
+ {error, Reason} ->
+ ?vlog("open ~p database ~p - "
+ "failed reading file info (clear): "
+ "~n ~p",
+ [Type, Name, Reason]),
+ user_err("Warning: could not read file info - "
+ "create new file: "
+ "~n File: ~p"
+ "~n Reason: ~p", [File, Reason]),
+ ID = ets:new(Name, [Type, protected, {keypos, 2}]),
+ write_ets_file(ID, File, Checksum),
+ {ok, #tab{id = ID,
+ rec_name = RecName,
+ file = File,
+ checksum = Checksum}}
+ end;
+ false ->
+ ?vdebug("open ~p database ~p - ok", [Type, Name]),
+ ID = ets:new(Name, [Type, protected, {keypos, 2}]),
+ {ok, #tab{id = ID, rec_name = RecName}}
+ end.
+
+
+%% ---------------------------------------------------------------
+%% close
+%%
+%% Close the mib-storage table.
+%% We will delete the table and if there is a file component,
+%% will also be written to file.
+%% ---------------------------------------------------------------
+close(#tab{id = ID, file = undefined}) ->
+ ?vtrace("close (delete) table ~p", [ID]),
+ ets:delete(ID);
+close(#tab{id = ID, file = File, checksum = Checksum}) ->
+ ?vtrace("close (delete) table ~p", [ID]),
+ write_ets_file(ID, File, Checksum),
+ ets:delete(ID).
+
+
+%% ---------------------------------------------------------------
+%% read
+%%
+%% Retrieve a record from the mib-storage table.
+%% ---------------------------------------------------------------
+
+read(#tab{id = ID}, Key) ->
+ ?vtrace("read from table ~p: ~p", [ID, Key]),
+ case ets:lookup(ID, Key) of
+ [Rec|_] -> {value, Rec};
+ _ -> false
+ end.
+
+
+%% ---------------------------------------------------------------
+%% write
+%%
+%% Write a record to the mib-storage table.
+%% ---------------------------------------------------------------
+
+%% This is a very crude guard test is used instead of: is_record(Rec, RecName)
+write(#tab{id = ID, rec_name = RecName}, Rec)
+ when (is_tuple(Rec) andalso (element(1, Rec) =:= RecName)) ->
+ ?vtrace("write to table ~p", [ID]),
+ ets:insert(ID, Rec).
+
+
+%% ---------------------------------------------------------------
+%% delete
+%%
+%% Delete the mib-storage table.
+%% ---------------------------------------------------------------
+delete(#tab{id = ID, file = undefined}) ->
+ ?vtrace("delete table ~p", [ID]),
+ ets:delete(ID);
+delete(#tab{id = ID, file = File}) ->
+ ?vtrace("delete table ~p", [ID]),
+ file:delete(File),
+ ets:delete(ID).
+
+
+%% ---------------------------------------------------------------
+%% delete
+%%
+%% Delete a record from the mib-storage table.
+%% ---------------------------------------------------------------
+delete(#tab{id = ID}, Key) ->
+ ?vtrace("delete from table ~p: ~p", [ID, Key]),
+ ets:delete(ID, Key).
+
+
+%% ---------------------------------------------------------------
+%% match_object
+%%
+%% Search the mib-storage table for records witch matches
+%% the pattern.
+%% ---------------------------------------------------------------
+
+match_object(#tab{id = ID}, Pattern) ->
+ ?vtrace("match_object in ~p of ~p", [ID, Pattern]),
+ ets:match_object(ID, Pattern).
+
+
+%% ---------------------------------------------------------------
+%% match_delete
+%%
+%% Search the mib-storage table for records witch matches
+%% the pattern and deletes them from the table.
+%% ---------------------------------------------------------------
+
+match_delete(#tab{id = ID}, Pattern) ->
+ ?vtrace("match_delete in ~p with pattern ~p", [ID, Pattern]),
+ Recs = ets:match_object(ID, Pattern),
+ ets:match_delete(ID, Pattern),
+ Recs.
+
+
+%% ---------------------------------------------------------------
+%% tab2list
+%%
+%% Return all records in the mib-storage table in the form
+%% of a list.
+%% ---------------------------------------------------------------
+
+tab2list(#tab{id = ID}) ->
+ ?vtrace("tab2list -> list of ~p", [ID]),
+ ets:tab2list(ID).
+
+
+
+%% ---------------------------------------------------------------
+%% info/1,2
+%%
+%% Retrieve implementation dependent mib-storage table
+%% information.
+%% ---------------------------------------------------------------
+info(#tab{id = ID}) ->
+ ?vtrace("info on ~p", [ID]),
+ case ets:info(ID) of
+ undefined ->
+ [];
+ L ->
+ L
+ end.
+
+
+info(TabId, all = _Item) ->
+ info(TabId);
+info(#tab{id = ID}, Item) ->
+ ?vtrace("info on ~p", [ID]),
+ ets:info(ID, Item).
+
+
+%% ---------------------------------------------------------------
+%% sync
+%%
+%% Dump mib-storage table to disc (if there is a file compionent)
+%% ---------------------------------------------------------------
+
+sync(#tab{file = undefined}) ->
+ ok;
+sync(#tab{id = ID, file = File, checksum = Checksum}) ->
+ ?vtrace("sync ~p", [ID]),
+ write_ets_file(ID, File, Checksum).
+
+
+%% ---------------------------------------------------------------
+%% backup
+%%
+%% Make a backup copy of the mib-storage table. Only valid id
+%% there is a file component.
+%% ---------------------------------------------------------------
+
+backup(#tab{file = undefined}, _BackupDir) ->
+ ok;
+backup(#tab{id = ID, file = File, checksum = Checksum}, BackupDir) ->
+ ?vtrace("backup ~p to ~p", [ID, BackupDir]),
+ Filename = filename:basename(File),
+ case filename:join(BackupDir, Filename) of
+ File ->
+ %% Oups: backup-dir and db-dir the same
+ {error, db_dir};
+ BackupFile ->
+ write_ets_file(ID, BackupFile, Checksum)
+ end.
+
+
+%%----------------------------------------------------------------------
+
+write_ets_file(ID, File, Checksum) when (Checksum =:= true) ->
+ do_write_ets_file(ID, File, [{extended_info, [md5sum]}]);
+write_ets_file(ID, File, Checksum) when (Checksum =:= false) ->
+ do_write_ets_file(ID, File, []).
+
+do_write_ets_file(ID, File, Options) ->
+ TmpFile = File ++ ".tmp",
+ case ets:tab2file(ID, TmpFile, Options) of
+ ok ->
+ case file:rename(TmpFile, File) of
+ ok ->
+ ok;
+ Else ->
+ user_err("Warning: could not move file ~p"
+ " (~p)", [File, Else])
+ end;
+ {error, Reason} ->
+ user_err("Warning: could not save file ~p (~p)",
+ [File, Reason])
+ end.
+
+
+%%----------------------------------------------------------------------
+
+user_err(F, A) ->
+ snmpa_error:user_err(F, A).
diff --git a/lib/snmp/src/agent/snmpa_mib_storage_mnesia.erl b/lib/snmp/src/agent/snmpa_mib_storage_mnesia.erl
new file mode 100644
index 0000000000..192b5aa26e
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_mib_storage_mnesia.erl
@@ -0,0 +1,302 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013-2013. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(snmpa_mib_storage_mnesia).
+
+
+-behaviour(snmpa_mib_storage).
+
+%%%-----------------------------------------------------------------
+%%% This module implements the snmpa_mib_storage behaviour.
+%%% It uses mnesia for storage.
+%%%-----------------------------------------------------------------
+
+-export([
+ open/5,
+ close/1,
+ read/2,
+ write/2,
+ delete/1,
+ delete/2,
+ match_object/2,
+ match_delete/2,
+ tab2list/1,
+ info/1, info/2,
+ sync/1,
+ backup/2
+ ]).
+
+
+-define(VMODULE,"MS-MNESIA").
+-include("snmp_verbosity.hrl").
+
+-record(tab, {id}).
+
+
+%% ---------------------------------------------------------------
+%% open
+%%
+%% Open or create a mnesia table.
+%%
+%% Opts - A list of implementation dependent options
+%% mnesia_open_options() = [mnesia_open_option()]
+%% mnesia_open_option() = {action, keep | clear} |
+%% {nodes, [node()]}
+%%
+%% ---------------------------------------------------------------
+
+open(Name, RecName, Fields, Type, Opts) ->
+ ?vtrace("open ~p table ~p for record ~p",
+ [Type, Name, RecName]),
+ Action = get_action(Opts),
+ Nodes = get_nodes(Opts),
+ case table_exists(Name) of
+ true when (Action =:= keep) ->
+ ?vtrace("open table ~p - exist (keep)", [Name]),
+ {ok, #tab{id = Name}};
+ true when (Action =:= clear) ->
+ ?vtrace("open table ~p - exist (clear)", [Name]),
+ F = fun() -> mnesia:clear_table(Name) end,
+ case mnesia:transaction(F) of
+ {aborted, Reason} ->
+ {error, {clear, Reason}};
+ {atomic, _} ->
+ {ok, #tab{id = Name}}
+ end;
+ false ->
+ ?vtrace("open table ~p - does not exist", [Name]),
+ Args = [{record_name, RecName},
+ {attributes, Fields},
+ {type, Type},
+ {disc_copies, Nodes}],
+ case mnesia:create_table(Name, Args) of
+ {atomic, ok} ->
+ ?vtrace("open table ~p - ok", [Name]),
+ {ok, #tab{id = Name}};
+ {aborted, Reason} ->
+ ?vinfo("open table ~p - aborted"
+ "~n Reason: ~p", [Name, Reason]),
+ {error, {create, Reason}}
+ end
+ end.
+
+table_exists(Name) ->
+ case (catch mnesia:table_info(Name, type)) of
+ {'EXIT', _Reason} ->
+ false;
+ _ ->
+ true
+ end.
+
+
+%% ---------------------------------------------------------------
+%% close
+%%
+%% Close the mib-storage table.
+%% This does nothing in the mnesia case.
+%% ---------------------------------------------------------------
+
+close(_) ->
+ ?vtrace("close mib-storage - ignore",[]),
+ ok.
+
+
+%% ---------------------------------------------------------------
+%% read
+%%
+%% Retrieve a record from the mib-storage table.
+%% ---------------------------------------------------------------
+
+read(#tab{id = ID}, Key) ->
+ ?vtrace("read (dirty) from database ~p: ~p", [ID, Key]),
+ case (catch mnesia:dirty_read(ID, Key)) of
+ [Rec|_] -> {value,Rec};
+ _ -> false
+ end.
+
+
+%% ---------------------------------------------------------------
+%% write
+%%
+%% Write a record to the mib-storage table.
+%% ---------------------------------------------------------------
+
+write(#tab{id = ID}, Rec) ->
+ ?vtrace("write to database ~p", [ID]),
+ F = fun() -> mnesia:write(ID, Rec, write) end,
+ case mnesia:transaction(F) of
+ {aborted, _Reason} = ABORTED ->
+ {error, ABORTED};
+ {atomic,_} ->
+ ok
+ end.
+
+
+%% ---------------------------------------------------------------
+%% delete
+%%
+%% Delete the mib-storage table.
+%% ---------------------------------------------------------------
+
+delete(#tab{id = ID}) ->
+ ?vtrace("delete database: ~p", [ID]),
+ mnesia:delete_table(ID).
+
+
+%% ---------------------------------------------------------------
+%% delete
+%%
+%% Delete a record from the mib-storage table.
+%% ---------------------------------------------------------------
+
+delete(#tab{id = ID}, Key) ->
+ ?vtrace("delete from database ~p: ~p", [ID, Key]),
+ F = fun() -> mnesia:delete(ID, Key, write) end,
+ case mnesia:transaction(F) of
+ {aborted, _Reason} = ABORTED ->
+ {error, ABORTED};
+ {atomic, _} ->
+ ok
+ end.
+
+
+%% ---------------------------------------------------------------
+%% match_object
+%%
+%% Search the mib-storage table for records witch matches
+%% the pattern.
+%% ---------------------------------------------------------------
+
+match_object(#tab{id = ID}, Pattern) ->
+ ?vtrace("match_object in ~p of ~p", [ID, Pattern]),
+ F = fun() -> mnesia:match_object(ID, Pattern, read) end,
+ case mnesia:transaction(F) of
+ {aborted, _Reason} = ABORTED ->
+ {error, ABORTED};
+ {atomic, Rs} ->
+ Rs
+ end.
+
+
+%% ---------------------------------------------------------------
+%% match_delete
+%%
+%% Search the mib-storage table for records witch matches
+%% the pattern and deletes them from the table.
+%% ---------------------------------------------------------------
+
+match_delete(#tab{id = ID}, Pattern) ->
+ ?vtrace("match_delete in ~p with pattern ~p", [ID, Pattern]),
+ F = fun() ->
+ Recs = mnesia:match_object(ID, Pattern, read),
+ lists:foreach(fun(Rec) ->
+ mnesia:delete_object(ID, Rec, write)
+ end, Recs),
+ Recs
+ end,
+ case mnesia:transaction(F) of
+ {aborted, _Reason} = ABORTED ->
+ {error, ABORTED};
+ {atomic, Rs} ->
+ Rs
+ end.
+
+
+%% ---------------------------------------------------------------
+%% tab2list
+%%
+%% Return all records in the mib-storage table in the form of
+%% a list.
+%% ---------------------------------------------------------------
+
+tab2list(#tab{id = ID} = Tab) ->
+ ?vtrace("tab2list -> list of ~p", [ID]),
+ match_object(Tab, mnesia:table_info(ID, wild_pattern)).
+
+
+%% ---------------------------------------------------------------
+%% info
+%%
+%% Retrieve implementation dependent mib-storage table
+%% information.
+%% ---------------------------------------------------------------
+
+info(#tab{id = ID}) ->
+ case (catch mnesia:table_info(ID, all)) of
+ Info when is_list(Info) ->
+ Info;
+ {'EXIT', {aborted, Reason}} ->
+ {error, Reason}
+ end.
+
+
+info(#tab{id = ID}, Item) ->
+ mnesia:table_info(ID, Item).
+
+
+%% ---------------------------------------------------------------
+%% sync
+%%
+%% Ignore
+%% ---------------------------------------------------------------
+
+sync(_) ->
+ ok.
+
+
+%% ---------------------------------------------------------------
+%% backup
+%%
+%% Ignore. Mnesia handles its own backups.
+%% ---------------------------------------------------------------
+
+backup(_, _) ->
+ ok.
+
+
+%%----------------------------------------------------------------------
+
+get_action(Opts) ->
+ snmp_misc:get_option(action, Opts, keep).
+
+get_nodes(Opts) ->
+ case snmp_misc:get_option(nodes, Opts, erlang:nodes()) of
+ [] ->
+ [node()];
+ Nodes when is_list(Nodes) ->
+ Nodes;
+ all ->
+ erlang:nodes();
+ visible ->
+ erlang:nodes(visible);
+ connected ->
+ erlang:nodes(connected);
+ db_nodes ->
+ try mnesia:system_info(db_nodes) of
+ DbNodes when is_list(DbNodes) ->
+ DbNodes;
+ _ ->
+ erlang:nodes()
+ catch
+ _:_ ->
+ erlang:nodes()
+ end
+ end.
+
+%% user_err(F, A) ->
+%% snmpa_error:user_err(F, A).
diff --git a/lib/snmp/src/agent/snmpa_supervisor.erl b/lib/snmp/src/agent/snmpa_supervisor.erl
index 886fd074bc..aebcdbaa84 100644
--- a/lib/snmp/src/agent/snmpa_supervisor.erl
+++ b/lib/snmp/src/agent/snmpa_supervisor.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. 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
@@ -224,26 +224,101 @@ init([AgentType, Opts]) ->
ets:insert(snmp_agent_table, {error_report_mod, ErrorReportMod}),
%% -- mib storage --
+ %% MibStorage has only one mandatory part: module
+ %% Everything else is module dependent and therefor
+ %% put in a special option: options
MibStorage =
- case get_opt(mib_storage, Opts, ets) of
+ case get_opt(mib_storage, Opts, [{module, snmpa_mib_storage_ets}]) of
+
+ %% --- ETS wrappers ---
+
+ ets ->
+ [{module, snmpa_mib_storage_ets}];
+ {ets, default} ->
+ [{module, snmpa_mib_storage_ets},
+ {options, [{dir, filename:join([DbDir])},
+ {action, keep}]}];
+ {ets, Dir} when is_list(Dir) ->
+ [{module, snmpa_mib_storage_ets},
+ {options, [{dir, filename:join([Dir])},
+ {action, keep}]}];
+ {ets, default, Action} when ((Action =:= keep) orelse
+ (Action =:= clear)) ->
+ [{module, snmpa_mib_storage_ets},
+ {options, [{dir, filename:join([DbDir])},
+ {action, Action}]}];
+ {ets, Dir, Action} when is_list(Dir) andalso
+ ((Action =:= keep) orelse
+ (Action =:= clear)) ->
+ [{module, snmpa_mib_storage_ets},
+ {options, [{dir, filename:join([Dir])},
+ {action, Action}]}];
+
+ %% --- DETS wrappers ---
+
dets ->
- {dets, DbDir};
+ [{module, snmpa_mib_storage_dets},
+ {options, [{dir, filename:join([DbDir])},
+ {action, keep}]}];
{dets, default} ->
- {dets, DbDir};
- {dets, default, Act} ->
- {dets, DbDir, Act};
- {ets, default} ->
- {ets, DbDir};
+ [{module, snmpa_mib_storage_dets},
+ {options, [{dir, filename:join([DbDir])},
+ {action, keep}]}];
+ {dets, default, Action} when ((Action =:= keep) orelse
+ (Action =:= clear)) ->
+ [{module, snmpa_mib_storage_dets},
+ {options, [{dir, filename:join([DbDir])},
+ {action, Action}]}];
+ {dets, Dir, Action} when is_list(Dir) andalso
+ ((Action =:= keep) orelse
+ (Action =:= clear)) ->
+ [{module, snmpa_mib_storage_dets},
+ {options, [{dir, filename:join([Dir])},
+ {action, Action}]}];
+
+ %% --- Mnesia wrappers ---
+
mnesia ->
- {mnesia, erlang:nodes()};
- {mnesia, visible} ->
- {mnesia, erlang:nodes(visible)};
- {mnesia, connected} ->
- {mnesia, erlang:nodes(connected)};
- Other ->
+ [{module, snmpa_mib_storage_mnesia},
+ {options, [{nodes, erlang:nodes()},
+ {action, keep}]}];
+ {mnesia, Nodes0} ->
+ Nodes =
+ if
+ Nodes0 =:= visible ->
+ erlang:nodes(visible);
+ Nodes0 =:= connected ->
+ erlang:nodes(connected);
+ Nodes0 =:= [] ->
+ [node()];
+ true ->
+ Nodes0
+ end,
+ [{module, snmpa_mib_storage_mnesia},
+ {options, [{nodes, Nodes},
+ {action, keep}]}];
+ {mnesia, Nodes0, Action} when ((Action =:= keep) orelse
+ (Action =:= clear)) ->
+ Nodes =
+ if
+ Nodes0 =:= visible ->
+ erlang:nodes(visible);
+ Nodes0 =:= connected ->
+ erlang:nodes(connected);
+ Nodes0 =:= [] ->
+ [node()];
+ true ->
+ Nodes0
+ end,
+ [{module, snmpa_mib_storage_mnesia},
+ {options, [{nodes, Nodes},
+ {action, Action}]}];
+
+ Other when is_list(Other) ->
Other
end,
- ?vdebug("[agent table] store mib storage: ~w",[MibStorage]),
+
+ ?vdebug("[agent table] store mib storage: ~w", [MibStorage]),
ets:insert(snmp_agent_table, {mib_storage, MibStorage}),
%% -- Agent mib storage --
@@ -388,7 +463,7 @@ init([AgentType, Opts]) ->
AgentSpec =
worker_spec(snmpa_agent,
- [Prio,snmp_master_agent,none,Ref,AgentOpts],
+ [Prio, snmp_master_agent, none, Ref, AgentOpts],
Restart, 15000),
AgentSupSpec =
sup_spec(snmpa_agent_sup, [AgentSpec],
diff --git a/lib/snmp/src/agent/snmpa_symbolic_store.erl b/lib/snmp/src/agent/snmpa_symbolic_store.erl
index 6c58ffde41..00178f4bcd 100644
--- a/lib/snmp/src/agent/snmpa_symbolic_store.erl
+++ b/lib/snmp/src/agent/snmpa_symbolic_store.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. 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
@@ -78,7 +78,7 @@
gen_server:start_link({local, ?SERVER}, ?MODULE, [Prio, Opts], [])).
-endif.
--record(state, {db, backup}).
+-record(state, {module, db, backup}).
-record(symbol, {key, mib_name, info}).
@@ -112,6 +112,9 @@ backup(BackupDir) ->
get_db() ->
call(get_db).
+which_module() ->
+ call(which_module).
+
%%----------------------------------------------------------------------
%% Returns: {value, Oid} | false
@@ -202,49 +205,63 @@ verbosity(Verbosity) ->
%%----------------------------------------------------------------------
%% DB access (read) functions: Returns: {value, Oid} | false
%%----------------------------------------------------------------------
+
aliasname_to_oid(Db, Aliasname) ->
- case snmpa_general_db:read(Db, {alias, Aliasname}) of
+ Mod = which_module(),
+ aliasname_to_oid(Mod, Db, Aliasname).
+
+aliasname_to_oid(Mod, Db, Aliasname) ->
+ case Mod:read(Db, {alias, Aliasname}) of
{value,#symbol{info = {Oid, _Enums}}} -> {value, Oid};
false -> false
end.
-oid_to_aliasname(Db,Oid) ->
- case snmpa_general_db:read(Db, {oid, Oid}) of
+oid_to_aliasname(Db, Oid) ->
+ Mod = which_module(),
+ oid_to_aliasname(Mod, Db, Oid).
+
+oid_to_aliasname(Mod, Db, Oid) ->
+ case Mod:read(Db, {oid, Oid}) of
{value,#symbol{info = Aliasname}} -> {value, Aliasname};
_ -> false
end.
-which_notifications(Db) ->
+which_notifications(Mod, Db) ->
Pattern = #symbol{key = {trap, '_'}, _ = '_'},
- Symbols = snmpa_general_db:match_object(Db, Pattern),
+ Symbols = Mod:match_object(Db, Pattern),
[{Name, Mib, Rec} || #symbol{key = {trap, Name},
mib_name = Mib,
info = Rec} <- Symbols].
-which_aliasnames(Db) ->
+which_aliasnames(Mod, Db) ->
Pattern = #symbol{key = {alias, '_'}, _ = '_'},
- Symbols = snmpa_general_db:match_object(Db, Pattern),
+ Symbols = Mod:match_object(Db, Pattern),
[Alias || #symbol{key = {alias, Alias}} <- Symbols].
-which_tables(Db) ->
+which_tables(Mod, Db) ->
Pattern = #symbol{key = {table_info, '_'}, _ = '_'},
- Symbols = snmpa_general_db:match_object(Db, Pattern),
+ Symbols = Mod:match_object(Db, Pattern),
[Name || #symbol{key = {table_info, Name}} <- Symbols].
-which_variables(Db) ->
+which_variables(Mod, Db) ->
Pattern = #symbol{key = {variable_info, '_'}, _ = '_'},
- Symbols = snmpa_general_db:match_object(Db, Pattern),
+ Symbols = Mod:match_object(Db, Pattern),
[Name || #symbol{key = {variable_info, Name}} <- Symbols].
-int_to_enum(Db,TypeOrObjName,Int) ->
- case snmpa_general_db:read(Db, {alias, TypeOrObjName}) of
+
+int_to_enum(Db, TypeOrObjName, Int) ->
+ Mod = which_module(),
+ int_to_enum(Mod, Db, TypeOrObjName, Int).
+
+int_to_enum(Mod, Db, TypeOrObjName, Int) ->
+ case Mod:read(Db, {alias, TypeOrObjName}) of
{value,#symbol{info = {_Oid, Enums}}} ->
case lists:keysearch(Int, 2, Enums) of
{value, {Enum, _Int}} -> {value, Enum};
false -> false
end;
false -> % Not an Aliasname ->
- case snmpa_general_db:read(Db, {type, TypeOrObjName}) of
+ case Mod:read(Db, {type, TypeOrObjName}) of
{value,#symbol{info = Enums}} ->
case lists:keysearch(Int, 2, Enums) of
{value, {Enum, _Int}} -> {value, Enum};
@@ -256,14 +273,18 @@ int_to_enum(Db,TypeOrObjName,Int) ->
end.
enum_to_int(Db, TypeOrObjName, Enum) ->
- case snmpa_general_db:read(Db, {alias, TypeOrObjName}) of
+ Mod = which_module(),
+ enum_to_int(Mod, Db, TypeOrObjName, Enum).
+
+enum_to_int(Mod, Db, TypeOrObjName, Enum) ->
+ case Mod:read(Db, {alias, TypeOrObjName}) of
{value,#symbol{info = {_Oid, Enums}}} ->
case lists:keysearch(Enum, 1, Enums) of
{value, {_Enum, Int}} -> {value, Int};
false -> false
end;
false -> % Not an Aliasname
- case snmpa_general_db:read(Db, {type, TypeOrObjName}) of
+ case Mod:read(Db, {type, TypeOrObjName}) of
{value,#symbol{info = Enums}} ->
case lists:keysearch(Enum, 1, Enums) of
{value, {_Enum, Int}} -> {value, Int};
@@ -278,8 +299,9 @@ enum_to_int(Db, TypeOrObjName, Enum) ->
%%----------------------------------------------------------------------
%% DB access (read) functions: Returns: false|{value, Info}
%%----------------------------------------------------------------------
-table_info(Db,TableName) ->
- case snmpa_general_db:read(Db, {table_info, TableName}) of
+
+table_info(Mod, Db, TableName) ->
+ case Mod:read(Db, {table_info, TableName}) of
{value,#symbol{info = Info}} -> {value, Info};
false -> false
end.
@@ -288,8 +310,8 @@ table_info(Db,TableName) ->
%%----------------------------------------------------------------------
%% DB access (read) functions: Returns: false|{value, Info}
%%----------------------------------------------------------------------
-variable_info(Db,VariableName) ->
- case snmpa_general_db:read(Db, {variable_info, VariableName}) of
+variable_info(Mod, Db, VariableName) ->
+ case Mod:read(Db, {variable_info, VariableName}) of
{value,#symbol{info = Info}} -> {value, Info};
false -> false
end.
@@ -299,7 +321,7 @@ variable_info(Db,VariableName) ->
%% Implementation
%%----------------------------------------------------------------------
-init([Prio,Opts]) ->
+init([Prio, Opts]) ->
?d("init -> entry with"
"~n Prio: ~p"
"~n Opts: ~p", [Prio,Opts]),
@@ -317,102 +339,125 @@ do_init(Prio, Opts) ->
put(sname,ss),
put(verbosity,get_verbosity(Opts)),
?vlog("starting",[]),
- Storage = get_mib_storage(Opts),
+ MibStorage = get_mib_storage(Opts),
+ Mod = snmp_misc:get_option(module, MibStorage),
+ MsOpts = snmp_misc:get_option(options, MibStorage, []),
+
%% type = bag solves the problem with import and multiple
%% object/type definitions.
- Db = snmpa_general_db:open(Storage, snmpa_symbolic_store,
- symbol, record_info(fields,symbol), bag),
- S = #state{db = Db},
- ?vdebug("started",[]),
- {ok, S}.
+ case Mod:open(?MODULE, symbol, record_info(fields, symbol), bag, MsOpts) of
+ {ok, Db} ->
+ S = #state{module = Mod, db = Db},
+ ?vdebug("started",[]),
+ {ok, S};
+ {error, _} = ERROR ->
+ ERROR
+ end.
handle_call(get_db, _From, #state{db = DB} = S) ->
?vlog("get db",[]),
{reply, DB, S};
-handle_call({table_info, TableName}, _From, #state{db = DB} = S) ->
+handle_call(which_module, _From, #state{module = Mod} = S) ->
+ ?vlog("which module",[]),
+ {reply, Mod, S};
+
+handle_call({table_info, TableName}, _From,
+ #state{module = Mod, db = DB} = S) ->
?vlog("table info: ~p",[TableName]),
- Res = table_info(DB, TableName),
+ Res = table_info(Mod, DB, TableName),
?vdebug("table info result: ~p",[Res]),
{reply, Res, S};
-handle_call({variable_info, VariableName}, _From, #state{db = DB} = S) ->
+handle_call({variable_info, VariableName}, _From,
+ #state{module = Mod, db = DB} = S) ->
?vlog("variable info: ~p",[VariableName]),
- Res = variable_info(DB, VariableName),
+ Res = variable_info(Mod, DB, VariableName),
?vdebug("variable info result: ~p",[Res]),
{reply, Res, S};
-handle_call({aliasname_to_oid, Aliasname}, _From, #state{db = DB} = S) ->
+handle_call({aliasname_to_oid, Aliasname}, _From,
+ #state{module = Mod, db = DB} = S) ->
?vlog("aliasname to oid: ~p",[Aliasname]),
- Res = aliasname_to_oid(DB,Aliasname),
+ Res = aliasname_to_oid(Mod, DB, Aliasname),
?vdebug("aliasname to oid result: ~p",[Res]),
{reply, Res, S};
-handle_call({oid_to_aliasname, Oid}, _From, #state{db = DB} = S) ->
+handle_call({oid_to_aliasname, Oid}, _From,
+ #state{module = Mod, db = DB} = S) ->
?vlog("oid to aliasname: ~p",[Oid]),
- Res = oid_to_aliasname(DB, Oid),
+ Res = oid_to_aliasname(Mod, DB, Oid),
?vdebug("oid to aliasname result: ~p",[Res]),
{reply, Res, S};
-handle_call(which_aliasnames, _From, #state{db = DB} = S) ->
+handle_call(which_aliasnames, _From,
+ #state{module = Mod, db = DB} = S) ->
?vlog("which aliasnames",[]),
- Res = which_aliasnames(DB),
+ Res = which_aliasnames(Mod, DB),
?vdebug("which aliasnames: ~p",[Res]),
{reply, Res, S};
-handle_call(which_tables, _From, #state{db = DB} = S) ->
+handle_call(which_tables, _From,
+ #state{module = Mod, db = DB} = S) ->
?vlog("which tables",[]),
- Res = which_tables(DB),
+ Res = which_tables(Mod, DB),
?vdebug("which tables: ~p",[Res]),
{reply, Res, S};
-handle_call(which_variables, _From, #state{db = DB} = S) ->
+handle_call(which_variables, _From,
+ #state{module = Mod, db = DB} = S) ->
?vlog("which variables",[]),
- Res = which_variables(DB),
+ Res = which_variables(Mod, DB),
?vdebug("which variables: ~p",[Res]),
{reply, Res, S};
-handle_call({enum_to_int, TypeOrObjName, Enum}, _From, #state{db = DB} = S) ->
+handle_call({enum_to_int, TypeOrObjName, Enum}, _From,
+ #state{module = Mod, db = DB} = S) ->
?vlog("enum to int: ~p, ~p",[TypeOrObjName,Enum]),
- Res = enum_to_int(DB, TypeOrObjName, Enum),
+ Res = enum_to_int(Mod, DB, TypeOrObjName, Enum),
?vdebug("enum to int result: ~p",[Res]),
{reply, Res, S};
-handle_call({int_to_enum, TypeOrObjName, Int}, _From, #state{db = DB} = S) ->
+handle_call({int_to_enum, TypeOrObjName, Int}, _From,
+ #state{module = Mod, db = DB} = S) ->
?vlog("int to enum: ~p, ~p",[TypeOrObjName,Int]),
- Res = int_to_enum(DB, TypeOrObjName, Int),
+ Res = int_to_enum(Mod, DB, TypeOrObjName, Int),
?vdebug("int to enum result: ~p",[Res]),
{reply, Res, S};
-handle_call({set_notification, MibName, Trap}, _From, #state{db = DB} = S) ->
+handle_call({set_notification, MibName, Trap}, _From,
+ #state{module = Mod, db = DB} = S) ->
?vlog("set notification:"
"~n ~p~n ~p", [MibName,Trap]),
- set_notif(DB, MibName, Trap),
+ set_notif(Mod, DB, MibName, Trap),
{reply, true, S};
-handle_call({delete_notifications, MibName}, _From, #state{db = DB} = S) ->
+handle_call({delete_notifications, MibName}, _From,
+ #state{module = Mod, db = DB} = S) ->
?vlog("delete notification: ~p",[MibName]),
- delete_notif(DB, MibName),
+ delete_notif(Mod, DB, MibName),
{reply, true, S};
-handle_call(which_notifications, _From, #state{db = DB} = S) ->
+handle_call(which_notifications, _From,
+ #state{module = Mod, db = DB} = S) ->
?vlog("which notifications", []),
- Reply = which_notifications(DB),
+ Reply = which_notifications(Mod, DB),
{reply, Reply, S};
-handle_call({get_notification, Key}, _From, #state{db = DB} = S) ->
+handle_call({get_notification, Key}, _From,
+ #state{module = Mod, db = DB} = S) ->
?vlog("get notification: ~p",[Key]),
- Res = get_notif(DB, Key),
+ Res = get_notif(Mod, DB, Key),
?vdebug("get notification result: ~p",[Res]),
{reply, Res, S};
-handle_call(info, _From, #state{db = DB} = S) ->
+handle_call(info, _From, #state{module = Mod, db = DB} = S) ->
?vlog("info",[]),
- Info = get_info(DB),
+ Info = get_info(Mod, DB),
{reply, Info, S};
-handle_call({backup, BackupDir}, From, #state{db = DB} = S) ->
+handle_call({backup, BackupDir}, From, #state{module = Mod, db = DB} = S) ->
?vlog("info to ~p",[BackupDir]),
Pid = self(),
V = get(verbosity),
@@ -424,7 +469,7 @@ handle_call({backup, BackupDir}, From, #state{db = DB} = S) ->
put(sname, albs),
put(verbosity, V),
Dir = filename:join([BackupDir]),
- Reply = snmpa_general_db:backup(DB, Dir),
+ Reply = Mod:backup(DB, Dir),
Pid ! {backup_done, Reply},
unlink(Pid)
end),
@@ -446,7 +491,7 @@ handle_call(Req, _From, S) ->
{reply, Reply, S}.
-handle_cast({add_types, MibName, Types}, #state{db = DB} = S) ->
+handle_cast({add_types, MibName, Types}, #state{module = Mod, db = DB} = S) ->
?vlog("add types for ~p:",[MibName]),
F = fun(#asn1_type{assocList = Alist, aliasname = Name}) ->
case snmp_misc:assq(enums, Alist) of
@@ -455,20 +500,21 @@ handle_cast({add_types, MibName, Types}, #state{db = DB} = S) ->
Rec = #symbol{key = {type, Name},
mib_name = MibName,
info = Es},
- snmpa_general_db:write(DB, Rec);
+ Mod:write(DB, Rec);
false -> done
end
end,
lists:foreach(F, Types),
{noreply, S};
-handle_cast({delete_types, MibName}, #state{db = DB} = S) ->
+handle_cast({delete_types, MibName}, #state{module = Mod, db = DB} = S) ->
?vlog("delete types: ~p",[MibName]),
Pattern = #symbol{key = {type, '_'}, mib_name = MibName, info = '_'},
- snmpa_general_db:match_delete(DB, Pattern),
+ Mod:match_delete(DB, Pattern),
{noreply, S};
-handle_cast({add_aliasnames, MibName, MEs}, #state{db = DB} = S) ->
+handle_cast({add_aliasnames, MibName, MEs},
+ #state{module = Mod, db = DB} = S) ->
?vlog("add aliasnames for ~p:",[MibName]),
F = fun(#me{aliasname = AN, oid = Oid, asn1_type = AT}) ->
Enums =
@@ -480,20 +526,21 @@ handle_cast({add_aliasnames, MibName, MEs}, #state{db = DB} = S) ->
end;
_ -> []
end,
- write_alias(AN, DB, Enums, MibName, Oid)
+ write_alias(Mod, AN, DB, Enums, MibName, Oid)
end,
lists:foreach(F, MEs),
{noreply, S};
-handle_cast({delete_aliasname, MibName}, #state{db = DB} = S) ->
+handle_cast({delete_aliasname, MibName}, #state{module = Mod, db = DB} = S) ->
?vlog("delete aliasname: ~p",[MibName]),
Pattern1 = #symbol{key = {alias, '_'}, mib_name = MibName, info = '_'},
- snmpa_general_db:match_delete(DB, Pattern1),
+ Mod:match_delete(DB, Pattern1),
Pattern2 = #symbol{key = {oid, '_'}, mib_name = MibName, info = '_'},
- snmpa_general_db:match_delete(DB, Pattern2),
+ Mod:match_delete(DB, Pattern2),
{noreply, S};
-handle_cast({add_table_infos, MibName, TableInfos}, #state{db = DB} = S) ->
+handle_cast({add_table_infos, MibName, TableInfos},
+ #state{module = Mod, db = DB} = S) ->
?vlog("add table infos for ~p:",[MibName]),
F = fun({Name, TableInfo}) ->
?vlog("add table info~n ~p -> ~p",
@@ -501,19 +548,20 @@ handle_cast({add_table_infos, MibName, TableInfos}, #state{db = DB} = S) ->
Rec = #symbol{key = {table_info, Name},
mib_name = MibName,
info = TableInfo},
- snmpa_general_db:write(DB, Rec)
+ Mod:write(DB, Rec)
end,
lists:foreach(F, TableInfos),
{noreply, S};
-handle_cast({delete_table_infos, MibName}, #state{db = DB} = S) ->
+handle_cast({delete_table_infos, MibName},
+ #state{module = Mod, db = DB} = S) ->
?vlog("delete table infos: ~p",[MibName]),
Pattern = #symbol{key = {table_info, '_'}, mib_name = MibName, info = '_'},
- snmpa_general_db:match_delete(DB, Pattern),
+ Mod:match_delete(DB, Pattern),
{noreply, S};
handle_cast({add_variable_infos, MibName, VariableInfos},
- #state{db = DB} = S) ->
+ #state{module = Mod, db = DB} = S) ->
?vlog("add variable infos for ~p:",[MibName]),
F = fun({Name, VariableInfo}) ->
?vlog("add variable info~n ~p -> ~p",
@@ -521,17 +569,18 @@ handle_cast({add_variable_infos, MibName, VariableInfos},
Rec = #symbol{key = {variable_info, Name},
mib_name = MibName,
info = VariableInfo},
- snmpa_general_db:write(DB, Rec)
+ Mod:write(DB, Rec)
end,
lists:foreach(F, VariableInfos),
{noreply, S};
-handle_cast({delete_variable_infos, MibName}, #state{db = DB} = S) ->
+handle_cast({delete_variable_infos, MibName},
+ #state{module = Mod, db = DB} = S) ->
?vlog("delete variable infos: ~p",[MibName]),
Pattern = #symbol{key = {variable_info,'_'},
mib_name = MibName,
info = '_'},
- snmpa_general_db:match_delete(DB, Pattern),
+ Mod:match_delete(DB, Pattern),
{noreply, S};
handle_cast({verbosity,Verbosity}, State) ->
@@ -565,9 +614,9 @@ handle_info(Info, S) ->
{noreply, S}.
-terminate(Reason, S) ->
- ?vlog("terminate: ~p",[Reason]),
- snmpa_general_db:close(S#state.db).
+terminate(Reason, #state{module = Mod, db = DB}) ->
+ ?vlog("terminate: ~p", [Reason]),
+ Mod:close(DB).
%%----------------------------------------------------------
@@ -575,18 +624,18 @@ terminate(Reason, S) ->
%%----------------------------------------------------------
% downgrade
-code_change({down, _Vsn}, #state{db = DB, backup = B}, downgrade_to_pre_4_7) ->
- ?d("code_change(down) -> entry", []),
- stop_backup_server(B),
- S = {state, DB},
- {ok, S};
-
-% upgrade
-code_change(_Vsn, S, upgrade_from_pre_4_7) ->
- ?d("code_change(up) -> entry", []),
- {state, DB} = S,
- S1 = #state{db = DB},
- {ok, S1};
+%% code_change({down, _Vsn}, #state{db = DB, backup = B}, downgrade_to_pre_4_7) ->
+%% ?d("code_change(down) -> entry", []),
+%% stop_backup_server(B),
+%% S = {state, DB},
+%% {ok, S};
+
+%% % upgrade
+%% code_change(_Vsn, S, upgrade_from_pre_4_7) ->
+%% ?d("code_change(up) -> entry", []),
+%% {state, DB} = S,
+%% S1 = #state{db = DB},
+%% {ok, S1};
code_change(_Vsn, S, _Extra) ->
?d("code_change -> entry [do nothing]", []),
@@ -609,13 +658,13 @@ stop_backup_server({Pid, _}) when is_pid(Pid) ->
%%-----------------------------------------------------------------
%% Returns: {value, Value} | undefined
%%-----------------------------------------------------------------
-get_notif(Db, Key) ->
- case snmpa_general_db:read(Db, {trap, Key}) of
+get_notif(Mod, Db, Key) ->
+ case Mod:read(Db, {trap, Key}) of
{value,#symbol{info = Value}} -> {value, Value};
false -> undefined
end.
-set_notif(Db, MibName, Trap) when is_record(Trap, trap) ->
+set_notif(Mod, Db, MibName, Trap) when is_record(Trap, trap) ->
#trap{trapname = Name} = Trap,
Rec = #symbol{key = {trap, Name}, mib_name = MibName, info = Trap},
%% convert old v1 trap to oid
@@ -625,40 +674,41 @@ set_notif(Db, MibName, Trap) when is_record(Trap, trap) ->
Oid0 ->
Oid0 ++ [0, Trap#trap.specificcode]
end,
- write_alias(Name, Db, MibName, Oid),
- snmpa_general_db:write(Db, Rec);
-set_notif(Db, MibName, Trap) ->
+ write_alias(Mod, Name, Db, MibName, Oid),
+ Mod:write(Db, Rec);
+set_notif(Mod, Db, MibName, Trap) ->
#notification{trapname = Name, oid = Oid} = Trap,
Rec = #symbol{key = {trap, Name}, mib_name = MibName, info = Trap},
- write_alias(Name, Db, MibName, Oid),
- snmpa_general_db:write(Db, Rec).
+ write_alias(Mod, Name, Db, MibName, Oid),
+ Mod:write(Db, Rec).
-delete_notif(Db, MibName) ->
+delete_notif(Mod, Db, MibName) ->
Pattern = #symbol{key = {trap, '_'}, mib_name = MibName, info = '_'},
- snmpa_general_db:match_delete(Db, Pattern).
+ Mod:match_delete(Db, Pattern).
-write_alias(AN, DB, MibName, Oid) ->
- write_alias(AN, DB, [], MibName, Oid).
+write_alias(Mod, AN, DB, MibName, Oid) ->
+ write_alias(Mod, AN, DB, [], MibName, Oid).
-write_alias(AN, DB, Enums, MibName, Oid) ->
+write_alias(Mod, AN, DB, Enums, MibName, Oid) ->
?vlog("add alias~n ~p -> {~p,~p}",[AN, Oid, Enums]),
Rec1 = #symbol{key = {alias, AN},
mib_name = MibName,
info = {Oid,Enums}},
- snmpa_general_db:write(DB, Rec1),
+ Mod:write(DB, Rec1),
?vlog("add oid~n ~p -> ~p",[Oid, AN]),
Rec2 = #symbol{key = {oid, Oid},
mib_name = MibName,
info = AN},
- snmpa_general_db:write(DB, Rec2).
+ Mod:write(DB, Rec2).
+
%% -------------------------------------
-get_info(DB) ->
+get_info(Mod, DB) ->
ProcSize = proc_mem(self()),
- DbSz = tab_size(DB),
- [{process_memory, ProcSize}, {db_memory, DbSz}].
+ DbMemory = Mod:info(DB, memory),
+ [{process_memory, ProcSize}, {db_memory, DbMemory}].
proc_mem(P) when is_pid(P) ->
case (catch erlang:process_info(P, memory)) of
@@ -667,26 +717,15 @@ proc_mem(P) when is_pid(P) ->
_ ->
undefined
end.
-%% proc_mem(_) ->
-%% undefined.
-
-tab_size(DB) ->
- case (catch snmpa_general_db:info(DB, memory)) of
- Sz when is_integer(Sz) ->
- Sz;
- _ ->
- undefined
- end.
-
%% -------------------------------------
get_verbosity(L) ->
- snmp_misc:get_option(verbosity,L,?default_verbosity).
+ snmp_misc:get_option(verbosity, L, ?default_verbosity).
get_mib_storage(L) ->
- snmp_misc:get_option(mib_storage,L,ets).
+ snmp_misc:get_option(mib_storage, L).
%% -------------------------------------
diff --git a/lib/snmp/src/app/snmp.app.src b/lib/snmp/src/app/snmp.app.src
index dc5acbd4a0..904d17954b 100644
--- a/lib/snmp/src/app/snmp.app.src
+++ b/lib/snmp/src/app/snmp.app.src
@@ -48,12 +48,15 @@
snmpa_error_io,
snmpa_error_logger,
snmpa_error_report,
- snmpa_general_db,
snmpa_local_db,
snmpa_mib,
snmpa_mib_data,
snmpa_mib_data_tttn,
snmpa_mib_lib,
+ snmpa_mib_storage,
+ snmpa_mib_storage_ets,
+ snmpa_mib_storage_dets,
+ snmpa_mib_storage_mnesia,
snmpa_misc_sup,
snmpa_mpd,
snmpa_net_if,
diff --git a/lib/snmp/src/app/snmp_app.erl b/lib/snmp/src/app/snmp_app.erl
index deb42cc373..0cfbb22a5a 100644
--- a/lib/snmp/src/app/snmp_app.erl
+++ b/lib/snmp/src/app/snmp_app.erl
@@ -62,17 +62,17 @@ entities([], []) ->
?d("entities -> converted config: ~n~p", [Conf]),
[{agent, Conf}]
end;
-entities([], E) ->
+entities([], Acc) ->
?d("entities -> done", []),
- lists:reverse(E);
-entities([ET|ETs], E) ->
+ lists:reverse(Acc);
+entities([Ent|Ents], Acc) ->
?d("entities -> entry with"
- "~n ET: ~p", [ET]),
- case application:get_env(snmp, ET) of
+ "~n Ent: ~p", [Ent]),
+ case application:get_env(snmp, Ent) of
{ok, Conf} ->
- entities(ETs, [{ET, Conf}|E]);
+ entities(Ents, [{Ent, Conf}|Acc]);
_ ->
- entities(ETs, E)
+ entities(Ents, Acc)
end.
start_entities(_Type, []) ->
diff --git a/lib/snmp/src/misc/snmp_config.erl b/lib/snmp/src/misc/snmp_config.erl
index 0bed097b62..22fe25941c 100644
--- a/lib/snmp/src/misc/snmp_config.erl
+++ b/lib/snmp/src/misc/snmp_config.erl
@@ -238,7 +238,7 @@ config_agent_sys() ->
MibStorage =
case MibStorageType of
ets ->
- ets;
+ [{module, snmpa_mib_storage_ets}];
dets ->
DetsDir = ask("6b. Mib storage directory (absolute path)?",
DbDir, fun verify_dir/1),
@@ -248,13 +248,14 @@ config_agent_sys() ->
"default", fun verify_mib_storage_action/1),
case DetsAction of
default ->
- {dets, DetsDir};
+ [{module, snmpa_mib_storage_dets},
+ {options, [{dir, DetsDir}]}];
_ ->
- {dets, DetsDir, DetsAction}
+ [{module, snmpa_mib_storage_dets},
+ {options, [{dir, DetsDir},
+ {action, DetsAction}]}]
end;
mnesia ->
-% Nodes = ask("Mib storage nodes?", "none",
-% fun verify_mib_storage_nodes/1),
Nodes = [],
MnesiaAction = ask("6b. Mib storage [mnesia] database start "
"action "
@@ -262,11 +263,18 @@ config_agent_sys() ->
"default", fun verify_mib_storage_action/1),
case MnesiaAction of
default ->
- {mnesia, Nodes};
+ [{module, snmpa_mib_storage_mnesia},
+ {options, [{nodes, Nodes}]}];
_ ->
- {mnesia, Nodes, MnesiaAction}
+ [{module, snmpa_mib_storage_mnesia},
+ {options, [{nodes, Nodes},
+ {action, MnesiaAction}]}]
end
end,
+
+ %% Here we should ask about mib-server data module,
+ %% but as we only have one at the moment...
+
TargetCacheVerb = ask("7. Target cache verbosity "
"(silence/info/log/debug/trace)?", "silence",
fun verify_verbosity/1),
diff --git a/lib/snmp/test/snmp_agent_mibs_test.erl b/lib/snmp/test/snmp_agent_mibs_test.erl
index 3e48130fac..248fe7d83e 100644
--- a/lib/snmp/test/snmp_agent_mibs_test.erl
+++ b/lib/snmp/test/snmp_agent_mibs_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2013. 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
@@ -19,13 +19,17 @@
%%
%%----------------------------------------------------------------------
-%% Purpose:
+%% Purpose: Test suite of the agent mib-server.
+%% Some of these tests should really be in a mib-storage suite.
%%----------------------------------------------------------------------
+
-module(snmp_agent_mibs_test).
+
%%----------------------------------------------------------------------
%% Include files
%%----------------------------------------------------------------------
+
-include_lib("test_server/include/test_server.hrl").
-include("snmp_test_lib.hrl").
-include_lib("snmp/include/snmp_types.hrl").
@@ -39,13 +43,25 @@
%% External exports
%%----------------------------------------------------------------------
-export([
- all/0,groups/0,init_per_group/2,end_per_group/2,
- init_per_testcase/2, end_per_testcase/2,
- init_per_suite/1, end_per_suite/1,
+ all/0,
+ groups/0,
+
+ init_per_suite/1,
+ end_per_suite/1,
+
+ init_per_group/2,
+ end_per_group/2,
+
+ init_per_testcase/2,
+ end_per_testcase/2,
start_and_stop/1,
- size_check_ets/1,
+ size_check_ets1/1,
+ size_check_ets2/1,
+ size_check_ets2_bad_file1/1,
+ size_check_ets3/1,
+ size_check_ets3_bad_file1/1,
size_check_dets/1,
size_check_mnesia/1,
load_unload/1,
@@ -55,6 +71,7 @@
]).
+
%%----------------------------------------------------------------------
%% Internal exports
%%----------------------------------------------------------------------
@@ -71,18 +88,51 @@
%% External functions
%%======================================================================
-init_per_testcase(size_check_dets, Config) when is_list(Config) ->
- Dir = ?config(priv_dir, Config),
- DetsDir = join(Dir, "dets_dir/"),
- ?line ok = file:make_dir(DetsDir),
- [{dets_dir, DetsDir}|Config];
-init_per_testcase(size_check_mnesia, Config) when is_list(Config) ->
- Dir = ?config(priv_dir, Config),
- MnesiaDir = join(Dir, "mnesia_dir/"),
- ?line ok = file:make_dir(MnesiaDir),
- mnesia_start([{dir, MnesiaDir}]),
- [{mnesia_dir, MnesiaDir}|Config];
-init_per_testcase(cache_test, Config) when is_list(Config) ->
+init_per_suite(Config0) when is_list(Config0) ->
+
+ ?DBG("init_per_suite -> entry with"
+ "~n Config0: ~p", [Config0]),
+
+ Config1 = snmp_test_lib:init_suite_top_dir(?MODULE, Config0),
+
+ ?DBG("init_per_suite -> done when"
+ "~n Config1: ~p", [Config1]),
+
+ Config1.
+
+end_per_suite(Config) when is_list(Config) ->
+
+ ?DBG("end_per_suite -> entry with"
+ "~n Config: ~p", [Config]),
+
+ Config.
+
+
+init_per_testcase(Case, Config0) when is_list(Config0) ->
+ Config1 = snmp_test_lib:fix_data_dir(Config0),
+ CaseTopDir = snmp_test_lib:init_testcase_top_dir(Case, Config1),
+ DbDir = join(CaseTopDir, "db_dir/"),
+ ?line ok = file:make_dir(DbDir),
+ init_per_testcase2(Case, [{db_dir, DbDir},
+ {case_top_dir, CaseTopDir} | Config1]).
+
+init_per_testcase2(size_check_ets2_bad_file1, Config) when is_list(Config) ->
+ DbDir = ?config(db_dir, Config),
+ %% Create a ad file
+ ok = file:write_file(join(DbDir, "snmpa_symbolic_store.db"),
+ "calvin and hoppes play chess"),
+ Config;
+init_per_testcase2(size_check_ets3_bad_file1, Config) when is_list(Config) ->
+ DbDir = ?config(db_dir, Config),
+ %% Create a ad file
+ ok = file:write_file(join(DbDir, "snmpa_symbolic_store.db"),
+ "calvin and hoppes play chess"),
+ Config;
+init_per_testcase2(size_check_mnesia, Config) when is_list(Config) ->
+ DbDir = ?config(db_dir, Config),
+ mnesia_start([{dir, DbDir}]),
+ Config;
+init_per_testcase2(cache_test, Config) when is_list(Config) ->
Min = timer:minutes(5),
Timeout =
case lists:keysearch(tc_timeout, 1, Config) of
@@ -95,18 +145,26 @@ init_per_testcase(cache_test, Config) when is_list(Config) ->
end,
Dog = test_server:timetrap(Timeout),
[{watchdog, Dog} | Config];
-init_per_testcase(_Case, Config) when is_list(Config) ->
+init_per_testcase2(_Case, Config) when is_list(Config) ->
Config.
-end_per_testcase(size_check_dets, Config) when is_list(Config) ->
- Dir = ?config(dets_dir, Config),
- ?line ok = ?DEL_DIR(Dir),
- lists:keydelete(dets_dir, 1, Config);
+%% end_per_testcase(EtsCase, Config)
+%% when (is_list(Config) andalso
+%% ((EtsCase =:= size_check_ets2) orelse
+%% (EtsCase =:= size_check_ets3))) ->
+%% Dir = ?config(ets_dir, Config),
+%% ?line ok = ?DEL_DIR(Dir),
+%% lists:keydelete(ets_dir, 1, Config);
+%% end_per_testcase(size_check_dets, Config) when is_list(Config) ->
+%% Dir = ?config(dets_dir, Config),
+%% ?line ok = ?DEL_DIR(Dir),
+%% lists:keydelete(dets_dir, 1, Config);
end_per_testcase(size_check_mnesia, Config) when is_list(Config) ->
mnesia_stop(),
- Dir = ?config(mnesia_dir, Config),
- ?line ok = ?DEL_DIR(Dir),
- lists:keydelete(mnesia_dir, 1, Config);
+ %% Dir = ?config(db_dir, Config),
+ %% ?line ok = ?DEL_DIR(Dir),
+ %% lists:keydelete(mnesia_dir, 1, Config);
+ Config;
end_per_testcase(cache_test, Config) when is_list(Config) ->
Dog = ?config(watchdog, Config),
test_server:timetrap_cancel(Dog),
@@ -120,33 +178,40 @@ end_per_testcase(_Case, Config) when is_list(Config) ->
%%======================================================================
all() ->
-cases().
+ cases().
groups() ->
[{size_check, [],
- [size_check_ets, size_check_dets, size_check_mnesia]}].
+ [
+ size_check_ets1, % Plain ets
+ size_check_ets2, % ets with a file
+ size_check_ets2_bad_file1, % ets with a bad file
+ size_check_ets3, % ets with a checksummed file
+ size_check_ets3_bad_file1, % ets with bad file (checksummed)
+ size_check_dets, % Plain dets
+ size_check_mnesia % Plain mnesia
+ ]
+ }].
+
-init_per_group(_GroupName, Config) ->
- Config.
+init_per_group(GroupName, Config) ->
+ snmp_test_lib:init_group_top_dir(GroupName, Config).
end_per_group(_GroupName, Config) ->
- Config.
+ %% Do we really need to do this?
+ %% lists:keydelete(snmp_group_top_dir, 1, Config).
+ Config.
cases() ->
-[start_and_stop, load_unload, {group, size_check},
- me_lookup, which_mib, cache_test].
-
-init_per_suite(Config) when is_list(Config) ->
- %% Data dir points wrong
- DataDir0 = ?config(data_dir, Config),
- DataDir1 = filename:split(filename:absname(DataDir0)),
- [_|DataDir2] = lists:reverse(DataDir1),
- DataDir = filename:join(lists:reverse(DataDir2) ++ [?snmp_test_data]),
- [{snmp_data_dir, DataDir ++ "/"}|Config].
-
-end_per_suite(Config) when is_list(Config) ->
- lists:keydelete(snmp_data_dir, 1, Config).
+ [
+ start_and_stop,
+ load_unload,
+ {group, size_check},
+ me_lookup,
+ which_mib,
+ cache_test
+ ].
%%======================================================================
@@ -175,8 +240,7 @@ load_unload(suite) -> [];
load_unload(Config) when is_list(Config) ->
Prio = normal,
Verbosity = log,
- %% MibStorage = ets,
- MibDir = ?config(snmp_data_dir, Config),
+ MibDir = ?config(data_dir, Config),
?DBG("load_unload -> start symbolic store", []),
?line sym_start(Prio, Verbosity),
@@ -221,30 +285,74 @@ load_unload(Config) when is_list(Config) ->
%% ---------------------------------------------------------------------
-size_check_ets(suite) ->
+size_check_ets1(suite) ->
+ [];
+size_check_ets1(Config) when is_list(Config) ->
+ MibStorage = [{module, snmpa_mib_storage_ets}],
+ do_size_check([{mib_storage, MibStorage}|Config]).
+
+size_check_ets2(suite) ->
+ [];
+size_check_ets2(Config) when is_list(Config) ->
+ Dir = ?config(db_dir, Config),
+ MibStorage = [{module, snmpa_mib_storage_ets},
+ {options, [{dir, Dir}]}],
+ do_size_check([{mib_storage, MibStorage}|Config]).
+
+size_check_ets2_bad_file1(suite) ->
+ [];
+size_check_ets2_bad_file1(Config) when is_list(Config) ->
+ Dir = ?config(db_dir, Config),
+ %% Ensure that the bad file does not cause any problems (action = clear)
+ MibStorage = [{module, snmpa_mib_storage_ets},
+ {options, [{dir, Dir},
+ {action, clear}]}],
+ do_size_check([{mib_storage, MibStorage}|Config]).
+
+size_check_ets3(suite) ->
[];
-size_check_ets(Config) when is_list(Config) ->
- do_size_check([{mib_storage, ets}|Config]).
+size_check_ets3(Config) when is_list(Config) ->
+ Dir = ?config(db_dir, Config),
+ MibStorage = [{module, snmpa_mib_storage_ets},
+ {options, [{dir, Dir},
+ {checksum, true}]}],
+ do_size_check([{mib_storage, MibStorage}|Config]).
+
+size_check_ets3_bad_file1(suite) ->
+ [];
+size_check_ets3_bad_file1(Config) when is_list(Config) ->
+ Dir = ?config(db_dir, Config),
+ %% Ensure that the bad file does not cause any problems (action = clear)
+ MibStorage = [{module, snmpa_mib_storage_ets},
+ {options, [{dir, Dir},
+ {action, clear},
+ {checksum, true}]}],
+ do_size_check([{mib_storage, MibStorage}|Config]).
size_check_dets(suite) ->
[];
size_check_dets(Config) when is_list(Config) ->
- Dir = ?config(dets_dir, Config),
- do_size_check([{mib_storage, {dets, Dir}}|Config]).
+ Dir = ?config(db_dir, Config),
+ MibStorage = [{module, snmpa_mib_storage_dets},
+ {options, [{dir, Dir}]}],
+ do_size_check([{mib_storage, MibStorage}|Config]).
size_check_mnesia(suite) ->
[];
size_check_mnesia(Config) when is_list(Config) ->
- do_size_check([{mib_storage, {mnesia, [node()]}}|Config]).
+ MibStorage = [{module, snmpa_mib_storage_mnesia},
+ {options, [{nodes, [node()]}]}],
+ do_size_check([{mib_storage, MibStorage}|Config]).
do_size_check(Config) ->
- ?DBG("do_size_check -> start", []),
+ ?DBG("do_size_check -> start with"
+ "~n Config: ~p", [Config]),
Prio = normal,
Verbosity = trace,
MibStorage = ?config(mib_storage, Config),
?DBG("do_size_check -> MibStorage: ~p", [MibStorage]),
- MibDir = ?config(snmp_data_dir, Config),
+ MibDir = ?config(data_dir, Config),
StdMibDir = filename:join(code:priv_dir(snmp), "mibs") ++ "/",
?DBG("do_size_check -> start symbolic store", []),
@@ -294,8 +402,7 @@ me_lookup(suite) -> [];
me_lookup(Config) when is_list(Config) ->
Prio = normal,
Verbosity = trace,
- %% MibStorage = ets,
- MibDir = ?config(snmp_data_dir, Config),
+ MibDir = ?config(data_dir, Config),
StdMibDir = filename:join(code:priv_dir(snmp), "mibs") ++ "/",
Mibs = ["Test2", "TestTrap", "TestTrapv2"],
StdMibs = ["OTP-SNMPEA-MIB",
@@ -348,8 +455,7 @@ which_mib(suite) -> [];
which_mib(Config) when is_list(Config) ->
Prio = normal,
Verbosity = trace,
- %% MibStorage = ets,
- MibDir = ?config(snmp_data_dir, Config),
+ MibDir = ?config(data_dir, Config),
StdMibDir = filename:join(code:priv_dir(snmp), "mibs") ++ "/",
Mibs = ["Test2", "TestTrap", "TestTrapv2"],
StdMibs = ["OTP-SNMPEA-MIB",
@@ -406,28 +512,28 @@ cache_test(Config) when is_list(Config) ->
?DBG("cache_test -> start", []),
Prio = normal,
Verbosity = trace,
- MibStorage = ets,
- MibDir = ?config(snmp_data_dir, Config),
+ MibStorage = [{module, snmpa_mib_storage_ets}],
+ MibDir = ?config(data_dir, Config),
StdMibDir = filename:join(code:priv_dir(snmp), "mibs") ++ "/",
- Mibs = ["Test2", "TestTrap", "TestTrapv2"],
- StdMibs = ["OTP-SNMPEA-MIB",
- "SNMP-COMMUNITY-MIB",
- "SNMP-FRAMEWORK-MIB",
- "SNMP-MPD-MIB",
- "SNMP-NOTIFICATION-MIB",
- "SNMP-TARGET-MIB",
- %% "SNMP-USER-BASED-SM-MIB",
- "SNMP-VIEW-BASED-ACM-MIB",
- "SNMPv2-MIB",
- "SNMPv2-TC",
- "SNMPv2-TM"],
+ Mibs = ["Test2", "TestTrap", "TestTrapv2"],
+ StdMibs = ["OTP-SNMPEA-MIB",
+ "SNMP-COMMUNITY-MIB",
+ "SNMP-FRAMEWORK-MIB",
+ "SNMP-MPD-MIB",
+ "SNMP-NOTIFICATION-MIB",
+ "SNMP-TARGET-MIB",
+ %% "SNMP-USER-BASED-SM-MIB",
+ "SNMP-VIEW-BASED-ACM-MIB",
+ "SNMPv2-MIB",
+ "SNMPv2-TC",
+ "SNMPv2-TM"],
?DBG("cache_test -> start symbolic store", []),
?line sym_start(Prio, MibStorage, Verbosity),
?DBG("cache_test -> start mib server", []),
- GcLimit = 2,
- Age = timer:seconds(10),
+ GcLimit = 2,
+ Age = timer:seconds(10),
CacheOpts = [{autogc, false}, {age, Age}, {gclimit, GcLimit}],
?line MibsPid = mibs_start(Prio, MibStorage, [], Verbosity, CacheOpts),
@@ -537,7 +643,7 @@ mnesia_stop() ->
%% - Symbolic Store mini interface
sym_start(Prio, Verbosity) ->
- sym_start(Prio, ets, Verbosity).
+ sym_start(Prio, mib_storage(), Verbosity).
sym_start(Prio, MibStorage, Verbosity) ->
Opts = [{mib_storage, MibStorage}, {verbosity,Verbosity}],
@@ -554,7 +660,7 @@ sym_info() ->
%% -- MIB server mini interface
mibs_start(Prio, Verbosity) when is_atom(Prio) andalso is_atom(Verbosity) ->
- mibs_start(Prio, ets, [], Verbosity).
+ mibs_start(Prio, mib_storage(), [], Verbosity).
mibs_start(Prio, MibStorage, Verbosity)
when is_atom(Prio) andalso is_atom(Verbosity) ->
@@ -671,6 +777,11 @@ which_mib(M1, M2) ->
{error, {invalid_mib, M1, M2}}.
+%% Default mib-storage
+mib_storage() ->
+ [{module, snmpa_mib_storage_ets}].
+
+
%% --
display_memory_usage(MibsPid) ->
diff --git a/lib/snmp/test/snmp_agent_test.erl b/lib/snmp/test/snmp_agent_test.erl
index a8e921d67d..01f0e58bc2 100644
--- a/lib/snmp/test/snmp_agent_test.erl
+++ b/lib/snmp/test/snmp_agent_test.erl
@@ -94,19 +94,8 @@ all() ->
groups() ->
[
- {all_tcs, [], cases()},
- {mib_storage, [],
- [
- {group, mib_storage_ets},
- {group, mib_storage_dets},
- {group, mib_storage_mnesia},
- {group, mib_storage_size_check_ets},
- {group, mib_storage_size_check_dets},
- {group, mib_storage_size_check_mnesia},
- {group, mib_storage_varm_dets},
- {group, mib_storage_varm_mnesia}
- ]
- },
+ {all_tcs, [], cases()},
+ {mib_storage, [], mib_storage_cases()},
{mib_storage_ets, [], mib_storage_ets_cases()},
{mib_storage_dets, [], mib_storage_dets_cases()},
{mib_storage_mnesia, [], mib_storage_mnesia_cases()},
@@ -123,109 +112,18 @@ groups() ->
{test_multi_threaded, [], mt_cases()},
{multiple_reqs, [], mul_cases()},
{multiple_reqs_2, [], mul_cases_2()},
- {v2_inform, [],
- [
- v2_inform_i
- ]
- },
- {v3_security, [],
- [
- v3_crypto_basic,
- v3_md5_auth,
- v3_sha_auth,
- v3_des_priv
- ]
- },
- {standard_mibs, [],
- [
- snmp_standard_mib,
- snmp_community_mib,
- snmp_framework_mib,
- snmp_target_mib,
- snmp_notification_mib,
- snmp_view_based_acm_mib
- ]
- },
- {standard_mibs_2, [],
- [
- snmpv2_mib_2,
- snmp_community_mib_2,
- snmp_framework_mib_2,
- snmp_target_mib_2,
- snmp_notification_mib_2,
- snmp_view_based_acm_mib_2
- ]
- },
- {standard_mibs_3, [],
- [
- snmpv2_mib_3,
- snmp_framework_mib_3,
- snmp_mpd_mib_3,
- snmp_target_mib_3,
- snmp_notification_mib_3,
- snmp_view_based_acm_mib_3,
- snmp_user_based_sm_mib_3
- ]
- },
- {reported_bugs, [],
- [
- otp_1128,
- otp_1129,
- otp_1131,
- otp_1162,
- otp_1222,
- otp_1298,
- otp_1331,
- otp_1338,
- otp_1342,
- otp_2776,
- otp_2979,
- otp_3187,
- otp_3725
- ]
- },
- {reported_bugs_2, [],
- [
- otp_1128_2,
- otp_1129_2,
- otp_1131_2,
- otp_1162_2,
- otp_1222_2,
- otp_1298_2,
- otp_1331_2,
- otp_1338_2,
- otp_1342_2,
- otp_2776_2,
- otp_2979_2,
- otp_3187_2
- ]
- },
- {reported_bugs_3, [],
- [
- otp_1128_3,
- otp_1129_3,
- otp_1131_3,
- otp_1162_3,
- otp_1222_3,
- otp_1298_3,
- otp_1331_3,
- otp_1338_3,
- otp_1342_3,
- otp_2776_3,
- otp_2979_3,
- otp_3187_3,
- otp_3542
- ]
- },
- {tickets1, [],
- [
- {group, otp_4394},
- {group, otp_7157}
- ]
- },
- {tickets2, [], [otp8395, otp9884]},
- {otp_4394, [], [otp_4394_test]},
- {otp_7157, [], [otp_7157_test]}
+ {v2_inform, [], v2_inform_cases()},
+ {v3_security, [], v3_security_cases()},
+ {standard_mibs, [], standard_mibs_cases()},
+ {standard_mibs_2, [], standard_mibs2_cases()},
+ {standard_mibs_3, [], standard_mibs3_cases()},
+ {reported_bugs, [], reported_bugs_cases()},
+ {reported_bugs_2, [], reported_bugs2_cases()},
+ {reported_bugs_3, [], reported_bugs3_cases()},
+ {tickets1, [], tickets1_cases()},
+ {tickets2, [], tickets2_cases()},
+ {otp_4394, [], [otp_4394_test]},
+ {otp_7157, [], [otp_7157_test]}
].
@@ -456,14 +354,14 @@ end_per_testcase2(_Case, Config) ->
cases() ->
[
- {group, misc},
- {group, test_v1},
- {group, test_v2},
- {group, test_v1_v2},
- {group, test_v3},
- {group, test_multi_threaded},
- {group, mib_storage},
- {group, tickets1}
+ {group, misc},
+ {group, test_v1},
+ {group, test_v2},
+ {group, test_v1_v2},
+ {group, test_v3},
+ {group, test_multi_threaded},
+ {group, mib_storage},
+ {group, tickets1}
].
@@ -549,7 +447,7 @@ delete_tables() ->
mnesia:delete_table(kompissTable2),
mnesia:delete_table(snmp_variables).
-%% Creation is done in runtime!
+%% Tables are created in runtime!
delete_mib_storage_mnesia_tables() ->
mnesia:delete_table(snmpa_mib_data),
mnesia:delete_table(snmpa_mib_tree),
@@ -572,40 +470,89 @@ delete_mib_storage_mnesia_tables() ->
%% versions as well, <base>_N.
%%-----------------------------------------------------------------
-
-
-
-
-
-
-
-
+mib_storage_cases() ->
+ [
+ {group, mib_storage_ets},
+ {group, mib_storage_dets},
+ {group, mib_storage_mnesia},
+ {group, mib_storage_size_check_ets},
+ {group, mib_storage_size_check_dets},
+ {group, mib_storage_size_check_mnesia},
+ {group, mib_storage_varm_dets},
+ {group, mib_storage_varm_mnesia}
+ ].
+
mib_storage_ets_cases() ->
-[mse_simple, mse_v1_processing, mse_big, mse_big2,
- mse_loop_mib, mse_api, mse_sa_register, mse_v1_trap,
- mse_sa_error, mse_next_across_sa, mse_undo,
- mse_standard_mib, mse_community_mib, mse_framework_mib,
- mse_target_mib, mse_notification_mib,
- mse_view_based_acm_mib, mse_sparse_table, mse_me_of,
- mse_mib_of].
+ [
+ mse_simple,
+ mse_v1_processing,
+ mse_big,
+ mse_big2,
+ mse_loop_mib,
+ mse_api,
+ mse_sa_register,
+ mse_v1_trap,
+ mse_sa_error,
+ mse_next_across_sa,
+ mse_undo,
+ mse_standard_mib,
+ mse_community_mib,
+ mse_framework_mib,
+ mse_target_mib,
+ mse_notification_mib,
+ mse_view_based_acm_mib,
+ mse_sparse_table,
+ mse_me_of,
+ mse_mib_of
+ ].
mib_storage_dets_cases() ->
-[msd_simple, msd_v1_processing, msd_big, msd_big2,
- msd_loop_mib, msd_api, msd_sa_register, msd_v1_trap,
- msd_sa_error, msd_next_across_sa, msd_undo,
- msd_standard_mib, msd_community_mib, msd_framework_mib,
- msd_target_mib, msd_notification_mib,
- msd_view_based_acm_mib, msd_sparse_table, msd_me_of,
- msd_mib_of].
+ [
+ msd_simple,
+ msd_v1_processing,
+ msd_big,
+ msd_big2,
+ msd_loop_mib,
+ msd_api,
+ msd_sa_register,
+ msd_v1_trap,
+ msd_sa_error,
+ msd_next_across_sa,
+ msd_undo,
+ msd_standard_mib,
+ msd_community_mib,
+ msd_framework_mib,
+ msd_target_mib,
+ msd_notification_mib,
+ msd_view_based_acm_mib,
+ msd_sparse_table,
+ msd_me_of,
+ msd_mib_of
+ ].
mib_storage_mnesia_cases() ->
-[msm_simple, msm_v1_processing, msm_big, msm_big2,
- msm_loop_mib, msm_api, msm_sa_register, msm_v1_trap,
- msm_sa_error, msm_next_across_sa, msm_undo,
- msm_standard_mib, msm_community_mib, msm_framework_mib,
- msm_target_mib, msm_notification_mib,
- msm_view_based_acm_mib, msm_sparse_table, msm_me_of,
- msm_mib_of].
+ [
+ msm_simple,
+ msm_v1_processing,
+ msm_big,
+ msm_big2,
+ msm_loop_mib,
+ msm_api,
+ msm_sa_register,
+ msm_v1_trap,
+ msm_sa_error,
+ msm_next_across_sa,
+ msm_undo,
+ msm_standard_mib,
+ msm_community_mib,
+ msm_framework_mib,
+ msm_target_mib,
+ msm_notification_mib,
+ msm_view_based_acm_mib,
+ msm_sparse_table,
+ msm_me_of,
+ msm_mib_of
+ ].
mse_size_check_cases() ->
[mse_size_check].
@@ -624,18 +571,21 @@ varm_mib_storage_mnesia_cases() ->
init_mib_storage_ets(Config) when is_list(Config) ->
?LOG("init_mib_storage_ets -> entry", []),
- MibStorage = {snmp_mib_storage,ets},
+ MibStorage = {mib_storage, [{module, snmpa_mib_storage_ets}]},
init_ms(Config, [MibStorage]).
init_mib_storage_dets(Config) when is_list(Config) ->
?LOG("init_mib_storage_dets -> entry", []),
?line AgentDbDir = ?GCONF(agent_db_dir, Config),
- MibStorage = {snmp_mib_storage, {dets, AgentDbDir}},
+ MibStorage = {mib_storage, [{module, snmpa_mib_storage_dets},
+ {options, [{dir, AgentDbDir}]}]},
init_ms(Config, [MibStorage]).
init_mib_storage_mnesia(Config) when is_list(Config) ->
?LOG("init_mib_storage_mnesia -> entry", []),
- MibStorage = {snmp_mib_storage, {mnesia,[]}},
+ ?line AgentNode = ?GCONF(snmp_master, Config),
+ MibStorage = {mib_storage, [{module, snmpa_mib_storage_mnesia},
+ {options, [{nodes, [AgentNode]}]}]},
init_ms(Config, [MibStorage]).
init_ms(Config, Opts) when is_list(Config) ->
@@ -649,23 +599,26 @@ init_ms(Config, Opts) when is_list(Config) ->
?line Ip = ?GCONF(ip, Config),
?line config([v1], MgrDir, AgentConfDir,
tuple_to_list(Ip), tuple_to_list(Ip)),
- MasterAgentVerbosity = {snmp_master_agent_verbosity, trace},
- MibsVerbosity = {snmp_mibserver_verbosity, trace},
- SymStoreVerbosity = {snmp_symbolic_store_verbosity, trace},
+ MasterAgentVerbosity = {agent_verbosity, trace},
+ MibsVerbosity = {mib_server, [{verbosity, trace}]},
+ SymStoreVerbosity = {symbolic_store, [{verbosity, trace}]},
Opts1 = [MasterAgentVerbosity, MibsVerbosity, SymStoreVerbosity | Opts],
[{vsn, v1} | start_v1_agent(Config, Opts1)].
init_size_check_mse(Config) when is_list(Config) ->
- MibStorage = {snmp_mib_storage, ets},
+ MibStorage = {mib_storage, [{module, snmpa_mib_storage_ets}]},
init_size_check_ms(Config, [MibStorage]).
init_size_check_msd(Config) when is_list(Config) ->
AgentDbDir = ?GCONF(agent_db_dir, Config),
- MibStorage = {snmp_mib_storage, {dets, AgentDbDir}},
+ MibStorage = {mib_storage, [{module, snmpa_mib_storage_dets},
+ {options, [{dir, AgentDbDir}]}]},
init_size_check_ms(Config, [MibStorage]).
init_size_check_msm(Config) when is_list(Config) ->
- MibStorage = {snmp_mib_storage, {mnesia,[]}},
+ ?line AgentNode = ?GCONF(snmp_master, Config),
+ MibStorage = {mib_storage, [{module, snmpa_mib_storage_mnesia},
+ {options, [{nodes, [AgentNode]}]}]},
init_size_check_ms(Config, [MibStorage]).
init_size_check_ms(Config, Opts) when is_list(Config) ->
@@ -700,12 +653,16 @@ init_varm_mib_storage_dets(Config) when is_list(Config) ->
?line Ip = ?GCONF(ip, Config),
?line config([v1], MgrDir, AgentConfDir,
tuple_to_list(Ip), tuple_to_list(Ip)),
- MibStorage = {snmp_mib_storage, {dets, AgentDbDir}},
- MasterAgentVerbosity = {snmp_master_agent_verbosity, trace},
- MibsVerbosity = {snmp_mibserver_verbosity, trace},
- SymStoreVerbosity = {snmp_symbolic_store_verbosity, trace},
- Opts = [MibStorage,MasterAgentVerbosity,MibsVerbosity,SymStoreVerbosity],
- [{vsn, v1}, {agent_opts,Opts} | Config].
+ MibStorage = {mib_storage, [{module, snmpa_mib_storage_dets},
+ {options, [{dir, AgentDbDir}]}]},
+ MasterAgentVerbosity = {agent_verbosity, trace},
+ MibsVerbosity = {mib_server, [{verbosity, trace}]},
+ SymStoreVerbosity = {symbolic_store, [{verbosity, trace}]},
+ Opts = [MibStorage,
+ MasterAgentVerbosity,
+ MibsVerbosity,
+ SymStoreVerbosity],
+ [{vsn, v1}, {agent_opts, Opts} | Config].
init_varm_mib_storage_mnesia(Config) when is_list(Config) ->
?LOG("init_varm_mib_storage_mnesia -> entry", []),
@@ -716,12 +673,17 @@ init_varm_mib_storage_mnesia(Config) when is_list(Config) ->
?line Ip = ?GCONF(ip, Config),
?line config([v1], MgrDir, AgentConfDir,
tuple_to_list(Ip), tuple_to_list(Ip)),
- MibStorage = {snmp_mib_storage,{mnesia,[]}},
- MasterAgentVerbosity = {snmp_master_agent_verbosity, trace},
- MibsVerbosity = {snmp_mibserver_verbosity, trace},
- SymStoreVerbosity = {snmp_symbolic_store_verbosity, trace},
- Opts = [MibStorage,MasterAgentVerbosity,MibsVerbosity,SymStoreVerbosity],
- [{vsn, v1}, {agent_opts,Opts} | Config].
+ ?line AgentNode = ?GCONF(snmp_master, Config),
+ MibStorage = {mib_storage, [{module, snmpa_mib_storage_mnesia},
+ {options, [{nodes, [AgentNode]}]}]},
+ MasterAgentVerbosity = {agent_verbosity, trace},
+ MibsVerbosity = {mib_server, [{verbosity, trace}]},
+ SymStoreVerbosity = {symbolic_store, [{verbosity, trace}]},
+ Opts = [MibStorage,
+ MasterAgentVerbosity,
+ MibsVerbosity,
+ SymStoreVerbosity],
+ [{vsn, v1}, {agent_opts, Opts} | Config].
finish_mib_storage_ets(Config) when is_list(Config) ->
?LOG("finish_mib_storage_ets -> entry", []),
@@ -1117,7 +1079,10 @@ finish_misc(Config) ->
finish_v1(Config).
misc_cases() ->
-[app_info, info_test].
+ [
+ app_info,
+ info_test
+ ].
app_info(suite) -> [];
app_info(Config) when is_list(Config) ->
@@ -1816,23 +1781,38 @@ mnesia_2(X) -> ?P(mnesia_2), mnesia(X).
mnesia_3(X) -> ?P(mnesia_3), mnesia(X).
-
mul_cases() ->
-[mul_get, mul_get_err, mul_next, mul_next_err,
- mul_set_err].
-
+ [
+ mul_get,
+ mul_get_err,
+ mul_next,
+ mul_next_err,
+ mul_set_err
+ ].
+
multiple_reqs_3(_X) ->
{req, [], {conf, init_mul, mul_cases_3(), finish_mul}}.
mul_cases_2() ->
-[mul_get_2, mul_get_err_2, mul_next_2, mul_next_err_2,
- mul_set_err_2].
-
+ [
+ mul_get_2,
+ mul_get_err_2,
+ mul_next_2,
+ mul_next_err_2,
+ mul_set_err_2
+ ].
+
mul_cases_3() ->
- [mul_get_3, mul_get_err_3, mul_next_3, mul_next_err_3, mul_set_err_3].
+ [
+ mul_get_3,
+ mul_get_err_3,
+ mul_next_3,
+ mul_next_err_3,
+ mul_set_err_3
+ ].
init_mul(Config) when is_list(Config) ->
@@ -2055,7 +2035,6 @@ v3_trap(Config) when is_list(Config) ->
v3_inform(_X) ->
- %% v2_inform(X).
{req, [], {conf, init_v3_inform, [v3_inform_i], finish_v3_inform}}.
init_v2_inform(Config) when is_list(Config) ->
@@ -2075,6 +2054,10 @@ finish_v3_inform(X) ->
finish_v2_inform(X).
+v2_inform_cases() ->
+ [
+ v2_inform_i
+ ].
v2_inform_i(suite) -> [];
v2_inform_i(Config) when is_list(Config) ->
@@ -2313,6 +2296,15 @@ v3_processing(Config) when is_list(Config) ->
%% report, which makes it in sync. The notification-generating
%% application times out, and send again. This time it'll work.
+v3_security_cases() ->
+ [
+ v3_crypto_basic,
+ v3_md5_auth,
+ v3_sha_auth,
+ v3_des_priv
+ ].
+
+
v3_crypto_basic(suite) -> [];
v3_crypto_basic(_Config) ->
?P(v3_crypto_basic),
@@ -4193,7 +4185,16 @@ bad_return() ->
%%% already tested by the normal tests.
%%%-----------------------------------------------------------------
-
+standard_mibs_cases() ->
+ [
+ snmp_standard_mib,
+ snmp_community_mib,
+ snmp_framework_mib,
+ snmp_target_mib,
+ snmp_notification_mib,
+ snmp_view_based_acm_mib
+ ].
+
%%-----------------------------------------------------------------
%% For this test, the agent is configured for v1.
@@ -4277,6 +4278,18 @@ std_mib_write() ->
std_mib_asn_err() ->
snmp_test_mgr:send_bytes([48,99,67,12,0,0,0,0,0,0,5]).
+
+standard_mibs2_cases() ->
+ [
+ snmpv2_mib_2,
+ snmp_community_mib_2,
+ snmp_framework_mib_2,
+ snmp_target_mib_2,
+ snmp_notification_mib_2,
+ snmp_view_based_acm_mib_2
+ ].
+
+
%%-----------------------------------------------------------------
%% For this test, the agent is configured for v2 and v3.
%% o Test the counters and control objects in SNMPv2-MIB
@@ -4325,6 +4338,19 @@ snmpv2_mib_2(Config) when is_list(Config) ->
?LOG("snmpv2_mib_2 -> done",[]).
+
+standard_mibs3_cases() ->
+ [
+ snmpv2_mib_3,
+ snmp_framework_mib_3,
+ snmp_mpd_mib_3,
+ snmp_target_mib_3,
+ snmp_notification_mib_3,
+ snmp_view_based_acm_mib_3,
+ snmp_user_based_sm_mib_3
+ ].
+
+
%% Req. SNMPv2-MIB
snmpv2_mib_3(suite) -> [];
snmpv2_mib_3(Config) when is_list(Config) ->
@@ -5237,7 +5263,57 @@ loop_it_2(Oid, N) ->
%%% Testing of reported bugs and other tickets.
%%%-----------------------------------------------------------------
+reported_bugs_cases() ->
+ [
+ otp_1128,
+ otp_1129,
+ otp_1131,
+ otp_1162,
+ otp_1222,
+ otp_1298,
+ otp_1331,
+ otp_1338,
+ otp_1342,
+ otp_2776,
+ otp_2979,
+ otp_3187,
+ otp_3725
+ ].
+
+reported_bugs2_cases() ->
+ [
+ otp_1128_2,
+ otp_1129_2,
+ otp_1131_2,
+ otp_1162_2,
+ otp_1222_2,
+ otp_1298_2,
+ otp_1331_2,
+ otp_1338_2,
+ otp_1342_2,
+ otp_2776_2,
+ otp_2979_2,
+ otp_3187_2
+ ].
+reported_bugs3_cases() ->
+ [
+ otp_1128_3,
+ otp_1129_3,
+ otp_1131_3,
+ otp_1162_3,
+ otp_1222_3,
+ otp_1298_3,
+ otp_1331_3,
+ otp_1338_3,
+ otp_1342_3,
+ otp_2776_3,
+ otp_2979_3,
+ otp_3187_3,
+ otp_3542
+ ].
+
+
%%-----------------------------------------------------------------
%% Ticket: OTP-1128
%% Slogan: Bug in handling of createAndWait set-requests.
@@ -5714,7 +5790,12 @@ otp_3725_test(MaNode) ->
%% Slogan: Target mib tag list check invalid
%%-----------------------------------------------------------------
-
+tickets1_cases() ->
+ [
+ {group, otp_4394},
+ {group, otp_7157}
+ ].
+
init_otp_4394(Config) when is_list(Config) ->
?DBG("init_otp_4394 -> entry with"
@@ -5876,6 +5957,13 @@ otp_7157_test1(MA) ->
%% These cases are started in the new way
%%-----------------------------------------------------------------
+tickets2_cases() ->
+ [
+ otp8395,
+ otp9884
+ ].
+
+
otp8395({init, Config}) when is_list(Config) ->
?DBG("otp8395(init) -> entry with"
"~n Config: ~p", [Config]),
diff --git a/lib/snmp/test/snmp_agent_test_lib.erl b/lib/snmp/test/snmp_agent_test_lib.erl
index 757aebfa9b..2c24dd3712 100644
--- a/lib/snmp/test/snmp_agent_test_lib.erl
+++ b/lib/snmp/test/snmp_agent_test_lib.erl
@@ -28,7 +28,7 @@
start_mt_agent/1, start_mt_agent/2,
stop_agent/1,
- start_sup/0, stop_sup/2,
+ %% start_sup/0, stop_sup/2,
start_subagent/3, stop_subagent/1,
start_sub_sup/1, start_sub_sup/2,
@@ -418,10 +418,10 @@ start_bilingual_agent(Config, Opts)
start_agent(Config, [v1,v2], Opts).
start_mt_agent(Config) when is_list(Config) ->
- start_agent(Config, [v2], [{snmp_multi_threaded, true}]).
+ start_agent(Config, [v2], [{multi_threaded, true}]).
start_mt_agent(Config, Opts) when is_list(Config) andalso is_list(Opts) ->
- start_agent(Config, [v2], [{snmp_multi_threaded, true}|Opts]).
+ start_agent(Config, [v2], [{multi_threaded, true}|Opts]).
start_agent(Config, Vsns) ->
start_agent(Config, Vsns, []).
@@ -437,79 +437,231 @@ start_agent(Config, Vsns, Opts) ->
?line AgentDbDir = ?config(agent_db_dir, Config),
?line SaNode = ?config(snmp_sa, Config),
- app_env_init(vsn_init(Vsns) ++
- [{audit_trail_log, read_write_log},
- {audit_trail_log_dir, AgentLogDir},
- {audit_trail_log_size, {10240, 10}},
- {force_config_reload, false},
- {snmp_agent_type, master},
- {snmp_config_dir, AgentConfDir},
- {snmp_db_dir, AgentDbDir},
- {snmp_local_db_auto_repair, true},
- {snmp_local_db_verbosity, log},
- {snmp_master_agent_verbosity, trace},
- {snmp_supervisor_verbosity, trace},
- {snmp_mibserver_verbosity, log},
- {snmp_symbolic_store_verbosity, log},
- {snmp_note_store_verbosity, log},
- {snmp_net_if_verbosity, trace}],
- Opts),
-
+ Env = app_agent_env_init(
+ [{versions, Vsns},
+ {agent_type, master},
+ {agent_verbosity, trace},
+ {db_dir, AgentDbDir},
+ {audit_trail_log, [{type, read_write},
+ {dir, AgentLogDir},
+ {size, {10240, 10}}]},
+ {config, [{dir, AgentConfDir},
+ {force_load, false},
+ {verbosity, trace}]},
+ {local_db, [{repair, true},
+ {verbosity, log}]},
+ {mib_server, [{verbosity, log}]},
+ {symbolic_store, [{verbosity, log}]},
+ {note_store, [{verbosity, log}]},
+ {net_if, [{verbosity, trace}]}],
+ Opts),
+
process_flag(trap_exit,true),
{ok, AppSup} = snmp_app_sup:start_link(),
unlink(AppSup),
- ?DBG("start_agent -> snmp app supervisor: ~p",[AppSup]),
+ ?DBG("start_agent -> snmp app supervisor: ~p", [AppSup]),
- ?DBG("start_agent -> start master agent (old style)",[]),
- ?line Sup = start_sup(),
+ ?DBG("start_agent -> start master agent",[]),
+ ?line Sup = start_sup(Env),
- ?DBG("start_agent -> unlink from supervisor",[]),
+ ?DBG("start_agent -> unlink from supervisor", []),
?line unlink(Sup),
?line SaDir = ?config(sa_dir, Config),
- ?DBG("start_agent -> (rpc) start sub on ~p",[SaNode]),
+ ?DBG("start_agent -> (rpc) start sub on ~p", [SaNode]),
?line {ok, Sub} = start_sub_sup(SaNode, SaDir),
?DBG("start_agent -> done",[]),
?line [{snmp_sup, {Sup, self()}}, {snmp_sub, Sub} | Config].
-vsn_init(Vsn) ->
- vsn_init([v1,v2,v3], Vsn, []).
+app_agent_env_init(Env0, Opts) ->
+ ?DBG("app_agent_env_init -> unload snmp",[]),
+ ?line application:unload(snmp),
+
+ ?DBG("app_agent_env_init -> load snmp",[]),
+ ?line application:load(snmp),
-vsn_init([], _Vsn, Acc) ->
- Acc;
-vsn_init([V|Vsns], Vsn, Acc) ->
- case lists:member(V, Vsn) of
- true ->
- vsn_init(Vsns, Vsn, [{V, true}|Acc]);
- false ->
- vsn_init(Vsns, Vsn, [{V, false}|Acc])
+ ?DBG("app_agent_env_init -> "
+ "merge or maybe replace (snmp agent) app env",[]),
+ Env = add_or_maybe_merge_agent_env(Opts, Env0),
+ ?DBG("app_agent_env_init -> merged env: "
+ "~n ~p", [Env]),
+
+ %% We put it into the app environment just as
+ %% a precaution, since when starting normally,
+ %% this is where the environment is extracted from.
+ app_agent_set_env(Env),
+ Env.
+
+app_agent_set_env(Value) ->
+ application_controller:set_env(snmp, agent, Value).
+
+add_or_maybe_merge_agent_env([], Env) ->
+ ?DBG("merging agent env -> merged", []),
+ lists:keysort(1, Env);
+add_or_maybe_merge_agent_env([{Key, Value1}|Opts], Env) ->
+ ?DBG("merging agent env -> add, replace or merge ~p", [Key]),
+ case lists:keysearch(Key, 1, Env) of
+ {value, {Key, Value1}} ->
+ %% Identical, move on
+ ?DBG("merging agent env -> "
+ "no need to merge ~p - identical - keep: "
+ "~n ~p", [Key, Value1]),
+ add_or_maybe_merge_agent_env(Opts, Env);
+ {value, {Key, Value2}} ->
+ %% Another value, merge or replace
+ NewValue = merge_or_replace_agent_env(Key, Value1, Value2),
+ Env2 = lists:keyreplace(Key, 1, Env, {Key, NewValue}),
+ add_or_maybe_merge_agent_env(Opts, Env2);
+ false ->
+ ?DBG("merging agent env -> no old ~p to merge with - add: "
+ "~n ~p", [Key, Value1]),
+ add_or_maybe_merge_agent_env(Opts, [{Key, Value1}|Env])
end.
-app_env_init(Env0, Opts) ->
- ?DBG("app_env_init -> unload snmp",[]),
- ?line application:unload(snmp),
- ?DBG("app_env_init -> load snmp",[]),
- ?line application:load(snmp),
- ?DBG("app_env_init -> initiate (snmp) application env",[]),
- F1 = fun({Key, Val} = New, Acc0) ->
- ?DBG("app_env_init -> "
- "updating setting ~p to ~p", [Key, Val]),
- case lists:keyreplace(Key, 1, Acc0, New) of
- Acc0 ->
- [New|Acc0];
- Acc ->
- Acc
- end
- end,
- Env = lists:foldr(F1, Env0, Opts),
- ?DBG("app_env_init -> Env: ~p",[Env]),
- F2 = fun({Key,Val}) ->
- ?DBG("app_env_init -> setting ~p to ~p",[Key, Val]),
- application_controller:set_env(snmp, Key, Val)
- end,
- lists:foreach(F2, Env).
+merge_or_replace_agent_env(versions, NewVersions, _OldVersions) ->
+ ?DBG("merging agent env -> versions replaced: ~p -> ~p",
+ [NewVersions, _OldVersions]),
+ NewVersions;
+merge_or_replace_agent_env(agent_type, NewType, _OldType) ->
+ ?DBG("merging agent env -> agent type replaced: ~p -> ~p",
+ [NewType, _OldType]),
+ NewType;
+merge_or_replace_agent_env(agent_verbosity, NewVerbosity, _OldVerbosity) ->
+ ?DBG("merging agent env -> agent verbosity replaced: ~p -> ~p",
+ [NewVerbosity, _OldVerbosity]),
+ NewVerbosity;
+merge_or_replace_agent_env(db_dir, NewDbDir, _OldDbDir) ->
+ ?DBG("merging agent env -> db-dir replaced: ~p -> ~p",
+ [NewDbDir, _OldDbDir]),
+ NewDbDir;
+merge_or_replace_agent_env(audit_trail_log, NewATL, OldATL) ->
+ merge_or_replace_agent_env_atl(NewATL, OldATL);
+merge_or_replace_agent_env(config, NewConfig, OldConfig) ->
+ merge_or_replace_agent_env_config(NewConfig, OldConfig);
+merge_or_replace_agent_env(local_db, NewLdb, OldLdb) ->
+ merge_or_replace_agent_env_ldb(NewLdb, OldLdb);
+merge_or_replace_agent_env(mib_storage, NewMst, OldMst) ->
+ merge_or_replace_agent_env_mib_storage(NewMst, OldMst);
+merge_or_replace_agent_env(mib_server, NewMibs, OldMibs) ->
+ merge_or_replace_agent_env_mib_server(NewMibs, OldMibs);
+merge_or_replace_agent_env(symbolic_store, NewSymStore, OldSymStore) ->
+ merge_or_replace_agent_env_symbolic_store(NewSymStore, OldSymStore);
+merge_or_replace_agent_env(note_store, NewNoteStore, OldNoteStore) ->
+ merge_or_replace_agent_env_note_store(NewNoteStore, OldNoteStore);
+merge_or_replace_agent_env(net_if, NewNetIf, OldNetIf) ->
+ merge_or_replace_agent_env_net_if(NewNetIf, OldNetIf);
+merge_or_replace_agent_env(Key, NewValue, OldValue) ->
+ ?FAIL({not_implemented_merge_or_replace,
+ Key, NewValue, OldValue}).
+
+merge_or_replace_agent_env_atl(New, Old) ->
+ ATL = merge_agent_options(New, Old),
+ ?DBG("merging agent env -> audit-trail-log merged: "
+ "~n ~p | ~p -> ~p", [New, Old, ATL]),
+ ATL.
+
+merge_or_replace_agent_env_config(New, Old) ->
+ Config = merge_agent_options(New, Old),
+ case lists:keymember(dir, 1, Config) of
+ true ->
+ ?DBG("merging agent env -> config merged: "
+ "~n ~p | ~p -> ~p", [New, Old, Config]),
+ Config;
+ false ->
+ ?FAIL({missing_mandatory_option, {config, dir}})
+ end.
+
+merge_or_replace_agent_env_ldb(New, Old) ->
+ LDB = merge_agent_options(New, Old),
+ ?DBG("merging agent env -> local-db merged: "
+ "~n ~p | ~p -> ~p", [New, Old, LDB]),
+ LDB.
+
+merge_or_replace_agent_env_mib_storage(NewMibStorage, OldMibStorage) ->
+ %% Shall we merge or replace?
+ %% module is mandatory. We will only merge if NewModule is
+ %% equal to OldModule.
+ NewModule =
+ case lists:keysearch(module, 1, NewMibStorage) of
+ {value, {module, M}} ->
+ M;
+ false ->
+ ?FAIL({missing_mandatory_option, {mib_storage, module}})
+ end,
+ case lists:keysearch(module, 1, OldMibStorage) of
+ {value, {module, NewModule}} ->
+ %% Same module => merge
+ %% Non-ex new options => remove
+ %% Ex new options and non-ex old options => replace
+ %% Otherwise merge
+ case lists:keysearch(options, 1, NewMibStorage) of
+ false ->
+ ?DBG("merging agent env -> "
+ "no mib-storage ~p merge needed - "
+ "no new options (= remove old options)", [NewModule]),
+ NewMibStorage;
+ {value, {options, NewOptions}} ->
+ case lists:keysearch(options, 1, OldMibStorage) of
+ false ->
+ ?DBG("merging agent env -> "
+ "no mib-storage ~p merge needed - "
+ "no old options", [NewModule]),
+ NewMibStorage;
+ {value, {options, OldOptions}} ->
+ MergedOptions =
+ merge_agent_options(NewOptions, OldOptions),
+ ?DBG("merging agent env -> mib-storage ~p merged: "
+ "~n Options: ~p | ~p -> ~p",
+ [NewModule,
+ NewOptions, OldOptions, MergedOptions]),
+ [{module, NewModule},
+ {options, MergedOptions}]
+ end
+ end;
+ _ ->
+ %% Diff module => replace
+ ?DBG("merging agent env -> "
+ "no mib-storage ~p merge needed - "
+ "new module", [NewModule]),
+ NewMibStorage
+ end.
+
+merge_or_replace_agent_env_mib_server(New, Old) ->
+ MibServer = merge_agent_options(New, Old),
+ ?DBG("merging agent env -> mib-server merged: "
+ "~n ~p | ~p -> ~p", [New, Old, MibServer]),
+ MibServer.
+
+merge_or_replace_agent_env_symbolic_store(New, Old) ->
+ SymbolicStore = merge_agent_options(New, Old),
+ ?DBG("merging agent env -> symbolic-store merged: "
+ "~n ~p | ~p -> ~p", [New, Old, SymbolicStore]),
+ SymbolicStore.
+
+merge_or_replace_agent_env_note_store(New, Old) ->
+ NoteStore = merge_agent_options(New, Old),
+ ?DBG("merging agent env -> note-store merged: "
+ "~n ~p | ~p -> ~p", [New, Old, NoteStore]),
+ NoteStore.
+
+merge_or_replace_agent_env_net_if(New, Old) ->
+ NetIf = merge_agent_options(New, Old),
+ ?DBG("merging agent env -> net-if merged: "
+ "~n ~p | ~p -> ~p", [New, Old, NetIf]),
+ NetIf.
+
+merge_agent_options([], Options) ->
+ lists:keysort(1, Options);
+merge_agent_options([{Key, _Value} = Opt|Opts], Options) ->
+ case lists:keysearch(Key, 1, Options) of
+ {value, _} ->
+ NewOptions = lists:keyreplace(Key, 1, Options, Opt),
+ merge_agent_options(Opts, NewOptions);
+ false ->
+ merge_agent_options(Opts, [Opt|Options])
+ end.
stop_agent(Config) when is_list(Config) ->
@@ -544,8 +696,8 @@ stop_agent(Config) when is_list(Config) ->
lists:keydelete(snmp_sub, 1, C1).
-start_sup() ->
- case (catch snmpa_app:start(normal)) of
+start_sup(Env) ->
+ case (catch snmp_app_sup:start_agent(normal, Env)) of
{ok, S} ->
?DBG("start_agent -> started, Sup: ~p",[S]),
S;
@@ -553,7 +705,7 @@ start_sup() ->
Else ->
?DBG("start_agent -> unknown result: ~n~p",[Else]),
%% Get info about the apps we depend on
- ?FAIL({start_failed,Else, ?IS_MNESIA_RUNNING()})
+ ?FAIL({start_failed, Else, ?IS_MNESIA_RUNNING()})
end.
stop_sup(Pid, _) when (node(Pid) =:= node()) ->
@@ -594,7 +746,7 @@ start_sub_sup(Node, Dir) ->
start_sub_sup(Dir) ->
?DBG("start_sub -> entry",[]),
- Opts = [{db_dir, Dir},
+ Opts = [{db_dir, Dir},
{supervisor, [{verbosity, trace}]}],
{ok, P} = snmpa_supervisor:start_sub_sup(Opts),
unlink(P),
diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl
index 42a42b7fd7..cebc9c91bd 100644
--- a/lib/stdlib/src/otp_internal.erl
+++ b/lib/stdlib/src/otp_internal.erl
@@ -250,10 +250,12 @@ obsolete_1(snmp, N, A) ->
false ->
no;
true ->
- {deprecated,"Deprecated; use snmpa:"++atom_to_list(N)++"/"++
+ {deprecated, "Deprecated (will be removed in R17B); use snmpa:"++atom_to_list(N)++"/"++
integer_to_list(A)++" instead"}
end;
+obsolete_1(snmpa, old_info_format, 1) ->
+ {deprecated, "Deprecated; (will be removed in R17B); use \"new\" format instead"};
obsolete_1(snmpm, agent_info, 3) ->
{removed, {snmpm, agent_info, 2}, "R16B"};
obsolete_1(snmpm, update_agent_info, 5) ->