aboutsummaryrefslogtreecommitdiffstats
path: root/lib/snmp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/snmp')
-rw-r--r--lib/snmp/Makefile12
-rw-r--r--lib/snmp/doc/src/notes.xml44
-rw-r--r--lib/snmp/doc/src/snmpa_mib_storage.xml6
-rw-r--r--lib/snmp/include/snmp_types.hrl5
-rw-r--r--lib/snmp/mibs/Makefile.in36
-rw-r--r--lib/snmp/mibs/OTP-REG.mib103
-rw-r--r--lib/snmp/mibs/OTP-TC.mib93
-rw-r--r--lib/snmp/src/agent/depend.mk19
-rw-r--r--lib/snmp/src/agent/modules.mk26
-rw-r--r--lib/snmp/src/agent/snmp_community_mib.erl32
-rw-r--r--lib/snmp/src/agent/snmp_framework_mib.erl3
-rw-r--r--lib/snmp/src/agent/snmp_generic.erl18
-rw-r--r--lib/snmp/src/agent/snmp_standard_mib.erl13
-rw-r--r--lib/snmp/src/agent/snmp_target_mib.erl13
-rw-r--r--lib/snmp/src/agent/snmp_user_based_sm_mib.erl12
-rw-r--r--lib/snmp/src/agent/snmp_view_based_acm_mib.erl37
-rw-r--r--lib/snmp/src/agent/snmpa_agent.erl1273
-rw-r--r--lib/snmp/src/agent/snmpa_app.erl4
-rw-r--r--lib/snmp/src/agent/snmpa_authentication_service.erl45
-rw-r--r--lib/snmp/src/agent/snmpa_conf.erl30
-rw-r--r--lib/snmp/src/agent/snmpa_discovery_handler.erl19
-rw-r--r--lib/snmp/src/agent/snmpa_error_report.erl16
-rw-r--r--lib/snmp/src/agent/snmpa_get.erl1175
-rw-r--r--lib/snmp/src/agent/snmpa_get_lib.erl254
-rw-r--r--lib/snmp/src/agent/snmpa_get_mechanism.erl79
-rw-r--r--lib/snmp/src/agent/snmpa_local_db.erl21
-rw-r--r--lib/snmp/src/agent/snmpa_mib_storage.erl6
-rw-r--r--lib/snmp/src/agent/snmpa_mib_storage_dets.erl14
-rw-r--r--lib/snmp/src/agent/snmpa_mib_storage_ets.erl9
-rw-r--r--lib/snmp/src/agent/snmpa_mpd.erl10
-rw-r--r--lib/snmp/src/agent/snmpa_network_interface.erl78
-rw-r--r--lib/snmp/src/agent/snmpa_set.erl13
-rw-r--r--lib/snmp/src/agent/snmpa_set_lib.erl8
-rw-r--r--lib/snmp/src/agent/snmpa_set_mechanism.erl37
-rw-r--r--lib/snmp/src/agent/snmpa_supervisor.erl99
-rw-r--r--lib/snmp/src/agent/snmpa_trap.erl25
-rw-r--r--lib/snmp/src/agent/snmpa_usm.erl22
-rw-r--r--lib/snmp/src/app/snmp.app.src3
-rw-r--r--lib/snmp/src/app/snmp.config1
-rw-r--r--lib/snmp/src/app/snmp.erl50
-rw-r--r--lib/snmp/src/app/snmp_internal.hrl11
-rw-r--r--lib/snmp/src/compile/Makefile4
-rw-r--r--lib/snmp/src/compile/snmpc.erl11
-rw-r--r--lib/snmp/src/manager/snmpm.erl11
-rw-r--r--lib/snmp/src/manager/snmpm_conf.erl3
-rw-r--r--lib/snmp/src/manager/snmpm_config.erl45
-rw-r--r--lib/snmp/src/manager/snmpm_mpd.erl14
-rw-r--r--lib/snmp/src/manager/snmpm_net_if.erl17
-rw-r--r--lib/snmp/src/manager/snmpm_network_interface.erl74
-rw-r--r--lib/snmp/src/manager/snmpm_server.erl35
-rw-r--r--lib/snmp/src/manager/snmpm_supervisor.erl40
-rw-r--r--lib/snmp/src/misc/snmp_conf.erl27
-rw-r--r--lib/snmp/src/misc/snmp_config.erl102
-rw-r--r--lib/snmp/src/misc/snmp_log.erl17
-rw-r--r--lib/snmp/src/misc/snmp_misc.erl112
-rw-r--r--lib/snmp/src/misc/snmp_verbosity.erl16
-rw-r--r--lib/snmp/test/Makefile2
-rw-r--r--lib/snmp/test/modules.mk3
-rw-r--r--lib/snmp/test/snmp_agent_test.erl103
-rw-r--r--lib/snmp/test/snmp_agent_test_get.erl58
-rw-r--r--lib/snmp/test/snmp_agent_test_lib.erl678
-rw-r--r--lib/snmp/test/snmp_compiler_test.erl33
-rw-r--r--lib/snmp/test/snmp_manager_config_test.erl13
-rw-r--r--lib/snmp/test/snmp_manager_test.erl725
-rw-r--r--lib/snmp/test/snmp_test_global_sys_monitor.erl214
-rw-r--r--lib/snmp/test/snmp_test_lib.erl352
-rw-r--r--lib/snmp/test/snmp_test_lib.hrl46
-rw-r--r--lib/snmp/test/snmp_test_mgr.erl105
-rw-r--r--lib/snmp/test/snmp_test_mgr_misc.erl294
-rw-r--r--lib/snmp/test/snmp_test_server.erl4
-rw-r--r--lib/snmp/test/snmp_test_sys_monitor.erl86
-rw-r--r--lib/snmp/test/snmp_to_snmpnet_SUITE.erl143
-rw-r--r--lib/snmp/test/test-mibs/ALARM-MIB.mib2
-rw-r--r--lib/snmp/test/test-mibs/SNMPv2-TC.mib4
-rw-r--r--lib/snmp/vsn.mk2
75 files changed, 4788 insertions, 2381 deletions
diff --git a/lib/snmp/Makefile b/lib/snmp/Makefile
index 879f1b05c5..df321fc2d1 100644
--- a/lib/snmp/Makefile
+++ b/lib/snmp/Makefile
@@ -2,7 +2,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2016. All Rights Reserved.
+# Copyright Ericsson AB 1996-2019. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -136,11 +136,17 @@ dclean:
dialyzer_plt: $(DIA_PLT)
-$(DIA_PLT):
+$(DIA_PLT): Makefile
@echo "Building $(APPLICATION) plt file"
@dialyzer --build_plt \
--output_plt $@ \
-r ../$(APPLICATION)/ebin \
+ ../../lib/kernel/ebin \
+ ../../lib/stdlib/ebin \
+ ../../lib/runtime_tools/ebin \
+ ../../lib/crypto/ebin \
+ ../../lib/mnesia/ebin \
+ ../../erts/preloaded/ebin \
--output $(DIA_ANALYSIS) \
--verbose
@@ -148,4 +154,4 @@ dialyzer: $(DIA_PLT)
@echo "Running dialyzer on $(APPLICATION)"
@dialyzer --plt $< \
../$(APPLICATION)/ebin \
- --verbose \ No newline at end of file
+ --verbose
diff --git a/lib/snmp/doc/src/notes.xml b/lib/snmp/doc/src/notes.xml
index 423d90fef6..780e0cae76 100644
--- a/lib/snmp/doc/src/notes.xml
+++ b/lib/snmp/doc/src/notes.xml
@@ -34,7 +34,32 @@
</header>
- <section><title>SNMP 5.2.12</title>
+ <section><title>SNMP 5.3</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ The application otp_mibs has been removed from OTP. Some
+ of its components (mibs) have been moved to other apps
+ (snmp), or removed completely (os_mon).</p>
+ <p>
+ Own Id: OTP-14984 Aux Id: OTP-15329 </p>
+ </item>
+ <item>
+ <p>
+ [snmp|agent] Add a get-mechanism callback module (and a
+ corresponding behaviour). The agent calls this module to
+ handle each get (get, get-next and get-bulk) request.</p>
+ <p>
+ Own Id: OTP-15691 Aux Id: ERIERL-324 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SNMP 5.2.12</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
@@ -73,6 +98,23 @@
</section>
+ <section><title>SNMP 5.2.11.1</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ [snmp|agent] Add a get-mechanism callback module (and a
+ corresponding behaviour). The agent calls this module to
+ handle each get (get, get-next and get-bulk) request.</p>
+ <p>
+ Own Id: OTP-15691 Aux Id: ERIERL-324 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>SNMP 5.2.11</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/snmp/doc/src/snmpa_mib_storage.xml b/lib/snmp/doc/src/snmpa_mib_storage.xml
index ee2b009e77..6db2f178a9 100644
--- a/lib/snmp/doc/src/snmpa_mib_storage.xml
+++ b/lib/snmp/doc/src/snmpa_mib_storage.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2013</year><year>2016</year>
+ <year>2013</year><year>2019</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -193,7 +193,7 @@
</func>
<func>
- <name since="OTP R16B01">Module:match_object(TabId, Pattern) -> {ok, Recs} | {error, Reason}</name>
+ <name since="OTP R16B01">Module:match_object(TabId, Pattern) -> Recs | {error, Reason}</name>
<fsummary>Search the mib-storage table for record matching pattern</fsummary>
<type>
<v>TabId = term()</v>
@@ -210,7 +210,7 @@
</func>
<func>
- <name since="OTP R16B01">Module:match_delete(TabId, Pattern) -> {ok, Recs} | {error, Reason}</name>
+ <name since="OTP R16B01">Module:match_delete(TabId, Pattern) -> Recs | {error, Reason}</name>
<fsummary>Delete records in the mib-storage table matching pattern</fsummary>
<type>
<v>TabId = term()</v>
diff --git a/lib/snmp/include/snmp_types.hrl b/lib/snmp/include/snmp_types.hrl
index ffe30996dc..eff17a13a3 100644
--- a/lib/snmp/include/snmp_types.hrl
+++ b/lib/snmp/include/snmp_types.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -349,6 +349,9 @@
-define(view_included, 1).
-define(view_excluded, 2).
+-define(view_wildcard, 0).
+-define(view_exact, 1).
+
%%-----------------------------------------------------------------
%% From SNMPv2-SMI
diff --git a/lib/snmp/mibs/Makefile.in b/lib/snmp/mibs/Makefile.in
index 2350194077..77893cbdc8 100644
--- a/lib/snmp/mibs/Makefile.in
+++ b/lib/snmp/mibs/Makefile.in
@@ -41,14 +41,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/snmp-$(VSN)
# Common macros
# ----------------------------------------------------
-# NOTE:
-# The OTP-REG mib actually belongs to another
-# application (otp_mibs), and is exported by this
-# app. But since that app is built later, we have
-# to built it here in order to be able to build
-# OTP-SNMPEA-MIB (that needs otpModules and
-# otpApplications).
-MIBS_A = \
+MIBS = \
RFC1213-MIB \
STANDARD-MIB \
SNMPv2-TM \
@@ -62,16 +55,10 @@ MIBS_A = \
SNMP-VIEW-BASED-ACM-MIB \
SNMP-USM-AES-MIB \
INET-ADDRESS-MIB \
- TRANSPORT-ADDRESS-MIB
-
-MIBS_B = OTP-SNMPEA-MIB
-
-BUILD_MIBS = \
- $(MIBS_A) \
+ TRANSPORT-ADDRESS-MIB \
OTP-REG \
- $(MIBS_B)
-
-MIBS = $(MIBS_A) $(MIBS_B)
+ OTP-TC \
+ OTP-SNMPEA-MIB
STD_v1_MIB_FILES = \
RFC1155-SMI.mib \
@@ -100,8 +87,8 @@ HRL_FILES = $(SNMP_HRL_TARGET_DIR)/SNMPv2-TC.hrl \
TARGET_FILES = \
$(ERL_TOP)/lib/snmp/bin/snmp-v2tov1 \
- $(BUILD_MIBS:%=$(SNMP_BIN_TARGET_DIR)/%.bin) \
- $(HRL_TARGETS) \
+ $(MIBS:%=$(SNMP_BIN_TARGET_DIR)/%.bin) \
+ $(HRL_TARGETS) \
$(V1_MIB_FILES)
@@ -136,21 +123,18 @@ endif
# Targets
# ----------------------------------------------------
-OTP_MIBDIR = $(shell if test -d ../../otp_mibs; then echo otp_mibs; \
- else echo sasl; fi)
-
debug opt: $(TARGET_FILES)
$(ERL_TOP)/lib/snmp/bin/snmp-v2tov1: $(ERL_TOP)/lib/snmp/bin/snmp-v2tov1.src
$(gen_verbose)$(PERL) -p -e 's?%PERL%?$(PERL)? ' < $< > $@
$(V_at)chmod 755 $@
-$(SNMP_BIN_TARGET_DIR)/OTP-REG.bin: $(ERL_TOP)/lib/$(OTP_MIBDIR)/mibs/OTP-REG.mib
- $(snmp_verbose)$(ERLC) -pa $(SNMP_TOOLKIT)/ebin -I $(SNMP_TOOLKIT)/priv/mibs $(SNMP_FLAGS) -o $(SNMP_BIN_TARGET_DIR) $<
-
# To support parallel make, we'll need explicit dependencies
# to ensure that an imported MIB has been compiled when it's needed.
+$(SNMP_BIN_TARGET_DIR)/OTP-TC.bin: \
+ $(SNMP_BIN_TARGET_DIR)/OTP-REG.bin
+
$(SNMP_BIN_TARGET_DIR)/STANDARD-MIB.bin: \
$(SNMP_BIN_TARGET_DIR)/RFC1213-MIB.bin
@@ -208,8 +192,6 @@ info:
@echo ""
@echo "TARGET_FILES = $(TARGET_FILES)"
@echo ""
- @echo "OTP_MIBDIR = $(OTP_MIBDIR)"
- @echo ""
@echo "SNMP_VSN = $(SNMP_VSN)"
@echo "VSN = $(VSN)"
@echo "RELSYSDIR = "$(RELSYSDIR)""
diff --git a/lib/snmp/mibs/OTP-REG.mib b/lib/snmp/mibs/OTP-REG.mib
new file mode 100644
index 0000000000..bf1585061c
--- /dev/null
+++ b/lib/snmp/mibs/OTP-REG.mib
@@ -0,0 +1,103 @@
+--
+-- %CopyrightBegin%
+--
+-- Copyright Ericsson AB 1997-2016. All Rights Reserved.
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-- %CopyrightEnd%
+--
+
+OTP-REG DEFINITIONS ::= BEGIN
+
+IMPORTS
+ MODULE-IDENTITY, enterprises
+ FROM SNMPv2-SMI
+ ;
+
+otpRegModule MODULE-IDENTITY
+ LAST-UPDATED "200305090900Z"
+ ORGANIZATION "Ericsson"
+ CONTACT-INFO
+ "Contact: Erlang Support see license agreement for Erlang/OTP."
+ DESCRIPTION
+ "The root MIB module for OTP."
+
+ REVISION "200305090900Z"
+ DESCRIPTION
+ "Changed CONTACT-INFO as it was outdated, made it more generic
+ to avoid such changes in the future."
+
+ REVISION "199902020900Z"
+ DESCRIPTION
+ "Cleaned up OBJECT IDENTIFIER registration. Changed the name
+ of the MODULE-IDENTITY of this module to non-conflicting name
+ otpRegModule."
+
+ REVISION "199712010900Z"
+ DESCRIPTION
+ "The initial revision of MIB module OTP-REG."
+ ::= { otpModules 1 }
+
+ericsson OBJECT IDENTIFIER ::= {enterprises 193}
+otp OBJECT IDENTIFIER ::= {ericsson 19}
+
+-- sub-tree for registraions, including Modules
+otpReg OBJECT IDENTIFIER ::= {otp 1}
+otpModules OBJECT IDENTIFIER ::= {otpReg 1}
+-- otpTcModule 2
+-- otpModule 3
+-- otpOsMonModule 4
+-- otpSnmpeaModule 5
+-- otpEvaModule 6
+-- otpLogModule 7
+-- otpEvaLogModule 8
+-- otpSnmpeaLogModule 9
+-- otpMeshModule 10
+
+
+-- sub-tree for OTP-wide objects and events
+otpGeneric OBJECT IDENTIFIER ::= {otp 2}
+
+-- sub-tree for product specific objects and events
+otpApplications
+ OBJECT IDENTIFIER ::= {otp 3}
+-- otpMib 1
+-- otpOsMonMib 2
+-- otpSnmpeaMib 3
+-- otpEvaMib 4
+-- otpLogMib 5
+-- otpMeshMib 6
+
+
+-- sub-tree for agent implementation capabilites
+otpCaps OBJECT IDENTIFIER ::= {otp 4}
+-- otpMibImplV10 1 (vsn of mib implementation, e.g. otp_mib)
+-- otpOsMonMibImplV10 2
+-- otpSnmpeaMibImplV10 3
+-- otpEvaMibImplV10 4
+-- otpLogMibImplV10 5
+
+
+-- sub-tree for requirement specifications
+otpReqs OBJECT IDENTIFIER ::= {otp 5}
+
+-- sub-tree for experimental modules within OTP
+otpExpr OBJECT IDENTIFIER ::= {otp 6}
+
+-- sub-tree for SSL within OTP
+-- Note that this subtree is not MIB related, but it
+-- is defined in this MIB file to avoid clashes.
+ssl OBJECT IDENTIFIER ::= {otp 10}
+
+END
diff --git a/lib/snmp/mibs/OTP-TC.mib b/lib/snmp/mibs/OTP-TC.mib
new file mode 100644
index 0000000000..efe5451f0c
--- /dev/null
+++ b/lib/snmp/mibs/OTP-TC.mib
@@ -0,0 +1,93 @@
+--
+-- %CopyrightBegin%
+--
+-- Copyright Ericsson AB 1997-2016. All Rights Reserved.
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-- %CopyrightEnd%
+--
+
+OTP-TC DEFINITIONS ::= BEGIN
+
+IMPORTS
+ MODULE-IDENTITY
+ FROM SNMPv2-SMI
+ TEXTUAL-CONVENTION, DisplayString
+ FROM SNMPv2-TC
+ otpModules
+ FROM OTP-REG
+ ;
+
+otpTcModule MODULE-IDENTITY
+ LAST-UPDATED "200305090900Z"
+ ORGANIZATION "Ericsson"
+ CONTACT-INFO
+ "Contact: Erlang Support see license agreement for Erlang/OTP."
+ DESCRIPTION
+ "This MIB is part of the OTP MIB. It defines common
+ Textual Conventions used in other OTP mib modules."
+
+ REVISION "200305090900Z"
+ DESCRIPTION
+ "Changed CONTACT-INFO as it was outdated, made it more generic
+ to avoid such changes in the future."
+
+
+ REVISION "199712010900Z"
+ DESCRIPTION
+ "The initial version of this module."
+ ::= { otpModules 2 }
+
+OwnerString ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "255a"
+ STATUS current
+ DESCRIPTION
+ "An OwnerString identifies the initiator or owner of a row
+ in a table. This label is set by the initiator to provide
+ for the following possibilities:
+
+ o A management station may recognize resources it owns
+ and no longer needs.
+ o A network operator can find the management station that
+ owns the resource and negotiate for it to be freed.
+ o A network operator may decide to unilaterally free
+ resources another network operator has reserved.
+ o Upon initialization, a management station may recognize
+ resources it had reserved in the past. With this
+ information it may free the resources if it no longer
+ needs them.
+
+ Management stations and agent systems should support any format
+ of the OwnerString dictated by the local policy of the
+ organization. It is suggested that this name contain one or
+ more of the following: IP address, management station name,
+ network manager's name, location, or phone number. This
+ information will help users to share the resources more
+ effectively.
+
+ There is often default functionality that the device or the
+ administrator of the agent (often the network administrator) wishes
+ to set up. The resources associated with this functionality are then
+ owned by the device itself or by the network administrator, and are
+ intended to be long-lived. In this case, the device or the
+ administrator will set the relevant owner object to a string starting
+ with 'local'. Indiscriminate modification of the local
+ configuration by network management stations is discouraged. In
+ fact, a network management station should only modify these objects
+ under the direction of the administrator of the agent system."
+ REFERENCE
+ "RFC1757, RMON-MIB"
+ SYNTAX DisplayString (SIZE (0..127))
+
+END
diff --git a/lib/snmp/src/agent/depend.mk b/lib/snmp/src/agent/depend.mk
index 8eba50fa3b..49c7669e41 100644
--- a/lib/snmp/src/agent/depend.mk
+++ b/lib/snmp/src/agent/depend.mk
@@ -2,7 +2,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2016. All Rights Reserved.
+# Copyright Ericsson AB 2004-2019. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -24,6 +24,9 @@ $(EBIN)/snmpa_authentication_service.$(EMULATOR): \
$(EBIN)/snmpa_error_report.$(EMULATOR): \
snmpa_error_report.erl
+$(EBIN)/snmpa_get_mechanism.$(EMULATOR): \
+ snmpa_get_mechanism.erl
+
$(EBIN)/snmpa_network_interface.$(EMULATOR): \
snmpa_network_interface.erl
@@ -78,6 +81,20 @@ $(EBIN)/snmpa_error_logger.$(EMULATOR): \
snmpa_error_report.erl \
snmpa_error_logger.erl
+$(EBIN)/snmpa_set.$(EMULATOR): \
+ snmpa_set_mechanism.erl \
+ snmpa_set.erl \
+ ../misc/snmp_verbosity.hrl
+
+$(EBIN)/snmpa_get.$(EMULATOR): \
+ snmpa_get_mechanism.erl \
+ snmpa_get.erl \
+ ../misc/snmp_verbosity.hrl
+
+$(EBIN)/snmpa_get_lib.$(EMULATOR): \
+ snmpa_get_lib.erl \
+ ../misc/snmp_verbosity.hrl
+
$(EBIN)/snmpa_local_db.$(EMULATOR): \
snmpa_local_db.erl \
../misc/snmp_debug.hrl \
diff --git a/lib/snmp/src/agent/modules.mk b/lib/snmp/src/agent/modules.mk
index 0f8615588a..49cc158c2e 100644
--- a/lib/snmp/src/agent/modules.mk
+++ b/lib/snmp/src/agent/modules.mk
@@ -2,7 +2,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2016. All Rights Reserved.
+# Copyright Ericsson AB 2004-2019. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@ BEHAVIOUR_MODULES = \
snmpa_authentication_service \
snmpa_discovery_handler \
snmpa_error_report \
+ snmpa_get_mechanism \
snmpa_mib_storage \
snmpa_mib_data \
snmpa_network_interface \
@@ -30,12 +31,24 @@ BEHAVIOUR_MODULES = \
snmpa_notification_filter \
snmpa_set_mechanism
+MIB_MODULES = \
+ snmp_community_mib \
+ snmp_framework_mib \
+ snmp_notification_mib \
+ snmp_standard_mib \
+ snmp_target_mib \
+ snmp_user_based_sm_mib \
+ snmp_view_based_acm_mib
+
# snmpa is "plain" interface module but also defines some agent specific types
# and therefor must be compiled before the modules that use them, including
# the behaviour modules...
+# Some of the MIB modules also define types used elsewhere and therefor
+# has to be built before the other mods.
# snmpa_mib_data_ttln
MODULES = \
snmpa \
+ $(MIB_MODULES) \
$(BEHAVIOUR_MODULES) \
snmpa_acm \
snmpa_agent \
@@ -46,6 +59,8 @@ MODULES = \
snmpa_error \
snmpa_error_io \
snmpa_error_logger \
+ snmpa_get \
+ snmpa_get_lib \
snmpa_local_db \
snmpa_mib_storage_ets \
snmpa_mib_storage_dets \
@@ -66,17 +81,10 @@ MODULES = \
snmpa_trap \
snmpa_usm \
snmpa_vacm \
- snmp_community_mib \
- snmp_framework_mib \
snmp_generic \
snmp_generic_mnesia \
snmp_index \
- snmp_notification_mib \
- snmp_shadow_table \
- snmp_standard_mib \
- snmp_target_mib \
- snmp_user_based_sm_mib \
- snmp_view_based_acm_mib
+ snmp_shadow_table
INTERNAL_HRL_FILES = \
diff --git a/lib/snmp/src/agent/snmp_community_mib.erl b/lib/snmp/src/agent/snmp_community_mib.erl
index 9fd7b30f9f..4bd30632f5 100644
--- a/lib/snmp/src/agent/snmp_community_mib.erl
+++ b/lib/snmp/src/agent/snmp_community_mib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -206,10 +206,10 @@ do_add_community(Community) ->
{error, create_failed}
end
catch
- {error, Reason} ->
- {error, Reason};
- Class:Reason ->
- {error, {Class, Reason, erlang:get_stacktrace()}}
+ throw:{error, _} = ERROR ->
+ ERROR;
+ C:E:S ->
+ {error, {C, E, S}}
end.
%% FIXME: does not work with mnesia
@@ -545,26 +545,18 @@ snmpTargetAddrExtTable(is_set_ok, RowIndex, Cols0) ->
end.
-
get_snmpTargetAddrTDomain(RowIndex, Col) ->
- case
- get(
- snmpTargetAddrTable, RowIndex,
- [?snmpTargetAddrRowStatus,?snmpTargetAddrTDomain])
- of
- [{value,?snmpTargetAddrRowStatus_active},ValueTDomain] ->
- case ValueTDomain of
- {value,TDomain} ->
- TDomain;
- _ ->
- ?snmpUDPDomain
- end;
- _ ->
+ Cols = [?snmpTargetAddrRowStatus,?snmpTargetAddrTDomain],
+ case snmp_target_mib:snmpTargetAddrTable(get, RowIndex, Cols) of
+ [{value, ?snmpTargetAddrRowStatus_active}, {value, TDomain}] ->
+ TDomain;
+ [{value, ?snmpTargetAddrRowStatus_active}, _] ->
+ ?snmpUDPDomain;
+ _ ->
wrongValue(Col)
end.
-
verify_snmpTargetAddrExtTable_cols([], _TDomain, Cols) ->
{ok, lists:reverse(Cols)};
verify_snmpTargetAddrExtTable_cols([{Col, Val0}|Cols], TDomain, Acc) ->
diff --git a/lib/snmp/src/agent/snmp_framework_mib.erl b/lib/snmp/src/agent/snmp_framework_mib.erl
index 7ea4f0ed97..6db6f87a85 100644
--- a/lib/snmp/src/agent/snmp_framework_mib.erl
+++ b/lib/snmp/src/agent/snmp_framework_mib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -246,6 +246,7 @@ check_agent(X) ->
%% Ordering function to sort intAgentTransportDomain first
%% hence before intAgentIpAddress. Sort other entries on the key.
+-dialyzer({nowarn_function, order_agent/2}).
order_agent(EntryA, EntryB) ->
snmp_conf:keyorder(
1, EntryA, EntryB,
diff --git a/lib/snmp/src/agent/snmp_generic.erl b/lib/snmp/src/agent/snmp_generic.erl
index e67a1b3c80..26a0dd0648 100644
--- a/lib/snmp/src/agent/snmp_generic.erl
+++ b/lib/snmp/src/agent/snmp_generic.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -421,12 +421,12 @@ table_check_status(NameDb, Col, ?'RowStatus_createAndGo', RowIndex, Cols) ->
_Found -> {inconsistentValue, Col}
end
catch
- _:_Reason ->
+ _:_E:_S ->
?vtrace(
"failed construct row (createAndGo): "
- " n Reason: ~p"
- " n Stack: ~p",
- [_Reason, erlang:get_stacktrace()]),
+ " n Error: ~p"
+ " n Stack: ~p",
+ [_E, _S]),
{noCreation, Col} % Bad RowIndex
end;
true -> {inconsistentValue, Col}
@@ -441,12 +441,12 @@ table_check_status(NameDb, Col, ?'RowStatus_createAndWait', RowIndex, Cols) ->
_Row ->
{noError, 0}
catch
- _:_Reason ->
+ _:_E:_S ->
?vtrace(
"failed construct row (createAndWait): "
- " n Reason: ~p"
- " n Stack: ~p",
- [_Reason, erlang:get_stacktrace()]),
+ " n Error: ~p"
+ " n Stack: ~p",
+ [_E, _S]),
{noCreation, Col} % Bad RowIndex
end;
true -> {inconsistentValue, Col}
diff --git a/lib/snmp/src/agent/snmp_standard_mib.erl b/lib/snmp/src/agent/snmp_standard_mib.erl
index bfe471178d..679d2657c6 100644
--- a/lib/snmp/src/agent/snmp_standard_mib.erl
+++ b/lib/snmp/src/agent/snmp_standard_mib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -27,6 +27,7 @@
-include("snmp_types.hrl").
-include("STANDARD-MIB.hrl").
+-include("snmpa_internal.hrl").
-define(VMODULE,"STANDARD-MIB").
-include("snmp_verbosity.hrl").
@@ -547,10 +548,12 @@ dummy(_Op) -> ok.
%%-----------------------------------------------------------------
snmp_set_serial_no(new) ->
snmp_generic:variable_func(new, {snmpSetSerialNo, volatile}),
- random:seed(erlang:phash2([node()]),
- erlang:monotonic_time(),
- erlang:unique_integer()),
- Val = random:uniform(2147483648) - 1,
+ ?SNMP_RAND_SEED(),
+ %% rand:seed(exrop,
+ %% {erlang:phash2([node()]),
+ %% erlang:monotonic_time(),
+ %% erlang:unique_integer()}),
+ Val = rand:uniform(2147483648) - 1,
snmp_generic:variable_func(set, Val, {snmpSetSerialNo, volatile});
snmp_set_serial_no(delete) ->
diff --git a/lib/snmp/src/agent/snmp_target_mib.erl b/lib/snmp/src/agent/snmp_target_mib.erl
index e65fa7f340..22fd3acb84 100644
--- a/lib/snmp/src/agent/snmp_target_mib.erl
+++ b/lib/snmp/src/agent/snmp_target_mib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -42,6 +42,7 @@
-define(VMODULE,"TARGET-MIB").
-include("snmp_verbosity.hrl").
+-include("snmpa_internal.hrl").
%% Column not accessible via SNMP - needed when the agent sends informs
@@ -673,10 +674,12 @@ snmpTargetSpinLock(print) ->
snmpTargetSpinLock(new) ->
snmp_generic:variable_func(new, {snmpTargetSpinLock, volatile}),
- random:seed(erlang:phash2([node()]),
- erlang:monotonic_time(),
- erlang:unique_integer()),
- Val = random:uniform(2147483648) - 1,
+ ?SNMP_RAND_SEED(),
+ %% rand:seed(exrop,
+ %% {erlang:phash2([node()]),
+ %% erlang:monotonic_time(),
+ %% erlang:unique_integer()}),
+ Val = rand:uniform(2147483648) - 1,
snmp_generic:variable_func(set, Val, {snmpTargetSpinLock, volatile});
snmpTargetSpinLock(delete) ->
diff --git a/lib/snmp/src/agent/snmp_user_based_sm_mib.erl b/lib/snmp/src/agent/snmp_user_based_sm_mib.erl
index f6e4fd3951..4842669fa4 100644
--- a/lib/snmp/src/agent/snmp_user_based_sm_mib.erl
+++ b/lib/snmp/src/agent/snmp_user_based_sm_mib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -440,10 +440,12 @@ usmUserSpinLock(print) ->
usmUserSpinLock(new) ->
snmp_generic:variable_func(new, {usmUserSpinLock, volatile}),
- random:seed(erlang:phash2([node()]),
- erlang:monotonic_time(),
- erlang:unique_integer()),
- Val = random:uniform(2147483648) - 1,
+ ?SNMP_RAND_SEED(),
+ %% rand:seed(exrop,
+ %% {erlang:phash2([node()]),
+ %% erlang:monotonic_time(),
+ %% erlang:unique_integer()}),
+ Val = rand:uniform(2147483648) - 1,
snmp_generic:variable_func(set, Val, {usmUserSpinLock, volatile});
usmUserSpinLock(delete) ->
diff --git a/lib/snmp/src/agent/snmp_view_based_acm_mib.erl b/lib/snmp/src/agent/snmp_view_based_acm_mib.erl
index 02415e8036..a5a65d9326 100644
--- a/lib/snmp/src/agent/snmp_view_based_acm_mib.erl
+++ b/lib/snmp/src/agent/snmp_view_based_acm_mib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -37,11 +37,18 @@
%%
-export([emask2imask/1]).
+-export_type([
+ mibview/0,
+ internal_view_mask/0,
+ internal_view_mask_element/0,
+ internal_view_type/0
+ ]).
-include("snmp_types.hrl").
-include("SNMPv2-TC.hrl").
-include("SNMP-VIEW-BASED-ACM-MIB.hrl").
-include("snmpa_vacm.hrl").
+-include("snmpa_internal.hrl").
-define(VMODULE,"VACM-MIB").
@@ -53,7 +60,13 @@
-type internal_view_mask() :: null | [internal_view_mask_element()].
--type internal_view_mask_element() :: 0 | 1.
+-type internal_view_mask_element() :: ?view_wildcard |
+ ?view_exact.
+-type internal_view_type() :: ?view_included | ?view_excluded.
+
+-type mibview() :: [{SubTree :: snmp:oid(),
+ Mask :: internal_view_mask(),
+ Type :: internal_view_type()}].
-type external_view_mask() :: octet_string(). % At most length of 16 octet
-type octet_string() :: [octet()].
@@ -641,7 +654,7 @@ vacmAccessTable(is_set_ok, RowIndex, Cols0) ->
{{Col, ?'RowStatus_createAndWait'}, _} ->
%% Row already exists => inconsistentValue
{inconsistentValue, Col};
- {value, {_Col, ?'RowStatus_destroy'}} ->
+ {{_Col, ?'RowStatus_destroy'}, _} ->
%% always ok!
{noError, 0};
{_, false} ->
@@ -848,10 +861,12 @@ vacmViewSpinLock(print) ->
vacmViewSpinLock(new) ->
snmp_generic:variable_func(new, volatile_db(vacmViewSpinLock)),
- random:seed(erlang:phash2([node()]),
- erlang:monotonic_time(),
- erlang:unique_integer()),
- Val = random:uniform(2147483648) - 1,
+ ?SNMP_RAND_SEED(),
+ %% rand:seed(exrop,
+ %% {erlang:phash2([node()]),
+ %% erlang:monotonic_time(),
+ %% erlang:unique_integer()}),
+ Val = rand:uniform(2147483648) - 1,
snmp_generic:variable_func(set, Val, volatile_db(vacmViewSpinLock));
vacmViewSpinLock(delete) ->
@@ -1100,9 +1115,7 @@ externalize_next(Name, Result) when is_list(Result) ->
F = fun({[Col | _] = Idx, Val}) -> {Idx, externalize(Name, Col, Val)};
(Other) -> Other
end,
- [F(R) || R <- Result];
-externalize_next(_, Result) ->
- Result.
+ [F(R) || R <- Result].
externalize_get(Name, Cols, Result) when is_list(Result) ->
@@ -1112,9 +1125,7 @@ externalize_get(Name, Cols, Result) when is_list(Result) ->
end,
%% Merge column numbers and return values. there must be as much
%% return values as there are columns requested. And then patch all values
- [F(R) || R <- lists:zip(Cols, Result)];
-externalize_get(_, _, Result) ->
- Result.
+ [F(R) || R <- lists:zip(Cols, Result)].
externalize(vacmViewTreeFamilyTable, ?vacmViewTreeFamilyMask, Val) ->
imask2emask(Val);
diff --git a/lib/snmp/src/agent/snmpa_agent.erl b/lib/snmp/src/agent/snmpa_agent.erl
index 458b88359b..7489f74223 100644
--- a/lib/snmp/src/agent/snmpa_agent.erl
+++ b/lib/snmp/src/agent/snmpa_agent.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -28,7 +28,8 @@
%% External exports
-export([start_link/4, start_link/5, stop/1]).
--export([subagent_set/2,
+-export([subagent_get/3, subagent_get_next/3,
+ subagent_set/2,
load_mibs/3, unload_mibs/3,
which_mibs/1, whereis_mib/2, info/1,
register_subagent/3, unregister_subagent/2,
@@ -362,12 +363,19 @@ do_init(Prio, Parent, Ref, Options) ->
"~n Options: ~p",[Prio, Parent, Ref, Options]),
Mibs = get_mibs(Options),
+
SetModule = get_set_mechanism(Options),
put(set_module, SetModule),
+ ?vtrace("set-module: ~w", [SetModule]),
+
+ GetModule = get_get_mechanism(Options),
+ put(get_module, GetModule),
+ ?vtrace("get-module: ~w", [GetModule]),
%% OTP-3324. For AXD301.
AuthModule = get_authentication_service(Options),
put(auth_module, AuthModule),
+ ?vtrace("auth-module: ~w", [AuthModule]),
MultiT = get_multi_threaded(Options),
Vsns = get_versions(Options),
@@ -517,9 +525,25 @@ unregister_subagent(Agent, SubagentOidOrPid) ->
%% These subagent_ functions either return a value, or exits
%% with {nodedown, Node} | Reason.
%%-----------------------------------------------------------------
-subagent_get(SubAgent, Varbinds, IsNotification) ->
+
+%% A proper spec for this would be something like this:
+%% But, there is now way to spec that a process *can* exit.
+%% -spec subagent_get(Agent, VBs, IsNotification) ->
+%% {noError, 0, NewVBs} |
+%% {ErrStatus, ErrIndex, []} |
+%% erlang:exit(Reason) when
+%% Agent :: pid(),
+%% VBs :: [snmp:varbind()],
+%% IsNotification :: boolean(),
+%% NewVBs :: [snmp:varbind()],
+%% ErrStatus :: snmp:error_status(),
+%% ErrIndex :: snmp:error_index(),
+%% Reason :: {nodedown, Node} | term(),
+%% Node :: atom().
+
+subagent_get(SubAgent, VBs, IsNotification) ->
PduData = get_pdu_data(),
- call(SubAgent, {subagent_get, Varbinds, PduData, IsNotification}).
+ call(SubAgent, {subagent_get, VBs, PduData, IsNotification}).
subagent_get_next(SubAgent, MibView, Varbinds) ->
PduData = get_pdu_data(),
@@ -1133,7 +1157,7 @@ handle_call({subagent_get_next, MibView, Varbinds, PduData}, _From, S) ->
"~n PduData: ~p",
[MibView,Varbinds,PduData]),
put_pdu_data(PduData),
- {reply, do_get_next(MibView, Varbinds, infinity), S};
+ {reply, do_get_next(MibView, Varbinds), S};
handle_call({subagent_set, Arguments, PduData}, _From, S) ->
?vlog("[handle_call] subagent set:"
"~n Arguments: ~p"
@@ -1174,7 +1198,7 @@ handle_call({get_next, Vars, Context}, _From, S) ->
?vdebug("Varbinds: ~p",[Varbinds]),
MibView = snmpa_acm:get_root_mib_view(),
Reply =
- case do_get_next(MibView, Varbinds, infinity) of
+ case do_get_next(MibView, Varbinds) of
{noError, 0, NewVarbinds} ->
Vbs = lists:keysort(#varbind.org_index, NewVarbinds),
[{Oid,Val} || #varbind{oid = Oid, value = Val} <- Vbs];
@@ -1786,9 +1810,8 @@ worker_loop(Master) ->
GbMaxVBs, Extra)
end
catch
- T:E ->
- exit({worker_crash, Req, T, E,
- erlang:get_stacktrace()})
+ C:E:S ->
+ exit({worker_crash, Req, C, E, S})
end,
Master ! worker_available,
HandlePduRes; % For debugging...
@@ -1814,9 +1837,8 @@ worker_loop(Master) ->
get(net_if))
end
catch
- T:E ->
- exit({worker_crash, Req, T, E,
- erlang:get_stacktrace()})
+ C:E:S ->
+ exit({worker_crash, Req, C, E, S})
end,
Master ! worker_available,
SendTrapRes; % For debugging...
@@ -2535,22 +2557,31 @@ process_msg(
process_pdu(#pdu{type='get-request', request_id = ReqId, varbinds=Vbs},
_PduMS, Vsn, MibView, _GbMaxVBs) ->
?vtrace("get ~p",[ReqId]),
- Res = get_err(do_get(MibView, Vbs, false)),
- ?vtrace("get result: "
- "~n ~p",[Res]),
+ OrigRes = do_get(MibView, Vbs, false),
+ Res = get_err(OrigRes),
{ErrStatus, ErrIndex, ResVarbinds} =
if
Vsn =:= 'version-1' -> validate_get_v1(Res);
true -> Res
end,
- ?vtrace("get final result: "
- "~n Error status: ~p"
- "~n Error index: ~p"
- "~n Varbinds: ~p",
- [ErrStatus,ErrIndex,ResVarbinds]),
+ if
+ (ErrStatus =/= noError) ->
+ ?vlog("get final result: "
+ "~n Error status: ~p"
+ "~n Error index: ~p"
+ "~n when"
+ "~n Original Result: "
+ "~n ~p", [ErrStatus, ErrIndex, OrigRes]);
+ true ->
+ ?vtrace("get final result: "
+ "~n Error status: ~p"
+ "~n Error index: ~p"
+ "~n Varbinds: ~p",
+ [ErrStatus, ErrIndex, ResVarbinds])
+ end,
ResponseVarbinds = lists:keysort(#varbind.org_index, ResVarbinds),
?vtrace("response varbinds: "
- "~n ~p",[ResponseVarbinds]),
+ "~n ~p", [ResponseVarbinds]),
make_response_pdu(ReqId, ErrStatus, ErrIndex, Vbs, ResponseVarbinds);
process_pdu(#pdu{type = 'get-next-request', request_id = ReqId, varbinds = Vbs},
@@ -2558,22 +2589,31 @@ process_pdu(#pdu{type = 'get-next-request', request_id = ReqId, varbinds = Vbs},
?vtrace("process get-next-request -> entry with"
"~n ReqId: ~p"
"~n Vbs: ~p"
- "~n MibView: ~p",[ReqId, Vbs, MibView]),
- Res = get_err(do_get_next(MibView, Vbs, infinity)),
- ?vtrace("get-next result: "
- "~n ~p",[Res]),
+ "~n MibView: ~p", [ReqId, Vbs, MibView]),
+ OrigRes = do_get_next(MibView, Vbs),
+ Res = get_err(OrigRes),
{ErrStatus, ErrIndex, ResVarbinds} =
if
Vsn =:= 'version-1' -> validate_next_v1(Res, MibView);
true -> Res
end,
- ?vtrace("get-next final result -> validation result:"
- "~n Error status: ~p"
- "~n Error index: ~p"
- "~n Varbinds: ~p",[ErrStatus,ErrIndex,ResVarbinds]),
+ if
+ (ErrStatus =/= noError) ->
+ ?vlog("get-next final result: "
+ "~n Error status: ~p"
+ "~n Error index: ~p"
+ "~n when"
+ "~n Original Result: "
+ "~n ~p", [ErrStatus, ErrIndex, OrigRes]);
+ true ->
+ ?vtrace("get-next final result:"
+ "~n Error status: ~p"
+ "~n Error index: ~p"
+ "~n Varbinds: ~p", [ErrStatus, ErrIndex, ResVarbinds])
+ end,
ResponseVarbinds = lists:keysort(#varbind.org_index, ResVarbinds),
?vtrace("get-next final result -> response varbinds: "
- "~n ~p",[ResponseVarbinds]),
+ "~n ~p", [ResponseVarbinds]),
make_response_pdu(ReqId, ErrStatus, ErrIndex, Vbs, ResponseVarbinds);
process_pdu(#pdu{type = 'get-bulk-request',
@@ -2582,31 +2622,50 @@ process_pdu(#pdu{type = 'get-bulk-request',
error_status = NonRepeaters,
error_index = MaxRepetitions},
PduMS, _Vsn, MibView, GbMaxVBs) ->
- {ErrStatus, ErrIndex, ResponseVarbinds} =
- get_err(do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Vbs,
- GbMaxVBs)),
- ?vtrace("get-bulk final result: "
- "~n Error status: ~p"
- "~n Error index: ~p"
- "~n Respons varbinds: ~p",
- [ErrStatus,ErrIndex,ResponseVarbinds]),
+ OrigRes = do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Vbs,
+ GbMaxVBs),
+ {ErrStatus, ErrIndex, ResponseVarbinds} = get_err(OrigRes),
+ if
+ (ErrStatus =/= noError) ->
+ ?vlog("get-bulk final result: "
+ "~n Error Status: ~p"
+ "~n Error Index: ~p"
+ "~n when"
+ "~n Original Result: "
+ "~n ~p", [ErrStatus, ErrIndex, OrigRes]);
+ true ->
+ ?vtrace("get-bulk final result: "
+ "~n Error status: ~p"
+ "~n Error index: ~p"
+ "~n Response Varbinds: ~p",
+ [ErrStatus, ErrIndex, ResponseVarbinds])
+ end,
make_response_pdu(ReqId, ErrStatus, ErrIndex, Vbs, ResponseVarbinds);
process_pdu(#pdu{type = 'set-request', request_id = ReqId, varbinds = Vbs},
- _PduMS, Vsn, MibView, _GbMaxVbs)->
- Res = do_set(MibView, Vbs),
- ?vtrace("set result: "
- "~n ~p",[Res]),
+ _PduMS, Vsn, MibView, _GbMaxVbs) ->
+ OrigRes = do_set(MibView, Vbs),
{ErrStatus, ErrIndex} =
if
- Vsn =:= 'version-1' -> validate_err(v2_to_v1, Res);
- true -> Res
+ Vsn =:= 'version-1' -> validate_err(v2_to_v1, OrigRes);
+ true -> OrigRes
end,
- ?vtrace("set final result: "
- "~n Error status: ~p"
- "~n Error index: ~p",[ErrStatus,ErrIndex]),
+ if
+ (ErrStatus =/= noError) ->
+ ?vlog("set final result: "
+ "~n Error Status: ~p"
+ "~n Error Index: ~p"
+ "~n when"
+ "~n Original Result: "
+ "~n ~p", [ErrStatus, ErrIndex, OrigRes]);
+ true ->
+ ?vtrace("set final result: "
+ "~n Error Status: ~p"
+ "~n Error Index: ~p", [ErrStatus, ErrIndex])
+ end,
make_response_pdu(ReqId, ErrStatus, ErrIndex, Vbs, Vbs).
+
%%-----------------------------------------------------------------
%% Transform a value == noSuchInstance | noSuchObject or a
%% Counter64 type to a noSuchName error for the whole pdu.
@@ -2650,8 +2709,7 @@ validate_next_v1_2([Vb | _Vbs], _MibView, _Res)
{noSuchName, Vb#varbind.org_index};
validate_next_v1_2([Vb | Vbs], MibView, Res)
when Vb#varbind.variabletype =:= 'Counter64' ->
- case validate_next_v1(
- do_get_next(MibView, [mk_next_oid(Vb)], infinity), MibView) of
+ case validate_next_v1( do_get_next(MibView, [mk_next_oid(Vb)]), MibView) of
{noError, 0, [NVb]} ->
validate_next_v1_2(Vbs, MibView, [NVb | Res]);
{Error, Index, _OrgVb} ->
@@ -2693,6 +2751,20 @@ mk_next_oid(Vb) ->
%%%-----------------------------------------------------------------
%%-----------------------------------------------------------------
+%% Func: do_get/2
+%% Purpose: Handles all VBs in a request that is inside the
+%% mibview (local).
+%% Returns: {noError, 0, ListOfNewVarbinds} |
+%% {ErrorStatus, ErrorIndex, []}
+%%-----------------------------------------------------------------
+
+do_get(UnsortedVarbinds, IsNotification) ->
+ Extra = get(net_if_data),
+ GetModule = get(get_module),
+ GetModule:do_get(UnsortedVarbinds, IsNotification, Extra).
+
+
+%%-----------------------------------------------------------------
%% Func: do_get/3
%% Purpose: do_get handles "getRequests".
%% Pre: incoming varbinds have type == 'NULL', value == unSpecified
@@ -2700,390 +2772,24 @@ mk_next_oid(Vb) ->
%% {ErrorStatus, ErrorIndex, []}
%%-----------------------------------------------------------------
-%% If this function is called from a worker-process, we *may*
-%% need to tunnel into the master-agent and let it do the
-%% work
+%% If this function is called from a worker-process (or other process),
+%% we *may* need to tunnel into the master-agent and let it do the work.
do_get(MibView, UnsortedVarbinds, IsNotification) ->
- do_get(MibView, UnsortedVarbinds, IsNotification, false).
+ Extra = get(net_if_data),
+ GetModule = get(get_module),
+ GetModule:do_get(MibView, UnsortedVarbinds, IsNotification, Extra).
do_get(MibView, UnsortedVarbinds, IsNotification, ForceMaster) ->
- ?vtrace("do_get -> entry with"
- "~n MibView: ~p"
- "~n UnsortedVarbinds: ~p"
- "~n IsNotification: ~p",
- [MibView, UnsortedVarbinds, IsNotification]),
case (whereis(snmp_master_agent) =:= self()) of
false when (ForceMaster =:= true) ->
- %% I am a lowly worker process, handoff to the master agent
PduData = get_pdu_data(),
call(snmp_master_agent,
{do_get, MibView, UnsortedVarbinds, IsNotification, PduData});
-
- _ ->
- %% This is me, the master, so go ahead
- {OutSideView, InSideView} =
- split_vbs_view(UnsortedVarbinds, MibView),
- {Error, Index, NewVbs} =
- do_get(InSideView, IsNotification),
- {Error, Index, NewVbs ++ OutSideView}
-
- end.
-
-
-split_vbs_view(Vbs, MibView) ->
- ?vtrace("split the varbinds view", []),
- split_vbs_view(Vbs, MibView, [], []).
-
-split_vbs_view([Vb | Vbs], MibView, Out, In) ->
- case snmpa_acm:validate_mib_view(Vb#varbind.oid, MibView) of
- true -> split_vbs_view(Vbs, MibView, Out, [Vb | In]);
- false -> split_vbs_view(Vbs, MibView,
- [Vb#varbind{value = noSuchObject} | Out], In)
- end;
-split_vbs_view([], _MibView, Out, In) ->
- {Out, In}.
-
-do_get(UnsortedVarbinds, IsNotification) ->
- {MyVarbinds, SubagentVarbinds} = sort_varbindlist(UnsortedVarbinds),
- case do_get_local(MyVarbinds, [], IsNotification) of
- {noError, 0, NewMyVarbinds} ->
- case do_get_subagents(SubagentVarbinds, IsNotification) of
- {noError, 0, NewSubagentVarbinds} ->
- {noError, 0, NewMyVarbinds ++ NewSubagentVarbinds};
- {ErrorStatus, ErrorIndex, _} ->
- {ErrorStatus, ErrorIndex, []}
- end;
- {ErrorStatus, ErrorIndex, _} ->
- {ErrorStatus, ErrorIndex, []}
- end.
-
-%%-----------------------------------------------------------------
-%% Func: do_get_local/3
-%% Purpose: Loop the variablebindings list. We know that each varbind
-%% in that list belongs to us.
-%% Returns: {noError, 0, ListOfNewVarbinds} |
-%% {ErrorStatus, ErrorIndex, []}
-%%-----------------------------------------------------------------
-do_get_local([Vb | Vbs], Res, IsNotification) ->
- case try_get(Vb, IsNotification) of
- NewVb when is_record(NewVb, varbind) ->
- do_get_local(Vbs, [NewVb | Res], IsNotification);
- ListOfNewVb when is_list(ListOfNewVb) ->
- do_get_local(Vbs, lists:append(ListOfNewVb, Res), IsNotification);
- {error, Error, OrgIndex} ->
- {Error, OrgIndex, []}
- end;
-do_get_local([], Res, _IsNotification) ->
- {noError, 0, Res}.
-
-%%-----------------------------------------------------------------
-%% Func: do_get_subagents/2
-%% Purpose: Loop the list of varbinds for different subagents.
-%% For each of them, call sub_agent_get to retreive
-%% the values for them.
-%% Returns: {noError, 0, ListOfNewVarbinds} |
-%% {ErrorStatus, ErrorIndex, []}
-%%-----------------------------------------------------------------
-do_get_subagents(SubagentVarbinds, IsNotification) ->
- do_get_subagents(SubagentVarbinds, [], IsNotification).
-do_get_subagents([{SubAgentPid, SAVbs} | Tail], Res, IsNotification) ->
- {_SAOids, Vbs} = sa_split(SAVbs),
- case catch subagent_get(SubAgentPid, Vbs, IsNotification) of
- {noError, 0, NewVbs} ->
- do_get_subagents(Tail, lists:append(NewVbs, Res), IsNotification);
- {ErrorStatus, ErrorIndex, _} ->
- {ErrorStatus, ErrorIndex, []};
- {'EXIT', Reason} ->
- user_err("Lost contact with subagent (get) ~w. Using genErr",
- [Reason]),
- {genErr, 0, []}
- end;
-do_get_subagents([], Res, _IsNotification) ->
- {noError, 0, Res}.
-
-
-%%-----------------------------------------------------------------
-%% Func: try_get/2
-%% Returns: {error, ErrorStatus, OrgIndex} |
-%% #varbind |
-%% List of #varbind
-%%-----------------------------------------------------------------
-try_get(IVb, IsNotification) when is_record(IVb, ivarbind) ->
- ?vtrace("try_get(ivarbind) -> entry with"
- "~n IVb: ~p", [IVb]),
- get_var_value_from_ivb(IVb, IsNotification);
-try_get({TableOid, TableVbs}, IsNotification) ->
- ?vtrace("try_get(table) -> entry with"
- "~n TableOid: ~p"
- "~n TableVbs: ~p", [TableOid, TableVbs]),
- [#ivarbind{mibentry = MibEntry}|_] = TableVbs,
- {NoAccessVbs, AccessVbs} =
- check_all_table_vbs(TableVbs, IsNotification, [], []),
- case get_tab_value_from_mib(MibEntry, TableOid, AccessVbs) of
- {error, ErrorStatus, OrgIndex} ->
- {error, ErrorStatus, OrgIndex};
- NVbs ->
- NVbs ++ NoAccessVbs
- end.
-
-%%-----------------------------------------------------------------
-%% Make sure all requested columns are accessible.
-%%-----------------------------------------------------------------
-check_all_table_vbs([IVb| IVbs], IsNotification, NoA, A) ->
- #ivarbind{mibentry = Me, varbind = Vb} = IVb,
- case Me#me.access of
- 'not-accessible' ->
- NNoA = [Vb#varbind{value = noSuchInstance} | NoA],
- check_all_table_vbs(IVbs, IsNotification, NNoA, A);
- 'accessible-for-notify' when IsNotification =:= false ->
- NNoA = [Vb#varbind{value = noSuchInstance} | NoA],
- check_all_table_vbs(IVbs, IsNotification, NNoA, A);
- 'write-only' ->
- NNoA = [Vb#varbind{value = noSuchInstance} | NoA],
- check_all_table_vbs(IVbs, IsNotification, NNoA, A);
- _ ->
- check_all_table_vbs(IVbs, IsNotification, NoA, [IVb | A])
- end;
-check_all_table_vbs([], _IsNotification, NoA, A) -> {NoA, A}.
-
-%%-----------------------------------------------------------------
-%% Returns: {error, ErrorStatus, OrgIndex} |
-%% #varbind
-%%-----------------------------------------------------------------
-get_var_value_from_ivb(IVb, IsNotification)
- when IVb#ivarbind.status =:= noError ->
- ?vtrace("get_var_value_from_ivb(noError) -> entry", []),
- #ivarbind{mibentry = Me, varbind = Vb} = IVb,
- #varbind{org_index = OrgIndex, oid = Oid} = Vb,
- case Me#me.access of
- 'not-accessible' ->
- Vb#varbind{value = noSuchInstance};
- 'accessible-for-notify' when IsNotification =:= false ->
- Vb#varbind{value = noSuchInstance};
- 'write-only' ->
- Vb#varbind{value = noSuchInstance};
- _ ->
- case get_var_value_from_mib(Me, Oid) of
- {value, Type, Value} ->
- Vb#varbind{variabletype = Type, value = Value};
- {error, ErrorStatus} ->
- {error, ErrorStatus, OrgIndex}
- end
- end;
-get_var_value_from_ivb(#ivarbind{status = Status, varbind = Vb}, _) ->
- ?vtrace("get_var_value_from_ivb(~p) -> entry", [Status]),
- Vb#varbind{value = Status}.
-
-%%-----------------------------------------------------------------
-%% Func: get_var_value_from_mib/1
-%% Purpose:
-%% Returns: {error, ErrorStatus} |
-%% {value, Type, Value}
-%%-----------------------------------------------------------------
-%% Pre: Oid is a correct instance Oid (lookup checked that).
-%% Returns: A correct return value (see make_value_a_correct_value)
-get_var_value_from_mib(#me{entrytype = variable,
- asn1_type = ASN1Type,
- mfa = {Mod, Func, Args}},
- _Oid) ->
- ?vtrace("get_var_value_from_mib(variable) -> entry when"
- "~n Mod: ~p"
- "~n Func: ~p"
- "~n Args: ~p", [Mod, Func, Args]),
- Result = (catch dbg_apply(Mod, Func, [get | Args])),
- % mib shall return {value, <a-nice-value-within-range>} |
- % {noValue, noSuchName} (v1) |
- % {noValue, noSuchObject | noSuchInstance} (v2, v1)
- % everything else (including 'genErr') will generate 'genErr'.
- make_value_a_correct_value(Result, ASN1Type, {Mod, Func, Args});
-
-get_var_value_from_mib(#me{entrytype = table_column,
- oid = MeOid,
- asn1_type = ASN1Type,
- mfa = {Mod, Func, Args}},
- Oid) ->
- ?vtrace("get_var_value_from_mib(table_column) -> entry when"
- "~n MeOid: ~p"
- "~n Mod: ~p"
- "~n Func: ~p"
- "~n Args: ~p"
- "~n Oid: ~p", [MeOid, Mod, Func, Args, Oid]),
- Col = lists:last(MeOid),
- Indexes = snmp_misc:diff(Oid, MeOid),
- [Result] = (catch dbg_apply(Mod, Func, [get, Indexes, [Col] | Args])),
- make_value_a_correct_value(Result, ASN1Type,
- {Mod, Func, Args, Indexes, Col}).
-
-
-%% For table operations we need to pass RestOid down to the table-function.
-%% Its up to the table-function to check for noSuchInstance (ex: a
-%% non-existing row).
-%% Returns: {error, ErrorStatus, OrgIndex} |
-%% {value, Type, Value}
-get_tab_value_from_mib(#me{mfa = {Mod, Func, Args}}, TableOid, TableVbs) ->
- ?vtrace("get_tab_value_from_mib -> entry when"
- "~n Mod: ~p"
- "~n Func: ~p"
- "~n Args: ~p", [Mod, Func, Args]),
- TableOpsWithShortOids = deletePrefixes(TableOid, TableVbs),
- SortedVBsRows = snmpa_svbl:sort_varbinds_rows(TableOpsWithShortOids),
- case get_value_all_rows(SortedVBsRows, Mod, Func, Args, []) of
- {Error, Index} ->
- #ivarbind{varbind = Vb} = lists:nth(Index, TableVbs),
- {error, Error, Vb#varbind.org_index};
- ListOfValues ->
- merge_varbinds_and_value(TableVbs, ListOfValues)
+ _ ->
+ do_get(MibView, UnsortedVarbinds, IsNotification)
end.
-%%-----------------------------------------------------------------
-%% Values is a scrambled list of {CorrectValue, Index}, where Index
-%% is index into the #ivarbind list. So for each Value, we must
-%% find the corresponding #ivarbind, and merge them into a new
-%% #varbind.
-%% The Values list comes from validate_tab_res.
-%%-----------------------------------------------------------------
-merge_varbinds_and_value(IVbs, [{{value, Type, Value}, Index} | Values]) ->
- #ivarbind{varbind = Vb} = lists:nth(Index, IVbs),
- [Vb#varbind{variabletype = Type, value = Value} |
- merge_varbinds_and_value(IVbs, Values)];
-merge_varbinds_and_value(_, []) -> [].
-
-get_value_all_rows([{[], OrgCols} | Rows], Mod, Func, Args, Res) ->
- ?vtrace("get_value_all_rows -> entry when"
- "~n OrgCols: ~p", [OrgCols]),
- Cols = [{{value, noValue, noSuchInstance}, Index} ||
- {_Col, _ASN1Type, Index} <- OrgCols],
- NewRes = lists:append(Cols, Res),
- get_value_all_rows(Rows, Mod, Func, Args, NewRes);
-get_value_all_rows([{RowIndex, OrgCols} | Rows], Mod, Func, Args, Res) ->
- ?vtrace("get_value_all_rows -> entry when"
- "~n RowIndex: ~p"
- "~n OrgCols: ~p", [RowIndex, OrgCols]),
- {DOrgCols, Dup} = remove_duplicates(OrgCols),
- Cols = delete_index(DOrgCols),
- Result = (catch dbg_apply(Mod, Func, [get, RowIndex, Cols | Args])),
- case validate_tab_res(Result, DOrgCols, {Mod, Func, Args}) of
- Values when is_list(Values) ->
- NVals = restore_duplicates(Dup, Values),
- NewRes = lists:append(NVals, Res),
- get_value_all_rows(Rows, Mod, Func, Args, NewRes);
- {error, ErrorStatus, Index} ->
- validate_err(row_set, {ErrorStatus, Index}, {Mod, Func, Args})
- end;
-get_value_all_rows([], _Mod, _Func, _Args, Res) ->
- ?vtrace("get_value_all_rows -> entry when done"
- "~n Res: ~p", [Res]),
- Res.
-
-%%-----------------------------------------------------------------
-%% Returns: list of {ShortOid, ASN1TYpe}
-%%-----------------------------------------------------------------
-deletePrefixes(Prefix, [#ivarbind{varbind = Varbind, mibentry = ME} | Vbs]) ->
- #varbind{oid = Oid} = Varbind,
- [{snmp_misc:diff(Oid, Prefix), ME#me.asn1_type} |
- deletePrefixes(Prefix, Vbs)];
-deletePrefixes(_Prefix, []) -> [].
-
-%%-----------------------------------------------------------------
-%% Args: {RowIndex, list of {ShortOid, ASN1Type}}
-%% Returns: list of Col
-%%-----------------------------------------------------------------
-delete_index([{Col, _Val, _OrgIndex} | T]) ->
- [Col | delete_index(T)];
-delete_index([]) -> [].
-
-%%-----------------------------------------------------------------
-%% This function is called before 'get' on a table, and removes
-%% any duplicate columns. It returns {Cols, DupInfo}. The Cols
-%% are the unique columns. The instrumentation function is
-%% called to get the values. These values, together with the
-%% DupInfo, is later passed to restore_duplicates, which uses
-%% the retrieved values to reconstruct the original column list,
-%% but with the retrieved value for each column.
-%%-----------------------------------------------------------------
-remove_duplicates(Cols) ->
- remove_duplicates(Cols, [], []).
-
-
-remove_duplicates([{Col, V1, OrgIdx1}, {Col, V2, OrgIdx2} | T], NCols, Dup) ->
- remove_duplicates([{Col, V1, OrgIdx1} | T], NCols,
- [{Col, V2, OrgIdx2} | Dup]);
-remove_duplicates([Col | T], NCols, Dup) ->
- remove_duplicates(T, [Col | NCols], Dup);
-remove_duplicates([], NCols, Dup) ->
- {lists:reverse(NCols), lists:reverse(Dup)}.
-
-restore_duplicates([], Cols) ->
- [{Val, OrgIndex} || {_Col, Val, OrgIndex} <- Cols];
-restore_duplicates([{Col, _Val2, OrgIndex2} | Dup],
- [{Col, NVal, OrgIndex1} | Cols]) ->
- [{NVal, OrgIndex2} |
- restore_duplicates(Dup, [{Col, NVal, OrgIndex1} | Cols])];
-restore_duplicates(Dup, [{_Col, Val, OrgIndex} | T]) ->
- [{Val, OrgIndex} | restore_duplicates(Dup, T)].
-
-%% Maps the column number to Index.
-% col_to_index(0, _) -> 0;
-% col_to_index(Col, [{Col, _, Index}|_]) ->
-% Index;
-% col_to_index(Col, [_|Cols]) ->
-% col_to_index(Col, Cols).
-
-%%-----------------------------------------------------------------
-%% Three cases:
-%% 1) All values ok
-%% 2) table_func returned {Error, ...}
-%% 3) Some value in Values list is erroneous.
-%% Args: Value is a list of values from table_func(get..)
-%% OrgCols is a list with {Col, ASN1Type, OrgIndex}
-%% each element in Values and OrgCols correspond to each
-%% other.
-%%-----------------------------------------------------------------
-validate_tab_res(Values, OrgCols, Mfa) when is_list(Values) ->
- {_Col, _ASN1Type, OneIdx} = hd(OrgCols),
- validate_tab_res(Values, OrgCols, Mfa, [], OneIdx);
-validate_tab_res({noValue, Error}, OrgCols, Mfa) ->
- Values = lists:duplicate(length(OrgCols), {noValue, Error}),
- validate_tab_res(Values, OrgCols, Mfa);
-validate_tab_res({genErr, Col}, OrgCols, Mfa) ->
- case lists:keysearch(Col, 1, OrgCols) of
- {value, {_Col, _ASN1Type, Index}} ->
- {error, genErr, Index};
- _ ->
- user_err("Invalid column in {genErr, ~w} from ~w (get)",
- [Col, Mfa]),
- [{_Col, _ASN1Type, Index} | _] = OrgCols,
- {error, genErr, Index}
- end;
-validate_tab_res(genErr, [{_Col, __ASN1Type, Index} | _OrgCols], _Mfa) ->
- {error, genErr, Index};
-validate_tab_res(Error, [{_Col, _ASN1Type, Index} | _OrgCols], Mfa) ->
- user_err("Invalid return value ~w from ~w (get)",[Error, Mfa]),
- {error, genErr, Index}.
-
-validate_tab_res([Value | Values],
- [{Col, ASN1Type, Index} | OrgCols],
- Mfa, Res, I) ->
- %% This one makes it possible to return a list of genErr, which
- %% is not allowed according to the manual. But that's ok, as
- %% everything else will generate a genErr! (the only problem is
- %% that it won't generate a user_error).
- case make_value_a_correct_value(Value, ASN1Type, Mfa) of
- {error, ErrorStatus} ->
- {error, ErrorStatus, Index};
- CorrectValue ->
- NewRes = [{Col, CorrectValue, Index} | Res],
- validate_tab_res(Values, OrgCols, Mfa, NewRes, I)
- end;
-validate_tab_res([], [], _Mfa, Res, _I) ->
- lists:reverse(Res);
-validate_tab_res([], [{_Col, _ASN1Type, Index}|_], Mfa, _Res, _I) ->
- user_err("Too few values returned from ~w (get)", [Mfa]),
- {error, genErr, Index};
-validate_tab_res(_TooMany, [], Mfa, _Res, I) ->
- user_err("Too many values returned from ~w (get)", [Mfa]),
- {error, genErr, I}.
%%%-----------------------------------------------------------------
@@ -3125,491 +2831,12 @@ validate_tab_res(_TooMany, [], Mfa, _Res, I) ->
%% subagent must be considered to be very rare.
%%-----------------------------------------------------------------
-%% It may be a bit agressive to check this already,
-%% but since it is a security measure, it makes sense.
-do_get_next(_MibView, UnsortedVarbinds, GbMaxVBs)
- when (is_integer(GbMaxVBs) andalso (length(UnsortedVarbinds) > GbMaxVBs)) ->
- {tooBig, 0, []}; % What is the correct index in this case?
-do_get_next(MibView, UnsortedVBs, GbMaxVBs) ->
- ?vt("do_get_next -> entry when"
- "~n MibView: ~p"
- "~n UnsortedVBs: ~p", [MibView, UnsortedVBs]),
- SortedVBs = oid_sort_vbs(UnsortedVBs),
- ?vt("do_get_next -> "
- "~n SortedVBs: ~p", [SortedVBs]),
- next_loop_varbinds([], SortedVBs, MibView, [], [], GbMaxVBs).
-
-oid_sort_vbs(Vbs) ->
- lists:keysort(#varbind.oid, Vbs).
-
-next_loop_varbinds(_, Vbs, _MibView, Res, _LAVb, GbMaxVBs)
- when (is_integer(GbMaxVBs) andalso
- ((length(Vbs) + length(Res)) > GbMaxVBs)) ->
- {tooBig, 0, []}; % What is the correct index in this case?
-
-%% LAVb is Last Accessible Vb
-next_loop_varbinds([], [Vb | Vbs], MibView, Res, LAVb, GbMaxVBs) ->
- ?vt("next_loop_varbinds -> entry when"
- "~n Vb: ~p"
- "~n MibView: ~p", [Vb, MibView]),
- case varbind_next(Vb, MibView) of
- endOfMibView ->
- ?vt("next_loop_varbind -> endOfMibView", []),
- RVb = if LAVb =:= [] -> Vb;
- true -> LAVb
- end,
- NewVb = RVb#varbind{variabletype = 'NULL', value = endOfMibView},
- next_loop_varbinds([], Vbs, MibView, [NewVb | Res], [], GbMaxVBs);
-
- {variable, ME, VarOid} when ((ME#me.access =/= 'not-accessible') andalso
- (ME#me.access =/= 'write-only') andalso
- (ME#me.access =/= 'accessible-for-notify')) ->
- ?vt("next_loop_varbind -> variable: "
- "~n ME: ~p"
- "~n VarOid: ~p", [ME, VarOid]),
- case try_get_instance(Vb, ME) of
- {value, noValue, _NoSuchSomething} ->
- ?vt("next_loop_varbind -> noValue", []),
- %% Try next one
- NewVb = Vb#varbind{oid = VarOid,
- value = 'NULL'},
- next_loop_varbinds([], [NewVb | Vbs], MibView, Res, [],
- GbMaxVBs);
- {value, Type, Value} ->
- ?vt("next_loop_varbind -> value"
- "~n Type: ~p"
- "~n Value: ~p", [Type, Value]),
- NewVb = Vb#varbind{oid = VarOid,
- variabletype = Type,
- value = Value},
- next_loop_varbinds([], Vbs, MibView, [NewVb | Res], [],
- GbMaxVBs);
- {error, ErrorStatus} ->
- ?vdebug("next loop varbinds:"
- "~n ErrorStatus: ~p",[ErrorStatus]),
- {ErrorStatus, Vb#varbind.org_index, []}
- end;
- {variable, _ME, VarOid} ->
- ?vt("next_loop_varbind -> variable: "
- "~n VarOid: ~p", [VarOid]),
- RVb = if LAVb =:= [] -> Vb;
- true -> LAVb
- end,
- NewVb = Vb#varbind{oid = VarOid, value = 'NULL'},
- next_loop_varbinds([], [NewVb | Vbs], MibView, Res, RVb, GbMaxVBs);
- {table, TableOid, TableRestOid, ME} ->
- ?vt("next_loop_varbind -> table: "
- "~n TableOid: ~p"
- "~n TableRestOid: ~p"
- "~n ME: ~p", [TableOid, TableRestOid, ME]),
- next_loop_varbinds({table, TableOid, ME,
- [{tab_oid(TableRestOid), Vb}]},
- Vbs, MibView, Res, [], GbMaxVBs);
- {subagent, SubAgentPid, SAOid} ->
- ?vt("next_loop_varbind -> subagent: "
- "~n SubAgentPid: ~p"
- "~n SAOid: ~p", [SubAgentPid, SAOid]),
- NewVb = Vb#varbind{variabletype = 'NULL', value = 'NULL'},
- next_loop_varbinds({subagent, SubAgentPid, SAOid, [NewVb]},
- Vbs, MibView, Res, [], GbMaxVBs)
- end;
-next_loop_varbinds({table, TableOid, ME, TabOids},
- [Vb | Vbs], MibView, Res, _LAVb, GbMaxVBs) ->
- ?vt("next_loop_varbinds(table) -> entry with"
- "~n TableOid: ~p"
- "~n Vb: ~p", [TableOid, Vb]),
- case varbind_next(Vb, MibView) of
- {table, TableOid, TableRestOid, _ME} ->
- next_loop_varbinds({table, TableOid, ME,
- [{tab_oid(TableRestOid), Vb} | TabOids]},
- Vbs, MibView, Res, [], GbMaxVBs);
- _ ->
- case get_next_table(ME, TableOid, TabOids, MibView) of
- {ok, TabRes, TabEndOfTabVbs} ->
- NewVbs = lists:append(TabEndOfTabVbs, [Vb | Vbs]),
- NewRes = lists:append(TabRes, Res),
- next_loop_varbinds([], NewVbs, MibView, NewRes, [],
- GbMaxVBs);
- {ErrorStatus, OrgIndex} ->
- ?vdebug("next loop varbinds: next varbind"
- "~n ErrorStatus: ~p"
- "~n OrgIndex: ~p",
- [ErrorStatus,OrgIndex]),
- {ErrorStatus, OrgIndex, []}
- end
- end;
-next_loop_varbinds({table, TableOid, ME, TabOids},
- [], MibView, Res, _LAVb, GbMaxVBs) ->
- ?vt("next_loop_varbinds(table) -> entry with"
- "~n TableOid: ~p", [TableOid]),
- case get_next_table(ME, TableOid, TabOids, MibView) of
- {ok, TabRes, TabEndOfTabVbs} ->
- ?vt("next_loop_varbinds(table) -> get_next_table result:"
- "~n TabRes: ~p"
- "~n TabEndOfTabVbs: ~p", [TabRes, TabEndOfTabVbs]),
- NewRes = lists:append(TabRes, Res),
- next_loop_varbinds([], TabEndOfTabVbs, MibView, NewRes, [],
- GbMaxVBs);
- {ErrorStatus, OrgIndex} ->
- ?vdebug("next loop varbinds: next table"
- "~n ErrorStatus: ~p"
- "~n OrgIndex: ~p",
- [ErrorStatus,OrgIndex]),
- {ErrorStatus, OrgIndex, []}
- end;
-next_loop_varbinds({subagent, SAPid, SAOid, SAVbs},
- [Vb | Vbs], MibView, Res, _LAVb, GbMaxVBs) ->
- ?vt("next_loop_varbinds(subagent) -> entry with"
- "~n SAPid: ~p"
- "~n SAOid: ~p"
- "~n Vb: ~p", [SAPid, SAOid, Vb]),
- case varbind_next(Vb, MibView) of
- {subagent, _SubAgentPid, SAOid} ->
- next_loop_varbinds({subagent, SAPid, SAOid,
- [Vb | SAVbs]},
- Vbs, MibView, Res, [], GbMaxVBs);
- _ ->
- case get_next_sa(SAPid, SAOid, SAVbs, MibView) of
- {ok, SARes, SAEndOfMibViewVbs} ->
- NewVbs = lists:append(SAEndOfMibViewVbs, [Vb | Vbs]),
- NewRes = lists:append(SARes, Res),
- next_loop_varbinds([], NewVbs, MibView, NewRes, [],
- GbMaxVBs);
- {noSuchName, OrgIndex} ->
- %% v1 reply, treat this Vb as endOfMibView, and try again
- %% for the others.
- case lists:keysearch(OrgIndex, #varbind.org_index, SAVbs) of
- {value, EVb} ->
- NextOid = next_oid(SAOid),
- EndOfVb =
- EVb#varbind{oid = NextOid,
- value = {endOfMibView, NextOid}},
- case lists:delete(EVb, SAVbs) of
- [] ->
- next_loop_varbinds([], [EndOfVb, Vb | Vbs],
- MibView, Res, [],
- GbMaxVBs);
- TryAgainVbs ->
- next_loop_varbinds({subagent, SAPid, SAOid,
- TryAgainVbs},
- [EndOfVb, Vb | Vbs],
- MibView, Res, [],
- GbMaxVBs)
- end;
- false ->
- %% bad index from subagent
- {genErr, (hd(SAVbs))#varbind.org_index, []}
- end;
- {ErrorStatus, OrgIndex} ->
- ?vdebug("next loop varbinds: next subagent"
- "~n Vb: ~p"
- "~n ErrorStatus: ~p"
- "~n OrgIndex: ~p",
- [Vb,ErrorStatus,OrgIndex]),
- {ErrorStatus, OrgIndex, []}
- end
- end;
-next_loop_varbinds({subagent, SAPid, SAOid, SAVbs},
- [], MibView, Res, _LAVb, GbMaxVBs) ->
- ?vt("next_loop_varbinds(subagent) -> entry with"
- "~n SAPid: ~p"
- "~n SAOid: ~p", [SAPid, SAOid]),
- case get_next_sa(SAPid, SAOid, SAVbs, MibView) of
- {ok, SARes, SAEndOfMibViewVbs} ->
- NewRes = lists:append(SARes, Res),
- next_loop_varbinds([], SAEndOfMibViewVbs, MibView, NewRes, [],
- GbMaxVBs);
- {noSuchName, OrgIndex} ->
- %% v1 reply, treat this Vb as endOfMibView, and try again for
- %% the others.
- case lists:keysearch(OrgIndex, #varbind.org_index, SAVbs) of
- {value, EVb} ->
- NextOid = next_oid(SAOid),
- EndOfVb = EVb#varbind{oid = NextOid,
- value = {endOfMibView, NextOid}},
- case lists:delete(EVb, SAVbs) of
- [] ->
- next_loop_varbinds([], [EndOfVb], MibView, Res, [],
- GbMaxVBs);
- TryAgainVbs ->
- next_loop_varbinds({subagent, SAPid, SAOid,
- TryAgainVbs},
- [EndOfVb], MibView, Res, [],
- GbMaxVBs)
- end;
- false ->
- %% bad index from subagent
- {genErr, (hd(SAVbs))#varbind.org_index, []}
- end;
- {ErrorStatus, OrgIndex} ->
- ?vdebug("next loop varbinds: next subagent"
- "~n ErrorStatus: ~p"
- "~n OrgIndex: ~p",
- [ErrorStatus,OrgIndex]),
- {ErrorStatus, OrgIndex, []}
- end;
-next_loop_varbinds([], [], _MibView, Res, _LAVb, _GbMaxVBs) ->
- ?vt("next_loop_varbinds -> entry when done", []),
- {noError, 0, Res}.
-
-try_get_instance(_Vb, #me{mfa = {M, F, A}, asn1_type = ASN1Type}) ->
- ?vtrace("try_get_instance -> entry with"
- "~n M: ~p"
- "~n F: ~p"
- "~n A: ~p", [M,F,A]),
- Result = (catch dbg_apply(M, F, [get | A])),
- % mib shall return {value, <a-nice-value-within-range>} |
- % {noValue, noSuchName} (v1) |
- % {noValue, noSuchObject | noSuchInstance} (v2, v1)
- % everything else (including 'genErr') will generate 'genErr'.
- make_value_a_correct_value(Result, ASN1Type, {M, F, A}).
-
-tab_oid([]) -> [0];
-tab_oid(X) -> X.
-
-
-%%-----------------------------------------------------------------
-%% Perform a next, using the varbinds Oid if value is simple
-%% value. If value is {endOf<something>, NextOid}, use NextOid.
-%% This case happens when a table has returned endOfTable, or
-%% a subagent has returned endOfMibView.
-%%-----------------------------------------------------------------
-varbind_next(#varbind{value = Value, oid = Oid}, MibView) ->
- ?vt("varbind_next -> entry with"
- "~n Value: ~p"
- "~n Oid: ~p"
- "~n MibView: ~p", [Value, Oid, MibView]),
- case Value of
- {endOfTable, NextOid} ->
- snmpa_mib:next(get(mibserver), NextOid, MibView);
- {endOfMibView, NextOid} ->
- snmpa_mib:next(get(mibserver), NextOid, MibView);
- _ ->
- snmpa_mib:next(get(mibserver), Oid, MibView)
- end.
-
-get_next_table(#me{mfa = {M, F, A}}, TableOid, TableOids, MibView) ->
- % We know that all TableOids have at least a column number as oid
- ?vt("get_next_table -> entry with"
- "~n M: ~p"
- "~n F: ~p"
- "~n A: ~p"
- "~n TableOid: ~p"
- "~n TableOids: ~p"
- "~n MibView: ~p", [M, F, A, TableOid, TableOids, MibView]),
- Sorted = snmpa_svbl:sort_varbinds_rows(TableOids),
- case get_next_values_all_rows(Sorted, M,F,A, [], TableOid) of
- NewVbs when is_list(NewVbs) ->
- ?vt("get_next_table -> "
- "~n NewVbs: ~p", [NewVbs]),
- % We must now check each Vb for endOfTable and that it is
- % in the MibView. If not, it becomes a endOfTable. We
- % collect all of these together.
- transform_tab_next_result(NewVbs, {[], []}, MibView);
- {ErrorStatus, OrgIndex} ->
- {ErrorStatus, OrgIndex}
- end.
-
-get_next_values_all_rows([Row | Rows], M, F, A, Res, TabOid) ->
- {RowIndex, TableOids} = Row,
- Cols = delete_index(TableOids),
- ?vt("get_next_values_all_rows -> "
- "~n Cols: ~p", [Cols]),
- Result = (catch dbg_apply(M, F, [get_next, RowIndex, Cols | A])),
- ?vt("get_next_values_all_rows -> "
- "~n Result: ~p", [Result]),
- case validate_tab_next_res(Result, TableOids, {M, F, A}, TabOid) of
- Values when is_list(Values) ->
- ?vt("get_next_values_all_rows -> "
- "~n Values: ~p", [Values]),
- NewRes = lists:append(Values, Res),
- get_next_values_all_rows(Rows, M, F, A, NewRes, TabOid);
- {ErrorStatus, OrgIndex} ->
- {ErrorStatus, OrgIndex}
- end;
-get_next_values_all_rows([], _M, _F, _A, Res, _TabOid) ->
- Res.
-
-transform_tab_next_result([Vb | Vbs], {Res, EndOfs}, MibView) ->
- case Vb#varbind.value of
- {endOfTable, _} ->
-%% ?vtrace("transform_tab_next_result -> endOfTable: "
-%% "split varbinds",[]),
-%% R = split_varbinds(Vbs, Res, [Vb | EndOfs]),
-%% ?vtrace("transform_tab_next_result -> "
-%% "~n R: ~p", [R]),
-%% R;
- split_varbinds(Vbs, Res, [Vb | EndOfs]);
- _ ->
- case snmpa_acm:validate_mib_view(Vb#varbind.oid, MibView) of
- true ->
- transform_tab_next_result(Vbs, {[Vb|Res], EndOfs},MibView);
- _ ->
- Oid = Vb#varbind.oid,
- NewEndOf = Vb#varbind{value = {endOfTable, Oid}},
- transform_tab_next_result(Vbs, {Res, [NewEndOf | EndOfs]},
- MibView)
- end
- end;
-transform_tab_next_result([], {Res, EndOfs}, _MibView) ->
- ?vt("transform_tab_next_result -> entry with: "
- "~n Res: ~p"
- "~n EndIfs: ~p",[Res, EndOfs]),
- {ok, Res, EndOfs}.
-
-%%-----------------------------------------------------------------
-%% Three cases:
-%% 1) All values ok
-%% 2) table_func returned {Error, ...}
-%% 3) Some value in Values list is erroneous.
-%% Args: Value is a list of values from table_func(get_next, ...)
-%% TableOids is a list of {TabRestOid, OrgVb}
-%% each element in Values and TableOids correspond to each
-%% other.
-%% Returns: List of NewVarbinds |
-%% {ErrorStatus, OrgIndex}
-%% (In the NewVarbinds list, the value may be endOfTable)
-%%-----------------------------------------------------------------
-validate_tab_next_res(Values, TableOids, Mfa, TabOid) ->
- ?vt("validate_tab_next_res -> entry with: "
- "~n Values: ~p"
- "~n TableOids: ~p"
- "~n Mfa: ~p"
- "~n TabOid: ~p", [Values, TableOids, Mfa, TabOid]),
- {_Col, _ASN1Type, OneIdx} = hd(TableOids),
- validate_tab_next_res(Values, TableOids, Mfa, [], TabOid,
- next_oid(TabOid), OneIdx).
-validate_tab_next_res([{NextOid, Value} | Values],
- [{_ColNo, OrgVb, _Index} | TableOids],
- Mfa, Res, TabOid, TabNextOid, I) ->
- ?vt("validate_tab_next_res -> entry with: "
- "~n NextOid: ~p"
- "~n Value: ~p"
- "~n Values: ~p"
- "~n TableOids: ~p"
- "~n Mfa: ~p"
- "~n TabOid: ~p",
- [NextOid, Value, Values, TableOids, Mfa, TabOid]),
- #varbind{org_index = OrgIndex} = OrgVb,
- ?vt("validate_tab_next_res -> OrgIndex: ~p", [OrgIndex]),
- NextCompleteOid = lists:append(TabOid, NextOid),
- case snmpa_mib:lookup(get(mibserver), NextCompleteOid) of
- {table_column, #me{asn1_type = ASN1Type}, _TableEntryOid} ->
- ?vt("validate_tab_next_res -> ASN1Type: ~p", [ASN1Type]),
- case make_value_a_correct_value({value, Value}, ASN1Type, Mfa) of
- {error, ErrorStatus} ->
- ?vt("validate_tab_next_res -> "
- "~n ErrorStatus: ~p", [ErrorStatus]),
- {ErrorStatus, OrgIndex};
- {value, Type, NValue} ->
- ?vt("validate_tab_next_res -> "
- "~n Type: ~p"
- "~n NValue: ~p", [Type, NValue]),
- NewVb = OrgVb#varbind{oid = NextCompleteOid,
- variabletype = Type, value = NValue},
- validate_tab_next_res(Values, TableOids, Mfa,
- [NewVb | Res], TabOid, TabNextOid, I)
- end;
- Error ->
- user_err("Invalid oid ~w from ~w (get_next). Using genErr => ~p",
- [NextOid, Mfa, Error]),
- {genErr, OrgIndex}
- end;
-validate_tab_next_res([endOfTable | Values],
- [{_ColNo, OrgVb, _Index} | TableOids],
- Mfa, Res, TabOid, TabNextOid, I) ->
- ?vt("validate_tab_next_res(endOfTable) -> entry with: "
- "~n Values: ~p"
- "~n OrgVb: ~p"
- "~n TableOids: ~p"
- "~n Mfa: ~p"
- "~n Res: ~p"
- "~n TabOid: ~p"
- "~n TabNextOid: ~p"
- "~n I: ~p",
- [Values, OrgVb, TableOids, Mfa, Res, TabOid, TabNextOid, I]),
- NewVb = OrgVb#varbind{value = {endOfTable, TabNextOid}},
- validate_tab_next_res(Values, TableOids, Mfa, [NewVb | Res],
- TabOid, TabNextOid, I);
-validate_tab_next_res([], [], _Mfa, Res, _TabOid, _TabNextOid, _I) ->
- Res;
-validate_tab_next_res([], [{_Col, _OrgVb, Index}|_], Mfa, _Res, _, _, _I) ->
- user_err("Too few values returned from ~w (get_next)", [Mfa]),
- {genErr, Index};
-validate_tab_next_res({genErr, ColNumber}, OrgCols,
- Mfa, _Res, _TabOid, _TabNextOid, _I) ->
- OrgIndex = snmpa_svbl:col_to_orgindex(ColNumber, OrgCols),
- validate_err(table_next, {genErr, OrgIndex}, Mfa);
-validate_tab_next_res({error, Reason}, [{_ColNo, OrgVb, _Index} | _TableOids],
- Mfa, _Res, _TabOid, _TabNextOid, _I) ->
- #varbind{org_index = OrgIndex} = OrgVb,
- user_err("Erroneous return value ~w from ~w (get_next)",
- [Reason, Mfa]),
- {genErr, OrgIndex};
-validate_tab_next_res(Error, [{_ColNo, OrgVb, _Index} | _TableOids],
- Mfa, _Res, _TabOid, _TabNextOid, _I) ->
- #varbind{org_index = OrgIndex} = OrgVb,
- user_err("Invalid return value ~w from ~w (get_next)",
- [Error, Mfa]),
- {genErr, OrgIndex};
-validate_tab_next_res(TooMany, [], Mfa, _Res, _, _, I) ->
- user_err("Too many values ~w returned from ~w (get_next)",
- [TooMany, Mfa]),
- {genErr, I}.
-
-%%-----------------------------------------------------------------
-%% Func: get_next_sa/4
-%% Purpose: Loop the list of varbinds for the subagent.
-%% Call subagent_get_next to retreive
-%% the next varbinds.
-%% Returns: {ok, ListOfNewVbs, ListOfEndOfMibViewsVbs} |
-%% {ErrorStatus, ErrorIndex}
-%%-----------------------------------------------------------------
-get_next_sa(SAPid, SAOid, SAVbs, MibView) ->
- case catch subagent_get_next(SAPid, MibView, SAVbs) of
- {noError, 0, NewVbs} ->
- NewerVbs = transform_sa_next_result(NewVbs,SAOid,next_oid(SAOid)),
- split_varbinds(NewerVbs, [], []);
- {ErrorStatus, ErrorIndex, _} ->
- {ErrorStatus, ErrorIndex};
- {'EXIT', Reason} ->
- user_err("Lost contact with subagent (next) ~w. Using genErr",
- [Reason]),
- {genErr, 0}
- end.
-%%-----------------------------------------------------------------
-%% Check for wrong prefix returned or endOfMibView, and convert
-%% into {endOfMibView, SANextOid}.
-%%-----------------------------------------------------------------
-transform_sa_next_result([Vb | Vbs], SAOid, SANextOid)
- when Vb#varbind.value =:= endOfMibView ->
- [Vb#varbind{value = {endOfMibView, SANextOid}} |
- transform_sa_next_result(Vbs, SAOid, SANextOid)];
-transform_sa_next_result([Vb | Vbs], SAOid, SANextOid) ->
- case lists:prefix(SAOid, Vb#varbind.oid) of
- true ->
- [Vb | transform_sa_next_result(Vbs, SAOid, SANextOid)];
- _ ->
- [Vb#varbind{oid = SANextOid, value = {endOfMibView, SANextOid}} |
- transform_sa_next_result(Vbs, SAOid, SANextOid)]
- end;
-transform_sa_next_result([], _SAOid, _SANextOid) ->
- [].
-
-split_varbinds([Vb | Vbs], Res, EndOfs) ->
- case Vb#varbind.value of
- {endOfMibView, _} -> split_varbinds(Vbs, Res, [Vb | EndOfs]);
- {endOfTable, _} -> split_varbinds(Vbs, Res, [Vb | EndOfs]);
- _ -> split_varbinds(Vbs, [Vb | Res], EndOfs)
- end;
-split_varbinds([], Res, EndOfs) -> {ok, Res, EndOfs}.
+do_get_next(MibView, UnsortedVarbinds) ->
+ Extra = get(net_if_data),
+ GetModule = get(get_module),
+ GetModule:do_get_next(MibView, UnsortedVarbinds, Extra).
-next_oid(Oid) ->
- case lists:reverse(Oid) of
- [H | T] -> lists:reverse([H+1 | T]);
- [] -> []
- end.
%%%-----------------------------------------------------------------
@@ -3623,200 +2850,12 @@ next_oid(Oid) ->
%%%-----------------------------------------------------------------
do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds, GbMaxVBs) ->
- ?vtrace("do_get_bulk -> entry with"
- "~n MibView: ~p"
- "~n NonRepeaters: ~p"
- "~n MaxRepetitions: ~p"
- "~n PduMS: ~p"
- "~n Varbinds: ~p"
- "~n GbMaxVBs: ~p",
- [MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds, GbMaxVBs]),
- {NonRepVbs, RestVbs} = split_vbs(NonRepeaters, Varbinds, []),
- ?vt("do_get_bulk -> split: "
- "~n NonRepVbs: ~p"
- "~n RestVbs: ~p", [NonRepVbs, RestVbs]),
- case do_get_next(MibView, NonRepVbs, GbMaxVBs) of
- {noError, 0, UResNonRepVbs} ->
- ?vt("do_get_bulk -> next noError: "
- "~n UResNonRepVbs: ~p", [UResNonRepVbs]),
- ResNonRepVbs = lists:keysort(#varbind.org_index, UResNonRepVbs),
- %% Decode the first varbinds, produce a reversed list of
- %% listOfBytes.
- case (catch enc_vbs(PduMS - ?empty_pdu_size, ResNonRepVbs)) of
- {error, Idx, Reason} ->
- user_err("failed encoding varbind ~w:~n~p", [Idx, Reason]),
- {genErr, Idx, []};
- {SizeLeft, Res} when is_integer(SizeLeft) and is_list(Res) ->
- ?vtrace("do_get_bulk -> encoded: "
- "~n SizeLeft: ~p"
- "~n Res: ~w", [SizeLeft, Res]),
- case (catch do_get_rep(SizeLeft, MibView, MaxRepetitions,
- RestVbs, Res,
- length(UResNonRepVbs), GbMaxVBs)) of
- {error, Idx, Reason} ->
- user_err("failed encoding varbind ~w:~n~p",
- [Idx, Reason]),
- {genErr, Idx, []};
- Res when is_list(Res) ->
- ?vtrace("do get bulk -> Res: "
- "~n ~w", [Res]),
- {noError, 0, conv_res(Res)};
- {noError, 0, Data} = OK ->
- ?vtrace("do get bulk -> OK: "
- "~n length(Data): ~w", [length(Data)]),
- OK;
- Else ->
- ?vtrace("do get bulk -> Else: "
- "~n ~w", [Else]),
- Else
- end;
- Res when is_list(Res) ->
- {noError, 0, conv_res(Res)}
- end;
+ Extra = get(net_if_data),
+ GetModule = get(get_module),
+ GetModule:do_get_bulk(MibView, NonRepeaters, MaxRepetitions,
+ PduMS, Varbinds, GbMaxVBs,
+ Extra).
- {ErrorStatus, Index, _} ->
- ?vdebug("do get bulk: "
- "~n ErrorStatus: ~p"
- "~n Index: ~p",[ErrorStatus, Index]),
- {ErrorStatus, Index, []}
- end.
-
-% sz(L) when list(L) -> length(L);
-% sz(B) when binary(B) -> size(B);
-% sz(_) -> unknown.
-
-split_vbs(N, Varbinds, Res) when N =< 0 -> {Res, Varbinds};
-split_vbs(N, [H | T], Res) -> split_vbs(N-1, T, [H | Res]);
-split_vbs(_N, [], Res) -> {Res, []}.
-
-enc_vbs(SizeLeft, Vbs) ->
- ?vt("enc_vbs -> entry with"
- "~n SizeLeft: ~w", [SizeLeft]),
- Fun = fun(Vb, {Sz, Res}) when Sz > 0 ->
- ?vt("enc_vbs -> (fun) entry with"
- "~n Vb: ~p"
- "~n Sz: ~p"
- "~n Res: ~w", [Vb, Sz, Res]),
- case (catch snmp_pdus:enc_varbind(Vb)) of
- {'EXIT', Reason} ->
- ?vtrace("enc_vbs -> encode failed: "
- "~n Reason: ~p", [Reason]),
- throw({error, Vb#varbind.org_index, Reason});
- X ->
- ?vt("enc_vbs -> X: ~w", [X]),
- Lx = length(X),
- ?vt("enc_vbs -> Lx: ~w", [Lx]),
- if
- Lx < Sz ->
- {Sz - length(X), [X | Res]};
- true ->
- throw(Res)
- end
- end;
- (_Vb, {_Sz, [_H | T]}) ->
- ?vt("enc_vbs -> (fun) entry with"
- "~n T: ~p", [T]),
- throw(T);
- (_Vb, {_Sz, []}) ->
- ?vt("enc_vbs -> (fun) entry", []),
- throw([])
- end,
- lists:foldl(Fun, {SizeLeft, []}, Vbs).
-
-do_get_rep(Sz, MibView, MaxRepetitions, Varbinds, Res, GbNumVBs, GbMaxVBs)
- when MaxRepetitions >= 0 ->
- do_get_rep(Sz, MibView, 0, MaxRepetitions, Varbinds, Res,
- GbNumVBs, GbMaxVBs);
-do_get_rep(Sz, MibView, _MaxRepetitions, Varbinds, Res, GbNumVBs, GbMaxVBs) ->
- do_get_rep(Sz, MibView, 0, 0, Varbinds, Res, GbNumVBs, GbMaxVBs).
-
-conv_res(ResVarbinds) ->
- conv_res(ResVarbinds, []).
-conv_res([VbListOfBytes | T], Bytes) ->
- conv_res(T, VbListOfBytes ++ Bytes);
-conv_res([], Bytes) ->
- Bytes.
-
-%% The only other value, then a positive integer, is infinity.
-do_get_rep(_Sz, _MibView, Count, Max, _, _Res, GbNumVBs, GbMaxVBs)
- when (is_integer(GbMaxVBs) andalso (GbNumVBs > GbMaxVBs)) ->
- ?vinfo("Max Get-BULK VBs limit (~w) exceeded (~w) when:"
- "~n Count: ~p"
- "~n Max: ~p", [GbMaxVBs, GbNumVBs, Count, Max]),
- {tooBig, 0, []};
-do_get_rep(_Sz, _MibView, Max, Max, _, Res, _GbNumVBs, _GbMaxVBs) ->
- ?vt("do_get_rep -> done when: "
- "~n Res: ~p", [Res]),
- {noError, 0, conv_res(Res)};
-do_get_rep(Sz, MibView, Count, Max, Varbinds, Res, GbNumVBs, GbMaxVBs) ->
- ?vt("do_get_rep -> entry when: "
- "~n Sz: ~p"
- "~n Count: ~p"
- "~n Res: ~w", [Sz, Count, Res]),
- case try_get_bulk(Sz, MibView, Varbinds, GbMaxVBs) of
- {noError, NextVarbinds, SizeLeft, Res2} ->
- ?vt("do_get_rep -> noError: "
- "~n SizeLeft: ~p"
- "~n Res2: ~p", [SizeLeft, Res2]),
- do_get_rep(SizeLeft, MibView, Count+1, Max, NextVarbinds,
- Res2 ++ Res,
- GbNumVBs + length(Varbinds), GbMaxVBs);
- {endOfMibView, _NextVarbinds, _SizeLeft, Res2} ->
- ?vt("do_get_rep -> endOfMibView: "
- "~n Res2: ~p", [Res2]),
- {noError, 0, conv_res(Res2 ++ Res)};
- {ErrorStatus, Index} ->
- ?vtrace("do_get_rep -> done when error: "
- "~n ErrorStatus: ~p"
- "~n Index: ~p", [ErrorStatus, Index]),
- {ErrorStatus, Index, []}
- end.
-
-org_index_sort_vbs(Vbs) ->
- lists:keysort(#varbind.org_index, Vbs).
-
-try_get_bulk(Sz, MibView, Varbinds, GbMaxVBs) ->
- ?vt("try_get_bulk -> entry with"
- "~n Sz: ~w"
- "~n MibView: ~w"
- "~n Varbinds: ~w", [Sz, MibView, Varbinds]),
- case do_get_next(MibView, Varbinds, GbMaxVBs) of
- {noError, 0, UNextVarbinds} ->
- ?vt("try_get_bulk -> noError: "
- "~n UNextVarbinds: ~p", [UNextVarbinds]),
- NextVarbinds = org_index_sort_vbs(UNextVarbinds),
- case (catch enc_vbs(Sz, NextVarbinds)) of
- {error, Idx, Reason} ->
- user_err("failed encoding varbind ~w:~n~p", [Idx, Reason]),
- ?vtrace("try_get_bulk -> encode error: "
- "~n Idx: ~p"
- "~n Reason: ~p", [Idx, Reason]),
- {genErr, Idx};
- {SizeLeft, Res} when is_integer(SizeLeft) andalso
- is_list(Res) ->
- ?vt("try get bulk -> encode ok: "
- "~n SizeLeft: ~w"
- "~n Res: ~w", [SizeLeft, Res]),
- {check_end_of_mibview(NextVarbinds),
- NextVarbinds, SizeLeft, Res};
- Res when is_list(Res) ->
- ?vt("try get bulk -> Res: "
- "~n ~w", [Res]),
- {endOfMibView, [], 0, Res}
- end;
- {ErrorStatus, Index, _} ->
- ?vt("try_get_bulk -> error: "
- "~n ErrorStatus: ~p"
- "~n Index: ~p", [ErrorStatus, Index]),
- {ErrorStatus, Index}
- end.
-
-%% If all variables in this pass are endOfMibView,
-%% there is no reason to continue.
-check_end_of_mibview([#varbind{value = endOfMibView} | T]) ->
- check_end_of_mibview(T);
-check_end_of_mibview([]) -> endOfMibView;
-check_end_of_mibview(_) -> noError.
%%%--------------------------------------------------
@@ -3834,14 +2873,11 @@ do_subagent_set(Arguments) ->
SetModule = get(set_module),
apply(SetModule, do_subagent_set, [Arguments]).
+
+
%%%-----------------------------------------------------------------
%%% 7. Misc functions
%%%-----------------------------------------------------------------
-sort_varbindlist(Varbinds) ->
- snmpa_svbl:sort_varbindlist(get(mibserver), Varbinds).
-
-sa_split(SubagentVarbinds) ->
- snmpa_svbl:sa_split(SubagentVarbinds).
make_response_pdu(ReqId, ErrStatus, ErrIndex, OrgVarbinds, _ResponseVarbinds)
when ErrIndex =/= 0 ->
@@ -4139,6 +3175,7 @@ report_err(Val, Mfa, Err) ->
user_err("Got ~p from ~w. Using ~w", [Val, Mfa, Err]),
{error, Err}.
+
is_valid_pdu_type('get-request') -> true;
is_valid_pdu_type('get-next-request') -> true;
is_valid_pdu_type('get-bulk-request') -> true;
@@ -4176,33 +3213,8 @@ mapfoldl(F, Eas, Accu0, [Hd|Tail]) ->
mapfoldl(_F, _Eas, Accu, []) -> {Accu,[]}.
-%%-----------------------------------------------------------------
-%% Runtime debugging of the agent.
-%%-----------------------------------------------------------------
-
-dbg_apply(M,F,A) ->
- case get(verbosity) of
- silence ->
- apply(M,F,A);
- _ ->
- ?vlog("~n apply: ~w,~w,~p~n", [M,F,A]),
- Res = (catch apply(M,F,A)),
- case Res of
- {'EXIT', Reason} ->
- ?vinfo("Call to: "
- "~n Module: ~p"
- "~n Function: ~p"
- "~n Args: ~p"
- "~n"
- "~nresulted in an exit"
- "~n"
- "~n ~p", [M, F, A, Reason]);
- _ ->
- ?vlog("~n returned: ~p", [Res])
- end,
- Res
- end.
+%% ---------------------------------------------------------------------
short_name(none) -> ma;
short_name(_Pid) -> sa.
@@ -4450,6 +3462,9 @@ get_mib_storage(Opts) ->
get_set_mechanism(Opts) ->
get_option(set_mechanism, Opts, snmpa_set).
+get_get_mechanism(Opts) ->
+ get_option(get_mechanism, Opts, snmpa_get).
+
get_authentication_service(Opts) ->
get_option(authentication_service, Opts, snmpa_acm).
diff --git a/lib/snmp/src/agent/snmpa_app.erl b/lib/snmp/src/agent/snmpa_app.erl
index 86ff145e93..c00929c334 100644
--- a/lib/snmp/src/agent/snmpa_app.erl
+++ b/lib/snmp/src/agent/snmpa_app.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -67,6 +67,7 @@ convert_config(Opts) ->
SaVerb = get_sub_agent_verbosity(Opts),
[{agent_type, AgentType},
{agent_verbosity, SaVerb},
+ {get_mechanism, snmpa_get},
{set_mechanism, SetModule},
{authentication_service, AuthModule},
{priority, Prio},
@@ -97,6 +98,7 @@ convert_config(Opts) ->
{verbosity, ConfVerb}],
[{agent_type, AgentType},
{agent_verbosity, MaVerb},
+ {get_mechanism, snmpa_get},
{set_mechanism, SetModule},
{authentication_service, AuthModule},
{db_dir, DbDir},
diff --git a/lib/snmp/src/agent/snmpa_authentication_service.erl b/lib/snmp/src/agent/snmpa_authentication_service.erl
index e4238a8384..b6b9f5bd96 100644
--- a/lib/snmp/src/agent/snmpa_authentication_service.erl
+++ b/lib/snmp/src/agent/snmpa_authentication_service.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -19,13 +19,27 @@
%%
-module(snmpa_authentication_service).
--export([behaviour_info/1]).
-
-behaviour_info(callbacks) ->
- [{init_check_access, 2}];
-behaviour_info(_) ->
- undefined.
-
+-export_type([
+ acm_data/0
+ ]).
+
+-type acm_data() :: {community,
+ SecModel :: 0 | 1 | 2 | 3, % any | v1 | v2c | v3
+ Community :: string(),
+ %% Oids for either:
+ %% transportDomainUdpIpv4 | transportDomainUdpIpv6
+ TDomain :: snmp:oid(),
+ TAddress :: [non_neg_integer()]} |
+ {v3,
+ MsgID :: integer(),
+ SecModel :: 0 | 1 | 2 | 3, % any | v1 | v2c | v3
+ SecName :: string(),
+ %% noAuthNoPriv | authNoPriv | authPriv
+ SecLevel :: 1 | 2 | 3,
+ ContextEngineID :: string(),
+ ContextName :: string(),
+ SecData :: term()}.
+
%%-----------------------------------------------------------------
%% init_check_access(Pdu, ACMData)
@@ -46,9 +60,7 @@ behaviour_info(_) ->
%% Variable = snmpInBadCommunityNames |
%% snmpInBadCommunityUses |
%% snmpInASNParseErrs
-%% Reason = snmp_message_decoding |
-%% {bad_community_name, Address, Community}} |
-%% {invalid_access, Access, Op}
+%% Reason = {bad_community_name, Address, Community}}
%%
%% Purpose: Called once for each Pdu. Returns a MibView
%% which is later used for each variable in the pdu.
@@ -57,3 +69,14 @@ behaviour_info(_) ->
%%
%% NOTE: This function is executed in the Master agents's context
%%-----------------------------------------------------------------
+
+-callback init_check_access(Pdu, ACMData) ->
+ {ok, MibView, ContextName} |
+ {error, Reason} |
+ {discarded, Variable, Reason} when
+ Pdu :: snmp:pdu(),
+ ACMData :: acm_data(),
+ MibView :: snmp_view_based_acm_mib:mibview(),
+ ContextName :: string(),
+ Reason :: term(),
+ Variable :: snmpInBadCommunityNames.
diff --git a/lib/snmp/src/agent/snmpa_conf.erl b/lib/snmp/src/agent/snmpa_conf.erl
index fc5116dac9..c2e9d4025a 100644
--- a/lib/snmp/src/agent/snmpa_conf.erl
+++ b/lib/snmp/src/agent/snmpa_conf.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -83,6 +83,34 @@
+-export_type([
+ usm_entry/0
+ ]).
+
+-type usm_entry() :: {
+ EngineID :: string(),
+ UserName :: string(),
+ SecName :: string(),
+ Clone :: zeroDotZero | [non_neg_integer()],
+ AuthP :: usmNoAuthProtocol |
+ usmHMACMD5AuthProtocol |
+ usmHMACSHAAuthProtocol,
+ AuthKeyC :: string(),
+ OwnAuthKeyC :: string(),
+ PrivP :: usmNoPrivProtocol |
+ usmDESPrivProtocol |
+ usmAesCfb128Protocol,
+ PrivKeyC :: string(),
+ OwnPrivKeyC :: string(),
+ Public :: string(),
+ %% Size 16 for usmHMACMD5AuthProtocol
+ %% Size 20 for usmHMACSHAAuthProtocol
+ AuthKey :: [non_neg_integer()],
+ %% Size 16 for usmDESPrivProtocol | usmAesCfb128Protocol
+ PrivKey :: [non_neg_integer()]
+ }.
+
+
%%
%% ------ agent.conf ------
%%
diff --git a/lib/snmp/src/agent/snmpa_discovery_handler.erl b/lib/snmp/src/agent/snmpa_discovery_handler.erl
index ffdd6aca1e..6fb1d1eb72 100644
--- a/lib/snmp/src/agent/snmpa_discovery_handler.erl
+++ b/lib/snmp/src/agent/snmpa_discovery_handler.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -19,12 +19,17 @@
%%
-module(snmpa_discovery_handler).
--export([behaviour_info/1, verify/1]).
-
-behaviour_info(callbacks) ->
- [{stage1_finish, 3}];
-behaviour_info(_) ->
- undefined.
+-export([verify/1]).
+-callback stage1_finish(TargetName, ManagerEngineID, ExtraInfo) ->
+ ignore |
+ {ok, snmpa_conf:usm_entry() | [snmpa_conf:usm_entry()]} |
+ {ok, snmpa_conf:usm_entry() | [snmpa_conf:usm_entry()], NewExtraInfo} when
+ TargetName :: string(),
+ ManagerEngineID :: string(),
+ ExtraInfo :: term(),
+ NewExtraInfo :: term().
+
verify(Mod) ->
snmp_misc:verify_behaviour(?MODULE, Mod).
+
diff --git a/lib/snmp/src/agent/snmpa_error_report.erl b/lib/snmp/src/agent/snmpa_error_report.erl
index 8f28eac653..6b281693e5 100644
--- a/lib/snmp/src/agent/snmpa_error_report.erl
+++ b/lib/snmp/src/agent/snmpa_error_report.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -19,10 +19,12 @@
%%
-module(snmpa_error_report).
--export([behaviour_info/1]).
+-callback config_err(Format, Args) ->
+ snmp:void() when
+ Format :: string(),
+ Args :: [term()].
-behaviour_info(callbacks) ->
- [{user_err, 2},
- {config_err, 2}];
-behaviour_info(_) ->
- undefined.
+-callback user_err(Format, Args) ->
+ snmp:void() when
+ Format :: string(),
+ Args :: [term()].
diff --git a/lib/snmp/src/agent/snmpa_get.erl b/lib/snmp/src/agent/snmpa_get.erl
new file mode 100644
index 0000000000..8b16016d84
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_get.erl
@@ -0,0 +1,1175 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(snmpa_get).
+
+-behaviour(snmpa_get_mechanism).
+
+
+%%%-----------------------------------------------------------------
+%%% snmpa_get_mechanism exports
+%%%-----------------------------------------------------------------
+
+-export([
+ do_get/3, do_get/4,
+ do_get_next/3,
+ do_get_bulk/7
+ ]).
+
+-define(VMODULE,"GET").
+-include("snmpa_internal.hrl").
+-include("snmp_types.hrl").
+-include("snmp_debug.hrl").
+-include("snmp_verbosity.hrl").
+
+-ifndef(default_verbosity).
+-define(default_verbosity,silence).
+-endif.
+
+-define(empty_pdu_size, 21).
+
+-ifdef(snmp_extended_verbosity).
+-define(vt(F,A), ?vtrace(F, A)).
+-else.
+-define(vt(_F, _A), ok).
+-endif.
+
+
+-define(AGENT, snmpa_agent).
+-define(LIB, snmpa_get_lib).
+
+
+
+%%%-----------------------------------------------------------------
+%%% 3. GET REQUEST
+%%% --------------
+%%% According to RFC1157, section 4.1.2 and RFC1905, section 4.2.1.
+%%% In rfc1157:4.1.2 it isn't specified if noSuchName should be
+%%% returned even if some other varbind generates a genErr.
+%%% In rfc1905:4.2.1 this is not a problem since exceptions are
+%%% used, and thus a genErr will be returned anyway.
+%%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% Func: do_get/2
+%% Purpose: Handles all VBs in a request that is inside the
+%% mibview (local).
+%% Returns: {noError, 0, ListOfNewVarbinds} |
+%% {ErrorStatus, ErrorIndex, []}
+%%-----------------------------------------------------------------
+
+%% There is now to properly spec the behaviour of the ?AGENT:subagent_get/3
+%% function (it *can* exit).
+-dialyzer({nowarn_function, do_get/3}).
+do_get(UnsortedVarbinds, IsNotification, _Extra) ->
+ {MyVarbinds, SubagentVarbinds} = ?LIB:agent_sort_vbs(UnsortedVarbinds),
+ case do_get_local(MyVarbinds, IsNotification) of
+ {noError, 0, NewMyVarbinds} ->
+ case do_get_subagents(SubagentVarbinds, IsNotification) of
+ {noError, 0, NewSubagentVarbinds} ->
+ {noError, 0, NewMyVarbinds ++ NewSubagentVarbinds};
+ {ErrorStatus, ErrorIndex, _} ->
+ {ErrorStatus, ErrorIndex, []}
+ end;
+ {ErrorStatus, ErrorIndex, _} ->
+ {ErrorStatus, ErrorIndex, []}
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Func: do_get/3
+%% Purpose: do_get handles "getRequests".
+%% Pre: incoming varbinds have type == 'NULL', value == unSpecified
+%% Returns: {noError, 0, ListOfNewVarbinds} |
+%% {ErrorStatus, ErrorIndex, []}
+%%-----------------------------------------------------------------
+
+do_get(MibView, UnsortedVarbinds, IsNotification, Extra) ->
+ ?vtrace("do_get -> entry with"
+ "~n MibView: ~p"
+ "~n UnsortedVarbinds: ~p"
+ "~n IsNotification: ~p",
+ [MibView, UnsortedVarbinds, IsNotification]),
+ %% This is me, the master, so go ahead
+ {OutSideView, InSideView} = ?LIB:split_vbs_view(UnsortedVarbinds, MibView),
+ {Error, Index, NewVbs} = do_get(InSideView, IsNotification, Extra),
+ {Error, Index, NewVbs ++ OutSideView}.
+
+
+
+%%-----------------------------------------------------------------
+%% Func: do_get_local/2,3
+%% Purpose: Loop the variablebindings list. We know that each varbind
+%% in that list belongs to us.
+%% Returns: {noError, 0, ListOfNewVarbinds} |
+%% {ErrorStatus, ErrorIndex, []}
+%%-----------------------------------------------------------------
+
+do_get_local(VBs, IsNotification) ->
+ do_get_local(VBs, [], IsNotification).
+
+-dialyzer({nowarn_function, do_get_local/3}).
+do_get_local([Vb | Vbs], Res, IsNotification) ->
+ case try_get(Vb, IsNotification) of
+ NewVb when is_record(NewVb, varbind) ->
+ do_get_local(Vbs, [NewVb | Res], IsNotification);
+ ListOfNewVb when is_list(ListOfNewVb) ->
+ do_get_local(Vbs, lists:append(ListOfNewVb, Res), IsNotification);
+ {error, Error, OrgIndex} ->
+ {Error, OrgIndex, []}
+ end;
+do_get_local([], Res, _IsNotification) ->
+ {noError, 0, Res}.
+
+
+
+%%-----------------------------------------------------------------
+%% Func: do_get_subagents/2
+%% Purpose: Loop the list of varbinds for different subagents.
+%% For each of them, call sub_agent_get to retreive
+%% the values for them.
+%% Returns: {noError, 0, ListOfNewVarbinds} |
+%% {ErrorStatus, ErrorIndex, []}
+%%-----------------------------------------------------------------
+
+%% There is now to properly spec the behaviour of the ?AGENT:subagent_get/3
+%% function (it *can* exit).
+-dialyzer({nowarn_function, do_get_subagents/3}).
+do_get_subagents(SubagentVarbinds, IsNotification) ->
+ do_get_subagents(SubagentVarbinds, [], IsNotification).
+
+do_get_subagents([{SubAgentPid, SAVbs} | Tail], Res, IsNotification) ->
+ {_SAOids, Vbs} = ?LIB:sa_split(SAVbs),
+ case (catch ?AGENT:subagent_get(SubAgentPid, Vbs, IsNotification)) of
+ {noError, 0, NewVbs} ->
+ do_get_subagents(Tail, lists:append(NewVbs, Res), IsNotification);
+ {ErrorStatus, ErrorIndex, _} ->
+ {ErrorStatus, ErrorIndex, []};
+ {'EXIT', Reason} ->
+ ?LIB:user_err("Lost contact with subagent (get) ~w. Using genErr",
+ [Reason]),
+ {genErr, 0, []}
+ end;
+do_get_subagents([], Res, _IsNotification) ->
+ {noError, 0, Res}.
+
+
+%%-----------------------------------------------------------------
+%% Func: try_get/2
+%% Returns: {error, ErrorStatus, OrgIndex} |
+%% #varbind |
+%% List of #varbind
+%%-----------------------------------------------------------------
+
+-dialyzer({nowarn_function, try_get/2}).
+try_get(IVb, IsNotification) when is_record(IVb, ivarbind) ->
+ ?vtrace("try_get(ivarbind) -> entry with"
+ "~n IVb: ~p", [IVb]),
+ get_var_value_from_ivb(IVb, IsNotification);
+try_get({TableOid, TableVbs}, IsNotification) ->
+ ?vtrace("try_get(table) -> entry with"
+ "~n TableOid: ~p"
+ "~n TableVbs: ~p", [TableOid, TableVbs]),
+ [#ivarbind{mibentry = MibEntry}|_] = TableVbs,
+ {NoAccessVbs, AccessVbs} =
+ check_all_table_vbs(TableVbs, IsNotification, [], []),
+ case get_tab_value_from_mib(MibEntry, TableOid, AccessVbs) of
+ {error, ErrorStatus, OrgIndex} ->
+ {error, ErrorStatus, OrgIndex};
+ NVbs ->
+ NVbs ++ NoAccessVbs
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Make sure all requested columns are accessible.
+%%-----------------------------------------------------------------
+
+-dialyzer({nowarn_function, check_all_table_vbs/4}).
+check_all_table_vbs([IVb| IVbs], IsNotification, NoA, A) ->
+ #ivarbind{mibentry = Me, varbind = Vb} = IVb,
+ case Me#me.access of
+ 'not-accessible' ->
+ NNoA = [Vb#varbind{value = noSuchInstance} | NoA],
+ check_all_table_vbs(IVbs, IsNotification, NNoA, A);
+ 'accessible-for-notify' when IsNotification =:= false ->
+ NNoA = [Vb#varbind{value = noSuchInstance} | NoA],
+ check_all_table_vbs(IVbs, IsNotification, NNoA, A);
+ 'write-only' ->
+ NNoA = [Vb#varbind{value = noSuchInstance} | NoA],
+ check_all_table_vbs(IVbs, IsNotification, NNoA, A);
+ _ ->
+ check_all_table_vbs(IVbs, IsNotification, NoA, [IVb | A])
+ end;
+check_all_table_vbs([], _IsNotification, NoA, A) -> {NoA, A}.
+
+%%-----------------------------------------------------------------
+%% Returns: {error, ErrorStatus, OrgIndex} |
+%% #varbind
+%%-----------------------------------------------------------------
+-dialyzer({nowarn_function, get_var_value_from_ivb/2}).
+get_var_value_from_ivb(IVb, IsNotification)
+ when IVb#ivarbind.status =:= noError ->
+ ?vtrace("get_var_value_from_ivb(noError) -> entry", []),
+ #ivarbind{mibentry = Me, varbind = Vb} = IVb,
+ #varbind{org_index = OrgIndex, oid = Oid} = Vb,
+ case Me#me.access of
+ 'not-accessible' ->
+ Vb#varbind{value = noSuchInstance};
+ 'accessible-for-notify' when IsNotification =:= false ->
+ Vb#varbind{value = noSuchInstance};
+ 'write-only' ->
+ Vb#varbind{value = noSuchInstance};
+ _ ->
+ case get_var_value_from_mib(Me, Oid) of
+ {value, Type, Value} ->
+ Vb#varbind{variabletype = Type, value = Value};
+ {error, ErrorStatus} ->
+ {error, ErrorStatus, OrgIndex}
+ end
+ end;
+get_var_value_from_ivb(#ivarbind{status = Status, varbind = Vb}, _) ->
+ ?vtrace("get_var_value_from_ivb(~p) -> entry", [Status]),
+ Vb#varbind{value = Status}.
+
+%%-----------------------------------------------------------------
+%% Func: get_var_value_from_mib/1
+%% Purpose:
+%% Returns: {error, ErrorStatus} |
+%% {value, Type, Value}
+%%-----------------------------------------------------------------
+%% Pre: Oid is a correct instance Oid (lookup checked that).
+%% Returns: A correct return value (see ?AGENT:make_value_a_correct_value)
+-dialyzer({nowarn_function, get_var_value_from_mib/2}).
+get_var_value_from_mib(#me{entrytype = variable,
+ asn1_type = ASN1Type,
+ mfa = {Mod, Func, Args}},
+ _Oid) ->
+ ?vtrace("get_var_value_from_mib(variable) -> entry when"
+ "~n Mod: ~p"
+ "~n Func: ~p"
+ "~n Args: ~p", [Mod, Func, Args]),
+ Result = (catch ?LIB:dbg_apply(Mod, Func, [get | Args])),
+ %% mib shall return {value, <a-nice-value-within-range>} |
+ %% {noValue, noSuchName} (v1) |
+ %% {noValue, noSuchObject | noSuchInstance} (v2, v1)
+ %% everything else (including 'genErr') will generate 'genErr'.
+ ?AGENT:make_value_a_correct_value(Result, ASN1Type, {Mod, Func, Args});
+
+get_var_value_from_mib(#me{entrytype = table_column,
+ oid = MeOid,
+ asn1_type = ASN1Type,
+ mfa = {Mod, Func, Args}},
+ Oid) ->
+ ?vtrace("get_var_value_from_mib(table_column) -> entry when"
+ "~n MeOid: ~p"
+ "~n Mod: ~p"
+ "~n Func: ~p"
+ "~n Args: ~p"
+ "~n Oid: ~p", [MeOid, Mod, Func, Args, Oid]),
+ Col = lists:last(MeOid),
+ Indexes = snmp_misc:diff(Oid, MeOid),
+ [Result] = (catch ?LIB:dbg_apply(Mod, Func, [get, Indexes, [Col] | Args])),
+ ?AGENT:make_value_a_correct_value(Result, ASN1Type,
+ {Mod, Func, Args, Indexes, Col}).
+
+
+%% For table operations we need to pass RestOid down to the table-function.
+%% Its up to the table-function to check for noSuchInstance (ex: a
+%% non-existing row).
+%% Returns: {error, ErrorStatus, OrgIndex} |
+%% {value, Type, Value}
+-dialyzer({nowarn_function, get_tab_value_from_mib/3}).
+get_tab_value_from_mib(#me{mfa = {Mod, Func, Args}}, TableOid, TableVbs) ->
+ ?vtrace("get_tab_value_from_mib -> entry when"
+ "~n Mod: ~p"
+ "~n Func: ~p"
+ "~n Args: ~p", [Mod, Func, Args]),
+ TableOpsWithShortOids = ?LIB:delete_prefixes(TableOid, TableVbs),
+ SortedVBsRows = snmpa_svbl:sort_varbinds_rows(TableOpsWithShortOids),
+ case get_value_all_rows(SortedVBsRows, Mod, Func, Args, []) of
+ {Error, Index} ->
+ #ivarbind{varbind = Vb} = lists:nth(Index, TableVbs),
+ {error, Error, Vb#varbind.org_index};
+ ListOfValues ->
+ merge_varbinds_and_value(TableVbs, ListOfValues)
+ end.
+
+%%-----------------------------------------------------------------
+%% Values is a scrambled list of {CorrectValue, Index}, where Index
+%% is index into the #ivarbind list. So for each Value, we must
+%% find the corresponding #ivarbind, and merge them into a new
+%% #varbind.
+%% The Values list comes from validate_tab_res.
+%%-----------------------------------------------------------------
+-dialyzer({nowarn_function, merge_varbinds_and_value/2}).
+merge_varbinds_and_value(IVbs, [{{value, Type, Value}, Index} | Values]) ->
+ #ivarbind{varbind = Vb} = lists:nth(Index, IVbs),
+ [Vb#varbind{variabletype = Type, value = Value} |
+ merge_varbinds_and_value(IVbs, Values)];
+merge_varbinds_and_value(_, []) -> [].
+
+-dialyzer({nowarn_function, get_value_all_rows/5}).
+get_value_all_rows([{[], OrgCols} | Rows], Mod, Func, Args, Res) ->
+ ?vtrace("get_value_all_rows -> entry when"
+ "~n OrgCols: ~p", [OrgCols]),
+ Cols = [{{value, noValue, noSuchInstance}, Index} ||
+ {_Col, _ASN1Type, Index} <- OrgCols],
+ NewRes = lists:append(Cols, Res),
+ get_value_all_rows(Rows, Mod, Func, Args, NewRes);
+get_value_all_rows([{RowIndex, OrgCols} | Rows], Mod, Func, Args, Res) ->
+ ?vtrace("get_value_all_rows -> entry when"
+ "~n RowIndex: ~p"
+ "~n OrgCols: ~p", [RowIndex, OrgCols]),
+ {DOrgCols, Dup} = remove_duplicates(OrgCols),
+ Cols = delete_index(DOrgCols),
+ Result = (catch ?LIB:dbg_apply(Mod, Func, [get, RowIndex, Cols | Args])),
+ case validate_tab_res(Result, DOrgCols, {Mod, Func, Args}) of
+ Values when is_list(Values) ->
+ NVals = restore_duplicates(Dup, Values),
+ NewRes = lists:append(NVals, Res),
+ get_value_all_rows(Rows, Mod, Func, Args, NewRes);
+ {error, ErrorStatus, Index} ->
+ ?AGENT:validate_err(row_set, {ErrorStatus, Index}, {Mod, Func, Args})
+ end;
+get_value_all_rows([], _Mod, _Func, _Args, Res) ->
+ ?vtrace("get_value_all_rows -> entry when done"
+ "~n Res: ~p", [Res]),
+ Res.
+
+%%-----------------------------------------------------------------
+%% Args: {RowIndex, list of {ShortOid, ASN1Type}}
+%% Returns: list of Col
+%%-----------------------------------------------------------------
+delete_index([{Col, _Val, _OrgIndex} | T]) ->
+ [Col | delete_index(T)];
+delete_index([]) -> [].
+
+%%-----------------------------------------------------------------
+%% This function is called before 'get' on a table, and removes
+%% any duplicate columns. It returns {Cols, DupInfo}. The Cols
+%% are the unique columns. The instrumentation function is
+%% called to get the values. These values, together with the
+%% DupInfo, is later passed to restore_duplicates, which uses
+%% the retrieved values to reconstruct the original column list,
+%% but with the retrieved value for each column.
+%%-----------------------------------------------------------------
+
+-dialyzer({nowarn_function, remove_duplicates/1}).
+remove_duplicates(Cols) ->
+ remove_duplicates(Cols, [], []).
+
+
+-dialyzer({nowarn_function, remove_duplicates/3}).
+remove_duplicates([{Col, V1, OrgIdx1}, {Col, V2, OrgIdx2} | T], NCols, Dup) ->
+ remove_duplicates([{Col, V1, OrgIdx1} | T], NCols,
+ [{Col, V2, OrgIdx2} | Dup]);
+remove_duplicates([Col | T], NCols, Dup) ->
+ remove_duplicates(T, [Col | NCols], Dup);
+remove_duplicates([], NCols, Dup) ->
+ {lists:reverse(NCols), lists:reverse(Dup)}.
+
+-dialyzer({nowarn_function, restore_duplicates/2}).
+restore_duplicates([], Cols) ->
+ [{Val, OrgIndex} || {_Col, Val, OrgIndex} <- Cols];
+restore_duplicates([{Col, _Val2, OrgIndex2} | Dup],
+ [{Col, NVal, OrgIndex1} | Cols]) ->
+ [{NVal, OrgIndex2} |
+ restore_duplicates(Dup, [{Col, NVal, OrgIndex1} | Cols])];
+restore_duplicates(Dup, [{_Col, Val, OrgIndex} | T]) ->
+ [{Val, OrgIndex} | restore_duplicates(Dup, T)].
+
+
+
+%%-----------------------------------------------------------------
+%% Three cases:
+%% 1) All values ok
+%% 2) table_func returned {Error, ...}
+%% 3) Some value in Values list is erroneous.
+%% Args: Value is a list of values from table_func(get..)
+%% OrgCols is a list with {Col, ASN1Type, OrgIndex}
+%% each element in Values and OrgCols correspond to each
+%% other.
+%%-----------------------------------------------------------------
+-dialyzer({nowarn_function, validate_tab_res/3}).
+validate_tab_res(Values, OrgCols, Mfa) when is_list(Values) ->
+ {_Col, _ASN1Type, OneIdx} = hd(OrgCols),
+ validate_tab_res(Values, OrgCols, Mfa, [], OneIdx);
+validate_tab_res({noValue, Error}, OrgCols, Mfa) ->
+ Values = lists:duplicate(length(OrgCols), {noValue, Error}),
+ validate_tab_res(Values, OrgCols, Mfa);
+validate_tab_res({genErr, Col}, OrgCols, Mfa) ->
+ case lists:keysearch(Col, 1, OrgCols) of
+ {value, {_Col, _ASN1Type, Index}} ->
+ {error, genErr, Index};
+ _ ->
+ ?LIB:user_err("Invalid column in {genErr, ~w} from ~w (get)",
+ [Col, Mfa]),
+ [{_Col, _ASN1Type, Index} | _] = OrgCols,
+ {error, genErr, Index}
+ end;
+validate_tab_res(genErr, [{_Col, __ASN1Type, Index} | _OrgCols], _Mfa) ->
+ {error, genErr, Index};
+validate_tab_res(Error, [{_Col, _ASN1Type, Index} | _OrgCols], Mfa) ->
+ ?LIB:user_err("Invalid return value ~w from ~w (get)",[Error, Mfa]),
+ {error, genErr, Index}.
+
+-dialyzer({nowarn_function, validate_tab_res/5}).
+validate_tab_res([Value | Values],
+ [{Col, ASN1Type, Index} | OrgCols],
+ Mfa, Res, I) ->
+ %% This one makes it possible to return a list of genErr, which
+ %% is not allowed according to the manual. But that's ok, as
+ %% everything else will generate a genErr! (the only problem is
+ %% that it won't generate a user_error).
+ case ?AGENT:make_value_a_correct_value(Value, ASN1Type, Mfa) of
+ {error, ErrorStatus} ->
+ {error, ErrorStatus, Index};
+ CorrectValue ->
+ NewRes = [{Col, CorrectValue, Index} | Res],
+ validate_tab_res(Values, OrgCols, Mfa, NewRes, I)
+ end;
+validate_tab_res([], [], _Mfa, Res, _I) ->
+ lists:reverse(Res);
+validate_tab_res([], [{_Col, _ASN1Type, Index}|_], Mfa, _Res, _I) ->
+ ?LIB:user_err("Too few values returned from ~w (get)", [Mfa]),
+ {error, genErr, Index};
+validate_tab_res(_TooMany, [], Mfa, _Res, I) ->
+ ?LIB:user_err("Too many values returned from ~w (get)", [Mfa]),
+ {error, genErr, I}.
+
+
+
+%%%-----------------------------------------------------------------
+%%% 4. GET-NEXT REQUEST
+%%% --------------
+%%% According to RFC1157, section 4.1.3 and RFC1905, section 4.2.2.
+%%%-----------------------------------------------------------------
+%%-----------------------------------------------------------------
+%% Func: do_get_next/3
+%% Purpose: do_get_next handles "getNextRequests".
+%% Note: Even if it is SNMPv1, a varbind's value can be
+%% endOfMibView. This is converted to noSuchName in process_pdu.
+%% Returns: {noError, 0, ListOfNewVarbinds} |
+%% {ErrorStatus, ErrorIndex, []}
+%% Note2: ListOfNewVarbinds is not sorted in any order!!!
+%% Alg: First, the variables are sorted in OID order.
+%%
+%% Second, next in the MIB is performed for each OID, and
+%% the result is collected as: if next oid is a variable,
+%% perform a get to retrieve its value; if next oid is in a
+%% table, save this value and continue until we get an oid
+%% outside this table. Then perform get_next on the table,
+%% and continue with all endOfTables and the oid outside the
+%% table; if next oid is an subagent, save this value and
+%% continue as in the table case.
+%%
+%% Third, each response is checked for endOfMibView, or (for
+%% subagents) that the Oid returned has the correct prefix.
+%% (This is necessary since an SA can be registered under many
+%% separated subtrees, and if the last variable in the first
+%% subtree is requested in a next, the SA will return the first
+%% variable in the second subtree. This might be working, since
+%% there may be a variable in between these subtrees.) For each
+%% of these, a new get-next is performed, one at a time.
+%% This alg. might be optimised in several ways. The most
+%% striking one is that the same SA might be called several
+%% times, when one time should be enough. But it isn't clear
+%% that this really matters, since many nexts across the same
+%% subagent must be considered to be very rare.
+%%-----------------------------------------------------------------
+
+do_get_next(MibView, UnsortedVBs, _Extra) ->
+ do_get_next2(MibView, UnsortedVBs, infinity).
+
+%% The third argument is only used if we are called as result
+%% of a get-bulk request.
+do_get_next2(_MibView, UnsortedVarbinds, GbMaxVBs)
+ when (is_integer(GbMaxVBs) andalso (length(UnsortedVarbinds) > GbMaxVBs)) ->
+ {tooBig, 0, []}; % What is the correct index in this case?
+do_get_next2(MibView, UnsortedVBs, GbMaxVBs) ->
+ ?vt("do_get_next2 -> entry when"
+ "~n MibView: ~p"
+ "~n UnsortedVBs: ~p", [MibView, UnsortedVBs]),
+ SortedVBs = ?LIB:oid_sort_vbs(UnsortedVBs),
+ ?vt("do_get_next -> "
+ "~n SortedVBs: ~p", [SortedVBs]),
+ next_loop_varbinds([], SortedVBs, MibView, [], [], GbMaxVBs).
+
+next_loop_varbinds(_, Vbs, _MibView, Res, _LAVb, GbMaxVBs)
+ when (is_integer(GbMaxVBs) andalso
+ ((length(Vbs) + length(Res)) > GbMaxVBs)) ->
+ {tooBig, 0, []}; % What is the correct index in this case?
+
+%% LAVb is Last Accessible Vb
+next_loop_varbinds([], [Vb | Vbs], MibView, Res, LAVb, GbMaxVBs) ->
+ ?vt("next_loop_varbinds -> entry when"
+ "~n Vb: ~p"
+ "~n MibView: ~p", [Vb, MibView]),
+ case varbind_next(Vb, MibView) of
+ endOfMibView ->
+ ?vt("next_loop_varbind -> endOfMibView", []),
+ RVb = if LAVb =:= [] -> Vb;
+ true -> LAVb
+ end,
+ NewVb = RVb#varbind{variabletype = 'NULL', value = endOfMibView},
+ next_loop_varbinds([], Vbs, MibView, [NewVb | Res], [], GbMaxVBs);
+
+ {variable, ME, VarOid} when ((ME#me.access =/= 'not-accessible') andalso
+ (ME#me.access =/= 'write-only') andalso
+ (ME#me.access =/= 'accessible-for-notify')) ->
+ ?vt("next_loop_varbind -> variable: "
+ "~n ME: ~p"
+ "~n VarOid: ~p", [ME, VarOid]),
+ case try_get_instance(Vb, ME) of
+ {value, noValue, _NoSuchSomething} ->
+ ?vt("next_loop_varbind -> noValue", []),
+ %% Try next one
+ NewVb = Vb#varbind{oid = VarOid,
+ value = 'NULL'},
+ next_loop_varbinds([], [NewVb | Vbs], MibView, Res, [],
+ GbMaxVBs);
+ {value, Type, Value} ->
+ ?vt("next_loop_varbind -> value"
+ "~n Type: ~p"
+ "~n Value: ~p", [Type, Value]),
+ NewVb = Vb#varbind{oid = VarOid,
+ variabletype = Type,
+ value = Value},
+ next_loop_varbinds([], Vbs, MibView, [NewVb | Res], [],
+ GbMaxVBs);
+ {error, ErrorStatus} ->
+ ?vdebug("next loop varbinds:"
+ "~n ErrorStatus: ~p",[ErrorStatus]),
+ {ErrorStatus, Vb#varbind.org_index, []}
+ end;
+ {variable, _ME, VarOid} ->
+ ?vt("next_loop_varbind -> variable: "
+ "~n VarOid: ~p", [VarOid]),
+ RVb = if LAVb =:= [] -> Vb;
+ true -> LAVb
+ end,
+ NewVb = Vb#varbind{oid = VarOid, value = 'NULL'},
+ next_loop_varbinds([], [NewVb | Vbs], MibView, Res, RVb, GbMaxVBs);
+ {table, TableOid, TableRestOid, ME} ->
+ ?vt("next_loop_varbind -> table: "
+ "~n TableOid: ~p"
+ "~n TableRestOid: ~p"
+ "~n ME: ~p", [TableOid, TableRestOid, ME]),
+ next_loop_varbinds({table, TableOid, ME,
+ [{tab_oid(TableRestOid), Vb}]},
+ Vbs, MibView, Res, [], GbMaxVBs);
+ {subagent, SubAgentPid, SAOid} ->
+ ?vt("next_loop_varbind -> subagent: "
+ "~n SubAgentPid: ~p"
+ "~n SAOid: ~p", [SubAgentPid, SAOid]),
+ NewVb = Vb#varbind{variabletype = 'NULL', value = 'NULL'},
+ next_loop_varbinds({subagent, SubAgentPid, SAOid, [NewVb]},
+ Vbs, MibView, Res, [], GbMaxVBs)
+ end;
+next_loop_varbinds({table, TableOid, ME, TabOids},
+ [Vb | Vbs], MibView, Res, _LAVb, GbMaxVBs) ->
+ ?vt("next_loop_varbinds(table) -> entry with"
+ "~n TableOid: ~p"
+ "~n Vb: ~p", [TableOid, Vb]),
+ case varbind_next(Vb, MibView) of
+ {table, TableOid, TableRestOid, _ME} ->
+ next_loop_varbinds({table, TableOid, ME,
+ [{tab_oid(TableRestOid), Vb} | TabOids]},
+ Vbs, MibView, Res, [], GbMaxVBs);
+ _ ->
+ case get_next_table(ME, TableOid, TabOids, MibView) of
+ {ok, TabRes, TabEndOfTabVbs} ->
+ NewVbs = lists:append(TabEndOfTabVbs, [Vb | Vbs]),
+ NewRes = lists:append(TabRes, Res),
+ next_loop_varbinds([], NewVbs, MibView, NewRes, [],
+ GbMaxVBs);
+ {ErrorStatus, OrgIndex} ->
+ ?vdebug("next loop varbinds: next varbind"
+ "~n ErrorStatus: ~p"
+ "~n OrgIndex: ~p",
+ [ErrorStatus,OrgIndex]),
+ {ErrorStatus, OrgIndex, []}
+ end
+ end;
+next_loop_varbinds({table, TableOid, ME, TabOids},
+ [], MibView, Res, _LAVb, GbMaxVBs) ->
+ ?vt("next_loop_varbinds(table) -> entry with"
+ "~n TableOid: ~p", [TableOid]),
+ case get_next_table(ME, TableOid, TabOids, MibView) of
+ {ok, TabRes, TabEndOfTabVbs} ->
+ ?vt("next_loop_varbinds(table) -> get_next_table result:"
+ "~n TabRes: ~p"
+ "~n TabEndOfTabVbs: ~p", [TabRes, TabEndOfTabVbs]),
+ NewRes = lists:append(TabRes, Res),
+ next_loop_varbinds([], TabEndOfTabVbs, MibView, NewRes, [],
+ GbMaxVBs);
+ {ErrorStatus, OrgIndex} ->
+ ?vdebug("next loop varbinds: next table"
+ "~n ErrorStatus: ~p"
+ "~n OrgIndex: ~p",
+ [ErrorStatus,OrgIndex]),
+ {ErrorStatus, OrgIndex, []}
+ end;
+next_loop_varbinds({subagent, SAPid, SAOid, SAVbs},
+ [Vb | Vbs], MibView, Res, _LAVb, GbMaxVBs) ->
+ ?vt("next_loop_varbinds(subagent) -> entry with"
+ "~n SAPid: ~p"
+ "~n SAOid: ~p"
+ "~n Vb: ~p", [SAPid, SAOid, Vb]),
+ case varbind_next(Vb, MibView) of
+ {subagent, _SubAgentPid, SAOid} ->
+ next_loop_varbinds({subagent, SAPid, SAOid,
+ [Vb | SAVbs]},
+ Vbs, MibView, Res, [], GbMaxVBs);
+ _ ->
+ case get_next_sa(SAPid, SAOid, SAVbs, MibView) of
+ {ok, SARes, SAEndOfMibViewVbs} ->
+ NewVbs = lists:append(SAEndOfMibViewVbs, [Vb | Vbs]),
+ NewRes = lists:append(SARes, Res),
+ next_loop_varbinds([], NewVbs, MibView, NewRes, [],
+ GbMaxVBs);
+ {noSuchName, OrgIndex} ->
+ %% v1 reply, treat this Vb as endOfMibView, and try again
+ %% for the others.
+ case lists:keysearch(OrgIndex, #varbind.org_index, SAVbs) of
+ {value, EVb} ->
+ NextOid = next_oid(SAOid),
+ EndOfVb =
+ EVb#varbind{oid = NextOid,
+ value = {endOfMibView, NextOid}},
+ case lists:delete(EVb, SAVbs) of
+ [] ->
+ next_loop_varbinds([], [EndOfVb, Vb | Vbs],
+ MibView, Res, [],
+ GbMaxVBs);
+ TryAgainVbs ->
+ next_loop_varbinds({subagent, SAPid, SAOid,
+ TryAgainVbs},
+ [EndOfVb, Vb | Vbs],
+ MibView, Res, [],
+ GbMaxVBs)
+ end;
+ false ->
+ %% bad index from subagent
+ {genErr, (hd(SAVbs))#varbind.org_index, []}
+ end;
+ {ErrorStatus, OrgIndex} ->
+ ?vdebug("next loop varbinds: next subagent"
+ "~n Vb: ~p"
+ "~n ErrorStatus: ~p"
+ "~n OrgIndex: ~p",
+ [Vb,ErrorStatus,OrgIndex]),
+ {ErrorStatus, OrgIndex, []}
+ end
+ end;
+next_loop_varbinds({subagent, SAPid, SAOid, SAVbs},
+ [], MibView, Res, _LAVb, GbMaxVBs) ->
+ ?vt("next_loop_varbinds(subagent) -> entry with"
+ "~n SAPid: ~p"
+ "~n SAOid: ~p", [SAPid, SAOid]),
+ case get_next_sa(SAPid, SAOid, SAVbs, MibView) of
+ {ok, SARes, SAEndOfMibViewVbs} ->
+ NewRes = lists:append(SARes, Res),
+ next_loop_varbinds([], SAEndOfMibViewVbs, MibView, NewRes, [],
+ GbMaxVBs);
+ {noSuchName, OrgIndex} ->
+ %% v1 reply, treat this Vb as endOfMibView, and try again for
+ %% the others.
+ case lists:keysearch(OrgIndex, #varbind.org_index, SAVbs) of
+ {value, EVb} ->
+ NextOid = next_oid(SAOid),
+ EndOfVb = EVb#varbind{oid = NextOid,
+ value = {endOfMibView, NextOid}},
+ case lists:delete(EVb, SAVbs) of
+ [] ->
+ next_loop_varbinds([], [EndOfVb], MibView, Res, [],
+ GbMaxVBs);
+ TryAgainVbs ->
+ next_loop_varbinds({subagent, SAPid, SAOid,
+ TryAgainVbs},
+ [EndOfVb], MibView, Res, [],
+ GbMaxVBs)
+ end;
+ false ->
+ %% bad index from subagent
+ {genErr, (hd(SAVbs))#varbind.org_index, []}
+ end;
+ {ErrorStatus, OrgIndex} ->
+ ?vdebug("next loop varbinds: next subagent"
+ "~n ErrorStatus: ~p"
+ "~n OrgIndex: ~p",
+ [ErrorStatus,OrgIndex]),
+ {ErrorStatus, OrgIndex, []}
+ end;
+next_loop_varbinds([], [], _MibView, Res, _LAVb, _GbMaxVBs) ->
+ ?vt("next_loop_varbinds -> entry when done", []),
+ {noError, 0, Res}.
+
+try_get_instance(_Vb, #me{mfa = {M, F, A}, asn1_type = ASN1Type}) ->
+ ?vtrace("try_get_instance -> entry with"
+ "~n M: ~p"
+ "~n F: ~p"
+ "~n A: ~p", [M,F,A]),
+ Result = (catch ?LIB:dbg_apply(M, F, [get | A])),
+ % mib shall return {value, <a-nice-value-within-range>} |
+ % {noValue, noSuchName} (v1) |
+ % {noValue, noSuchObject | noSuchInstance} (v2, v1)
+ % everything else (including 'genErr') will generate 'genErr'.
+ ?AGENT:make_value_a_correct_value(Result, ASN1Type, {M, F, A}).
+
+tab_oid([]) -> [0];
+tab_oid(X) -> X.
+
+
+%%-----------------------------------------------------------------
+%% Perform a next, using the varbinds Oid if value is simple
+%% value. If value is {endOf<something>, NextOid}, use NextOid.
+%% This case happens when a table has returned endOfTable, or
+%% a subagent has returned endOfMibView.
+%%-----------------------------------------------------------------
+varbind_next(#varbind{value = Value, oid = Oid}, MibView) ->
+ ?vt("varbind_next -> entry with"
+ "~n Value: ~p"
+ "~n Oid: ~p"
+ "~n MibView: ~p", [Value, Oid, MibView]),
+ case Value of
+ {endOfTable, NextOid} ->
+ snmpa_mib:next(get(mibserver), NextOid, MibView);
+ {endOfMibView, NextOid} ->
+ snmpa_mib:next(get(mibserver), NextOid, MibView);
+ _ ->
+ snmpa_mib:next(get(mibserver), Oid, MibView)
+ end.
+
+get_next_table(#me{mfa = {M, F, A}}, TableOid, TableOids, MibView) ->
+ % We know that all TableOids have at least a column number as oid
+ ?vt("get_next_table -> entry with"
+ "~n M: ~p"
+ "~n F: ~p"
+ "~n A: ~p"
+ "~n TableOid: ~p"
+ "~n TableOids: ~p"
+ "~n MibView: ~p", [M, F, A, TableOid, TableOids, MibView]),
+ Sorted = snmpa_svbl:sort_varbinds_rows(TableOids),
+ case get_next_values_all_rows(Sorted, M,F,A, [], TableOid) of
+ NewVbs when is_list(NewVbs) ->
+ ?vt("get_next_table -> "
+ "~n NewVbs: ~p", [NewVbs]),
+ % We must now check each Vb for endOfTable and that it is
+ % in the MibView. If not, it becomes a endOfTable. We
+ % collect all of these together.
+ transform_tab_next_result(NewVbs, {[], []}, MibView);
+ {ErrorStatus, OrgIndex} ->
+ {ErrorStatus, OrgIndex}
+ end.
+
+get_next_values_all_rows([Row | Rows], M, F, A, Res, TabOid) ->
+ {RowIndex, TableOids} = Row,
+ Cols = delete_index(TableOids),
+ ?vt("get_next_values_all_rows -> "
+ "~n Cols: ~p", [Cols]),
+ Result = (catch ?LIB:dbg_apply(M, F, [get_next, RowIndex, Cols | A])),
+ ?vt("get_next_values_all_rows -> "
+ "~n Result: ~p", [Result]),
+ case validate_tab_next_res(Result, TableOids, {M, F, A}, TabOid) of
+ Values when is_list(Values) ->
+ ?vt("get_next_values_all_rows -> "
+ "~n Values: ~p", [Values]),
+ NewRes = lists:append(Values, Res),
+ get_next_values_all_rows(Rows, M, F, A, NewRes, TabOid);
+ {ErrorStatus, OrgIndex} ->
+ {ErrorStatus, OrgIndex}
+ end;
+get_next_values_all_rows([], _M, _F, _A, Res, _TabOid) ->
+ Res.
+
+transform_tab_next_result([Vb | Vbs], {Res, EndOfs}, MibView) ->
+ case Vb#varbind.value of
+ {endOfTable, _} ->
+ {ResVBs, EndOfVBs} = ?LIB:split_vbs(Vbs, Res, [Vb | EndOfs]),
+ {ok, ResVBs, EndOfVBs};
+ _ ->
+ case snmpa_acm:validate_mib_view(Vb#varbind.oid, MibView) of
+ true ->
+ transform_tab_next_result(Vbs, {[Vb|Res], EndOfs},MibView);
+ _ ->
+ Oid = Vb#varbind.oid,
+ NewEndOf = Vb#varbind{value = {endOfTable, Oid}},
+ transform_tab_next_result(Vbs, {Res, [NewEndOf | EndOfs]},
+ MibView)
+ end
+ end;
+transform_tab_next_result([], {Res, EndOfs}, _MibView) ->
+ ?vt("transform_tab_next_result -> entry with: "
+ "~n Res: ~p"
+ "~n EndIfs: ~p",[Res, EndOfs]),
+ {ok, Res, EndOfs}.
+
+
+
+%%-----------------------------------------------------------------
+%% Three cases:
+%% 1) All values ok
+%% 2) table_func returned {Error, ...}
+%% 3) Some value in Values list is erroneous.
+%% Args: Value is a list of values from table_func(get_next, ...)
+%% TableOids is a list of {TabRestOid, OrgVb}
+%% each element in Values and TableOids correspond to each
+%% other.
+%% Returns: List of NewVarbinds |
+%% {ErrorStatus, OrgIndex}
+%% (In the NewVarbinds list, the value may be endOfTable)
+%%-----------------------------------------------------------------
+validate_tab_next_res(Values, TableOids, Mfa, TabOid) ->
+ ?vt("validate_tab_next_res -> entry with: "
+ "~n Values: ~p"
+ "~n TableOids: ~p"
+ "~n Mfa: ~p"
+ "~n TabOid: ~p", [Values, TableOids, Mfa, TabOid]),
+ {_Col, _ASN1Type, OneIdx} = hd(TableOids),
+ validate_tab_next_res(Values, TableOids, Mfa, [], TabOid,
+ next_oid(TabOid), OneIdx).
+validate_tab_next_res([{NextOid, Value} | Values],
+ [{_ColNo, OrgVb, _Index} | TableOids],
+ Mfa, Res, TabOid, TabNextOid, I) ->
+ ?vt("validate_tab_next_res -> entry with: "
+ "~n NextOid: ~p"
+ "~n Value: ~p"
+ "~n Values: ~p"
+ "~n TableOids: ~p"
+ "~n Mfa: ~p"
+ "~n TabOid: ~p",
+ [NextOid, Value, Values, TableOids, Mfa, TabOid]),
+ #varbind{org_index = OrgIndex} = OrgVb,
+ ?vt("validate_tab_next_res -> OrgIndex: ~p", [OrgIndex]),
+ NextCompleteOid = lists:append(TabOid, NextOid),
+ case snmpa_mib:lookup(get(mibserver), NextCompleteOid) of
+ {table_column, #me{asn1_type = ASN1Type}, _TableEntryOid} ->
+ ?vt("validate_tab_next_res -> ASN1Type: ~p", [ASN1Type]),
+ case ?AGENT:make_value_a_correct_value({value, Value}, ASN1Type, Mfa) of
+ {error, ErrorStatus} ->
+ ?vt("validate_tab_next_res -> "
+ "~n ErrorStatus: ~p", [ErrorStatus]),
+ {ErrorStatus, OrgIndex};
+ {value, Type, NValue} ->
+ ?vt("validate_tab_next_res -> "
+ "~n Type: ~p"
+ "~n NValue: ~p", [Type, NValue]),
+ NewVb = OrgVb#varbind{oid = NextCompleteOid,
+ variabletype = Type, value = NValue},
+ validate_tab_next_res(Values, TableOids, Mfa,
+ [NewVb | Res], TabOid, TabNextOid, I)
+ end;
+ Error ->
+ ?LIB:user_err("Invalid oid ~w from ~w (get_next). Using genErr => ~p",
+ [NextOid, Mfa, Error]),
+ {genErr, OrgIndex}
+ end;
+validate_tab_next_res([endOfTable | Values],
+ [{_ColNo, OrgVb, _Index} | TableOids],
+ Mfa, Res, TabOid, TabNextOid, I) ->
+ ?vt("validate_tab_next_res(endOfTable) -> entry with: "
+ "~n Values: ~p"
+ "~n OrgVb: ~p"
+ "~n TableOids: ~p"
+ "~n Mfa: ~p"
+ "~n Res: ~p"
+ "~n TabOid: ~p"
+ "~n TabNextOid: ~p"
+ "~n I: ~p",
+ [Values, OrgVb, TableOids, Mfa, Res, TabOid, TabNextOid, I]),
+ NewVb = OrgVb#varbind{value = {endOfTable, TabNextOid}},
+ validate_tab_next_res(Values, TableOids, Mfa, [NewVb | Res],
+ TabOid, TabNextOid, I);
+validate_tab_next_res([], [], _Mfa, Res, _TabOid, _TabNextOid, _I) ->
+ Res;
+validate_tab_next_res([], [{_Col, _OrgVb, Index}|_], Mfa, _Res, _, _, _I) ->
+ ?LIB:user_err("Too few values returned from ~w (get_next)", [Mfa]),
+ {genErr, Index};
+validate_tab_next_res({genErr, ColNumber}, OrgCols,
+ Mfa, _Res, _TabOid, _TabNextOid, _I) ->
+ OrgIndex = snmpa_svbl:col_to_orgindex(ColNumber, OrgCols),
+ ?AGENT:validate_err(table_next, {genErr, OrgIndex}, Mfa);
+validate_tab_next_res({error, Reason}, [{_ColNo, OrgVb, _Index} | _TableOids],
+ Mfa, _Res, _TabOid, _TabNextOid, _I) ->
+ #varbind{org_index = OrgIndex} = OrgVb,
+ ?LIB:user_err("Erroneous return value ~w from ~w (get_next)",
+ [Reason, Mfa]),
+ {genErr, OrgIndex};
+validate_tab_next_res(Error, [{_ColNo, OrgVb, _Index} | _TableOids],
+ Mfa, _Res, _TabOid, _TabNextOid, _I) ->
+ #varbind{org_index = OrgIndex} = OrgVb,
+ ?LIB:user_err("Invalid return value ~w from ~w (get_next)",
+ [Error, Mfa]),
+ {genErr, OrgIndex};
+validate_tab_next_res(TooMany, [], Mfa, _Res, _, _, I) ->
+ ?LIB:user_err("Too many values ~w returned from ~w (get_next)",
+ [TooMany, Mfa]),
+ {genErr, I}.
+
+%%-----------------------------------------------------------------
+%% Func: get_next_sa/4
+%% Purpose: Loop the list of varbinds for the subagent.
+%% Call subagent_get_next to retreive
+%% the next varbinds.
+%% Returns: {ok, ListOfNewVbs, ListOfEndOfMibViewsVbs} |
+%% {ErrorStatus, ErrorIndex}
+%%-----------------------------------------------------------------
+get_next_sa(SAPid, SAOid, SAVbs, MibView) ->
+ case catch ?AGENT:subagent_get_next(SAPid, MibView, SAVbs) of
+ {noError, 0, NewVbs} ->
+ NewerVbs = transform_sa_next_result(NewVbs,SAOid,next_oid(SAOid)),
+ {ResVBs, EndOfVBs} = ?LIB:split_vbs(NewerVbs),
+ {ok, ResVBs, EndOfVBs};
+ {ErrorStatus, ErrorIndex, _} ->
+ {ErrorStatus, ErrorIndex};
+ {'EXIT', Reason} ->
+ ?LIB:user_err("Lost contact with subagent (next) ~w. Using genErr",
+ [Reason]),
+ {genErr, 0}
+ end.
+
+%%-----------------------------------------------------------------
+%% Check for wrong prefix returned or endOfMibView, and convert
+%% into {endOfMibView, SANextOid}.
+%%-----------------------------------------------------------------
+transform_sa_next_result([Vb | Vbs], SAOid, SANextOid)
+ when Vb#varbind.value =:= endOfMibView ->
+ [Vb#varbind{value = {endOfMibView, SANextOid}} |
+ transform_sa_next_result(Vbs, SAOid, SANextOid)];
+transform_sa_next_result([Vb | Vbs], SAOid, SANextOid) ->
+ case lists:prefix(SAOid, Vb#varbind.oid) of
+ true ->
+ [Vb | transform_sa_next_result(Vbs, SAOid, SANextOid)];
+ _ ->
+ [Vb#varbind{oid = SANextOid, value = {endOfMibView, SANextOid}} |
+ transform_sa_next_result(Vbs, SAOid, SANextOid)]
+ end;
+transform_sa_next_result([], _SAOid, _SANextOid) ->
+ [].
+
+
+next_oid(Oid) ->
+ case lists:reverse(Oid) of
+ [H | T] -> lists:reverse([H+1 | T]);
+ [] -> []
+ end.
+
+
+
+%%%-----------------------------------------------------------------
+%%% 5. GET-BULK REQUEST
+%%%
+%%% In order to prevent excesses in reply sizes there are two
+%%% preventive methods in place. One is to check that the encode
+%%% size does not exceed Max PDU size (this is mentioned in the
+%%% standard). The other is a simple VBs limit. That is, the
+%%% resulting response cannot contain more then this number of VBs.
+%%%-----------------------------------------------------------------
+
+do_get_bulk(MibView, NonRepeaters, MaxRepetitions,
+ PduMS, Varbinds, GbMaxVBs, _Extra) ->
+ ?vtrace("do_get_bulk -> entry with"
+ "~n MibView: ~p"
+ "~n NonRepeaters: ~p"
+ "~n MaxRepetitions: ~p"
+ "~n PduMS: ~p"
+ "~n Varbinds: ~p"
+ "~n GbMaxVBs: ~p",
+ [MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds, GbMaxVBs]),
+ {NonRepVbs, RestVbs} = ?LIB:split_vbs_gb(NonRepeaters, Varbinds),
+ ?vt("do_get_bulk -> split: "
+ "~n NonRepVbs: ~p"
+ "~n RestVbs: ~p", [NonRepVbs, RestVbs]),
+ case do_get_next2(MibView, NonRepVbs, GbMaxVBs) of
+ {noError, 0, UResNonRepVbs} ->
+ ?vt("do_get_bulk -> next noError: "
+ "~n UResNonRepVbs: ~p", [UResNonRepVbs]),
+ ResNonRepVbs = lists:keysort(#varbind.org_index, UResNonRepVbs),
+ %% Decode the first varbinds, produce a reversed list of
+ %% listOfBytes.
+ case (catch enc_vbs(PduMS - ?empty_pdu_size, ResNonRepVbs)) of
+ {error, Idx, Reason} ->
+ ?LIB:user_err("failed encoding varbind ~w:~n~p", [Idx, Reason]),
+ {genErr, Idx, []};
+ {SizeLeft, Res} when is_integer(SizeLeft) and is_list(Res) ->
+ ?vtrace("do_get_bulk -> encoded: "
+ "~n SizeLeft: ~p"
+ "~n Res: ~w", [SizeLeft, Res]),
+ case (catch do_get_rep(SizeLeft, MibView, MaxRepetitions,
+ RestVbs, Res,
+ length(UResNonRepVbs), GbMaxVBs)) of
+ {error, Idx, Reason} ->
+ ?LIB:user_err("failed encoding varbind ~w:~n~p",
+ [Idx, Reason]),
+ {genErr, Idx, []};
+ Res when is_list(Res) ->
+ ?vtrace("do get bulk -> Res: "
+ "~n ~w", [Res]),
+ {noError, 0, conv_res(Res)};
+ {noError, 0, Data} = OK ->
+ ?vtrace("do get bulk -> OK: "
+ "~n length(Data): ~w", [length(Data)]),
+ OK;
+ Else ->
+ ?vtrace("do get bulk -> Else: "
+ "~n ~w", [Else]),
+ Else
+ end;
+ Res when is_list(Res) ->
+ {noError, 0, conv_res(Res)}
+ end;
+
+ {ErrorStatus, Index, _} ->
+ ?vdebug("do get bulk: "
+ "~n ErrorStatus: ~p"
+ "~n Index: ~p",[ErrorStatus, Index]),
+ {ErrorStatus, Index, []}
+ end.
+
+enc_vbs(SizeLeft, Vbs) ->
+ ?vt("enc_vbs -> entry with"
+ "~n SizeLeft: ~w", [SizeLeft]),
+ Fun = fun(Vb, {Sz, Res}) when Sz > 0 ->
+ ?vt("enc_vbs -> (fun) entry with"
+ "~n Vb: ~p"
+ "~n Sz: ~p"
+ "~n Res: ~w", [Vb, Sz, Res]),
+ case (catch snmp_pdus:enc_varbind(Vb)) of
+ {'EXIT', Reason} ->
+ ?vtrace("enc_vbs -> encode failed: "
+ "~n Reason: ~p", [Reason]),
+ throw({error, Vb#varbind.org_index, Reason});
+ X ->
+ ?vt("enc_vbs -> X: ~w", [X]),
+ Lx = length(X),
+ ?vt("enc_vbs -> Lx: ~w", [Lx]),
+ if
+ Lx < Sz ->
+ {Sz - length(X), [X | Res]};
+ true ->
+ throw(Res)
+ end
+ end;
+ (_Vb, {_Sz, [_H | T]}) ->
+ ?vt("enc_vbs -> (fun) entry with"
+ "~n T: ~p", [T]),
+ throw(T);
+ (_Vb, {_Sz, []}) ->
+ ?vt("enc_vbs -> (fun) entry", []),
+ throw([])
+ end,
+ lists:foldl(Fun, {SizeLeft, []}, Vbs).
+
+do_get_rep(Sz, MibView, MaxRepetitions, Varbinds, Res, GbNumVBs, GbMaxVBs)
+ when MaxRepetitions >= 0 ->
+ do_get_rep(Sz, MibView, 0, MaxRepetitions, Varbinds, Res,
+ GbNumVBs, GbMaxVBs);
+do_get_rep(Sz, MibView, _MaxRepetitions, Varbinds, Res, GbNumVBs, GbMaxVBs) ->
+ do_get_rep(Sz, MibView, 0, 0, Varbinds, Res, GbNumVBs, GbMaxVBs).
+
+conv_res(ResVarbinds) ->
+ conv_res(ResVarbinds, []).
+conv_res([VbListOfBytes | T], Bytes) ->
+ conv_res(T, VbListOfBytes ++ Bytes);
+conv_res([], Bytes) ->
+ Bytes.
+
+%% The only other value, then a positive integer, is infinity.
+do_get_rep(_Sz, _MibView, Count, Max, _, _Res, GbNumVBs, GbMaxVBs)
+ when (is_integer(GbMaxVBs) andalso (GbNumVBs > GbMaxVBs)) ->
+ ?vinfo("Max Get-BULK VBs limit (~w) exceeded (~w) when:"
+ "~n Count: ~p"
+ "~n Max: ~p", [GbMaxVBs, GbNumVBs, Count, Max]),
+ {tooBig, 0, []};
+do_get_rep(_Sz, _MibView, Max, Max, _, Res, _GbNumVBs, _GbMaxVBs) ->
+ ?vt("do_get_rep -> done when: "
+ "~n Res: ~p", [Res]),
+ {noError, 0, conv_res(Res)};
+do_get_rep(Sz, MibView, Count, Max, Varbinds, Res, GbNumVBs, GbMaxVBs) ->
+ ?vt("do_get_rep -> entry when: "
+ "~n Sz: ~p"
+ "~n Count: ~p"
+ "~n Res: ~w", [Sz, Count, Res]),
+ case try_get_bulk(Sz, MibView, Varbinds, GbMaxVBs) of
+ {noError, NextVarbinds, SizeLeft, Res2} ->
+ ?vt("do_get_rep -> noError: "
+ "~n SizeLeft: ~p"
+ "~n Res2: ~p", [SizeLeft, Res2]),
+ do_get_rep(SizeLeft, MibView, Count+1, Max, NextVarbinds,
+ Res2 ++ Res,
+ GbNumVBs + length(Varbinds), GbMaxVBs);
+ {endOfMibView, _NextVarbinds, _SizeLeft, Res2} ->
+ ?vt("do_get_rep -> endOfMibView: "
+ "~n Res2: ~p", [Res2]),
+ {noError, 0, conv_res(Res2 ++ Res)};
+ {ErrorStatus, Index} ->
+ ?vtrace("do_get_rep -> done when error: "
+ "~n ErrorStatus: ~p"
+ "~n Index: ~p", [ErrorStatus, Index]),
+ {ErrorStatus, Index, []}
+ end.
+
+try_get_bulk(Sz, MibView, Varbinds, GbMaxVBs) ->
+ ?vt("try_get_bulk -> entry with"
+ "~n Sz: ~w"
+ "~n MibView: ~w"
+ "~n Varbinds: ~w", [Sz, MibView, Varbinds]),
+ case do_get_next2(MibView, Varbinds, GbMaxVBs) of
+ {noError, 0, UNextVarbinds} ->
+ ?vt("try_get_bulk -> noError: "
+ "~n UNextVarbinds: ~p", [UNextVarbinds]),
+ NextVarbinds = ?LIB:org_index_sort_vbs(UNextVarbinds),
+ case (catch enc_vbs(Sz, NextVarbinds)) of
+ {error, Idx, Reason} ->
+ ?LIB:user_err("failed encoding varbind ~w:~n~p", [Idx, Reason]),
+ ?vtrace("try_get_bulk -> encode error: "
+ "~n Idx: ~p"
+ "~n Reason: ~p", [Idx, Reason]),
+ {genErr, Idx};
+ {SizeLeft, Res} when is_integer(SizeLeft) andalso
+ is_list(Res) ->
+ ?vt("try get bulk -> encode ok: "
+ "~n SizeLeft: ~w"
+ "~n Res: ~w", [SizeLeft, Res]),
+ {check_end_of_mibview(NextVarbinds),
+ NextVarbinds, SizeLeft, Res};
+ Res when is_list(Res) ->
+ ?vt("try get bulk -> Res: "
+ "~n ~w", [Res]),
+ {endOfMibView, [], 0, Res}
+ end;
+ {ErrorStatus, Index, _} ->
+ ?vt("try_get_bulk -> error: "
+ "~n ErrorStatus: ~p"
+ "~n Index: ~p", [ErrorStatus, Index]),
+ {ErrorStatus, Index}
+ end.
+
+%% If all variables in this pass are endOfMibView,
+%% there is no reason to continue.
+check_end_of_mibview([#varbind{value = endOfMibView} | T]) ->
+ check_end_of_mibview(T);
+check_end_of_mibview([]) -> endOfMibView;
+check_end_of_mibview(_) -> noError.
+
+
+
diff --git a/lib/snmp/src/agent/snmpa_get_lib.erl b/lib/snmp/src/agent/snmpa_get_lib.erl
new file mode 100644
index 0000000000..eaf7fe2641
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_get_lib.erl
@@ -0,0 +1,254 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%% Note that most of these functions *assume* that they are executed
+%% by the agent. If they are not they may note work as they require
+%% some properties to be set in the process dictionary!
+%%
+
+-module(snmpa_get_lib).
+
+-export([
+ split_vbs/1, split_vbs/3,
+ split_vbs_view/2,
+ split_vbs_gb/2,
+
+ agent_sort_vbs/1,
+ oid_sort_vbs/1, org_index_sort_vbs/1,
+
+ sa_split/1,
+
+ delete_prefixes/2,
+
+ dbg_apply/3,
+
+ user_err/2
+ ]).
+
+-define(VMODULE,"GET-LIB").
+-include("snmpa_internal.hrl").
+-include("snmp_types.hrl").
+-include("snmp_debug.hrl").
+-include("snmp_verbosity.hrl").
+
+
+
+
+%%-----------------------------------------------------------------
+%% split_vbs/1,3
+%%
+%% Splits the list of varbinds (basically) into two lists. One
+%% of 'end of'-varbinds (mib view and tables) and then the rest
+%% of the varbinds.
+%%-----------------------------------------------------------------
+
+-spec split_vbs(VBs :: [snmp:varbind()]) ->
+ {ResVBs :: [snmp:varbind()],
+ EndOfVBs :: [snmp:varbind()]}.
+
+split_vbs(VBs) ->
+ split_vbs(VBs, [], []).
+
+-spec split_vbs(VBs :: [snmp:varbind()],
+ Res :: [snmp:varbind()],
+ EndOfs :: [snmp:varbind()]) ->
+ {ResVBs :: [snmp:varbind()],
+ EndOfVBs :: [snmp:varbind()]}.
+
+split_vbs([], ResVBs, EndOfVBs) ->
+ {ResVBs, EndOfVBs};
+split_vbs([VB | VBs], Res, EndOfs) ->
+ case VB#varbind.value of
+ {endOfMibView, _} -> split_vbs(VBs, Res, [VB | EndOfs]);
+ {endOfTable, _} -> split_vbs(VBs, Res, [VB | EndOfs]);
+ _ -> split_vbs(VBs, [VB | Res], EndOfs)
+ end.
+
+
+
+%%-----------------------------------------------------------------
+%% split_vbs_view/2
+%%
+%% Splits a list of varbinds into two lists based on the provided
+%% MibView. One list of varbinds inside the MibView and one of
+%% varbinds outside the MibView.
+%%-----------------------------------------------------------------
+
+-spec split_vbs_view(VBs :: [snmp:varbind()],
+ MibView :: snmp_view_based_acm_mib:mibview()) ->
+ {OutSideView :: [snmp:varbind()],
+ InSideView :: [snmp:varbind()]}.
+
+split_vbs_view(VBs, MibView) ->
+ ?vtrace("split the varbinds view", []),
+ split_vbs_view(VBs, MibView, [], []).
+
+split_vbs_view([], _MibView, Out, In) ->
+ {Out, In};
+split_vbs_view([VB | VBs], MibView, Out, In) ->
+ case snmpa_acm:validate_mib_view(VB#varbind.oid, MibView) of
+ true ->
+ split_vbs_view(VBs, MibView, Out, [VB | In]);
+ false ->
+ VB2 = VB#varbind{value = noSuchObject},
+ split_vbs_view(VBs, MibView, [VB2 | Out], In)
+ end.
+
+
+
+%%-----------------------------------------------------------------
+%% split_vbs_gb/2
+%%
+%% Performs a get-bulk split of the varbinds
+%%-----------------------------------------------------------------
+
+-spec split_vbs_gb(NonRepeaters :: integer(),
+ VBs :: [snmp:varbind()]) ->
+ {NonRepVBs :: [snmp:varbind()],
+ RestVBs :: [snmp:varbind()]}.
+
+split_vbs_gb(N, VBs) ->
+ split_vbs_gb(N, VBs, []).
+
+split_vbs_gb(N, Varbinds, Res) when N =< 0 ->
+ {Res, Varbinds};
+split_vbs_gb(N, [H | T], Res) ->
+ split_vbs_gb(N-1, T, [H | Res]);
+split_vbs_gb(_N, [], Res) ->
+ {Res, []}.
+
+
+
+%%-----------------------------------------------------------------
+%% agent_sort_vbs/1
+%%
+%% Sorts the varbinds into two categories. The first is varbinds
+%% belonging to "our" agent and the other is varbinds for
+%% subagents.
+%%-----------------------------------------------------------------
+
+-spec agent_sort_vbs(VBs :: [snmp:varbind()]) ->
+ {AgentVBs :: [snmp:varbind()],
+ SubAgentVBs :: [snmp:varbind()]}.
+
+agent_sort_vbs(VBs) ->
+ snmpa_svbl:sort_varbindlist(get(mibserver), VBs).
+
+
+%%-----------------------------------------------------------------
+%% oid_sort_vbs/1
+%%
+%% Sorts the varbinds based on their oid.
+%%-----------------------------------------------------------------
+
+-spec oid_sort_vbs(VBs :: [snmp:varbind()]) -> SortedVBs :: [snmp:varbind()].
+
+oid_sort_vbs(VBs) ->
+ lists:keysort(#varbind.oid, VBs).
+
+
+%%-----------------------------------------------------------------
+%% org_index_sort_vbs/1
+%%
+%% Sorts the varbinds based on their org_index.
+%%-----------------------------------------------------------------
+
+-spec org_index_sort_vbs(VBs :: [snmp:varbind()]) -> SortedVBs :: [snmp:varbind()].
+
+org_index_sort_vbs(Vbs) ->
+ lists:keysort(#varbind.org_index, Vbs).
+
+
+
+%%-----------------------------------------------------------------
+%% sa_split/1
+%%
+%% Splits a list of {oid(), varbind()} into two lists of oid()
+%% and varbind. The resulting lists are reversed!
+%%-----------------------------------------------------------------
+
+-spec sa_split(SAVBs :: [{SAOid :: snmp:oid(), snmp:varbind()}]) ->
+ {Oids :: [snmp:oid()], VBs :: [snmp:varbind()]}.
+
+sa_split(SAVBs) ->
+ snmpa_svbl:sa_split(SAVBs).
+
+
+
+%%-----------------------------------------------------------------
+%% delete_prefixes/2
+%%
+%% Takes an Oid prefix and a list of ivarbinds and produces a list
+%% of {ShortOid, ASN1Type}. The ShortOid is basically the oid with
+%% the OidPrefix removed.
+%%-----------------------------------------------------------------
+
+-spec delete_prefixes(OidPrefix :: snmp:oid(),
+ VBs :: [snmp:ivarbind()]) ->
+ [{ShortOid :: snmp:oid(),
+ ASN1Type :: snmp:asn1_type()}].
+
+delete_prefixes(OidPrefix, IVBs) ->
+ [{snmp_misc:diff(Oid, OidPrefix), ME#me.asn1_type} ||
+ #ivarbind{varbind = #varbind{oid = Oid}, mibentry = ME} <- IVBs].
+
+
+
+%%-----------------------------------------------------------------
+%% dbg_apply/3
+%%
+%% Call instrumentation functions, but allow for debug printing
+%% of useful debug info.
+%%-----------------------------------------------------------------
+
+-spec dbg_apply(M :: atom(), F :: atom(), A :: list()) ->
+ any().
+
+dbg_apply(M, F, A) ->
+ case get(verbosity) of
+ silence ->
+ apply(M,F,A);
+ _ ->
+ ?vlog("~n apply: ~w, ~w, ~p~n", [M,F,A]),
+ Res = (catch apply(M,F,A)),
+ case Res of
+ {'EXIT', Reason} ->
+ ?vinfo("Call to: "
+ "~n Module: ~p"
+ "~n Function: ~p"
+ "~n Args: ~p"
+ "~n"
+ "~nresulted in an exit"
+ "~n"
+ "~n ~p~n", [M, F, A, Reason]);
+ _ ->
+ ?vlog("~n returned: ~p~n", [Res])
+ end,
+ Res
+ end.
+
+
+%% ---------------------------------------------------------------------
+
+user_err(F, A) ->
+ snmpa_error:user_err(F, A).
+
+
diff --git a/lib/snmp/src/agent/snmpa_get_mechanism.erl b/lib/snmp/src/agent/snmpa_get_mechanism.erl
new file mode 100644
index 0000000000..744a6529e1
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_get_mechanism.erl
@@ -0,0 +1,79 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(snmpa_get_mechanism).
+
+%%
+%% This module defines the behaviour for the undocumented (hidden)
+%% get-mechanism feature. This allows for implementing your own
+%% handling of get, get-next and get-bulk requests.
+%% Probably only useful for special cases (e.g. optimization).
+%%
+
+
+
+%% ----------- do_get/2,3 -----------------------------------------------------
+
+%% Purpose: Handles all VBs in a request that is inside the
+%% mibview (local).
+
+-callback do_get(UnsortedVBs :: [snmp:varbind()],
+ IsNotification :: boolean(),
+ Extra :: term()) ->
+ {noError, 0, ResVBs :: [snmp:varbind()]} |
+ {ErrStatus :: snmp:error_status(), ErrIndex :: snmp:error_index(), []}.
+
+
+%% Purpose: Handles "get-requests".
+
+-callback do_get(MibView :: snmp_view_based_acm_mib:mibview(),
+ UnsortedVBs :: [snmp:varbind()],
+ IsNotification :: boolean(),
+ Extra :: term()) ->
+ {noError, 0, ResVBs :: [snmp:varbind()]} |
+ {ErrStatus :: snmp:error_status(), ErrIndex :: snmp:error_index(), []}.
+
+
+
+
+%% ----------- do_get_next/2 ------------------------------------------------
+
+%% Purpose: Handles "get-next-requests".
+
+-callback do_get_next(MibView :: snmp_view_based_acm_mib:mibview(),
+ UnsortedVBs :: [snmp:varbind()],
+ Extra :: term()) ->
+ {noError, 0, ResVBs :: [snmp:varbind()]} |
+ {ErrStatus :: snmp:error_status(), ErrIndex :: snmp:error_index(), []}.
+
+
+
+
+%% ----------- do_get_bulk/6 ------------------------------------------------
+
+-callback do_get_bulk(MibView :: snmp_view_based_acm_mib:mibview(),
+ NonRepeaters :: non_neg_integer(),
+ MaxRepetitions :: non_neg_integer(),
+ PduMS :: pos_integer(),
+ VBs :: [snmp:varbind()],
+ MaxVBs :: pos_integer(),
+ Extra :: term()) ->
+ {noError, 0, ResVBs :: [snmp:varbind()]} |
+ {ErrStatus :: snmp:error_status(), ErrIndex :: snmp:error_index(), []}.
diff --git a/lib/snmp/src/agent/snmpa_local_db.erl b/lib/snmp/src/agent/snmpa_local_db.erl
index eb67b9cd6f..c9093fcdb9 100644
--- a/lib/snmp/src/agent/snmpa_local_db.erl
+++ b/lib/snmp/src/agent/snmpa_local_db.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -147,12 +147,13 @@ init([Prio, DbDir, DbInitError, Opts]) ->
do_init(Prio, DbDir, DbInitError, Opts) ->
process_flag(priority, Prio),
process_flag(trap_exit, true),
- put(sname,ldb),
- put(verbosity,get_opt(verbosity, Opts, ?default_verbosity)),
+ put(sname, get_opt(sname, Opts, ldb)),
+ put(verbosity, get_opt(verbosity, Opts, ?default_verbosity)),
?vlog("starting",[]),
Dets = dets_open(DbDir, DbInitError, Opts),
Ets = ets:new(?ETS_TAB, [set, protected]),
?vdebug("started",[]),
+ put(started, snmp_misc:formated_timestamp()),
{ok, #state{dets = Dets, ets = Ets}}.
dets_open(DbDir, DbInitError, Opts) ->
@@ -625,7 +626,7 @@ handle_info(Info, State) ->
terminate(Reason, State) ->
- ?vlog("terminate: ~p",[Reason]),
+ ?vlog("terminate: ~p", [Reason]),
close(State).
@@ -732,16 +733,16 @@ dets_backup(close, _Cont, _D, B) ->
ok;
dets_backup(read, Cont1, D, B) ->
case dets:bchunk(D, Cont1) of
+ {error, _} = ERROR ->
+ ERROR;
+ '$end_of_table' ->
+ dets:close(B),
+ end_of_input;
{Cont2, Data} ->
F = fun(Arg) ->
dets_backup(Arg, Cont2, D, B)
end,
- {Data, F};
- '$end_of_table' ->
- dets:close(B),
- end_of_input;
- Error ->
- Error
+ {Data, F}
end.
diff --git a/lib/snmp/src/agent/snmpa_mib_storage.erl b/lib/snmp/src/agent/snmpa_mib_storage.erl
index ed0607fb84..d46dab0be0 100644
--- a/lib/snmp/src/agent/snmpa_mib_storage.erl
+++ b/lib/snmp/src/agent/snmpa_mib_storage.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -120,7 +120,7 @@
-callback match_object(TabId :: mib_storage_table_id(),
Pattern :: ets:match_pattern()) ->
- {ok, Recs :: [tuple()]} | {error, Reason :: term()}.
+ Recs :: [tuple()] | {error, Reason :: term()}.
%% ---------------------------------------------------------------
@@ -133,7 +133,7 @@
-callback match_delete(TabId :: mib_storage_table_id(),
Pattern :: ets:match_pattern()) ->
- {ok, Recs :: [tuple()]} | {error, Reason :: term()}.
+ Recs :: [tuple()] | {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
index 2459b6bc3e..0fcb8083f5 100644
--- a/lib/snmp/src/agent/snmpa_mib_storage_dets.erl
+++ b/lib/snmp/src/agent/snmpa_mib_storage_dets.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -291,16 +291,16 @@ dets_backup(close, _Cont, _ID, B) ->
ok;
dets_backup(read, Cont1, ID, B) ->
case dets:bchunk(ID, Cont1) of
+ {error, _} = ERROR ->
+ ERROR;
+ '$end_of_table' ->
+ dets:close(B),
+ end_of_input;
{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
+ {Data, F}
end.
diff --git a/lib/snmp/src/agent/snmpa_mib_storage_ets.erl b/lib/snmp/src/agent/snmpa_mib_storage_ets.erl
index 68dfa83247..173dac276e 100644
--- a/lib/snmp/src/agent/snmpa_mib_storage_ets.erl
+++ b/lib/snmp/src/agent/snmpa_mib_storage_ets.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -189,7 +189,8 @@ read(#tab{id = ID}, Key) ->
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).
+ ets:insert(ID, Rec),
+ ok.
%% ---------------------------------------------------------------
@@ -213,7 +214,9 @@ delete(#tab{id = ID, file = File}) ->
%% ---------------------------------------------------------------
delete(#tab{id = ID}, Key) ->
?vtrace("delete from table ~p: ~p", [ID, Key]),
- ets:delete(ID, Key).
+ ets:delete(ID, Key),
+ ok.
+
%% ---------------------------------------------------------------
diff --git a/lib/snmp/src/agent/snmpa_mpd.erl b/lib/snmp/src/agent/snmpa_mpd.erl
index b440d57d03..2ec5dcb5e6 100644
--- a/lib/snmp/src/agent/snmpa_mpd.erl
+++ b/lib/snmp/src/agent/snmpa_mpd.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -76,11 +76,9 @@
init(Vsns) ->
?vlog("init -> entry with"
"~n Vsns: ~p", [Vsns]),
- random:seed(erlang:phash2([node()]),
- erlang:monotonic_time(),
- erlang:unique_integer()),
- ets:insert(snmp_agent_table, {msg_id, random:uniform(2147483647)}),
- ets:insert(snmp_agent_table, {req_id, random:uniform(2147483647)}),
+ ?SNMP_RAND_SEED(),
+ ets:insert(snmp_agent_table, {msg_id, rand:uniform(2147483647)}),
+ ets:insert(snmp_agent_table, {req_id, rand:uniform(2147483647)}),
init_counters(),
init_versions(Vsns, #state{}).
diff --git a/lib/snmp/src/agent/snmpa_network_interface.erl b/lib/snmp/src/agent/snmpa_network_interface.erl
index 699fbde671..24985c113e 100644
--- a/lib/snmp/src/agent/snmpa_network_interface.erl
+++ b/lib/snmp/src/agent/snmpa_network_interface.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -19,28 +19,56 @@
%%
-module(snmpa_network_interface).
--export([behaviour_info/1]).
-
-behaviour_info(callbacks) ->
- [{start_link, 4},
- {get_log_type, 1},
- {set_log_type, 2},
- {get_request_limit, 1},
- {set_request_limit, 2},
- {info, 1},
- {verbosity, 2}];
-behaviour_info(_) ->
- undefined.
-
-
-%% behaviour_info(callbacks) ->
-%% [{start_link, 4},
-%% {send_pdu, 5},
-%% {send_response_pdu, 6},
-%% {discard_pdu, 6},
-%% {send_pdu_req, 6},
-%% {verbosity, 2},
-%% {change_log_type, 2}];
-%% behaviour_info(_) ->
-%% undefined.
+%% Note that this behaviour is not enough!
+%% There is also a set of mandatory messages which the
+%% network interface entity must be able to receive and
+%% be able to send. See the documentation for more info.
+
+-callback start_link(Prio, NoteStore, MasterAgent, Opts) ->
+ {ok, Pid} | {error, Reason} when
+ Prio :: low | normal | high, % priority_level(),
+ NoteStore :: pid(),
+ MasterAgent :: pid(),
+ Opts :: [Option],
+ Option :: {verbosity, snmp:verbosity()} |
+ {versions, [snmp:version()]} |
+ term(),
+ Pid :: pid(),
+ Reason :: term().
+
+-callback info(Pid) ->
+ Info when
+ Pid :: pid(),
+ Info :: [{Key, Value}],
+ Key :: term(),
+ Value :: term().
+
+-callback verbosity(Pid, Verbosity) ->
+ snmp:void() when
+ Pid :: pid(),
+ Verbosity :: snmp:verbosity().
+
+-callback get_log_type(Pid) ->
+ {ok, LogType} | {error, Reason} when
+ Pid :: pid(),
+ LogType :: snmp:atl_type(),
+ Reason :: term().
+
+-callback set_log_type(Pid, NewType) ->
+ {ok, OldType} | {error, Reason} when
+ Pid :: pid(),
+ NewType :: snmp:atl_type(),
+ OldType :: snmp:atl_type(),
+ Reason :: term().
+
+-callback get_request_limit(Pid) ->
+ {ok, Limit} when
+ Pid :: pid(),
+ Limit :: non_neg_integer() | infinity.
+
+-callback set_request_limit(Pid, NewLimit) ->
+ {ok, OldLimit} when
+ Pid :: pid(),
+ NewLimit :: non_neg_integer() | infinity,
+ OldLimit :: non_neg_integer() | infinity.
diff --git a/lib/snmp/src/agent/snmpa_set.erl b/lib/snmp/src/agent/snmpa_set.erl
index 9833d6fdcc..b3a3bf0ab0 100644
--- a/lib/snmp/src/agent/snmpa_set.erl
+++ b/lib/snmp/src/agent/snmpa_set.erl
@@ -163,10 +163,14 @@ set_phase_two(MyVarbinds, SubagentVarbinds) ->
[MyVarbinds, SubagentVarbinds]),
case snmpa_set_lib:try_set(MyVarbinds) of
{noError, 0} ->
+ ?vtrace("set phase two: (local) varbinds set ok", []),
set_phase_two_subagents(SubagentVarbinds);
- {ErrorStatus, Index} ->
+ {ErrorStatus, ErrorIndex} ->
+ ?vlog("set phase two: (local) varbinds set failed"
+ "~n ErrorStatus: ~p"
+ "~n ErrorIndex: ~p", [ErrorStatus, ErrorIndex]),
set_phase_two_undo_subagents(SubagentVarbinds),
- {ErrorStatus, Index}
+ {ErrorStatus, ErrorIndex}
end.
%%-----------------------------------------------------------------
@@ -188,6 +192,7 @@ set_phase_two_subagents([{SubAgentPid, SAVbs} | SubagentVarbinds]) ->
{_SAOids, Vbs} = sa_split(SAVbs),
case catch snmpa_agent:subagent_set(SubAgentPid, [phase_two, set, Vbs]) of
{noError, 0} ->
+ ?vtrace("set phase two: subagent ~p varbinds set ok", [SubAgentPid]),
set_phase_two_subagents(SubagentVarbinds);
{'EXIT', Reason} ->
user_err("Lost contact with subagent (set)~n~w. Using genErr",
@@ -195,10 +200,14 @@ set_phase_two_subagents([{SubAgentPid, SAVbs} | SubagentVarbinds]) ->
set_phase_two_undo_subagents(SubagentVarbinds),
{genErr, 0};
{ErrorStatus, ErrorIndex} ->
+ ?vlog("set phase two: subagent ~p varbinds set failed"
+ "~n ErrorStatus: ~p"
+ "~n ErrorIndex: ~p", [SubAgentPid, ErrorStatus, ErrorIndex]),
set_phase_two_undo_subagents(SubagentVarbinds),
{ErrorStatus, ErrorIndex}
end;
set_phase_two_subagents([]) ->
+ ?vtrace("set phase two: subagent(s) set ok", []),
{noError, 0}.
%%-----------------------------------------------------------------
diff --git a/lib/snmp/src/agent/snmpa_set_lib.erl b/lib/snmp/src/agent/snmpa_set_lib.erl
index 57507a36e8..94120f4c7d 100644
--- a/lib/snmp/src/agent/snmpa_set_lib.erl
+++ b/lib/snmp/src/agent/snmpa_set_lib.erl
@@ -46,9 +46,9 @@
%%* 6) IF value is outside the acceptable range THEN wrongValue.
%% 7) IF variable does not exist and could not ever be created
%% THEN noCreation.
-%% 8) IF variable can not be created now THEN inconsistentName.
-%% 9) IF value can not be set now THEN inconsistentValue.
-%%* 9) IF instances of the variable can not be modified THEN notWritable.
+%% 8) IF variable cannot be created now THEN inconsistentName.
+%% 9) IF value cannot be set now THEN inconsistentValue.
+%%* 9) IF instances of the variable cannot be modified THEN notWritable.
%% 10) IF an unavailable resource is needed THEN resourceUnavailable.
%% 11) IF any other error THEN genErr.
%% 12) Otherwise ok!
@@ -390,7 +390,7 @@ dbg_apply(M,F,A) ->
{'EXIT', {function_clause, [{M, F, A} | _]}} ->
{'EXIT', {hook_function_clause, {M, F, A}}};
- % XYZ: Older format for compatibility
+ %% XYZ: Older format for compatibility
{'EXIT', {undef, {M, F, A}}} ->
{'EXIT', {hook_undef, {M, F, A}}};
{'EXIT', {function_clause, {M, F, A}}} ->
diff --git a/lib/snmp/src/agent/snmpa_set_mechanism.erl b/lib/snmp/src/agent/snmpa_set_mechanism.erl
index 2f24f38092..4eee7d7257 100644
--- a/lib/snmp/src/agent/snmpa_set_mechanism.erl
+++ b/lib/snmp/src/agent/snmpa_set_mechanism.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -19,18 +19,26 @@
%%
-module(snmpa_set_mechanism).
--export([behaviour_info/1]).
-
-behaviour_info(callbacks) ->
- [{do_set, 2}, {do_subagent_set, 1}];
-behaviour_info(_) ->
- undefined.
+%% -export([behaviour_info/1]).
+%% behaviour_info(callbacks) ->
+%% [{do_set, 2}, {do_subagent_set, 1}];
+%% behaviour_info(_) ->
+%% undefined.
+
%%-----------------------------------------------------------------
%% do_set(MibView, UnsortedVarbinds)
%%-----------------------------------------------------------------
+-callback do_set(MibView, UnsortedVBs) ->
+ {noError, 0} | {ErrStatus, ErrIndex} when
+ MibView :: snmp_view_based_acm_mib:mibview(),
+ UnsortedVBs :: [snmp:varbind()],
+ ErrStatus :: snmp:error_status(),
+ ErrIndex :: snmp:error_index().
+
+
%%-----------------------------------------------------------------
%% do_subagent_set(Args)
%%
@@ -41,3 +49,18 @@ behaviour_info(_) ->
%% [phase_two, set, UnsortedVarbinds]
%% [phase_two, undo, UnsortedVarbinds]
%%-----------------------------------------------------------------
+
+%% -callback do_subagent_set(Args) ->
+%% {noError, 0} | {ErrStatus, ErrIndex} when
+%% Args :: [phase_one, UnsortedVBs] |
+%% [phase_two, set, UnsortedVBs] |
+%% [phase_two, undo, UnsortedVBs],
+%% ErrStatus :: snmp:error_status(),
+%% ErrIndex :: snmp:error_index(),
+%% UnsortedVBs :: [snmp:varbind()].
+
+-callback do_subagent_set(Args) ->
+ {noError, 0} | {ErrStatus, ErrIndex} when
+ Args :: list(),
+ ErrStatus :: snmp:error_status(),
+ ErrIndex :: snmp:error_index().
diff --git a/lib/snmp/src/agent/snmpa_supervisor.erl b/lib/snmp/src/agent/snmpa_supervisor.erl
index cdb5ca840d..7d5c6da2c8 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-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -22,7 +22,7 @@
-behaviour(supervisor).
%% External exports
--export([start_link/2]).
+-export([start_link/2, stop/0, stop/1]).
-export([start_sub_sup/1, start_master_sup/1]).
-export([start_sub_agent/3, stop_sub_agent/1]).
@@ -91,6 +91,39 @@ start_link(master, Opts, {takeover, Node}) ->
Else
end.
+
+stop() ->
+ stop(0).
+
+stop(Timeout) ->
+ case whereis(?SERVER) of
+ Pid when is_pid(Pid) ->
+ stop(Pid, Timeout);
+ _ ->
+ not_running
+ end.
+
+%% For some unfathomable reason there is no "nice" way to stop
+%% a supervisor. The "normal" way to do it is:
+%% 1) exit(Pid, kill) (kaboom)
+%% 2) If the caller is the *parent*: exit(Pid, shutdown)
+%% So, here we do it the really ugly way...but since this function is
+%% intended for testing (mostly)...
+stop(Pid, Timeout) when (Timeout =:= 0) ->
+ sys:terminate(Pid, shutdown),
+ ok;
+stop(Pid, Timeout) ->
+ MRef = erlang:monitor(process, Pid),
+ sys:terminate(Pid, shutdown),
+ receive
+ {'DOWN', MRef, process, Pid, _} ->
+ ok
+ after Timeout ->
+ erlang:demonitor(MRef, [flush]),
+ {error, timeout}
+ end.
+
+
get_own_loaded_mibs() ->
AgentInfo = snmpa:info(snmp_master_agent),
[ Name || {Name, _, _} <- loaded_mibs(AgentInfo) ].
@@ -193,36 +226,36 @@ init([AgentType, Opts]) ->
?vdebug("agent restart type: ~w", [Restart]),
%% -- Agent type --
- ets:insert(snmp_agent_table, {agent_type, AgentType}),
+ store(agent_type, AgentType),
%% -- Prio --
Prio = get_opt(priority, Opts, normal),
?vdebug("[agent table] store priority: ~p",[Prio]),
- ets:insert(snmp_agent_table, {priority, Prio}),
+ store(priority, Prio),
%% -- Versions --
Vsns = get_opt(versions, Opts, [v1,v2,v3]),
?vdebug("[agent table] store versions: ~p",[Vsns]),
- ets:insert(snmp_agent_table, {versions, Vsns}),
+ store(versions, Vsns),
%% -- Max number of VBs in a Get-BULK response --
GbMaxVBs = get_gb_max_vbs(Opts),
?vdebug("[agent table] Get-BULK max VBs: ~p", [GbMaxVBs]),
- ets:insert(snmp_agent_table, {gb_max_vbs, GbMaxVBs}),
+ store(gb_max_vbs, GbMaxVBs),
%% -- DB-directory --
DbDir = get_opt(db_dir, Opts),
?vdebug("[agent table] store db_dir: ~n ~p",[DbDir]),
- ets:insert(snmp_agent_table, {db_dir, filename:join([DbDir])}),
+ store(db_dir, filename:join([DbDir])),
DbInitError = get_opt(db_init_error, Opts, terminate),
?vdebug("[agent table] store db_init_error: ~n ~p",[DbInitError]),
- ets:insert(snmp_agent_table, {db_init_error, DbInitError}),
+ store(db_init_error, DbInitError),
%% -- Error report module --
ErrorReportMod = get_opt(error_report_mod, Opts, snmpa_error_logger),
?vdebug("[agent table] store error report module: ~w",[ErrorReportMod]),
- ets:insert(snmp_agent_table, {error_report_mod, ErrorReportMod}),
+ store(error_report_mod, ErrorReportMod),
%% -- mib storage --
%% MibStorage has only one mandatory part: module
@@ -320,31 +353,31 @@ init([AgentType, Opts]) ->
end,
?vdebug("[agent table] store mib storage: ~w", [MibStorage]),
- ets:insert(snmp_agent_table, {mib_storage, MibStorage}),
+ store(mib_storage, MibStorage),
%% -- Agent mib storage --
AgentMibStorage = get_opt(agent_mib_storage, Opts, persistent),
%% ?vdebug("[agent table] store agent mib storage: ~w",[AgentMibStorage]),
- ets:insert(snmp_agent_table, {agent_mib_storage, AgentMibStorage}),
+ store(agent_mib_storage, AgentMibStorage),
%% -- System start time --
?vdebug("[agent table] store system start time",[]),
- ets:insert(snmp_agent_table, {system_start_time, snmp_misc:now(cs)}),
+ store(system_start_time, snmp_misc:now(cs)),
%% -- Symbolic store options --
SsOpts = get_opt(symbolic_store, Opts, []),
?vdebug("[agent table] store symbolic store options: ~w",[SsOpts]),
- ets:insert(snmp_agent_table, {symbolic_store, SsOpts}),
+ store(symbolic_store, SsOpts),
%% -- Local DB options --
LdbOpts = get_opt(local_db, Opts, []),
?vdebug("[agent table] store local db options: ~w",[LdbOpts]),
- ets:insert(snmp_agent_table, {local_db, LdbOpts}),
+ store(local_db, LdbOpts),
%% -- Target cache options --
TargetCacheOpts = get_opt(target_cache, Opts, []),
?vdebug("[agent table] store target cache options: ~w",[TargetCacheOpts]),
- ets:insert(snmp_agent_table, {target_cache, TargetCacheOpts}),
+ store(target_cache, TargetCacheOpts),
%% -- Specs --
SupFlags = {one_for_all, 0, 3600},
@@ -377,7 +410,7 @@ init([AgentType, Opts]) ->
%% -- Config --
ConfOpts = get_opt(config, Opts, []),
?vdebug("[agent table] store config options: ~p", [ConfOpts]),
- ets:insert(snmp_agent_table, {config, ConfOpts}),
+ store(config, ConfOpts),
ConfigArgs = [Vsns, ConfOpts],
ConfigSpec =
@@ -390,43 +423,46 @@ init([AgentType, Opts]) ->
%% -- Discovery processing --
DiscoOpts = get_opt(discovery, Opts, []),
?vdebug("[agent table] store discovery options: ~p", [DiscoOpts]),
- ets:insert(snmp_agent_table, {discovery, DiscoOpts}),
+ store(discovery, DiscoOpts),
%% -- Mibs --
Mibs = get_mibs(get_opt(mibs, Opts, []), Vsns),
?vdebug("[agent table] store mibs: ~n ~p",[Mibs]),
- ets:insert(snmp_agent_table, {mibs, Mibs}),
+ store(mibs, Mibs),
Ref = make_ref(),
+ %% -- Get module --
+ GetModule = get_opt(get_mechanism, Opts, snmpa_get),
+ ?vdebug("[agent table] store get-module: ~p", [GetModule]),
+ store(get_mechanism, GetModule),
+
%% -- Set module --
SetModule = get_opt(set_mechanism, Opts, snmpa_set),
?vdebug("[agent table] store set-module: ~p",[SetModule]),
- ets:insert(snmp_agent_table, {set_mechanism, ConfOpts}),
+ store(set_mechanism, SetModule),
%% -- Authentication service --
AuthModule = get_opt(authentication_service, Opts, snmpa_acm),
?vdebug("[agent table] store authentication service: ~w",
[AuthModule]),
- ets:insert(snmp_agent_table,
- {authentication_service, AuthModule}),
+ store(authentication_service, AuthModule),
%% -- Multi-threaded --
MultiT = get_opt(multi_threaded, Opts, false),
- ?vdebug("[agent table] store multi-threaded: ~p",[MultiT]),
- ets:insert(snmp_agent_table, {multi_threaded, MultiT}),
+ ?vdebug("[agent table] store multi-threaded: ~p", [MultiT]),
+ store(multi_threaded, MultiT),
%% -- Audit trail log --
case get_opt(audit_trail_log, Opts, not_found) of
not_found ->
- ?vdebug("[agent table] no audit trail log",[]),
+ ?vdebug("[agent table] no audit trail log", []),
ok;
AtlOpts ->
?vdebug("[agent table] "
"store audit trail log options: ~p",
[AtlOpts]),
- ets:insert(snmp_agent_table,
- {audit_trail_log, AtlOpts}),
+ store(audit_trail_log, AtlOpts),
ok
end,
@@ -434,24 +470,25 @@ init([AgentType, Opts]) ->
MibsOpts = get_opt(mib_server, Opts, []),
?vdebug("[agent table] store mib-server options: "
"~n ~p", [MibsOpts]),
- ets:insert(snmp_agent_table, {mib_server, MibsOpts}),
+ store(mib_server, MibsOpts),
%% -- Network interface --
NiOpts = get_opt(net_if, Opts, []),
?vdebug("[agent table] store net-if options: "
"~n ~p", [NiOpts]),
- ets:insert(snmp_agent_table, {net_if, NiOpts}),
+ store(net_if, NiOpts),
%% -- Note store --
NsOpts = get_opt(note_store, Opts, []),
?vdebug("[agent table] store note-store options: "
"~n ~p",[NsOpts]),
- ets:insert(snmp_agent_table, {note_store, NsOpts}),
+ store(note_store, NsOpts),
AgentOpts =
[{verbosity, AgentVerb},
{mibs, Mibs},
{mib_storage, MibStorage},
+ {get_mechanism, GetModule},
{set_mechanism, SetModule},
{authentication_service, AuthModule},
{multi_threaded, MultiT},
@@ -480,6 +517,10 @@ init([AgentType, Opts]) ->
{ok, {SupFlags, [MiscSupSpec, SymStoreSpec, LocalDbSpec, TargetCacheSpec |
Rest]}}.
+
+store(Key, Value) ->
+ ets:insert(snmp_agent_table, {Key, Value}).
+
get_mibs(Mibs, Vsns) ->
MibDir = filename:join(code:priv_dir(snmp), "mibs"),
StdMib =
diff --git a/lib/snmp/src/agent/snmpa_trap.erl b/lib/snmp/src/agent/snmpa_trap.erl
index e75016f7ec..119207c76b 100644
--- a/lib/snmp/src/agent/snmpa_trap.erl
+++ b/lib/snmp/src/agent/snmpa_trap.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -364,13 +364,14 @@ send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID,
LocalEngineID, ExtraInfo, NetIf)
end
catch
- T:E ->
- Info = [{args, [TrapRec, NotifyName, ContextName,
- Recv, Vbs, LocalEngineID, ExtraInfo, NetIf]},
- {tag, T},
- {err, E},
- {stacktrace, erlang:get_stacktrace()}],
- ?vlog("snmpa_trap:send_trap exception: ~p", [Info]),
+ C:E:S ->
+ Info = [{args, [TrapRec, NotifyName, ContextName,
+ Recv, Vbs, LocalEngineID, ExtraInfo, NetIf]},
+ {class, C},
+ {err, E},
+ {stacktrace, S}],
+ ?vlog("snmpa_trap:send_trap exception: "
+ "~n ~p", [Info]),
{error, {failed_sending_trap, Info}}
end.
@@ -830,11 +831,11 @@ do_send_v1_trap(Enter, Spec, V1Res, NVbs, ExtraInfo, NetIf, SysUpTime) ->
case lists:keyfind(transportDomainUdpIpv4, 1, Transports) of
false ->
?vtrace(
- "snmpa_trap: can not send v1 trap "
+ "snmpa_trap: cannot send v1 trap "
"without IPv4 domain: ~p",
[Transports]),
user_err(
- "snmpa_trap: can not send v1 trap "
+ "snmpa_trap: cannot send v1 trap "
"without IPv4 domain: ~p",
[Transports]);
DomainAddr ->
@@ -917,7 +918,7 @@ do_send_v2_trap(Recvs, Vbs, ExtraInfo, NetIf) ->
TrapPdu = make_v2_notif_pdu(Vbs, 'snmpv2-trap'),
AddrCommunities = mk_addr_communities(Recvs),
lists:foreach(fun({Community, Addrs}) ->
- ?vtrace("~n send v2 trap to ~p",[Addrs]),
+ ?vtrace("send v2 trap to ~p",[Addrs]),
NetIf ! {send_pdu, 'version-2', TrapPdu,
{community, Community}, Addrs, ExtraInfo}
end, AddrCommunities),
@@ -1114,7 +1115,7 @@ transform_taddrs(TAddrs) ->
%% v2
transform_taddr({?snmpUDPDomain, Addr}) ->
- transform_taddr(transportDomainIdpIpv4, Addr);
+ transform_taddr(transportDomainUdpIpv4, Addr);
transform_taddr({?transportDomainUdpIpv4, Addr}) ->
transform_taddr(transportDomainUdpIpv4, Addr);
transform_taddr({?transportDomainUdpIpv6, Addr}) ->
diff --git a/lib/snmp/src/agent/snmpa_usm.erl b/lib/snmp/src/agent/snmpa_usm.erl
index fb616cd9ef..1debceae98 100644
--- a/lib/snmp/src/agent/snmpa_usm.erl
+++ b/lib/snmp/src/agent/snmpa_usm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -646,10 +646,12 @@ get_des_salt() ->
ets:insert(snmp_agent_table, {usm_des_salt, 0}),
0;
_ -> % it doesn't exist, initialize
- random:seed(erlang:phash2([node()]),
- erlang:monotonic_time(),
- erlang:unique_integer()),
- R = random:uniform(4294967295),
+ ?SNMP_RAND_SEED(),
+ %% rand:seed(exrop,
+ %% {erlang:phash2([node()]),
+ %% erlang:monotonic_time(),
+ %% erlang:unique_integer()}),
+ R = rand:uniform(4294967295),
ets:insert(snmp_agent_table, {usm_des_salt, R}),
R
end,
@@ -679,10 +681,12 @@ get_aes_salt() ->
ets:insert(snmp_agent_table, {usm_aes_salt, 0}),
0;
_ -> % it doesn't exist, initialize
- random:seed(erlang:phash2([node()]),
- erlang:monotonic_time(),
- erlang:unique_integer()),
- R = random:uniform(36893488147419103231),
+ ?SNMP_RAND_SEED(),
+ %% rand:seed(exrop,
+ %% {erlang:phash2([node()]),
+ %% erlang:monotonic_time(),
+ %% erlang:unique_integer()}),
+ R = rand:uniform(36893488147419103231),
ets:insert(snmp_agent_table, {usm_aes_salt, R}),
R
end,
diff --git a/lib/snmp/src/app/snmp.app.src b/lib/snmp/src/app/snmp.app.src
index d4bf0de61a..178309b488 100644
--- a/lib/snmp/src/app/snmp.app.src
+++ b/lib/snmp/src/app/snmp.app.src
@@ -49,6 +49,9 @@
snmpa_error_io,
snmpa_error_logger,
snmpa_error_report,
+ snmpa_get,
+ snmpa_get_lib,
+ snmpa_get_mechanism,
snmpa_local_db,
snmpa_mib,
snmpa_mib_data,
diff --git a/lib/snmp/src/app/snmp.config b/lib/snmp/src/app/snmp.config
index b66ef5d7df..f35a636157 100644
--- a/lib/snmp/src/app/snmp.config
+++ b/lib/snmp/src/app/snmp.config
@@ -8,6 +8,7 @@
%% {agent_verbosity, verbosity()} |
%% {versions, versions()} |
%% {priority, atom()} |
+%% {get_mechanism, module()} |
%% {set_mechanism, module()} |
%% {authentication_service, module()} |
%% {multi_threaded, bool()} |
diff --git a/lib/snmp/src/app/snmp.erl b/lib/snmp/src/app/snmp.erl
index 8a736f688b..1e6a93deff 100644
--- a/lib/snmp/src/app/snmp.erl
+++ b/lib/snmp/src/app/snmp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -95,6 +95,9 @@
dir/0,
snmp_timer/0,
+ atl_type/0,
+ verbosity/0,
+
engine_id/0,
tdomain/0,
community/0,
@@ -116,7 +119,10 @@
pdu/0,
trappdu/0,
mib/0,
- mib_name/0,
+ mib_name/0,
+
+ error_status/0,
+ error_index/0,
void/0
]).
@@ -185,6 +191,9 @@
-type dir() :: string().
-type snmp_timer() :: #snmp_incr_timer{}.
+-type atl_type() :: read | write | read_write.
+-type verbosity() :: info | log | debug | trace | silence.
+
-type engine_id() :: string().
-type tdomain() :: transportDomainUdpIpv4 | transportDomainUdpIpv6.
-type community() :: string().
@@ -208,6 +217,23 @@
-type pdu() :: #pdu{}.
-type trappdu() :: #trappdu{}.
+%% We should really specify all of these, but they are so numerous...
+%% See the validate_err/1 function in the snmpa_agent.
+%% Here are a number of them:
+%% badValue |
+%% commitFailed |
+%% genErr |
+%% inconsistentName | inconsistentValue |
+%% noAccess | noCreation |
+%% noSuchInstance | noSuchName | noSuchObject |
+%% notWritable |
+%% resourceUnavailable |
+%% undoFailed |
+%% wrongValue
+
+-type error_status() :: atom().
+-type error_index() :: pos_integer().
+
-type void() :: term().
@@ -570,15 +596,6 @@ print_mod_info(Prefix, {Module, Info}) ->
_ ->
"Not found"
end,
- CompDate =
- case key1search(compile_time, Info) of
- {value, {Year, Month, Day, Hour, Min, Sec}} ->
- io_lib:format(
- "~w-~2..0w-~2..0w ~2..0w:~2..0w:~2..0w",
- [Year, Month, Day, Hour, Min, Sec]);
- _ ->
- "Not found"
- end,
Digest =
case key1search(md5, Info) of
{value, MD5} when is_binary(MD5) ->
@@ -590,13 +607,11 @@ print_mod_info(Prefix, {Module, Info}) ->
"~s Vsn: ~s~n"
"~s App vsn: ~s~n"
"~s Compiler ver: ~s~n"
- "~s Compile time: ~s~n"
"~s MD5 digest: ~s~n",
[Prefix, Module,
Prefix, Vsn,
Prefix, AppVsn,
Prefix, CompVer,
- Prefix, CompDate,
Prefix, Digest]),
ok.
@@ -691,13 +706,8 @@ sys_info() ->
[{arch, SysArch}, {ver, SysVer}].
os_info() ->
- V = os:version(),
- case os:type() of
- {OsFam, OsName} ->
- [{fam, OsFam}, {name, OsName}, {ver, V}];
- OsFam ->
- [{fam, OsFam}, {ver, V}]
- end.
+ {OsFam, OsName} = os:type(),
+ [{fam, OsFam}, {name, OsName}, {ver, os:version()}].
ms1() ->
App = ?APPLICATION,
diff --git a/lib/snmp/src/app/snmp_internal.hrl b/lib/snmp/src/app/snmp_internal.hrl
index 374767df15..f9a758ab7b 100644
--- a/lib/snmp/src/app/snmp_internal.hrl
+++ b/lib/snmp/src/app/snmp_internal.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,7 +25,12 @@
-define(APPLICATION, snmp).
-endif.
--define(STACK(), erlang:get_stacktrace()).
+
+-define(SNMP_RAND_SEED_ALG, exrop).
+-define(SNMP_RAND_SEED(), rand:seed(?SNMP_RAND_SEED_ALG,
+ {erlang:phash2([node()]),
+ erlang:monotonic_time(),
+ erlang:unique_integer()})).
-define(snmp_info(C, F, A), ?snmp_msg(info_msg, C, F, A)).
-define(snmp_warning(C, F, A), ?snmp_msg(warning_msg, C, F, A)).
@@ -39,5 +44,3 @@
-endif. % -ifdef(snmp_internal).
-
-
diff --git a/lib/snmp/src/compile/Makefile b/lib/snmp/src/compile/Makefile
index 4093ffa9ca..d9678669a5 100644
--- a/lib/snmp/src/compile/Makefile
+++ b/lib/snmp/src/compile/Makefile
@@ -2,7 +2,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
+# Copyright Ericsson AB 1997-2019. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -59,6 +59,8 @@ PARSER_TARGET = $(PARSER_MODULE).$(EMULATOR)
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
+ERL_COMPILE_FLAGS += -pa $(ERL_TOP)/lib/snmp/ebin
+
ifeq ($(WARN_UNUSED_VARS),true)
ERL_COMPILE_FLAGS += +warn_unused_vars
endif
diff --git a/lib/snmp/src/compile/snmpc.erl b/lib/snmp/src/compile/snmpc.erl
index c810bfcd41..4249799195 100644
--- a/lib/snmp/src/compile/snmpc.erl
+++ b/lib/snmp/src/compile/snmpc.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -31,6 +31,7 @@
-export([init/3]).
-include_lib("stdlib/include/erl_compile.hrl").
+-include_lib("snmp/src/app/snmp_internal.hrl").
-include("snmp_types.hrl").
-include("snmpc.hrl").
-include("snmpc_lib.hrl").
@@ -413,9 +414,11 @@ get_verbosity(Options) ->
%%----------------------------------------------------------------------
init(From, MibFileName, Options) ->
- random:seed(erlang:phash2([node()]),
- erlang:monotonic_time(),
- erlang:unique_integer()),
+ ?SNMP_RAND_SEED(),
+ %% rand:seed(exrop,
+ %% {erlang:phash2([node()]),
+ %% erlang:monotonic_time(),
+ %% erlang:unique_integer()}),
put(options, Options),
put(verbosity, get_verbosity(Options)),
put(description, get_description(Options)),
diff --git a/lib/snmp/src/manager/snmpm.erl b/lib/snmp/src/manager/snmpm.erl
index cf8c95d69f..8e60cecaf9 100644
--- a/lib/snmp/src/manager/snmpm.erl
+++ b/lib/snmp/src/manager/snmpm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -32,7 +32,7 @@
%% Management API
start/0, start/1,
start_link/0, start_link/1,
- stop/0,
+ stop/0, stop/1,
monitor/0, demonitor/1,
notify_started/1, cancel_notify_started/1,
@@ -196,7 +196,12 @@ start(Opts) ->
ok.
stop() ->
- snmpm_supervisor:stop().
+ stop(0).
+
+stop(Timeout) when (Timeout =:= infinity) orelse
+ (is_integer(Timeout) andalso (Timeout >= 0)) ->
+ snmpm_supervisor:stop(Timeout).
+
monitor() ->
diff --git a/lib/snmp/src/manager/snmpm_conf.erl b/lib/snmp/src/manager/snmpm_conf.erl
index 0421f49c88..d097b40438 100644
--- a/lib/snmp/src/manager/snmpm_conf.erl
+++ b/lib/snmp/src/manager/snmpm_conf.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -356,6 +356,7 @@ read_config_file(Dir, File, Order, Check) ->
%% ---- config file utility functions ----
+-dialyzer({nowarn_function, check_ok/1}). % Future compat
check_ok(ok) ->
ok;
check_ok({ok, _}) ->
diff --git a/lib/snmp/src/manager/snmpm_config.erl b/lib/snmp/src/manager/snmpm_config.erl
index 118cdcd1df..4653d9822d 100644
--- a/lib/snmp/src/manager/snmpm_config.erl
+++ b/lib/snmp/src/manager/snmpm_config.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -479,10 +479,7 @@ agent_info(Domain, Address, Item) when is_atom(Domain) ->
NAddress ->
do_agent_info(Domain, NAddress, Item)
catch
- _Thrown ->
- %% p(?MODULE_STRING":agent_info(~p, ~p, ~p) throwed ~p at.~n"
- %% " ~p",
- %% [Domain, Address, Item, _Thrown, erlang:get_stacktrace()]),
+ _C:_E:_S ->
{error, not_found}
end;
agent_info(Ip, Port, Item) when is_integer(Port) ->
@@ -493,10 +490,7 @@ agent_info(Ip, Port, Item) when is_integer(Port) ->
Address ->
do_agent_info(Domain, Address, Item)
catch
- _Thrown ->
- %% p(?MODULE_STRING":agent_info(~p, ~p, ~p) throwed ~p at.~n"
- %% " ~p",
- %% [Ip, Port, Item, _Thrown, erlang:get_stacktrace()]),
+ _C:_E:_S ->
{error, not_found}
end.
@@ -1688,9 +1682,10 @@ read_agents_config_file(Dir) ->
Check = fun check_agent_config/2,
try read_file(Dir, "agents.conf", Order, Check, [])
catch
- throw:Error ->
- ?vlog("agent config error: ~p", [Error]),
- erlang:raise(throw, Error, erlang:get_stacktrace())
+ throw:E:S ->
+ ?vlog("agent config error: "
+ "~n ~p", [E]),
+ erlang:raise(throw, E, S)
end.
check_agent_config(Agent, State) ->
@@ -1935,9 +1930,10 @@ read_users_config_file(Dir) ->
Check = fun (User, State) -> {check_user_config(User), State} end,
try read_file(Dir, "users.conf", Order, Check, [])
catch
- throw:Error ->
- ?vlog("failure reading users config file: ~n ~p", [Error]),
- erlang:raise(throw, Error, erlang:get_stacktrace())
+ throw:E:S ->
+ ?vlog("failure reading users config file: "
+ "~n ~p", [E]),
+ erlang:raise(throw, E, S)
end.
check_user_config({Id, Mod, Data}) ->
@@ -2351,10 +2347,11 @@ read_file(Dir, FileName, Order, Check, Default) ->
read_file(Dir, FileName, Order, Check) ->
try snmp_conf:read(filename:join(Dir, FileName), Order, Check)
catch
- throw:{error, Reason} = Error
+ throw:{error, Reason} = E:S
when element(1, Reason) =:= failed_open ->
- error_msg("failed reading config from ~s: ~p", [FileName, Reason]),
- erlang:raise(throw, Error, erlang:get_stacktrace())
+ error_msg("failed reading config from ~s: "
+ "~n ~p", [FileName, Reason]),
+ erlang:raise(throw, E, S)
end.
%%--------------------------------------------------------------------
@@ -2741,16 +2738,16 @@ dets_backup(close, _Cont, _D, B) ->
ok;
dets_backup(read, Cont1, D, B) ->
case dets:bchunk(D, Cont1) of
+ {error, _} = ERROR ->
+ ERROR;
+ '$end_of_table' ->
+ dets:close(B),
+ end_of_input;
{Cont2, Data} ->
F = fun(Arg) ->
dets_backup(Arg, Cont2, D, B)
end,
- {Data, F};
- '$end_of_table' ->
- dets:close(B),
- end_of_input;
- Error ->
- Error
+ {Data, F}
end.
diff --git a/lib/snmp/src/manager/snmpm_mpd.erl b/lib/snmp/src/manager/snmpm_mpd.erl
index 191dc2c281..8d0a7918a6 100644
--- a/lib/snmp/src/manager/snmpm_mpd.erl
+++ b/lib/snmp/src/manager/snmpm_mpd.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -68,11 +68,13 @@
%%%-----------------------------------------------------------------
init(Vsns) ->
?vdebug("init -> entry with ~p", [Vsns]),
- random:seed(erlang:phash2([node()]),
- erlang:monotonic_time(),
- erlang:unique_integer()),
- snmpm_config:cre_counter(msg_id, random:uniform(2147483647)),
- snmpm_config:cre_counter(req_id, random:uniform(2147483647)),
+ ?SNMP_RAND_SEED(),
+ %% rand:seed(exrop,
+ %% {erlang:phash2([node()]),
+ %% erlang:monotonic_time(),
+ %% erlang:unique_integer()}),
+ snmpm_config:cre_counter(msg_id, rand:uniform(2147483647)),
+ snmpm_config:cre_counter(req_id, rand:uniform(2147483647)),
init_counters(),
State = init_versions(Vsns, #state{}),
init_usm(State#state.v3),
diff --git a/lib/snmp/src/manager/snmpm_net_if.erl b/lib/snmp/src/manager/snmpm_net_if.erl
index 29216f9d6a..184f782860 100644
--- a/lib/snmp/src/manager/snmpm_net_if.erl
+++ b/lib/snmp/src/manager/snmpm_net_if.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -182,11 +182,9 @@ worker(Worker, Failer, #state{log = Log} = State) ->
%% Winds up in handle_info {'DOWN', ...}
erlang:exit({net_if_worker, Result})
catch
- Class:Reason ->
+ C:E:S ->
%% Winds up in handle_info {'DOWN', ...}
- erlang:exit(
- {net_if_worker, Failer,
- Class, Reason, erlang:get_stacktrace()})
+ erlang:exit({net_if_worker, Failer, C, E, S})
end
end,
[monitor]).
@@ -983,11 +981,10 @@ udp_send(Sock, To, Msg) ->
error_msg("failed sending message to ~p:~p:~n"
" ~p",[IpAddr, IpPort, Reason])
catch
- error:Error ->
- error_msg("failed sending message to ~p:~p:~n"
- " error:~p~n"
- " ~p",
- [IpAddr, IpPort, Error, erlang:get_stacktrace()])
+ error:E:S ->
+ error_msg("failed sending message to ~p:~p:"
+ "~n ~p"
+ "~n ~p", [IpAddr, IpPort, E, S])
end.
sz(B) when is_binary(B) ->
diff --git a/lib/snmp/src/manager/snmpm_network_interface.erl b/lib/snmp/src/manager/snmpm_network_interface.erl
index d0f6f709d3..7123bb94f0 100644
--- a/lib/snmp/src/manager/snmpm_network_interface.erl
+++ b/lib/snmp/src/manager/snmpm_network_interface.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -20,19 +20,61 @@
-module(snmpm_network_interface).
--export([behaviour_info/1]).
-
-behaviour_info(callbacks) ->
- [{start_link, 2},
- {stop, 1},
- {send_pdu, 7},
- {inform_response, 4},
- {note_store, 2},
- {info, 1},
- {verbosity, 2},
- %% {system_info_updated, 2},
- {get_log_type, 1},
- {set_log_type, 2}];
-behaviour_info(_) ->
- undefined.
+-callback start_link(Server, NoteStore) ->
+ {ok, Pid} | {error, Reason} when
+ Server :: pid(),
+ NoteStore :: pid(),
+ Pid :: pid(),
+ Reason :: term().
+
+-callback stop(Pid) ->
+ snmp:void() when
+ Pid :: pid().
+
+-callback send_pdu(Pid, Pdu, Vsn, MsgData, Domain, Addr, ExtraInfo) ->
+ snmp:void() when
+ Pid :: pid(),
+ Pdu :: snmp:pdu(),
+ Vsn :: 'version-1' | 'version-2' | 'version-3',
+ MsgData :: term(),
+ Domain :: snmp:tdomain(),
+ Addr :: {inet:ip_address(), inet:port_number()},
+ ExtraInfo :: term().
+
+-callback inform_response(Pid, Ref, Addr, Port) ->
+ snmp:void() when
+ Pid :: pid(),
+ Ref :: term(),
+ Addr :: inet:ip_address(),
+ Port :: inet:port_number().
+
+-callback note_store(Pid, NoteStore) ->
+ snmp:void() when
+ Pid :: pid(),
+ NoteStore :: pid().
+
+-callback info(Pid) ->
+ Info when
+ Pid :: pid(),
+ Info :: [{Key, Value}],
+ Key :: term(),
+ Value :: term().
+
+-callback verbosity(Pid, Verbosity) ->
+ snmp:void() when
+ Pid :: pid(),
+ Verbosity :: snmp:verbosity().
+
+-callback get_log_type(Pid) ->
+ {ok, LogType} | {error, Reason} when
+ Pid :: pid(),
+ LogType :: snmp:atl_type(),
+ Reason :: term().
+
+-callback set_log_type(Pid, NewType) ->
+ {ok, OldType} | {error, Reason} when
+ Pid :: pid(),
+ NewType :: snmp:atl_type(),
+ OldType :: snmp:atl_type(),
+ Reason :: term().
diff --git a/lib/snmp/src/manager/snmpm_server.erl b/lib/snmp/src/manager/snmpm_server.erl
index c8d7fa1e8b..a6ca2b2b14 100644
--- a/lib/snmp/src/manager/snmpm_server.erl
+++ b/lib/snmp/src/manager/snmpm_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1755,9 +1755,10 @@ handle_error(_UserId, Mod, Reason, ReqId, Data, _State) ->
Mod:handle_error(ReqId, Reason, Data)
end
catch
- T:E ->
+ C:E:S ->
CallbackArgs = [ReqId, Reason, Data],
- handle_invalid_result(handle_error, CallbackArgs, T, E)
+ handle_invalid_result(handle_error, CallbackArgs,
+ C, E, S)
end
end,
handle_callback(F),
@@ -1948,9 +1949,10 @@ handle_pdu(
Mod:handle_pdu(TargetName, ReqId, SnmpResponse, Data)
end
catch
- T:E ->
+ C:E:S ->
CallbackArgs = [TargetName, ReqId, SnmpResponse, Data],
- handle_invalid_result(handle_pdu, CallbackArgs, T, E)
+ handle_invalid_result(handle_pdu, CallbackArgs,
+ C, E, S)
end
end,
handle_callback(F),
@@ -2119,10 +2121,10 @@ do_handle_agent(DefUserId, DefMod,
"<~p,~p>: ~n~w", [Type, Domain, Addr, SnmpInfo])
end;
- T:E ->
+ C:E:S ->
CallbackArgs =
[Domain_or_Ip, Addr_or_Port, Type, SnmpInfo, DefData],
- handle_invalid_result(handle_agent, CallbackArgs, T, E)
+ handle_invalid_result(handle_agent, CallbackArgs, C, E, S)
end.
@@ -2331,8 +2333,8 @@ do_handle_trap(
handle_invalid_result(handle_trap, CallbackArgs, InvalidResult)
catch
- T:E ->
- handle_invalid_result(handle_trap, CallbackArgs, T, E)
+ C:E:S ->
+ handle_invalid_result(handle_trap, CallbackArgs, C, E, S)
end.
@@ -2523,8 +2525,8 @@ do_handle_inform(
reply
catch
- T:E ->
- handle_invalid_result(handle_inform, CallbackArgs, T, E),
+ C:E:S ->
+ handle_invalid_result(handle_inform, CallbackArgs, C, E, S),
reply
end,
@@ -2837,8 +2839,8 @@ do_handle_report(
reply
catch
- T:E ->
- handle_invalid_result(handle_report, CallbackArgs, T, E),
+ C:E:S ->
+ handle_invalid_result(handle_report, CallbackArgs, C, E, S),
reply
end.
@@ -2855,15 +2857,14 @@ handle_callback(F) ->
-handle_invalid_result(Func, Args, T, E) ->
- Stacktrace = ?STACK(),
+handle_invalid_result(Func, Args, C, E, S) ->
error_msg("Callback function failed: "
"~n Function: ~p"
"~n Args: ~p"
- "~n Error Type: ~p"
+ "~n Class: ~p"
"~n Error: ~p"
"~n Stacktrace: ~p",
- [Func, Args, T, E, Stacktrace]).
+ [Func, Args, C, E, S]).
handle_invalid_result(Func, Args, InvalidResult) ->
error_msg("Callback function returned invalid result: "
diff --git a/lib/snmp/src/manager/snmpm_supervisor.erl b/lib/snmp/src/manager/snmpm_supervisor.erl
index c36bbe1bdd..bc66025c6f 100644
--- a/lib/snmp/src/manager/snmpm_supervisor.erl
+++ b/lib/snmp/src/manager/snmpm_supervisor.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -24,7 +24,7 @@
%% External exports
--export([start_link/2, stop/0]).
+-export([start_link/2, stop/0, stop/1]).
%% supervisor callbacks
-export([init/1]).
@@ -38,26 +38,54 @@
%%%-------------------------------------------------------------------
%%% API
%%%-------------------------------------------------------------------
+
start_link(Type, Opts) ->
?d("start_link -> entry with"
"~n Opts: ~p", [Opts]),
SupName = {local, ?MODULE},
supervisor:start_link(SupName, ?MODULE, [Type, Opts]).
+
stop() ->
+ stop(0).
+
+stop(Timeout) ->
?d("stop -> entry", []),
case whereis(?SERVER) of
Pid when is_pid(Pid) ->
- ?d("stop -> Pid: ~p", [Pid]),
- exit(Pid, shutdown),
- ?d("stop -> stopped", []),
- ok;
+ stop(Pid, Timeout);
_ ->
?d("stop -> not running", []),
not_running
end.
+%% For some unfathomable reason there is no "nice" way to stop
+%% a supervisor. The "normal" way to do it is:
+%% 1) exit(Pid, kill) (kaboom)
+%% 2) If the caller is the *parent*: exit(Pid, shutdown)
+%% So, here we do it the really ugly way...but since this function is
+%% intended for testing (mostly)...
+stop(Pid, Timeout) when (Timeout =:= 0) ->
+ ?d("stop -> Pid: ~p", [Pid]),
+ sys:terminate(Pid, shutdown),
+ ?d("stop -> stopped", []),
+ ok;
+stop(Pid, Timeout) ->
+ ?d("stop -> Pid: ~p", [Pid]),
+ MRef = erlang:monitor(process, Pid),
+ sys:terminate(Pid, shutdown),
+ receive
+ {'DOWN', MRef, process, Pid, _} ->
+ ?d("stop -> stopped", []),
+ ok
+ after Timeout ->
+ ?d("stop -> timeout", []),
+ erlang:demonitor(MRef, [flush]),
+ {error, timeout}
+ end.
+
+
%%%-------------------------------------------------------------------
%%% Callback functions from supervisor
%%%-------------------------------------------------------------------
diff --git a/lib/snmp/src/misc/snmp_conf.erl b/lib/snmp/src/misc/snmp_conf.erl
index 513616a285..20b7af0373 100644
--- a/lib/snmp/src/misc/snmp_conf.erl
+++ b/lib/snmp/src/misc/snmp_conf.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -164,6 +164,14 @@ no_filter(X) -> X.
%% An ordering function (A, B) shall return true iff
%% A is less than or equal to B i.e shall return
%% false iff A is to be ordered after B.
+
+-spec keyorder(N, A, B, Keys) ->
+ boolean() when
+ N :: integer(),
+ A :: tuple(),
+ B :: tuple(),
+ Keys :: maybe_improper_list().
+
keyorder(N, A, B, _) when element(N, A) == element(N, B) ->
true;
keyorder(N, A, B, [Key | _])
@@ -236,15 +244,16 @@ read_check(File, Check, [{StartLine, Row, EndLine}|Lines], State, Res) ->
" NewRow: ~p~n", [NewRow]),
read_check(File, Check, Lines, NewState, [NewRow | Res])
catch
- {error, Reason} ->
- ?vtrace("read_check -> error:~n"
- " Reason: ~p", [Reason]),
+ throw:{error, Reason} ->
+ ?vtrace("read_check -> error:"
+ "~n Reason: ~p", [Reason]),
error({failed_check, File, StartLine, EndLine, Reason});
- Class:Reason ->
- Error = {Class,Reason,erlang:get_stacktrace()},
- ?vtrace("read_check -> failure:~n"
- " Error: ~p", [Error]),
- error({failed_check, File, StartLine, EndLine, Error})
+ C:E:S ->
+ ?vtrace("read_check -> failure:"
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ error({failed_check, File, StartLine, EndLine, {C, E, S}})
end.
open_file(File) ->
diff --git a/lib/snmp/src/misc/snmp_config.erl b/lib/snmp/src/misc/snmp_config.erl
index 45661b71a7..3104f2a096 100644
--- a/lib/snmp/src/misc/snmp_config.erl
+++ b/lib/snmp/src/misc/snmp_config.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -96,17 +96,15 @@
]).
--export_type([void/0,
- order_config_entry_function/0,
+-export_type([
+ order_config_entry_function/0,
check_config_entry_function/0,
- write_config_function/0]).
+ write_config_function/0
+ ]).
%%----------------------------------------------------------------------
--type void() :: term(). % Any value - ignored
-
-
%%----------------------------------------------------------------------
%% Handy SNMP configuration
%%----------------------------------------------------------------------
@@ -1106,6 +1104,7 @@ verify_sec_type(ST) -> {error, "invalid security type: " ++ ST}.
verify_address(A) ->
verify_address(A, snmpUDPDomain).
+-dialyzer({nowarn_function, verify_address/2}). % Future compat
verify_address(A, snmpUDPDomain = _Domain) ->
do_verify_address(A, inet);
verify_address(A, transportDomainUdpIpv4 = _Domain) ->
@@ -2573,15 +2572,17 @@ write_config_file(Dir, FileName, Order, Check, Write, Entries)
Error
end
catch
- Error ->
- S = erlang:get_stacktrace(),
- d("File write of ~s throwed: ~p~n ~p~n",
- [FileName, Error, S]),
- Error;
- C:E ->
- S = erlang:get_stacktrace(),
- d("File write of ~s exception: ~p:~p~n ~p~n",
- [FileName,C,E,S]),
+ throw:E:S ->
+ d("File write of ~s throwed: "
+ "~n ~p"
+ "~n ~p"
+ "~n", [FileName, E, S]),
+ E;
+ C:E:S ->
+ d("File write of ~s exception: "
+ "~n ~p:~p"
+ "~n ~p"
+ "~n", [FileName, C, E, S]),
{error, {failed_write, Dir, FileName, {C, E, S}}}
end.
@@ -2590,16 +2591,18 @@ write_config_file(Dir, FileName, Write, Entries, Fd) ->
ok ->
close_config_file(Dir, FileName, Fd)
catch
- Error ->
- S = erlang:get_stacktrace(),
- d("File write of ~s throwed: ~p~n ~p~n",
- [FileName, Error, S]),
+ throw:E:S ->
+ d("File write of ~s throwed: "
+ "~n ~p"
+ "~n ~p"
+ "~n", [FileName, E, S]),
close_config_file(Dir, FileName, Fd),
- Error;
- C:E ->
- S = erlang:get_stacktrace(),
- d("File write of ~s exception: ~p:~p~n ~p~n",
- [FileName,C,E,S]),
+ E;
+ C:E:S ->
+ d("File write of ~s exception: "
+ "~n ~p:~p"
+ "~n ~p"
+ "~n", [FileName, C, E, S]),
close_config_file(Dir, FileName, Fd),
{error, {failed_write, Dir, FileName, {C, E, S}}}
end.
@@ -2661,16 +2664,18 @@ append_config_file(Dir, FileName, Order, Check, Write, Entries, Fd) ->
ok ->
close_config_file(Dir, FileName, Fd)
catch
- Error ->
- S = erlang:get_stacktrace(),
- d("File append of ~s throwed: ~p~n ~p~n",
- [FileName, Error, S]),
+ throw:E:S ->
+ d("File append of ~s throwed: "
+ "~n ~p"
+ "~n ~p"
+ "~n", [FileName, E, S]),
close_config_file(Dir, FileName, Fd),
- Error;
- C:E ->
- S = erlang:get_stacktrace(),
- d("File append of ~s exception: ~p:~p~n ~p~n",
- [FileName,C,E,S]),
+ E;
+ C:E:S ->
+ d("File append of ~s exception: "
+ "~n ~p:~p"
+ "~n ~p"
+ "~n", [FileName, C, E, S]),
close_config_file(Dir, FileName, Fd),
{error, {failed_append, Dir, FileName, {C, E, S}}}
end.
@@ -2702,16 +2707,18 @@ read_config_file(Dir, FileName, Order, Check)
SortedLines = sort_lines(Lines, Order),
{ok, verify_lines(SortedLines, Check, undefined, [])}
catch
- Error ->
- S = erlang:get_stacktrace(),
- d("File read of ~s throwed: ~p~n ~p~n",
- [FileName, Error, S]),
- {error, Error};
- T:E ->
- S = erlang:get_stacktrace(),
- d("File read of ~s exception: ~p:~p~n ~p~n",
- [FileName,T,E,S]),
- {error, {failed_read, Dir, FileName, {T, E, S}}}
+ throw:E:S ->
+ d("File read of ~s throwed: "
+ "~n ~p"
+ "~n ~p"
+ "~n", [FileName, E, S]),
+ {error, E};
+ C:E:S ->
+ d("File read of ~s exception: "
+ "~n ~p:~p"
+ "~n ~p"
+ "~n", [FileName, C, E, S]),
+ {error, {failed_read, Dir, FileName, {C, E, S}}}
after
file:close(Fd)
end;
@@ -2760,11 +2767,10 @@ verify_lines(
{{ok, NewTerm}, NewState} ->
verify_lines(Lines, Check, NewState, [NewTerm|Acc])
catch
- {error, Reason} ->
+ throw:{error, Reason}:_ ->
throw({failed_check, StartLine, EndLine, Reason});
- C:R ->
- S = erlang:get_stacktrace(),
- throw({failed_check, StartLine, EndLine, {C, R, S}})
+ C:E:S ->
+ throw({failed_check, StartLine, EndLine, {C, E, S}})
end.
diff --git a/lib/snmp/src/misc/snmp_log.erl b/lib/snmp/src/misc/snmp_log.erl
index 5713c14912..8a4dfa621b 100644
--- a/lib/snmp/src/misc/snmp_log.erl
+++ b/lib/snmp/src/misc/snmp_log.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -342,9 +342,9 @@ validate_loop({Cont, Terms, BadBytes}, Log, Validator, PrevTS, PrevSN) ->
?vtrace("validate_loop -> "
"~n NextTS: ~p"
"~n NextSN: ~p", [NextTS, NextSN]),
- validate_loop(disk_log:chunk(Log, Cont), Log, Validator, NextTS, NextSN);
-validate_loop(Error, _Log, _Write, _PrevTS, _PrevSN) ->
- Error.
+ validate_loop(disk_log:chunk(Log, Cont), Log, Validator, NextTS, NextSN).
+%% validate_loop(Error, _Log, _Write, _PrevTS, _PrevSN) ->
+%% Error.
%% -- log ---
@@ -924,14 +924,7 @@ f(TimeStamp, SeqNo,
end,
format_tab(
"~w ~s - ~s [~s]~s ~w\n~s",
- [Class, AddrStr, HdrStr, TimeStamp, SeqNo, Vsn, Str]);
-f(TimeStamp, SeqNo, Msg, AddrStr, _Mib) ->
- io:format("<ERROR> Unexpected data: "
- "~n TimeStamp: ~s~s"
- "~n Msg: ~p"
- "~n AddrStr: ~p"
- "~n", [TimeStamp, SeqNo, Msg, AddrStr]),
- throw({error, 'invalid-message'}).
+ [Class, AddrStr, HdrStr, TimeStamp, SeqNo, Vsn, Str]).
f(F, A) ->
lists:flatten(io_lib:format(F, A)).
diff --git a/lib/snmp/src/misc/snmp_misc.erl b/lib/snmp/src/misc/snmp_misc.erl
index 1f847b7a29..39254503ac 100644
--- a/lib/snmp/src/misc/snmp_misc.erl
+++ b/lib/snmp/src/misc/snmp_misc.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -64,8 +64,18 @@
strip_extension_from_filename/2,
str_xor/2,
time/3,
-
- verify_behaviour/2
+
+ verify_behaviour/2,
+
+ %% These are used both for debugging (verbosity printouts)
+ %% and other such "utility" operations.
+ format_timestamp/1, format_timestamp/2,
+ format_short_timestamp/1, format_short_timestamp/2,
+ format_long_timestamp/1, format_long_timestamp/2,
+ formated_timestamp/0,
+ formated_short_timestamp/0,
+ formated_long_timestamp/0
+
]).
@@ -112,6 +122,102 @@ now(sec) ->
erlang:monotonic_time(seconds).
+
+%% ---------------------------------------------------------------------------
+%% # formated_timstamp/0, formated_timstamp/1
+%% # format_short_timstamp/0, format_short_timstamp/1
+%% # format_long_timstamp/0, format_long_timstamp/1
+%%
+%% Create a formatted timestamp. Short means that it will not include
+%% the date in the formatted timestamp. Also it will only include millis.
+%% ---------------------------------------------------------------------------
+
+formated_timestamp() ->
+ formated_long_timestamp().
+
+formated_short_timestamp() ->
+ format_short_timestamp(os:timestamp()).
+
+formated_long_timestamp() ->
+ format_long_timestamp(os:timestamp()).
+
+
+%% ---------------------------------------------------------------------------
+%% # format_timstamp/1, format_timstamp/2
+%% # format_short_timstamp/1, format_short_timstamp/2
+%% # format_long_timstamp/1, format_long_timstamp/2
+%%
+%% Formats the provided timestamp. Short means that it will not include
+%% the date in the formatted timestamp.
+%% ---------------------------------------------------------------------------
+
+-spec format_timestamp(Now :: erlang:timestamp()) ->
+ string().
+
+format_timestamp(Now) ->
+ format_long_timestamp(Now).
+
+-spec format_short_timestamp(Now :: erlang:timestamp()) ->
+ string().
+
+format_short_timestamp(Now) ->
+ N2T = fun(N) -> calendar:now_to_local_time(N) end,
+ format_timestamp(short, Now, N2T).
+
+-spec format_long_timestamp(Now :: erlang:timestamp()) ->
+ string().
+
+format_long_timestamp(Now) ->
+ N2T = fun(N) -> calendar:now_to_local_time(N) end,
+ format_timestamp(long, Now, N2T).
+
+-spec format_timestamp(Now :: erlang:timestamp(),
+ N2T :: function()) ->
+ string().
+
+format_timestamp(Now, N2T) when is_tuple(Now) andalso is_function(N2T) ->
+ format_long_timestamp(Now, N2T).
+
+-spec format_short_timestamp(Now :: erlang:timestamp(),
+ N2T :: function()) ->
+ string().
+
+format_short_timestamp(Now, N2T) when is_tuple(Now) andalso is_function(N2T) ->
+ format_timestamp(short, Now, N2T).
+
+-spec format_long_timestamp(Now :: erlang:timestamp(),
+ N2T :: function()) ->
+ string().
+
+format_long_timestamp(Now, N2T) when is_tuple(Now) andalso is_function(N2T) ->
+ format_timestamp(long, Now, N2T).
+
+format_timestamp(Format, {_N1, _N2, N3} = Now, N2T) ->
+ {Date, Time} = N2T(Now),
+ do_format_timestamp(Format, Date, Time, N3).
+
+do_format_timestamp(short, _Date, Time, N3) ->
+ do_format_short_timestamp(Time, N3);
+do_format_timestamp(long, Date, Time, N3) ->
+ do_format_long_timestamp(Date, Time, N3).
+
+do_format_long_timestamp(Date, Time, N3) ->
+ {YYYY,MM,DD} = Date,
+ {Hour,Min,Sec} = Time,
+ FormatDate =
+ io_lib:format("~.4w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w.~.3.0w",
+ [YYYY, MM, DD, Hour, Min, Sec, N3 div 1000]),
+ lists:flatten(FormatDate).
+
+do_format_short_timestamp(Time, N3) ->
+ {Hour,Min,Sec} = Time,
+ FormatDate =
+ io_lib:format("~.2.0w:~.2.0w:~.2.0w.~.3.0w",
+ [Hour, Min, Sec, N3 div 1000]),
+ lists:flatten(FormatDate).
+
+
+
is_crypto_supported(Alg) ->
%% The 'try catch' handles the case when 'crypto' is
%% not present in the system (or not started).
diff --git a/lib/snmp/src/misc/snmp_verbosity.erl b/lib/snmp/src/misc/snmp_verbosity.erl
index edfb52a474..9b2676d048 100644
--- a/lib/snmp/src/misc/snmp_verbosity.erl
+++ b/lib/snmp/src/misc/snmp_verbosity.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -70,16 +70,7 @@ print2(_Verbosity,Format,Arguments) ->
timestamp() ->
- format_timestamp(os:timestamp()).
-
-format_timestamp({_N1, _N2, N3} = Now) ->
- {Date, Time} = calendar:now_to_datetime(Now),
- {YYYY,MM,DD} = Date,
- {Hour,Min,Sec} = Time,
- FormatDate =
- io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w ~w",
- [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
- lists:flatten(FormatDate).
+ snmp_misc:formated_timestamp().
process_args([], Acc) ->
lists:reverse(Acc);
@@ -155,7 +146,8 @@ image_of_sname(mgr) -> "MGR";
image_of_sname(mgr_misc) -> "MGR_MISC";
image_of_sname(undefined) -> "";
-image_of_sname(V) -> lists:flatten(io_lib:format("~p",[V])).
+image_of_sname(N) when is_list(N) -> N; % Used in testing
+image_of_sname(N) -> lists:flatten(io_lib:format("~p", [N])).
validate(info) -> info;
diff --git a/lib/snmp/test/Makefile b/lib/snmp/test/Makefile
index a9142d911d..d9b01536ea 100644
--- a/lib/snmp/test/Makefile
+++ b/lib/snmp/test/Makefile
@@ -180,7 +180,7 @@ emakebuild: $(EMAKEFILE)
targets: mib $(EMAKEFILE)
erl -make
-old_targets: $(TARGET_FILES) $(TEST_SERVER_TARGETS)
+old_targets: mib $(TARGET_FILES) $(TEST_SERVER_TARGETS)
$(EMAKEFILE): Makefile
$(MAKE_EMAKE) $(ERL_COMPILE_FLAGS) -o$(EBIN) '*_SUITE_make' > $(EMAKEFILE)
diff --git a/lib/snmp/test/modules.mk b/lib/snmp/test/modules.mk
index 0f54e67c65..ec3870dbd8 100644
--- a/lib/snmp/test/modules.mk
+++ b/lib/snmp/test/modules.mk
@@ -31,6 +31,7 @@ SUITE_MODULES = \
snmp_agent_mibs_test \
snmp_agent_nfilter_test \
snmp_agent_test \
+ snmp_agent_test_get \
snmp_agent_conf_test \
snmp_agent_test_lib \
snmp_manager_config_test \
@@ -41,6 +42,8 @@ SUITE_MODULES = \
snmp_manager_test
TEST_UTIL_MODULES = \
+ snmp_test_global_sys_monitor \
+ snmp_test_sys_monitor \
snmp_test_lib \
snmp_test_manager \
snmp_test_mgr \
diff --git a/lib/snmp/test/snmp_agent_test.erl b/lib/snmp/test/snmp_agent_test.erl
index f9c18af6ea..a45cfa9e98 100644
--- a/lib/snmp/test/snmp_agent_test.erl
+++ b/lib/snmp/test/snmp_agent_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -557,6 +557,8 @@ init_per_suite(Config0) when is_list(Config0) ->
Config3 = [{mib_dir, MibDir}, {std_mib_dir, StdMibDir} | Config2],
+ snmp_test_global_sys_monitor:start(),
+ snmp_test_sys_monitor:start(), % We need one on this node also
snmp_test_mgr_counter_server:start(),
p("init_per_suite -> end when"
@@ -580,6 +582,8 @@ end_per_suite(Config) when is_list(Config) ->
p("end_per_suite -> failed stopping counter server"
"~n Reason: ~p", [Reason])
end,
+ snmp_test_sys_monitor:stop(),
+ snmp_test_global_sys_monitor:stop(),
p("end_per_suite -> end when"
"~n Nodes: ~p", [erlang:nodes()]),
@@ -667,22 +671,39 @@ init_per_group(GroupName, Config) ->
snmp_test_lib:init_group_top_dir(GroupName, Config).
init_per_group_ipv6(GroupName, Config, Init) ->
- {ok, Hostname0} = inet:gethostname(),
- case ct:require(ipv6_hosts) of
- ok ->
- case lists:member(list_to_atom(Hostname0), ct:get_config(ipv6_hosts)) of
- true ->
- Init(
- snmp_test_lib:init_group_top_dir(
- GroupName,
- [{ipfamily, inet6},
- {ip, ?LOCALHOST(inet6)}
- | lists:keydelete(ip, 1, Config)]));
- false ->
- {skip, "Host does not support IPV6"}
- end;
- _ ->
- {skip, "Test config ipv6_hosts is missing"}
+ %% <OS-CONDITIONAL-SKIP>
+ %% This is a higly questionable test.
+ %% But until we have time to figure out what IPv6 issues
+ %% are actually causing the failures...
+ OSSkipable = [{unix,
+ [
+ {darwin, fun(V) when (V > {9, 8, 0}) ->
+ %% This version is OK: No Skip
+ false;
+ (_) ->
+ %% This version is *not* ok: Skip
+ true
+ end}
+ ]
+ }],
+ %% </OS-CONDITIONAL-SKIP>
+ case ?OS_BASED_SKIP(OSSkipable) of
+ true ->
+ {skip, "Host *may* not *properly* support IPV6"};
+ false ->
+ %% Even if this host supports IPv6 we don't use it unless its
+ %% one of the configured/supported IPv6 hosts...
+ case (?HAS_SUPPORT_IPV6() andalso ?IS_IPV6_HOST()) of
+ true ->
+ Init(
+ snmp_test_lib:init_group_top_dir(
+ GroupName,
+ [{ipfamily, inet6},
+ {ip, ?LOCALHOST(inet6)}
+ | lists:keydelete(ip, 1, Config)]));
+ false ->
+ {skip, "Host does not support IPv6"}
+ end
end.
end_per_group(all_tcs, Config) ->
@@ -751,6 +772,8 @@ init_per_testcase(Case, Config) when is_list(Config) ->
Result = init_per_testcase1(Case, Config),
+ snmp_test_global_sys_monitor:reset_events(),
+
p("init_per_testcase -> done when"
"~n Result: ~p"
"~n Nodes: ~p", [Result, erlang:nodes()]),
@@ -800,6 +823,9 @@ end_per_testcase(Case, Config) when is_list(Config) ->
"~n Nodes: ~p", [Config, erlang:nodes()]),
display_log(Config),
+
+ p("system events during test: "
+ "~n ~p", [snmp_test_global_sys_monitor:events()]),
Result = end_per_testcase1(Case, Config),
@@ -1116,15 +1142,15 @@ init_ms(Config, Opts) when is_list(Config) ->
Opts1 = [MasterAgentVerbosity, MibsVerbosity, SymStoreVerbosity | Opts],
[{vsn, v1} | start_v1_agent(Config, Opts1)].
-init_size_check_mse(Config) when is_list(Config) ->
- MibStorage = {mib_storage, [{module, snmpa_mib_storage_ets}]},
- init_size_check_ms(Config, [MibStorage]).
+%% init_size_check_mse(Config) when is_list(Config) ->
+%% 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 = {mib_storage, [{module, snmpa_mib_storage_dets},
- {options, [{dir, AgentDbDir}]}]},
- init_size_check_ms(Config, [MibStorage]).
+%% init_size_check_msd(Config) when is_list(Config) ->
+%% AgentDbDir = ?GCONF(agent_db_dir, Config),
+%% 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) ->
?line AgentNode = ?GCONF(snmp_master, Config),
@@ -1637,7 +1663,7 @@ create_local_db_dir(Config) when is_list(Config) ->
Name = list_to_atom(atom_to_list(create_local_db_dir)
++"-"++As++"-"++Bs++"-"++Cs),
Pa = filename:dirname(code:which(?MODULE)),
- {ok,Node} = ?t:start_node(Name, slave, [{args, "-pa "++Pa}]),
+ {ok,Node} = ?t:start_node(Name, slave, [{args, "-pa " ++ Pa}]),
%% first start with a nonexisting DbDir
Fun1 = fun() ->
@@ -5146,12 +5172,21 @@ snmp_framework_mib_3(Config) when is_list(Config) ->
%% Req. SNMP-FRAMEWORK-MIB
snmp_framework_mib_test() ->
?line ["agentEngine"] = get_req(1, [[snmpEngineID,0]]),
+ T1 = snmp_misc:now(ms),
?line [EngineTime] = get_req(2, [[snmpEngineTime,0]]),
+ T2 = snmp_misc:now(ms),
?SLEEP(5000),
+ T3 = snmp_misc:now(ms),
?line [EngineTime2] = get_req(3, [[snmpEngineTime,0]]),
- ?DBG("snmp_framework_mib -> time(s): "
- "~n EngineTime 1 = ~p"
- "~n EngineTime 2 = ~p", [EngineTime, EngineTime2]),
+ T4 = snmp_misc:now(ms),
+ ?PRINT2("snmp_framework_mib -> time(s): "
+ "~n EngineTime 1: ~p"
+ "~n Time to acquire: ~w ms"
+ "~n EngineTime 2: ~p"
+ "~n Time to acquire: ~w ms"
+ "~n => (5 sec sleep between get(snmpEngineTime))"
+ "~n Total time to acquire: ~w ms",
+ [EngineTime, T2-T1, EngineTime2, T4-T3, T4-T1]),
if
(EngineTime+7) < EngineTime2 ->
?line ?FAIL({too_large_diff, EngineTime, EngineTime2});
@@ -5160,11 +5195,18 @@ snmp_framework_mib_test() ->
true ->
ok
end,
+ T5 = snmp_misc:now(ms),
?line case get_req(4, [[snmpEngineBoots,0]]) of
[Boots] when is_integer(Boots) ->
+ T6 = snmp_misc:now(ms),
+ ?PRINT2("snmp_framework_mib -> "
+ "~n boots: ~p"
+ "~n Time to acquire: ~w ms", [Boots, T6-T5]),
ok;
Else ->
- ?FAIL(Else)
+ ?PRINT2("snmp_framework_mib -> failed get proper boots:"
+ "~n ~p", [Else]),
+ ?FAIL({invalid_boots, Else})
end,
ok.
@@ -6551,7 +6593,6 @@ otp_4394_test() ->
gn([[1,1]]),
Res =
case snmp_test_mgr:expect(1, [{[sysDescr,0], "Erlang SNMP agent"}]) of
- %% {error, 1, {"?",[]}, {"~w",[timeout]}}
{error, 1, _, {_, [timeout]}} ->
?DBG("otp_4394_test -> expected result: timeout", []),
ok;
diff --git a/lib/snmp/test/snmp_agent_test_get.erl b/lib/snmp/test/snmp_agent_test_get.erl
new file mode 100644
index 0000000000..517c71507a
--- /dev/null
+++ b/lib/snmp/test/snmp_agent_test_get.erl
@@ -0,0 +1,58 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(snmp_agent_test_get).
+
+-behaviour(snmpa_get_mechanism).
+
+
+%%%-----------------------------------------------------------------
+%%% snmpa_get_mechanism exports
+%%%-----------------------------------------------------------------
+
+-export([
+ do_get/3, do_get/4,
+ do_get_next/3,
+ do_get_bulk/7
+ ]).
+
+
+
+do_get(UnsortedVarbinds, IsNotification, Extra) ->
+ snmpa_get:do_get(UnsortedVarbinds, IsNotification, Extra).
+
+
+
+do_get(MibView, UnsortedVarbinds, IsNotification, Extra) ->
+ snmpa_get:do_get(MibView, UnsortedVarbinds, IsNotification, Extra).
+
+
+
+do_get_next(MibView, UnsortedVBs, Extra) ->
+ snmpa_get:do_get_next(MibView, UnsortedVBs, Extra).
+
+
+
+
+do_get_bulk(MibView, NonRepeaters, MaxRepetitions,
+ PduMS, Varbinds, GbMaxVBs, Extra) ->
+ snmpa_get:do_get_bulk(MibView, NonRepeaters, MaxRepetitions,
+ PduMS, Varbinds, GbMaxVBs,
+ Extra).
diff --git a/lib/snmp/test/snmp_agent_test_lib.erl b/lib/snmp/test/snmp_agent_test_lib.erl
index 66211d7105..c0da47dc4c 100644
--- a/lib/snmp/test/snmp_agent_test_lib.erl
+++ b/lib/snmp/test/snmp_agent_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -66,7 +66,7 @@
]).
%% Internal exports
--export([wait/5, run/4]).
+-export([tc_wait/5, tc_run/4]).
-include_lib("kernel/include/file.hrl").
-include_lib("common_test/include/ct.hrl").
@@ -276,117 +276,256 @@ init_case(Config) when is_list(Config) ->
%%% configuration.
%%%--------------------------------------------------
-try_test(Mod, Func) ->
- call(get(mgr_node), ?MODULE, run, [Mod, Func, [], []]).
-
-try_test(Mod, Func, A) ->
- call(get(mgr_node), ?MODULE, run, [Mod, Func, A, []]).
-
-try_test(Mod, Func, A, Opts) ->
- call(get(mgr_node), ?MODULE, run, [Mod, Func, A, Opts]).
-
-call(N,M,F,A) ->
- ?DBG("call -> entry with~n"
- " N: ~p~n"
- " M: ~p~n"
- " F: ~p~n"
- " A: ~p~n"
- " when~n"
- " get(): ~p",
- [N,M,F,A,get()]),
- spawn(N, ?MODULE, wait, [self(),get(),M,F,A]),
+try_test(TcRunMod, TcRunFunc) ->
+ try_test(TcRunMod, TcRunFunc, []).
+
+try_test(TcRunMod, TcRunFunc, TcRunArgs) ->
+ try_test(TcRunMod, TcRunFunc, TcRunArgs, []).
+
+try_test(TcRunMod, TcRunFunc, TcRunArgs, TcRunOpts) ->
+ Node = get(mgr_node),
+ Mod = ?MODULE,
+ Func = tc_run,
+ Args = [TcRunMod, TcRunFunc, TcRunArgs, TcRunOpts],
+ tc_try(Node, Mod, Func, Args).
+
+%% We spawn a test case runner process on the manager node.
+%% The assumption is that the manager shall do something, but
+%% not all test cases have the manager perform actions.
+%% In some cases we make a rpc call back to the agent node directly
+%% and call something in the agent... (for example the info_test
+%% test case).
+%% We should use link (instead of monitor) in order for the test case
+%% timeout cleanup (kills) should have effect on the test case runner
+%% process as well.
+
+tc_try(N, M, F, A) ->
+ ?PRINT2("tc_try -> entry with"
+ "~n N: ~p"
+ "~n M: ~p"
+ "~n F: ~p"
+ "~n A: ~p"
+ "~n when"
+ "~n get(): ~p"
+ "~n", [N,
+ M, F, A,
+ get()]),
+ case net_adm:ping(N) of
+ pong ->
+ ?PRINT2("tc_try -> ~p still running - start runner~n", [N]),
+ OldFlag = trap_exit(true), % Make sure we catch it
+ Runner = spawn_link(N, ?MODULE, tc_wait, [self(), get(), M, F, A]),
+ await_tc_runner_started(Runner, OldFlag),
+ await_tc_runner_done(Runner, OldFlag);
+ pang ->
+ ?EPRINT2("tc_try -> ~p *not* running~n", [N]),
+ skip({node_not_running, N})
+ end.
+
+await_tc_runner_started(Runner, OldFlag) ->
+ ?PRINT2("await tc-runner (~p) start ack~n", [Runner]),
+ receive
+ {'EXIT', Runner, Reason} ->
+ ?EPRINT2("TC runner start failed: "
+ "~n ~p~n", [Reason]),
+ exit({tx_runner_start_failed, Reason});
+ {tc_runner_started, Runner} ->
+ ?PRINT2("TC runner start acknowledged~n"),
+ ok
+ after 10000 -> %% We should *really* not have to wait this long, but...
+ trap_exit(OldFlag),
+ unlink_and_flush_exit(Runner),
+ RunnerInfo = process_info(Runner),
+ ?EPRINT2("TC runner start timeout: "
+ "~n ~p", [RunnerInfo]),
+ %% If we don't get a start ack within 10 seconds, we are f*ed
+ exit(Runner, kill),
+ exit({tc_runner_start, timeout, RunnerInfo})
+ end.
+
+await_tc_runner_done(Runner, OldFlag) ->
receive
- {done, {'EXIT', Rn}, Loc} ->
- ?DBG("call -> done with exit: "
- "~n Rn: ~p"
- "~n Loc: ~p", [Rn, Loc]),
+ {'EXIT', Runner, Reason} ->
+ %% This is not a normal (tc) failure (that is the clause below).
+ %% Instead the tc runner process crashed, for some reason. So
+ %% check if have got any system events, and if so, skip.
+ SysEvs = snmp_test_global_sys_monitor:events(),
+ if
+ (SysEvs =:= []) ->
+ ?EPRINT2("TC runner failed: "
+ "~n ~p~n", [Reason]),
+ exit({tx_runner_failed, Reason});
+ true ->
+ ?EPRINT2("TC runner failed when we got system events: "
+ "~n Reason: ~p"
+ "~n Sys Events: ~p"
+ "~n", [Reason, SysEvs]),
+ skip([{reason, Reason}, {system_events, SysEvs}])
+ end;
+ {tc_runner_done, Runner, {'EXIT', {skip, Reason}}, Loc} ->
+ ?PRINT2("call -> done with skip: "
+ "~n Reason: ~p"
+ "~n Loc: ~p"
+ "~n", [Reason, Loc]),
+ trap_exit(OldFlag),
+ unlink_and_flush_exit(Runner),
+ put(test_server_loc, Loc),
+ skip(Reason);
+ {tc_runner_done, Runner, {'EXIT', Rn}, Loc} ->
+ ?PRINT2("call -> done with exit: "
+ "~n Rn: ~p"
+ "~n Loc: ~p"
+ "~n", [Rn, Loc]),
+ trap_exit(OldFlag),
+ unlink_and_flush_exit(Runner),
put(test_server_loc, Loc),
exit(Rn);
- {done, Ret, _Zed} ->
+ {tc_runner_done, Runner, Ret, _Zed} ->
?DBG("call -> done:"
"~n Ret: ~p"
"~n Zed: ~p", [Ret, _Zed]),
+ trap_exit(OldFlag),
+ unlink_and_flush_exit(Runner),
case Ret of
{error, Reason} ->
exit(Reason);
+ {skip, Reason} ->
+ skip(Reason);
OK ->
OK
end
end.
-wait(From, Env, M, F, A) ->
- ?DBG("wait -> entry with"
- "~n From: ~p"
- "~n Env: ~p"
- "~n M: ~p"
- "~n F: ~p"
- "~n A: ~p", [From, Env, M, F, A]),
+trap_exit(Flag) when is_boolean(Flag) ->
+ erlang:process_flag(trap_exit, Flag).
+
+unlink_and_flush_exit(Pid) ->
+ unlink(Pid),
+ receive
+ {'EXIT', Pid, _} ->
+ ok
+ after 0 ->
+ ok
+ end.
+
+tc_wait(From, Env, M, F, A) ->
+ ?PRINT2("tc_wait -> entry with"
+ "~n From: ~p"
+ "~n Env: ~p"
+ "~n M: ~p"
+ "~n F: ~p"
+ "~n A: ~p", [From, Env, M, F, A]),
+ From ! {tc_runner_started, self()},
lists:foreach(fun({K,V}) -> put(K,V) end, Env),
- Rn = (catch apply(M, F, A)),
- ?DBG("wait -> Rn: ~n~p", [Rn]),
- From ! {done, Rn, get(test_server_loc)},
- exit(Rn).
-
-run(Mod, Func, Args, Opts) ->
- ?DBG("run -> entry with"
- "~n Mod: ~p"
- "~n Func: ~p"
- "~n Args: ~p"
- "~n Opts: ~p", [Mod, Func, Args, Opts]),
- M = get(mib_dir),
- Dir = get(mgr_dir),
- User = snmp_misc:get_option(user, Opts, "all-rights"),
- SecLevel = snmp_misc:get_option(sec_level, Opts, noAuthNoPriv),
- EngineID = snmp_misc:get_option(engine_id, Opts, "agentEngine"),
+ ?PRINT2("tc_wait -> env set - now run tc~n"),
+ Res = (catch apply(M, F, A)),
+ ?PRINT2("tc_wait -> tc run done: "
+ "~n ~p"
+ "~n", [Res]),
+ From ! {tc_runner_done, self(), Res, get(test_server_loc)},
+ %% The point of this is that in some cases we have seen that the
+ %% exit signal having been "passed on" to the CT, which consider any
+ %% exit a fail (even if its {'EXIT', ok}).
+ %% So, just to be on the safe side, convert an 'ok' to a 'normal'.
+ case Res of
+ ok ->
+ exit(normal);
+ {ok, _} ->
+ exit(normal);
+ _ ->
+ exit(Res)
+ end.
+
+tc_run(Mod, Func, Args, Opts) ->
+ ?PRINT2("tc_run -> entry with"
+ "~n Mod: ~p"
+ "~n Func: ~p"
+ "~n Args: ~p"
+ "~n Opts: ~p"
+ "~n", [Mod, Func, Args, Opts]),
+ (catch snmp_test_mgr:stop()), % If we had a running mgr from a failed case
+ M = get(mib_dir),
+ Dir = get(mgr_dir),
+ User = snmp_misc:get_option(user, Opts, "all-rights"),
+ SecLevel = snmp_misc:get_option(sec_level, Opts, noAuthNoPriv),
+ EngineID = snmp_misc:get_option(engine_id, Opts, "agentEngine"),
CtxEngineID = snmp_misc:get_option(context_engine_id, Opts, EngineID),
- Community = snmp_misc:get_option(community, Opts, "all-rights"),
- ?DBG("run -> start crypto app",[]),
- _CryptoRes = ?CRYPTO_START(),
- ?DBG("run -> Crypto: ~p", [_CryptoRes]),
- catch snmp_test_mgr:stop(), % If we had a running mgr from a failed case
- StdM = join(code:priv_dir(snmp), "mibs") ++ "/",
- Vsn = get(vsn),
- ?DBG("run -> config:"
- "~n M: ~p"
- "~n Vsn: ~p"
- "~n Dir: ~p"
- "~n User: ~p"
- "~n SecLevel: ~p"
- "~n EngineID: ~p"
- "~n CtxEngineID: ~p"
- "~n Community: ~p"
- "~n StdM: ~p",
- [M,Vsn,Dir,User,SecLevel,EngineID,CtxEngineID,Community,StdM]),
+ Community = snmp_misc:get_option(community, Opts, "all-rights"),
+ ?DBG("tc_run -> start crypto app",[]),
+ _CryptoRes = ?CRYPTO_START(),
+ ?DBG("tc_run -> Crypto: ~p", [_CryptoRes]),
+ StdM = join(code:priv_dir(snmp), "mibs") ++ "/",
+ Vsn = get(vsn),
+ ?PRINT2("tc_run -> config:"
+ "~n M: ~p"
+ "~n Vsn: ~p"
+ "~n Dir: ~p"
+ "~n User: ~p"
+ "~n SecLevel: ~p"
+ "~n EngineID: ~p"
+ "~n CtxEngineID: ~p"
+ "~n Community: ~p"
+ "~n StdM: ~p"
+ "~n", [M,Vsn,Dir,User,SecLevel,EngineID,CtxEngineID,Community,StdM]),
case snmp_test_mgr:start([%% {agent, snmp_test_lib:hostname()},
- {packet_server_debug,true},
- {debug,true},
- {agent, get(master_host)},
- {ipfamily, get(ipfamily)},
- {agent_udp, 4000},
- {trap_udp, 5000},
- {recbuf,65535},
+ {packet_server_debug, true},
+ {debug, true},
+ {agent, get(master_host)},
+ {ipfamily, get(ipfamily)},
+ {agent_udp, 4000},
+ {trap_udp, 5000},
+ {recbuf, 65535},
quiet,
Vsn,
- {community, Community},
- {user, User},
- {sec_level, SecLevel},
- {engine_id, EngineID},
- {context_engine_id, CtxEngineID},
- {dir, Dir},
- {mibs, mibs(StdM, M)}]) of
+ {community, Community},
+ {user, User},
+ {sec_level, SecLevel},
+ {engine_id, EngineID},
+ {context_engine_id, CtxEngineID},
+ {dir, Dir},
+ {mibs, mibs(StdM, M)}]) of
{ok, _Pid} ->
case (catch apply(Mod, Func, Args)) of
+ {'EXIT', {skip, Reason}} ->
+ ?EPRINT2("apply skip detected: "
+ "~n ~p", [Reason]),
+ (catch snmp_test_mgr:stop()),
+ ?SKIP(Reason);
{'EXIT', Reason} ->
- catch snmp_test_mgr:stop(),
- ?FAIL({apply_failed, {Mod, Func, Args}, Reason});
+ %% We have hosts (mostly *very* slooow VMs) that
+ %% can timeout anything. Since we are basically
+ %% testing communication, we therefor must check
+ %% for system events at every failure. Grrr!
+ SysEvs = snmp_test_global_sys_monitor:events(),
+ (catch snmp_test_mgr:stop()),
+ if
+ (SysEvs =:= []) ->
+ ?EPRINT2("TC runner failed: "
+ "~n ~p~n", [Reason]),
+ ?FAIL({apply_failed, {Mod, Func, Args}, Reason});
+ true ->
+ ?EPRINT2("apply exit catched when we got system events: "
+ "~n Reason: ~p"
+ "~n Sys Events: ~p"
+ "~n", [Reason, SysEvs]),
+ ?SKIP([{reason, Reason}, {system_events, SysEvs}])
+ end;
Res ->
- catch snmp_test_mgr:stop(),
+ (catch snmp_test_mgr:stop()),
Res
end;
+
+ {error, Reason} ->
+ ?EPRINT2("Failed starting (test) manager: "
+ "~n ~p", [Reason]),
+ (catch snmp_test_mgr:stop()),
+ ?line ?FAIL({mgr_start_error, Reason});
+
Err ->
- io:format("Error starting manager: ~p\n", [Err]),
- catch snmp_test_mgr:stop(),
- ?line ?FAIL({mgr_start, Err})
+ ?EPRINT2("Failed starting (test) manager: "
+ "~n ~p", [Err]),
+ (catch snmp_test_mgr:stop()),
+ ?line ?FAIL({mgr_start_failure, Err})
end.
@@ -445,6 +584,7 @@ start_agent(Config, Vsns, Opts) ->
[{versions, Vsns},
{agent_type, master},
{agent_verbosity, trace},
+ {get_mechanism, snmp_agent_test_get},
{db_dir, AgentDbDir},
{audit_trail_log, [{type, read_write},
{dir, AgentLogDir},
@@ -463,20 +603,24 @@ start_agent(Config, Vsns, Opts) ->
process_flag(trap_exit,true),
+ ?PRINT2("start_agent -> try start snmp app supervisor", []),
{ok, AppSup} = snmp_app_sup:start_link(),
unlink(AppSup),
?DBG("start_agent -> snmp app supervisor: ~p", [AppSup]),
- ?DBG("start_agent -> start master agent",[]),
+ ?PRINT2("start_agent -> try start master agent",[]),
?line Sup = start_sup(Env),
-
- ?DBG("start_agent -> unlink from supervisor", []),
?line unlink(Sup),
+ ?DBG("start_agent -> snmp supervisor: ~p", [Sup]),
+
+ ?PRINT2("start_agent -> try (rpc) start sub agent on ~p", [SaNode]),
?line SaDir = ?config(sa_dir, Config),
- ?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].
+ ?DBG("start_agent -> done", []),
+
+ ?line [{snmp_app_sup, AppSup},
+ {snmp_sup, {Sup, self()}},
+ {snmp_sub, Sub} | Config].
app_agent_env_init(Env0, Opts) ->
@@ -669,35 +813,52 @@ merge_agent_options([{Key, _Value} = Opt|Opts], Options) ->
stop_agent(Config) when is_list(Config) ->
- ?LOG("stop_agent -> entry with"
- "~n Config: ~p",[Config]),
-
- {Sup, Par} = ?config(snmp_sup, Config),
- ?DBG("stop_agent -> attempt to stop (sup) ~p"
- "~n Sup: ~p"
- "~n Par: ~p",
- [Sup,
- (catch process_info(Sup)),
- (catch process_info(Par))]),
-
- _Info = agent_info(Sup),
- ?DBG("stop_agent -> Agent info: "
- "~n ~p", [_Info]),
-
- stop_sup(Sup, Par),
-
- {Sup2, Par2} = ?config(snmp_sub, Config),
- ?DBG("stop_agent -> attempt to stop (sub) ~p"
- "~n Sup2: ~p"
- "~n Par2: ~p",
- [Sup2,
- (catch process_info(Sup2)),
- (catch process_info(Par2))]),
- stop_sup(Sup2, Par2),
-
- ?DBG("stop_agent -> done - now cleanup config", []),
- C1 = lists:keydelete(snmp_sup, 1, Config),
- lists:keydelete(snmp_sub, 1, C1).
+ ?PRINT2("stop_agent -> entry with"
+ "~n Config: ~p",[Config]),
+
+
+ %% Stop the sub-agent (the agent supervisor)
+ {SubSup, SubPar} = ?config(snmp_sub, Config),
+ ?PRINT2("stop_agent -> attempt to stop sub agent (~p)"
+ "~n Sub Sup info: "
+ "~n ~p"
+ "~n Sub Par info: "
+ "~n ~p",
+ [SubSup,
+ (catch process_info(SubSup)),
+ (catch process_info(SubPar))]),
+ stop_sup(SubSup, SubPar),
+ Config2 = lists:keydelete(snmp_sub, 1, Config),
+
+
+ %% Stop the master-agent (the top agent supervisor)
+ {MasterSup, MasterPar} = ?config(snmp_sup, Config),
+ ?PRINT2("stop_agent -> attempt to stop master agent (~p)"
+ "~n Master Sup: "
+ "~n ~p"
+ "~n Master Par: "
+ "~n ~p"
+ "~n Agent Info: "
+ "~n ~p",
+ [MasterSup,
+ (catch process_info(MasterSup)),
+ (catch process_info(MasterPar)),
+ agent_info(MasterSup)]),
+ stop_sup(MasterSup, MasterPar),
+ Config3 = lists:keydelete(snmp_sup, 1, Config2),
+
+
+ %% Stop the top supervisor (of the snmp app)
+ AppSup = ?config(snmp_app_sup, Config),
+ ?PRINT2("stop_agent -> attempt to app sup ~p"
+ "~n App Sup: ~p",
+ [AppSup,
+ (catch process_info(AppSup))]),
+ Config4 = lists:keydelete(snmp_app_sup, 1, Config3),
+
+
+ ?PRINT2("stop_agent -> done", []),
+ Config4.
start_sup(Env) ->
@@ -727,7 +888,6 @@ stop_sup(Pid, _) ->
?LOG("stop_sup -> attempt to stop ~p", [Pid]),
Ref = erlang:monitor(process, Pid),
?LOG("stop_sup -> Ref: ~p", [Ref]),
- %% Pid ! {'EXIT', Parent, shutdown}, % usch
exit(Pid, kill),
await_stopped(Pid, Ref).
@@ -863,23 +1023,37 @@ expect(Mod, Line, Type, Enterp, Generic, Specific, ExpVBs) ->
expect2(Mod, Line, Fun).
expect2(Mod, Line, F) ->
- io:format("EXPECT for ~w:~w~n", [Mod, Line]),
+ io_format_expect("for ~w:~w", [Mod, Line]),
case F() of
{error, Reason} ->
- io:format("EXPECT failed at ~w:~w => ~n~p~n", [Mod, Line, Reason]),
+ io_format_expect("failed at ~w:~w => "
+ "~n ~p", [Mod, Line, Reason]),
throw({error, {expect, Mod, Line, Reason}});
Else ->
- io:format("EXPECT result for ~w:~w => ~n~p~n", [Mod, Line, Else]),
+ io_format_expect("result for ~w:~w => "
+ "~n ~p", [Mod, Line, Else]),
Else
end.
%% ----------------------------------------------------------------------
-get_timeout() ->
- get_timeout(os:type()).
+-define(BASE_REQ_TIMEOUT, 3500).
-get_timeout(_) -> 3500.
+get_timeout() ->
+ %% Try to figure out how "fast" a machine is.
+ %% We assume that the number of schedulers
+ %% (which depends on the number of core:s)
+ %% effect the performance of the host...
+ %% This is obviously not enough. The network
+ %% also matterns, clock freq or the CPU, ...
+ %% But its better than what we had before...
+ case erlang:system_info(schedulers) of
+ N when is_integer(N) ->
+ ?BASE_REQ_TIMEOUT + timer:seconds(10 div N);
+ _ ->
+ ?BASE_REQ_TIMEOUT
+ end.
receive_pdu(To) ->
receive
@@ -898,20 +1072,27 @@ receive_trap(To) ->
end.
+io_format_expect(F) ->
+ io_format_expect(F, []).
+
+io_format_expect(F, A) ->
+ ?PRINT2("EXPECT " ++ F, A).
+
+
do_expect(Expect) when is_atom(Expect) ->
do_expect({Expect, get_timeout()});
do_expect({any_pdu, To})
when is_integer(To) orelse (To =:= infinity) ->
- io:format("EXPECT any PDU~n", []),
+ io_format_expect("any PDU"),
receive_pdu(To);
do_expect({any_trap, To}) ->
- io:format("EXPECT any TRAP within ~w~n", [To]),
+ io_format_expect("any TRAP within ~w", [To]),
receive_trap(To);
do_expect({timeout, To}) ->
- io:format("EXPECT nothing within ~w~n", [To]),
+ io_format_expect("nothing within ~w", [To]),
receive
X ->
{error, {unexpected, X}}
@@ -923,16 +1104,16 @@ do_expect({timeout, To}) ->
do_expect({Err, To})
when (is_atom(Err) andalso
((is_integer(To) andalso To > 0) orelse (To =:= infinity))) ->
- io:format("EXPECT error ~w within ~w~n", [Err, To]),
+ io_format_expect("error ~w within ~w", [Err, To]),
do_expect({{error, Err}, To});
do_expect({error, Err}) when is_atom(Err) ->
Check = fun(_, R) -> R end,
- io:format("EXPECT error ~w~n", [Err]),
+ io_format_expect("error ~w", [Err]),
do_expect2(Check, any, Err, any, any, get_timeout());
do_expect({{error, Err}, To}) ->
Check = fun(_, R) -> R end,
- io:format("EXPECT error ~w within ~w~n", [Err, To]),
+ io_format_expect("error ~w within ~w", [Err, To]),
do_expect2(Check, any, Err, any, any, To);
%% exp_varbinds() -> [exp_varbind()]
@@ -942,25 +1123,23 @@ do_expect({{error, Err}, To}) ->
%% ExpVBs -> exp_varbinds() | {VbsCondition, exp_varbinds()}
do_expect(ExpVBs) ->
Check = fun(_, R) -> R end,
- io:format("EXPECT 'get-response'"
- "~n with"
- "~n Varbinds: ~p~n", [ExpVBs]),
+ io_format_expect("'get-response'"
+ "~n with"
+ "~n Varbinds: ~p", [ExpVBs]),
do_expect2(Check, 'get-response', noError, 0, ExpVBs, get_timeout()).
do_expect(v2trap, ExpVBs) ->
Check = fun(_, R) -> R end,
- io:format("EXPECT 'snmpv2-trap'"
- "~n with"
- "~n Varbinds: ~p~n", [ExpVBs]),
+ io_format_expect("'snmpv2-trap' with"
+ "~n Varbinds: ~p", [ExpVBs]),
do_expect2(Check, 'snmpv2-trap', noError, 0, ExpVBs, get_timeout());
do_expect(report, ExpVBs) ->
Check = fun(_, R) -> R end,
- io:format("EXPECT 'report'"
- "~n with"
- "~n Varbinds: ~p~n", [ExpVBs]),
+ io_format_expect("'report' with"
+ "~n Varbinds: ~p", [ExpVBs]),
do_expect2(Check, 'report', noError, 0, ExpVBs, get_timeout());
@@ -969,9 +1148,8 @@ do_expect(inform, ExpVBs) ->
do_expect({inform, false}, ExpVBs) ->
Check = fun(_, R) -> R end,
- io:format("EXPECT 'inform-request' (false)"
- "~n with"
- "~n Varbinds: ~p~n", [ExpVBs]),
+ io_format_expect("'inform-request' (false) with"
+ "~n Varbinds: ~p", [ExpVBs]),
do_expect2(Check, 'inform-request', noError, 0, ExpVBs, get_timeout());
do_expect({inform, true}, ExpVBs) ->
@@ -985,9 +1163,8 @@ do_expect({inform, true}, ExpVBs) ->
(_, Err) ->
Err
end,
- io:format("EXPECT 'inform-request' (true)"
- "~n with"
- "~n Varbinds: ~p~n", [ExpVBs]),
+ io_format_expect("'inform-request' (true) with"
+ "~n Varbinds: ~p", [ExpVBs]),
do_expect2(Check, 'inform-request', noError, 0, ExpVBs, get_timeout());
do_expect({inform, {error, EStat, EIdx}}, ExpVBs)
@@ -1002,11 +1179,10 @@ do_expect({inform, {error, EStat, EIdx}}, ExpVBs)
(_, Err) ->
Err
end,
- io:format("EXPECT 'inform-request' (error)"
- "~n with"
- "~n Error Status: ~p"
- "~n Error Index: ~p"
- "~n Varbinds: ~p~n", [EStat, EIdx, ExpVBs]),
+ io_format_expect("'inform-request' (error) with"
+ "~n Error Status: ~p"
+ "~n Error Index: ~p"
+ "~n Varbinds: ~p", [EStat, EIdx, ExpVBs]),
do_expect2(Check, 'inform-request', noError, 0, ExpVBs, get_timeout()).
@@ -1017,26 +1193,23 @@ do_expect(Err, Idx, ExpVBs, To)
when is_atom(Err) andalso
(is_integer(Idx) orelse is_list(Idx) orelse (Idx == any)) ->
Check = fun(_, R) -> R end,
- io:format("EXPECT 'get-response'"
- "~n with"
- "~n Error: ~p"
- "~n Index: ~p"
- "~n Varbinds: ~p"
- "~n within ~w~n", [Err, Idx, ExpVBs, To]),
+ io_format_expect("'get-response' withing ~w ms with"
+ "~n Error: ~p"
+ "~n Index: ~p"
+ "~n Varbinds: ~p", [To, Err, Idx, ExpVBs]),
do_expect2(Check, 'get-response', Err, Idx, ExpVBs, To).
do_expect(Type, Enterp, Generic, Specific, ExpVBs) ->
- do_expect(Type, Enterp, Generic, Specific, ExpVBs, 3500).
+ do_expect(Type, Enterp, Generic, Specific, ExpVBs, get_timeout()).
do_expect(trap, Enterp, Generic, Specific, ExpVBs, To) ->
- io:format("EXPECT trap"
- "~n with"
- "~n Enterp: ~w"
- "~n Generic: ~w"
- "~n Specific: ~w"
- "~n Varbinds: ~w"
- "~n within ~w~n", [Enterp, Generic, Specific, ExpVBs, To]),
+ io_format_expect("trap within ~w ms with"
+ "~n Enterp: ~w"
+ "~n Generic: ~w"
+ "~n Specific: ~w"
+ "~n Varbinds: ~w",
+ [To, Enterp, Generic, Specific, ExpVBs]),
PureE = purify_oid(Enterp),
case receive_trap(To) of
#trappdu{enterprise = PureE,
@@ -1053,6 +1226,18 @@ do_expect(trap, Enterp, Generic, Specific, ExpVBs, To) ->
{PureE, Generic, Specific, ExpVBs},
{Ent2, G2, Spec2, VBs}}};
+ {error, timeout} = Error ->
+ SysEvs = snmp_test_global_sys_monitor:events(),
+ io_format_expect("[expecting trap] got timeout when system events:"
+ "~n ~p", [SysEvs]),
+ if
+ (SysEvs =:= []) ->
+ Error;
+ true ->
+ skip({system_events, SysEvs})
+ end;
+
+
Error ->
Error
end.
@@ -1071,46 +1256,46 @@ do_expect2(Check, Type, Err, Idx, ExpVBs, To)
#pdu{type = Type,
error_status = Err,
error_index = Idx} when ExpVBs =:= any ->
- io:format("EXPECT received expected pdu (1)~n", []),
+ io_format_expect("received expected pdu (1)"),
ok;
#pdu{type = Type,
request_id = ReqId,
error_status = Err2,
error_index = Idx} when ExpVBs =:= any ->
- io:format("EXPECT received expected pdu with "
- "unexpected error status (2): "
- "~n Error Status: ~p~n", [Err2]),
+ io_format_expect("received expected pdu with "
+ "unexpected error status (2): "
+ "~n Error Status: ~p", [Err2]),
{error, {unexpected_error_status, Err, Err2, ReqId}};
#pdu{error_status = Err} when (Type =:= any) andalso
(Idx =:= any) andalso
(ExpVBs =:= any) ->
- io:format("EXPECT received expected pdu (3)~n", []),
+ io_format_expect("received expected pdu (3)"),
ok;
#pdu{request_id = ReqId,
error_status = Err2} when (Type =:= any) andalso
(Idx =:= any) andalso
(ExpVBs =:= any) ->
- io:format("EXPECT received expected pdu with "
- "unexpected error status (4): "
- "~n Error Status: ~p~n", [Err2]),
+ io_format_expect("received expected pdu with "
+ "unexpected error status (4): "
+ "~n Error Status: ~p", [Err2]),
{error, {unexpected_error_status, Err, Err2, ReqId}};
#pdu{type = Type,
error_status = Err} when (Idx =:= any) andalso
(ExpVBs =:= any) ->
- io:format("EXPECT received expected pdu (5)~n", []),
+ io_format_expect("received expected pdu (5)", []),
ok;
#pdu{type = Type,
request_id = ReqId,
error_status = Err2} when (Idx =:= any) andalso
(ExpVBs =:= any) ->
- io:format("EXPECT received expected pdu with "
- "unexpected error status (6): "
- "~n Error Status: ~p~n", [Err2]),
+ io_format_expect("received expected pdu with "
+ "unexpected error status (6): "
+ "~n Error Status: ~p", [Err2]),
{error, {unexpected_error_status, Err, Err2, ReqId}};
#pdu{type = Type,
@@ -1119,13 +1304,13 @@ do_expect2(Check, Type, Err, Idx, ExpVBs, To)
error_index = EI} when is_list(Idx) andalso (ExpVBs =:= any) ->
case lists:member(EI, Idx) of
true ->
- io:format("EXPECT received expected pdu with "
- "expected error index (7)~n", []),
+ io_format_expect("received expected pdu with "
+ "expected error index (7)"),
ok;
false ->
- io:format("EXPECT received expected pdu with "
- "unexpected error index (8): "
- "~n Error Index: ~p~n", [EI]),
+ io_format_expect("received expected pdu with "
+ "unexpected error index (8): "
+ "~n Error Index: ~p", [EI]),
{error, {unexpected_error_index, EI, Idx, ReqId}}
end;
@@ -1135,15 +1320,15 @@ do_expect2(Check, Type, Err, Idx, ExpVBs, To)
error_index = EI} when is_list(Idx) andalso (ExpVBs =:= any) ->
case lists:member(EI, Idx) of
true ->
- io:format("EXPECT received expected pdu with "
- "unexpected error status (9): "
- "~n Error Status: ~p~n", [Err2]),
+ io_format_expect("received expected pdu with "
+ "unexpected error status (9): "
+ "~n Error Status: ~p", [Err2]),
{error, {unexpected_error_status, Err, Err2, ReqId}};
false ->
- io:format("EXPECT received expected pdu with "
- "unexpected error (10): "
- "~n Error Status: ~p"
- "~n Error index: ~p~n", [Err2, EI]),
+ io_format_expect("received expected pdu with "
+ "unexpected error (10): "
+ "~n Error Status: ~p"
+ "~n Error index: ~p", [Err2, EI]),
{error, {unexpected_error, {Err, Idx}, {Err2, EI}, ReqId}}
end;
@@ -1151,12 +1336,12 @@ do_expect2(Check, Type, Err, Idx, ExpVBs, To)
request_id = ReqId,
error_status = Err2,
error_index = Idx2} when ExpVBs =:= any ->
- io:format("EXPECT received unexpected pdu with (11) "
- "~n Type: ~p"
- "~n ReqId: ~p"
- "~n Errot status: ~p"
- "~n Error index: ~p"
- "~n", [Type2, ReqId, Err2, Idx2]),
+ io_format_expect("received unexpected pdu with (11) "
+ "~n Type: ~p"
+ "~n ReqId: ~p"
+ "~n Error status: ~p"
+ "~n Error index: ~p",
+ [Type2, ReqId, Err2, Idx2]),
{error,
{unexpected_pdu,
{Type, Err, Idx}, {Type2, Err2, Idx2}, ReqId}};
@@ -1165,26 +1350,26 @@ do_expect2(Check, Type, Err, Idx, ExpVBs, To)
error_status = Err,
error_index = Idx,
varbinds = VBs} = PDU ->
- io:format("EXPECT received pdu (12): "
- "~n [exp] Type: ~p"
- "~n [exp] Error Status: ~p"
- "~n [exp] Error Index: ~p"
- "~n VBs: ~p"
- "~nwhen"
- "~n ExpVBs: ~p"
- "~n", [Type, Err, Idx, VBs, ExpVBs]),
+ io_format_expect("received pdu (12): "
+ "~n [exp] Type: ~p"
+ "~n [exp] Error Status: ~p"
+ "~n [exp] Error Index: ~p"
+ "~n VBs: ~p"
+ "~nwhen"
+ "~n ExpVBs: ~p",
+ [Type, Err, Idx, VBs, ExpVBs]),
Check(PDU, check_vbs(purify_oids(ExpVBs), VBs));
#pdu{type = Type,
error_status = Err,
varbinds = VBs} = PDU when Idx =:= any ->
- io:format("EXPECT received pdu (13): "
- "~n [exp] Type: ~p"
- "~n [exp] Error Status: ~p"
- "~n VBs: ~p"
- "~nwhen"
- "~n ExpVBs: ~p"
- "~n", [Type, Err, VBs, ExpVBs]),
+ io_format_expect("received pdu (13): "
+ "~n [exp] Type: ~p"
+ "~n [exp] Error Status: ~p"
+ "~n VBs: ~p"
+ "~nwhen"
+ "~n ExpVBs: ~p",
+ [Type, Err, VBs, ExpVBs]),
Check(PDU, check_vbs(purify_oids(ExpVBs), VBs));
#pdu{type = Type,
@@ -1192,15 +1377,15 @@ do_expect2(Check, Type, Err, Idx, ExpVBs, To)
error_status = Err,
error_index = EI,
varbinds = VBs} = PDU when is_list(Idx) ->
- io:format("EXPECT received pdu (14): "
- "~n [exp] Type: ~p"
- "~n ReqId: ~p"
- "~n [exp] Error Status: ~p"
- "~n [exp] Error Index: ~p"
- "~n VBs: ~p"
- "~nwhen"
- "~n ExpVBs: ~p"
- "~n", [Type, ReqId, Err, EI, VBs, ExpVBs]),
+ io_format_expect("received pdu (14): "
+ "~n [exp] Type: ~p"
+ "~n ReqId: ~p"
+ "~n [exp] Error Status: ~p"
+ "~n [exp] Error Index: ~p"
+ "~n VBs: ~p"
+ "~nwhen"
+ "~n ExpVBs: ~p",
+ [Type, ReqId, Err, EI, VBs, ExpVBs]),
PureVBs = purify_oids(ExpVBs),
case lists:member(EI, Idx) of
true ->
@@ -1214,24 +1399,36 @@ do_expect2(Check, Type, Err, Idx, ExpVBs, To)
error_status = Err2,
error_index = Idx2,
varbinds = VBs2} ->
- io:format("EXPECT received unexpected pdu with (15) "
- "~n Type: ~p"
- "~n ReqId: ~p"
- "~n Errot status: ~p"
- "~n Error index: ~p"
- "~n Varbinds: ~p"
- "~n", [Type2, ReqId, Err2, Idx2, VBs2]),
+ io_format_expect("received unexpected pdu with (15) "
+ "~n Type: ~p"
+ "~n ReqId: ~p"
+ "~n Error status: ~p"
+ "~n Error index: ~p"
+ "~n Varbinds: ~p",
+ [Type2, ReqId, Err2, Idx2, VBs2]),
{error,
{unexpected_pdu,
{Type, Err, Idx, purify_oids(ExpVBs)},
{Type2, Err2, Idx2, VBs2},
ReqId}};
- Error ->
- io:format("EXPECT received error (16): "
- "~n Error: ~p"
- "~n", [Error]),
- Error
+
+ {error, timeout} = Error ->
+ SysEvs = snmp_test_global_sys_monitor:events(),
+ io_format_expect("got timeout (16) when system events:"
+ "~n ~p", [SysEvs]),
+ if
+ (SysEvs =:= []) ->
+ Error;
+ true ->
+ skip({system_events, SysEvs})
+ end;
+
+
+ Error ->
+ io_format_expect("received error (17): "
+ "~n Error: ~p", [Error]),
+ Error
end.
@@ -1349,12 +1546,15 @@ start_node(Name) ->
""
end,
%% Do not use start_link!!! (the proc that calls this one is tmp)
- ?DBG("start_node -> Args: ~p~n",[Args]),
- A = Args ++ " -pa " ++ Pa,
+ ?DBG("start_node -> Args: ~p~n", [Args]),
+ A = Args ++ " -pa " ++ Pa ++
+ " -s " ++ atom_to_list(snmp_test_sys_monitor) ++ " start" ++
+ " -s global sync",
case (catch ?START_NODE(Name, A)) of
{ok, Node} ->
%% Tell the test_server to not clean up things it never started.
?DBG("start_node -> Node: ~p",[Node]),
+ global:sync(),
{ok, Node};
Else ->
?ERR("start_node -> failed with(other): Else: ~p",[Else]),
@@ -1672,6 +1872,10 @@ rpc(Node, F, A) ->
join(Dir, File) ->
filename:join(Dir, File).
+
+skip(R) ->
+ exit({skip, R}).
+
%% await_pdu(To) ->
%% await_response(To, pdu).
%%
diff --git a/lib/snmp/test/snmp_compiler_test.erl b/lib/snmp/test/snmp_compiler_test.erl
index 0a7b729d1f..a28f925a22 100644
--- a/lib/snmp/test/snmp_compiler_test.erl
+++ b/lib/snmp/test/snmp_compiler_test.erl
@@ -226,22 +226,20 @@ agent_capabilities(Config) when is_list(Config) ->
put(tname,agent_capabilities),
p("starting with Config: ~p~n", [Config]),
- SnmpPrivDir = code:priv_dir(snmp),
+ SnmpPrivDir = which_priv_dir(snmp),
SnmpMibsDir = join(SnmpPrivDir, "mibs"),
- OtpMibsPrivDir = code:priv_dir(otp_mibs),
- OtpMibsMibsDir = join(OtpMibsPrivDir, "mibs"),
Dir = ?config(mib_dir, Config),
AcMib = join(Dir,"AC-TEST-MIB.mib"),
?line {ok, MibFile1} = snmpc:compile(AcMib, [options,
version,
- {i, [SnmpMibsDir, OtpMibsMibsDir]},
+ {i, [SnmpMibsDir]},
{outdir, Dir},
{verbosity, trace}]),
?line {ok, Mib1} = snmp_misc:read_mib(MibFile1),
?line {ok, MibFile2} = snmpc:compile(AcMib, [options,
version,
agent_capabilities,
- {i, [SnmpMibsDir, OtpMibsMibsDir]},
+ {i, [SnmpMibsDir]},
{outdir, Dir},
{verbosity, trace}]),
?line {ok, Mib2} = snmp_misc:read_mib(MibFile2),
@@ -269,28 +267,26 @@ module_compliance(Config) when is_list(Config) ->
put(tname,module_compliance),
p("starting with Config: ~p~n", [Config]),
- SnmpPrivDir = code:priv_dir(snmp),
- SnmpMibsDir = join(SnmpPrivDir, "mibs"),
- OtpMibsPrivDir = code:priv_dir(otp_mibs),
- OtpMibsMibsDir = join(OtpMibsPrivDir, "mibs"),
- Dir = ?config(mib_dir, Config),
- AcMib = join(Dir,"MC-TEST-MIB.mib"),
+ SnmpPrivDir = which_priv_dir(snmp),
+ SnmpMibsDir = join(SnmpPrivDir, "mibs"),
+ Dir = ?config(mib_dir, Config),
+ AcMib = join(Dir,"MC-TEST-MIB.mib"),
?line {ok, MibFile1} = snmpc:compile(AcMib, [options,
version,
- {i, [SnmpMibsDir, OtpMibsMibsDir]},
+ {i, [SnmpMibsDir]},
{outdir, Dir},
{verbosity, trace}]),
?line {ok, Mib1} = snmp_misc:read_mib(MibFile1),
?line {ok, MibFile2} = snmpc:compile(AcMib, [options,
version,
module_compliance,
- {i, [SnmpMibsDir, OtpMibsMibsDir]},
+ {i, [SnmpMibsDir]},
{outdir, Dir},
{verbosity, trace}]),
?line {ok, Mib2} = snmp_misc:read_mib(MibFile2),
MEDiff = Mib2#mib.mes -- Mib1#mib.mes,
%% This is a rather pathetic test, but it is somthing...
- io:format("agent_capabilities -> "
+ io:format("module_compliance -> "
"~n MEDiff: ~p"
"~n Mib1: ~p"
"~n Mib2: ~p"
@@ -731,6 +727,15 @@ check_desc(Desc1, Desc2) ->
exit({'description not equal', Desc1, Desc2}).
+which_priv_dir(App) ->
+ case code:priv_dir(App) of
+ Dir when is_list(Dir) ->
+ Dir;
+ {error, Reason} ->
+ exit({App, priv_dir_not_found, Reason})
+ end.
+
+
%% join(Comp) ->
%% filename:join(Comp).
diff --git a/lib/snmp/test/snmp_manager_config_test.erl b/lib/snmp/test/snmp_manager_config_test.erl
index 64d3134055..ccbdd77629 100644
--- a/lib/snmp/test/snmp_manager_config_test.erl
+++ b/lib/snmp/test/snmp_manager_config_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -35,6 +35,7 @@
-include_lib("common_test/include/ct.hrl").
-include("snmp_test_lib.hrl").
-include_lib("snmp/src/manager/snmpm_usm.hrl").
+-include_lib("snmp/src/app/snmp_internal.hrl").
%%----------------------------------------------------------------------
@@ -2259,11 +2260,13 @@ create_and_increment(Conf) when is_list(Conf) ->
?line {ok, _Pid} = snmpm_config:start_link(Opts),
%% Random init
- random:seed(erlang:phash2([node()]),
- erlang:monotonic_time(),
- erlang:unique_integer()),
+ ?SNMP_RAND_SEED(),
+ %% rand:seed(exrop,
+ %% {erlang:phash2([node()]),
+ %% erlang:monotonic_time(),
+ %% erlang:unique_integer()}),
- StartVal = random:uniform(2147483647),
+ StartVal = rand:uniform(2147483647),
IncVal = 42,
EndVal = StartVal + IncVal,
diff --git a/lib/snmp/test/snmp_manager_test.erl b/lib/snmp/test/snmp_manager_test.erl
index 6ced55f0cc..c31bb92e1f 100644
--- a/lib/snmp/test/snmp_manager_test.erl
+++ b/lib/snmp/test/snmp_manager_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -62,7 +62,7 @@
register_user1/1,
- register_agent1/1,
+ register_agent_old/1,
register_agent2/1,
register_agent3/1,
@@ -185,7 +185,6 @@ end_per_suite(Config) when is_list(Config) ->
init_per_testcase(Case, Config) when is_list(Config) ->
- io:format(user, "~n~n*** INIT ~w:~w ***~n~n", [?MODULE, Case]),
p(Case, "init_per_testcase begin when"
"~n Nodes: ~p~n~n", [erlang:nodes()]),
%% This version of the API, based on Addr and Port, has been deprecated
@@ -204,10 +203,17 @@ init_per_testcase(Case, Config) when is_list(Config) ->
Result =
case lists:member(Case, DeprecatedApiCases) of
true ->
- %% ?SKIP(api_no_longer_supported);
- {skip, api_no_longer_supported};
+ {skip, "API no longer supported"};
false ->
- init_per_testcase2(Case, Config)
+ try init_per_testcase2(Case, Config)
+ catch
+ C:{skip, _} = E:_ when ((C =:= throw) orelse
+ (C =:= exit)) ->
+ E;
+ C:E:_ when ((C =:= throw) orelse
+ (C =:= exit)) ->
+ {skip, {catched, C, E}}
+ end
end,
p(Case, "init_per_testcase end when"
"~n Nodes: ~p"
@@ -326,9 +332,25 @@ init_per_testcase3(Case, Config) ->
true ->
Config
end,
+ %% We don't need to try catch this (init_agent)
+ %% since we have a try catch "higher up"...
Conf2 = init_agent(Conf1),
- Conf3 = init_manager(AutoInform, Conf2),
- Conf4 = init_mgr_user(Conf3),
+ Conf3 = try init_manager(AutoInform, Conf2)
+ catch AC:AE:_ ->
+ %% Ouch we need to clean up:
+ %% The init_agent starts an agent node!
+ init_per_testcase_fail_agent_cleanup(Conf2),
+ throw({skip, {manager_init_failed, AC, AE}})
+ end,
+ Conf4 = try init_mgr_user(Conf3)
+ catch MC:ME:_ ->
+ %% Ouch we need to clean up:
+ %% The init_agent starts an agent node!
+ %% The init_magager starts an manager node!
+ init_per_testcase_fail_manager_cleanup(Conf3),
+ init_per_testcase_fail_agent_cleanup(Conf3),
+ throw({skip, {manager_user_init_failed, MC, ME}})
+ end,
case lists:member(Case, ApiCases02 ++ ApiCases03) of
true ->
init_mgr_user_data2(Conf4);
@@ -339,6 +361,12 @@ init_per_testcase3(Case, Config) ->
Config
end.
+init_per_testcase_fail_manager_cleanup(Conf) ->
+ (catch fin_manager(Conf)).
+
+init_per_testcase_fail_agent_cleanup(Conf) ->
+ (catch fin_agent(Conf)).
+
end_per_testcase(Case, Config) when is_list(Config) ->
p(Case, "end_per_testcase begin when"
"~n Nodes: ~p~n~n", [erlang:nodes()]),
@@ -452,7 +480,7 @@ groups() ->
},
{agent_tests, [],
[
- register_agent1,
+ register_agent_old,
register_agent2,
register_agent3
]
@@ -568,7 +596,7 @@ groups() ->
ipv6_tests() ->
[
- register_agent1,
+ register_agent_old,
simple_sync_get_next3,
simple_async_get2,
simple_sync_get3,
@@ -592,38 +620,47 @@ init_per_group(event_tests_mt = GroupName, Config) ->
GroupName,
[{manager_net_if_module, snmpm_net_if_mt} | Config]);
init_per_group(ipv6_mt = GroupName, Config) ->
- {ok, Hostname0} = inet:gethostname(),
- case ct:require(ipv6_hosts) of
- ok ->
- case lists:member(list_to_atom(Hostname0), ct:get_config(ipv6_hosts)) of
- true ->
- ipv6_init(
- snmp_test_lib:init_group_top_dir(
- GroupName,
- [{manager_net_if_module, snmpm_net_if_mt}
- | Config]));
- false ->
- {skip, "Host does not support IPv6"}
- end;
- _ ->
- {skip, "Test config ipv6_hosts is missing"}
- end;
+ init_per_group_ipv6(GroupName,
+ [{manager_net_if_module, snmpm_net_if_mt} | Config]);
init_per_group(ipv6 = GroupName, Config) ->
- {ok, Hostname0} = inet:gethostname(),
- case ct:require(ipv6_hosts) of
- ok ->
- case lists:member(list_to_atom(Hostname0), ct:get_config(ipv6_hosts)) of
- true ->
- ipv6_init(snmp_test_lib:init_group_top_dir(GroupName, Config));
- false ->
- {skip, "Host does not support IPv6"}
- end;
- _ ->
- {skip, "Test config ipv6_hosts is missing"}
- end;
+ init_per_group_ipv6(GroupName, Config);
init_per_group(GroupName, Config) ->
snmp_test_lib:init_group_top_dir(GroupName, Config).
+
+init_per_group_ipv6(GroupName, Config) ->
+ %% <OS-CONDITIONAL-SKIP>
+ OSSkipable = [{unix,
+ [
+ {darwin, fun(V) when (V > {9, 8, 0}) ->
+ %% This version is OK: No Skip
+ false;
+ (_) ->
+ %% This version is *not* ok: Skip
+ %% We need a fully qualified hostname
+ %% to get a proper IPv6 address (in this
+ %% version), but its just to messy, so
+ %% instead we skip this **OLD** darwin...
+ true
+ end}
+ ]
+ }],
+ %% </OS-CONDITIONAL-SKIP>
+ case ?OS_BASED_SKIP(OSSkipable) of
+ true ->
+ {skip, "Host *may* not *properly* support IPV6"};
+ false ->
+ %% Even if this host supports IPv6 we don't use it unless its
+ %% one of the configures/supported IPv6 hosts...
+ case (?HAS_SUPPORT_IPV6() andalso ?IS_IPV6_HOST()) of
+ true ->
+ ipv6_init(snmp_test_lib:init_group_top_dir(GroupName, Config));
+ false ->
+ {skip, "Host does not support IPv6"}
+ end
+ end.
+
+
end_per_group(_GroupName, Config) ->
%% Do we really need to do this?
lists:keydelete(snmp_group_top_dir, 1, Config).
@@ -635,11 +672,11 @@ end_per_group(_GroupName, Config) ->
simple_start_and_stop1(suite) -> [];
simple_start_and_stop1(Config) when is_list(Config) ->
- %% ?SKIP(not_yet_implemented),
- process_flag(trap_exit, true),
- put(tname,ssas1),
- p("starting with Config: ~n~p", [Config]),
+ ?TC_TRY(simple_start_and_stop1,
+ fun() -> do_simple_start_and_stop1(Config) end).
+do_simple_start_and_stop1(Config) ->
+ p("starting with Config: ~n~p", [Config]),
ConfDir = ?config(manager_conf_dir, Config),
DbDir = ?config(manager_db_dir, Config),
@@ -660,7 +697,6 @@ simple_start_and_stop1(Config) when is_list(Config) ->
?SLEEP(1000),
- p("end"),
ok.
@@ -668,9 +704,10 @@ simple_start_and_stop1(Config) when is_list(Config) ->
simple_start_and_stop2(suite) -> [];
simple_start_and_stop2(Config) when is_list(Config) ->
- %% ?SKIP(not_yet_implemented),
- process_flag(trap_exit, true),
- put(tname,ssas2),
+ ?TC_TRY(simple_start_and_stop2,
+ fun() -> do_simple_start_and_stop2(Config) end).
+
+do_simple_start_and_stop2(Config) ->
p("starting with Config: ~p~n", [Config]),
ManagerNode = start_manager_node(),
@@ -708,7 +745,6 @@ simple_start_and_stop2(Config) when is_list(Config) ->
?SLEEP(1000),
- p("end"),
ok.
@@ -716,8 +752,10 @@ simple_start_and_stop2(Config) when is_list(Config) ->
simple_start_and_monitor_crash1(suite) -> [];
simple_start_and_monitor_crash1(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- put(tname,ssamc1),
+ ?TC_TRY(simple_start_and_monitor_crash1,
+ fun() -> do_simple_start_and_monitor_crash1(Config) end).
+
+do_simple_start_and_monitor_crash1(Config) ->
p("starting with Config: ~n~p", [Config]),
ConfDir = ?config(manager_conf_dir, Config),
@@ -761,7 +799,6 @@ simple_start_and_monitor_crash1(Config) when is_list(Config) ->
?FAIL(timeout)
end,
- p("end"),
ok.
@@ -769,8 +806,10 @@ simple_start_and_monitor_crash1(Config) when is_list(Config) ->
simple_start_and_monitor_crash2(suite) -> [];
simple_start_and_monitor_crash2(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- put(tname,ssamc2),
+ ?TC_TRY(simple_start_and_monitor_crash2,
+ fun() -> do_simple_start_and_monitor_crash2(Config) end).
+
+do_simple_start_and_monitor_crash2(Config) ->
p("starting with Config: ~n~p", [Config]),
ConfDir = ?config(manager_conf_dir, Config),
@@ -815,7 +854,6 @@ simple_start_and_monitor_crash2(Config) when is_list(Config) ->
?FAIL(timeout)
end,
- p("end"),
ok.
@@ -861,8 +899,10 @@ simulate_crash(NumKills, _) ->
notify_started01(suite) -> [];
notify_started01(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- put(tname,ns01),
+ ?TC_TRY(notify_started01,
+ fun() -> do_notify_started01(Config) end).
+
+do_notify_started01(Config) ->
p("starting with Config: ~n~p", [Config]),
ConfDir = ?config(manager_conf_dir, Config),
@@ -949,37 +989,34 @@ snmpm_starter(Opts, To) ->
notify_started02(suite) -> [];
notify_started02(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- put(tname,ns02),
+ ?TC_TRY(notify_started02,
+ fun() -> notify_started02_cond(Config) end,
+ fun() -> do_notify_started02(Config) end).
- %% <CONDITIONAL-SKIP>
- %% The point of this is to catch machines running
- %% SLES9 (2.6.5)
+notify_started02_cond(Config) ->
LinuxVersionVerify =
fun() ->
case os:cmd("uname -m") of
"i686" ++ _ ->
-%% io:format("found an i686 machine, "
-%% "now check version~n", []),
case os:version() of
{2, 6, Rev} when Rev >= 16 ->
- true;
+ false;
{2, Min, _} when Min > 6 ->
- true;
+ false;
{Maj, _, _} when Maj > 2 ->
- true;
+ false;
_ ->
- false
+ true
end;
_ ->
- true
+ false
end
end,
Skippable = [{unix, [{linux, LinuxVersionVerify}]}],
Condition = fun() -> ?OS_BASED_SKIP(Skippable) end,
- ?NON_PC_TC_MAYBE_SKIP(Config, Condition),
- %% </CONDITIONAL-SKIP>
-
+ ?NON_PC_TC_MAYBE_SKIP(Config, Condition).
+
+do_notify_started02(Config) ->
p("starting with Config: ~n~p", [Config]),
ConfDir = ?config(manager_conf_dir, Config),
@@ -987,24 +1024,52 @@ notify_started02(Config) when is_list(Config) ->
write_manager_conf(ConfDir),
- Opts = [{server, [{verbosity, log}]},
- {net_if, [{verbosity, silence}]},
+ Opts = [{server, [{verbosity, log}]},
+ {net_if, [{verbosity, silence}]},
{note_store, [{verbosity, silence}]},
- {config, [{verbosity, log}, {dir, ConfDir}, {db_dir, DbDir}]}],
+ {config, [{verbosity, debug}, {dir, ConfDir}, {db_dir, DbDir}]}],
p("start snmpm client process"),
- Pid1 = ns02_loop1_start(),
+ NumIterations = 5,
+ Pid1 = ns02_client_start(NumIterations),
+
+ p("start snmpm ctrl (starter) process"),
+ Pid2 = ns02_ctrl_start(Opts, NumIterations),
+
+ %% On a reasonably fast machine, one iteration takes approx 4 seconds.
+ %% We measure the first iteration, and then we wait for the remaining
+ %% ones (4 in this case).
+ ApproxStartTime =
+ case ns02_client_await_approx_runtime(Pid1) of
+ {ok, T} ->
+ T;
+ {error, Reason} ->
+ %% Attempt cleanup just in case
+ exit(Pid1, kill),
+ exit(Pid2, kill),
+ ?FAIL(Reason);
+ {skip, Reason} ->
+ %% Attempt cleanup just in case
+ exit(Pid1, kill),
+ exit(Pid2, kill),
+ ?SKIP(Reason)
+ end,
- p("start snmpm starter process"),
- Pid2 = ns02_loop2_start(Opts),
-
- p("await snmpm client process exit"),
+ p("await snmpm client process exit (max ~p+10000 msec)", [ApproxStartTime]),
receive
+ %% We take this opportunity to check if we got a skip from
+ %% the ctrl process.
+ {'EXIT', Pid2, {skip, SkipReason1}} ->
+ ?SKIP(SkipReason1);
{'EXIT', Pid1, normal} ->
ok;
+ {'EXIT', Pid1, {suite_failed, Reason1}} ->
+ ?FAIL({client, Reason1});
{'EXIT', Pid1, Reason1} ->
- ?FAIL(Reason1)
- after 25000 ->
+ ?FAIL({client, Reason1})
+ after ApproxStartTime + 10000 ->
+ exit(Pid1, kill),
+ exit(Pid2, kill),
?FAIL(timeout)
end,
@@ -1012,9 +1077,13 @@ notify_started02(Config) when is_list(Config) ->
receive
{'EXIT', Pid2, normal} ->
ok;
+ {'EXIT', Pid2, {skip, SkipReason2}} ->
+ %% In case of a race
+ ?SKIP(SkipReason2);
{'EXIT', Pid2, Reason2} ->
- ?FAIL(Reason2)
+ ?FAIL({ctrl, Reason2})
after 5000 ->
+ exit(Pid2, kill),
?FAIL(timeout)
end,
@@ -1022,26 +1091,63 @@ notify_started02(Config) when is_list(Config) ->
ok.
-ns02_loop1_start() ->
- spawn_link(fun() -> ns02_loop1() end).
+ns02_client_start(N) ->
+ Self = self(),
+ spawn_link(fun() -> ns02_client(Self, N) end).
+
+ns02_client_await_approx_runtime(Pid) ->
+ receive
+ {?MODULE, client_time, Time} ->
+ {ok, Time};
+ {'EXIT', Pid, Reason} ->
+ p("client (~p) failed: "
+ "~n ~p", [Pid, Reason]),
+ {error, Reason}
+
+ after 30000 ->
+ %% Either something is *really* wrong or this machine
+ %% is dog slow. Either way, this is a skip-reason...
+ {skip, approx_runtime_timeout}
+ end.
+
-ns02_loop1() ->
- put(tname,ns02_loop1),
+ns02_client(Parent, N) when is_pid(Parent) ->
+ put(tname, ns02_client),
p("starting"),
- ns02_loop1(dummy, snmpm:notify_started(?NS_TIMEOUT), 5).
+ ns02_client_loop(Parent,
+ dummy, snmpm:notify_started(?NS_TIMEOUT),
+ snmp_misc:now(ms), undefined,
+ N).
-ns02_loop1(_Ref, _Pid, 0) ->
- p("done"),
+ns02_client_loop(_Parent, _Ref, _Pid, _Begin, _End, 0) ->
+ %% p("loop -> done"),
exit(normal);
-ns02_loop1(Ref, Pid, N) ->
- p("entry when"
- "~n Ref: ~p"
- "~n Pid: ~p"
- "~n N: ~p", [Ref, Pid, N]),
+ns02_client_loop(Parent, Ref, Pid, Begin, End, N)
+ when is_pid(Parent) andalso is_integer(Begin) andalso is_integer(End) ->
+ %% p("loop -> [~w] inform parent: ~w, ~w => ~w", [N, Begin, End, End-Begin]),
+ Parent ! {?MODULE, client_time, N*(End-Begin)},
+ ns02_client_loop(undefined, Ref, Pid, snmp_misc:now(ms), undefined, N);
+ns02_client_loop(Parent, Ref, Pid, Begin, End, N)
+ when is_integer(Begin) andalso is_integer(End) ->
+ %% p("loop -> [~w] entry when"
+ %% "~n Ref: ~p"
+ %% "~n Pid: ~p"
+ %% "~n Begin: ~p"
+ %% "~n End: ~p", [N, Ref, Pid, Begin, End]),
+ ns02_client_loop(Parent, Ref, Pid, snmp_misc:now(ms), undefined, N);
+ns02_client_loop(Parent, Ref, Pid, Begin, End, N) ->
+ %% p("loop(await message) -> [~w] entry when"
+ %% "~n Ref: ~p"
+ %% "~n Pid: ~p"
+ %% "~n Begin: ~p"
+ %% "~n End: ~p", [N, Ref, Pid, Begin, End]),
receive
{snmpm_started, Pid} ->
p("received expected started message (~w)", [N]),
- ns02_loop1(snmpm:monitor(), dummy, N);
+ ns02_client_loop(Parent,
+ snmpm:monitor(), dummy,
+ Begin, End,
+ N);
{snmpm_start_timeout, Pid} ->
p("unexpected timout"),
?FAIL({unexpected_start_timeout, Pid});
@@ -1049,40 +1155,72 @@ ns02_loop1(Ref, Pid, N) ->
p("received expected DOWN message (~w) with"
"~n Obj: ~p"
"~n Reason: ~p", [N, Obj, Reason]),
- ns02_loop1(dummy, snmpm:notify_started(?NS_TIMEOUT), N-1)
- after 10000 ->
- ?FAIL(timeout)
+ ns02_client_loop(Parent,
+ dummy, snmpm:notify_started(?NS_TIMEOUT),
+ Begin, snmp_misc:now(ms),
+ N-1)
end.
-
-ns02_loop2_start(Opts) ->
- spawn_link(fun() -> ns02_loop2(Opts) end).
+ns02_ctrl_start(Opts, N) ->
+ spawn_link(fun() -> ns02_ctrl(Opts, N) end).
-ns02_loop2(Opts) ->
- put(tname,ns02_loop2),
+ns02_ctrl(Opts, N) ->
+ put(tname, ns02_ctrl),
p("starting"),
- ns02_loop2(Opts, 5).
+ ns02_ctrl_loop(Opts, N).
+
-ns02_loop2(_Opts, 0) ->
+%% We have seen that some times it takes unreasonably long time to
+%% start the manager (it got "stuck" in snmpm_config). But since
+%% we did not have enough verbosity, we do not know how far it got.
+%% So, we try to monitor each start attempt. We allow 5 sec (just
+%% to give slow boxes a chance).
+ns02_ctrl_loop(_Opts, 0) ->
p("done"),
exit(normal);
-ns02_loop2(Opts, N) ->
+ns02_ctrl_loop(Opts, N) ->
p("entry when N: ~p", [N]),
?SLEEP(2000),
p("start manager"),
- snmpm:start(Opts),
+ TS1 = erlang:system_time(millisecond),
+ {StarterPid, StarterMRef} =
+ erlang:spawn_monitor(fun() -> exit(snmpm:start(Opts)) end),
+ receive
+ {'DOWN', StarterMRef, process, StarterPid, ok} ->
+ TS2 = erlang:system_time(millisecond),
+ p("manager started: ~w ms", [TS2-TS1]),
+ ok
+ after 5000 ->
+ p("manager (~p) start timeout - kill", [StarterPid]),
+ exit(StarterPid, kill),
+ exit({skip, start_timeout})
+ end,
?SLEEP(2000),
p("stop manager"),
- snmpm:stop(),
- ns02_loop2(Opts, N-1).
+ ?SLEEP(100), % Give the verbosity to take effect...
+ TS3 = erlang:system_time(millisecond),
+ case snmpm:stop(5000) of
+ ok ->
+ TS4 = erlang:system_time(millisecond),
+ p("manager stopped: ~p ms", [TS4-TS3]),
+ ok;
+ {error, timeout} ->
+ p("manager stop timeout - kill (cleanup) and skip"),
+ exit(whereis(snmpm_supervisor), kill),
+ exit({skip, stop_timeout})
+ end,
+ ns02_ctrl_loop(Opts, N-1).
+
%%======================================================================
info(suite) -> [];
info(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- put(tname,info),
+ ?TC_TRY(info,
+ fun() -> do_info(Config) end).
+
+do_info(Config) ->
p("starting with Config: ~n~p", [Config]),
ConfDir = ?config(manager_conf_dir, Config),
@@ -1110,7 +1248,6 @@ info(Config) when is_list(Config) ->
?SLEEP(1000),
- p("end"),
ok.
verify_info(Info) when is_list(Info) ->
@@ -1150,9 +1287,10 @@ verify_info([{Key, SubKeys}|Keys], Info) ->
register_user1(suite) -> [];
register_user1(Config) when is_list(Config) ->
- %% ?SKIP(not_yet_implemented).
- process_flag(trap_exit, true),
- put(tname,ru1),
+ ?TC_TRY(register_user1,
+ fun() -> do_register_user1(Config) end).
+
+do_register_user1(Config) ->
p("starting with Config: ~p~n", [Config]),
ManagerNode = start_manager_node(),
@@ -1226,7 +1364,6 @@ register_user1(Config) when is_list(Config) ->
?SLEEP(1000),
- p("end"),
ok.
verify_users([], []) ->
@@ -1244,14 +1381,15 @@ verify_users(ActualUsers0, [User|RegUsers]) ->
%%======================================================================
-register_agent1(doc) ->
+register_agent_old(doc) ->
["Test registration of agents with the OLD interface functions"];
-register_agent1(suite) ->
+register_agent_old(suite) ->
[];
-register_agent1(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- put(tname,ra1),
-
+register_agent_old(Config) when is_list(Config) ->
+ ?TC_TRY(register_agent_old,
+ fun() -> do_register_agent_old(Config) end).
+
+do_register_agent_old(Config) ->
p("starting with Config: ~p~n", [Config]),
ManagerNode = start_manager_node(),
@@ -1366,7 +1504,6 @@ register_agent1(Config) when is_list(Config) ->
?SLEEP(1000),
- p("end"),
ok.
@@ -1377,8 +1514,10 @@ register_agent2(doc) ->
register_agent2(suite) ->
[];
register_agent2(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- put(tname, ra2),
+ ?TC_TRY(register_agent2,
+ fun() -> do_register_agent2(Config) end).
+
+do_register_agent2(Config) ->
p("starting with Config: ~p~n", [Config]),
ManagerNode = start_manager_node(),
@@ -1511,7 +1650,6 @@ register_agent2(Config) when is_list(Config) ->
?SLEEP(1000),
- p("end"),
ok.
@@ -1523,8 +1661,10 @@ register_agent3(doc) ->
register_agent3(suite) ->
[];
register_agent3(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- put(tname, ra3),
+ ?TC_TRY(register_agent3,
+ fun() -> do_register_agent3(Config) end).
+
+do_register_agent3(Config) ->
p("starting with Config: ~p~n", [Config]),
ManagerNode = start_manager_node(),
@@ -1661,7 +1801,6 @@ register_agent3(Config) when is_list(Config) ->
?SLEEP(1000),
- p("end"),
ok.
@@ -1670,10 +1809,11 @@ register_agent3(Config) when is_list(Config) ->
simple_sync_get1(doc) -> ["Simple sync get-request - Old style (Addr & Port)"];
simple_sync_get1(suite) -> [];
simple_sync_get1(Config) when is_list(Config) ->
- ?SKIP(api_no_longer_supported),
+ ?TC_TRY(simple_sync_get1,
+ fun() -> {skip, "API no longer supported"} end,
+ fun() -> do_simple_sync_get1(Config) end).
- process_flag(trap_exit, true),
- put(tname, ssg1),
+do_simple_sync_get1(Config) ->
p("starting with Config: ~p~n", [Config]),
Node = ?config(manager_node, Config),
@@ -1732,18 +1872,18 @@ simple_sync_get2(doc) ->
["Simple sync get-request - Version 2 API (TargetName)"];
simple_sync_get2(suite) -> [];
simple_sync_get2(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- put(tname, ssg2),
- do_simple_sync_get2(Config),
- display_log(Config),
- ok.
+ ?TC_TRY(simple_sync_get2,
+ fun() -> do_simple_sync_get2(Config) end).
do_simple_sync_get2(Config) ->
+ p("starting with Config: ~n~p", [Config]),
Get = fun(Node, TargetName, Oids) ->
mgr_user_sync_get(Node, TargetName, Oids)
end,
PostVerify = fun() -> ok end,
- do_simple_sync_get2(Config, Get, PostVerify).
+ do_simple_sync_get2(Config, Get, PostVerify),
+ display_log(Config),
+ ok.
do_simple_sync_get2(Config, Get, PostVerify) ->
p("starting with Config: ~p~n", [Config]),
@@ -1799,13 +1939,11 @@ simple_sync_get3(doc) ->
["Simple sync get-request - Version 3 API (TargetName and send-opts)"];
simple_sync_get3(suite) -> [];
simple_sync_get3(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- put(tname, ssg3),
- do_simple_sync_get3(Config),
- display_log(Config),
- ok.
+ ?TC_TRY(simple_sync_get3,
+ fun() -> do_simple_sync_get3(Config) end).
do_simple_sync_get3(Config) ->
+ p("starting with Config: ~n~p", [Config]),
Self = self(),
Msg = simple_sync_get3,
Fun = fun() -> Self ! Msg end,
@@ -1824,7 +1962,9 @@ do_simple_sync_get3(Config) ->
ok
end
end,
- do_simple_sync_get2(Config, Get, PostVerify).
+ do_simple_sync_get2(Config, Get, PostVerify),
+ display_log(Config),
+ ok.
%%======================================================================
@@ -1833,10 +1973,11 @@ simple_async_get1(doc) ->
["Simple (async) get-request - Old style (Addr & Port)"];
simple_async_get1(suite) -> [];
simple_async_get1(Config) when is_list(Config) ->
- ?SKIP(api_no_longer_supported),
+ ?TC_TRY(simple_async_get1,
+ fun() -> {skip, "API no longer supported"} end,
+ fun() -> do_simple_async_get1(Config) end).
- process_flag(trap_exit, true),
- put(tname, sag1),
+do_simple_async_get1(Config) ->
p("starting with Config: ~p~n", [Config]),
MgrNode = ?config(manager_node, Config),
@@ -1937,8 +2078,10 @@ simple_async_get2(doc) ->
["Simple (async) get-request - Version 2 API (TargetName)"];
simple_async_get2(suite) -> [];
simple_async_get2(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- put(tname, sag2),
+ ?TC_TRY(simple_async_get2,
+ fun() -> do_simple_async_get2(Config) end).
+
+do_simple_async_get2(Config) ->
p("starting with Config: ~p~n", [Config]),
MgrNode = ?config(manager_node, Config),
AgentNode = ?config(agent_node, Config),
@@ -2018,8 +2161,10 @@ simple_async_get3(doc) ->
["Simple (async) get-request - Version 3 API (TargetName and send-opts)"];
simple_async_get3(suite) -> [];
simple_async_get3(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- put(tname, sag3),
+ ?TC_TRY(simple_async_get3,
+ fun() -> do_simple_async_get3(Config) end).
+
+do_simple_async_get3(Config) ->
p("starting with Config: ~p~n", [Config]),
MgrNode = ?config(manager_node, Config),
AgentNode = ?config(agent_node, Config),
@@ -2050,10 +2195,11 @@ simple_sync_get_next1(doc) -> ["Simple (sync) get_next-request - "
"Old style (Addr & Port)"];
simple_sync_get_next1(suite) -> [];
simple_sync_get_next1(Config) when is_list(Config) ->
- ?SKIP(api_no_longer_supported),
+ ?TC_TRY(simple_sync_get_next1,
+ fun() -> {skip, "API no longer supported"} end,
+ fun() -> do_simple_sync_get_next1(Config) end).
- process_flag(trap_exit, true),
- put(tname, ssgn1),
+do_simple_sync_get_next1(Config) ->
p("starting with Config: ~p~n", [Config]),
MgrNode = ?config(manager_node, Config),
@@ -2191,8 +2337,10 @@ simple_sync_get_next2(doc) ->
["Simple (sync) get_next-request - Version 2 API (TargetName)"];
simple_sync_get_next2(suite) -> [];
simple_sync_get_next2(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- put(tname, ssgn2),
+ ?TC_TRY(simple_sync_get_next2,
+ fun() -> do_simple_sync_get_next2(Config) end).
+
+do_simple_sync_get_next2(Config) ->
p("starting with Config: ~p~n", [Config]),
GetNext = fun(Node, TargetName, Oids) ->
@@ -2344,10 +2492,11 @@ simple_async_get_next1(doc) -> ["Simple (async) get_next-request - "
"Old style (Addr & Port)"];
simple_async_get_next1(suite) -> [];
simple_async_get_next1(Config) when is_list(Config) ->
- ?SKIP(api_no_longer_supported),
+ ?TC_TRY(simple_async_get_next1,
+ fun() -> {skip, "API no longer supported"} end,
+ fun() -> do_simple_async_get_next1(Config) end).
- process_flag(trap_exit, true),
- put(tname, ssgn1),
+do_simple_async_get_next1(Config) ->
p("starting with Config: ~p~n", [Config]),
MgrNode = ?config(manager_node, Config),
@@ -2444,8 +2593,10 @@ simple_async_get_next2(doc) ->
["Simple (async) get_next-request - Version 2 API (TargetName)"];
simple_async_get_next2(suite) -> [];
simple_async_get_next2(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- put(tname, ssgn2),
+ ?TC_TRY(simple_async_get_next2,
+ fun() -> do_simple_async_get_next2(Config) end).
+
+do_simple_async_get_next2(Config) ->
p("starting with Config: ~p~n", [Config]),
MgrNode = ?config(manager_node, Config),
@@ -2555,8 +2706,10 @@ simple_async_get_next3(doc) ->
"Version 3 API (TargetName with send-opts)"];
simple_async_get_next3(suite) -> [];
simple_async_get_next3(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- put(tname, ssgn2),
+ ?TC_TRY(simple_async_get_next3,
+ fun() -> do_simple_async_get_next3(Config) end).
+
+do_simple_async_get_next3(Config) ->
p("starting with Config: ~p~n", [Config]),
MgrNode = ?config(manager_node, Config),
@@ -2598,10 +2751,11 @@ simple_sync_set1(doc) -> ["Simple (sync) set-request - "
"Old style (Addr & Port)"];
simple_sync_set1(suite) -> [];
simple_sync_set1(Config) when is_list(Config) ->
- ?SKIP(api_no_longer_supported),
+ ?TC_TRY(simple_sync_set1,
+ fun() -> {skip, "API no longer supported"} end,
+ fun() -> do_simple_sync_set1(Config) end).
- process_flag(trap_exit, true),
- put(tname, sss1),
+do_simple_sync_set1(Config) ->
p("starting with Config: ~p~n", [Config]),
Node = ?config(manager_node, Config),
@@ -2671,8 +2825,10 @@ simple_sync_set2(doc) ->
["Simple (sync) set-request - Version 2 API (TargetName)"];
simple_sync_set2(suite) -> [];
simple_sync_set2(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- put(tname, sss2),
+ ?TC_TRY(simple_sync_set2,
+ fun() -> do_simple_sync_set2(Config) end).
+
+do_simple_sync_set2(Config) ->
p("starting with Config: ~p~n", [Config]),
Set = fun(Node, TargetName, VAVs) ->
@@ -2741,8 +2897,10 @@ simple_sync_set3(doc) ->
["Simple (sync) set-request - Version 3 API (TargetName with send-opts)"];
simple_sync_set3(suite) -> [];
simple_sync_set3(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- put(tname, sss3),
+ ?TC_TRY(simple_sync_set3,
+ fun() -> do_simple_sync_set3(Config) end).
+
+do_simple_sync_set3(Config) ->
p("starting with Config: ~p~n", [Config]),
Self = self(),
@@ -2770,10 +2928,11 @@ simple_async_set1(doc) -> ["Simple (async) set-request - "
"Old style (Addr & Port)"];
simple_async_set1(suite) -> [];
simple_async_set1(Config) when is_list(Config) ->
- ?SKIP(api_no_longer_supported),
+ ?TC_TRY(simple_async_set1,
+ fun() -> {skip, "API no longer supported"} end,
+ fun() -> do_simple_async_set1(Config) end).
- process_flag(trap_exit, true),
- put(tname, sas1),
+do_simple_async_set1(Config) ->
p("starting with Config: ~p~n", [Config]),
MgrNode = ?config(manager_node, Config),
@@ -2865,8 +3024,10 @@ simple_async_set2(doc) ->
["Simple (async) set-request - Version 2 API (TargetName)"];
simple_async_set2(suite) -> [];
simple_async_set2(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- put(tname, sas2),
+ ?TC_TRY(simple_async_set2,
+ fun() -> do_simple_async_set2(Config) end).
+
+do_simple_async_set2(Config) ->
p("starting with Config: ~p~n", [Config]),
MgrNode = ?config(manager_node, Config),
@@ -2938,8 +3099,10 @@ simple_async_set3(doc) ->
["Simple (async) set-request - Version 3 API (TargetName with send-opts)"];
simple_async_set3(suite) -> [];
simple_async_set3(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- put(tname, sas3),
+ ?TC_TRY(simple_async_set3,
+ fun() -> do_simple_async_set3(Config) end).
+
+do_simple_async_set3(Config) ->
p("starting with Config: ~p~n", [Config]),
MgrNode = ?config(manager_node, Config),
@@ -2982,10 +3145,11 @@ simple_sync_get_bulk1(doc) -> ["Simple (sync) get_bulk-request - "
"Old style (Addr & Port)"];
simple_sync_get_bulk1(suite) -> [];
simple_sync_get_bulk1(Config) when is_list(Config) ->
- ?SKIP(api_no_longer_supported),
+ ?TC_TRY(simple_sync_get_bulk1,
+ fun() -> {skip, "API no longer supported"} end,
+ fun() -> do_simple_sync_get_bulk1(Config) end).
- process_flag(trap_exit, true),
- put(tname, ssgb1),
+do_simple_sync_get_bulk1(Config) ->
p("starting with Config: ~p~n", [Config]),
MgrNode = ?config(manager_node, Config),
@@ -3156,8 +3320,10 @@ simple_sync_get_bulk2(doc) ->
["Simple (sync) get_bulk-request - Version 2 API (TargetName)"];
simple_sync_get_bulk2(suite) -> [];
simple_sync_get_bulk2(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- put(tname, ssgb2),
+ ?TC_TRY(simple_sync_get_bulk2,
+ fun() -> do_simple_sync_get_bulk2(Config) end).
+
+do_simple_sync_get_bulk2(Config) ->
p("starting with Config: ~p~n", [Config]),
MgrNode = ?config(manager_node, Config),
@@ -3312,8 +3478,10 @@ simple_sync_get_bulk3(doc) ->
"Version 3 API (TargetName with send-opts)"];
simple_sync_get_bulk3(suite) -> [];
simple_sync_get_bulk3(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- put(tname, ssgb3),
+ ?TC_TRY(simple_sync_get_bulk3,
+ fun() -> do_simple_sync_get_bulk3(Config) end).
+
+do_simple_sync_get_bulk3(Config) ->
p("starting with Config: ~p~n", [Config]),
MgrNode = ?config(manager_node, Config),
@@ -3349,10 +3517,11 @@ simple_async_get_bulk1(doc) -> ["Simple (async) get_bulk-request - "
"Old style (Addr & Port)"];
simple_async_get_bulk1(suite) -> [];
simple_async_get_bulk1(Config) when is_list(Config) ->
- ?SKIP(api_no_longer_supported),
+ ?TC_TRY(simple_async_get_bulk1,
+ fun() -> {skip, "API no longer supported"} end,
+ fun() -> do_simple_async_get_bulk1(Config) end).
- process_flag(trap_exit, true),
- put(tname, sagb1),
+do_simple_async_get_bulk1(Config) ->
p("starting with Config: ~p~n", [Config]),
MgrNode = ?config(manager_node, Config),
@@ -3495,8 +3664,10 @@ simple_async_get_bulk2(doc) ->
["Simple (async) get_bulk-request - Version 2 API (TargetName)"];
simple_async_get_bulk2(suite) -> [];
simple_async_get_bulk2(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- put(tname, sagb2),
+ ?TC_TRY(simple_async_get_bulk2,
+ fun() -> do_simple_async_get_bulk2(Config) end).
+
+do_simple_async_get_bulk2(Config) ->
p("starting with Config: ~p~n", [Config]),
MgrNode = ?config(manager_node, Config),
@@ -3651,8 +3822,10 @@ simple_async_get_bulk3(doc) ->
"Version 3 API (TargetName with send-opts)"];
simple_async_get_bulk3(suite) -> [];
simple_async_get_bulk3(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- put(tname, sagb3),
+ ?TC_TRY(simple_async_get_bulk3,
+ fun() -> do_simple_async_get_bulk3(Config) end).
+
+do_simple_async_get_bulk3(Config) ->
p("starting with Config: ~p~n", [Config]),
MgrNode = ?config(manager_node, Config),
@@ -3695,10 +3868,11 @@ misc_async1(doc) -> ["Misc (async) request(s) - "
"Old style (Addr & Port)"];
misc_async1(suite) -> [];
misc_async1(Config) when is_list(Config) ->
- ?SKIP(api_no_longer_supported),
+ ?TC_TRY(misc_async1,
+ fun() -> {skip, "API no longer supported"} end,
+ fun() -> do_misc_async1(Config) end).
- process_flag(trap_exit, true),
- put(tname, ms1),
+do_misc_async1(Config) ->
p("starting with Config: ~p~n", [Config]),
MgrNode = ?config(manager_node, Config),
@@ -3887,8 +4061,10 @@ misc_async2(doc) ->
["Misc (async) request(s) - Version 2 API (TargetName)"];
misc_async2(suite) -> [];
misc_async2(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- put(tname, ms2),
+ ?TC_TRY(misc_async2,
+ fun() -> do_misc_async2(Config) end).
+
+do_misc_async2(Config) ->
p("starting with Config: ~p~n", [Config]),
MgrNode = ?config(manager_node, Config),
@@ -4137,8 +4313,10 @@ verify_trap(Trap, [{Id, Verifier}|Verifiers]) ->
trap1(suite) -> [];
trap1(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- put(tname,t1),
+ ?TC_TRY(trap1,
+ fun() -> do_trap1(Config) end).
+
+do_trap1(Config) ->
p("starting with Config: ~p~n", [Config]),
MgrNode = ?config(manager_node, Config),
@@ -4290,8 +4468,10 @@ trap1(Config) when is_list(Config) ->
trap2(suite) -> [];
trap2(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- put(tname,t2),
+ ?TC_TRY(trap2,
+ fun() -> do_trap2(Config) end).
+
+do_trap2(Config) ->
p("starting with Config: ~p~n", [Config]),
MgrNode = ?config(manager_node, Config),
@@ -4483,8 +4663,10 @@ trap2(Config) when is_list(Config) ->
inform1(suite) -> [];
inform1(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- put(tname,i1),
+ ?TC_TRY(inform1,
+ fun() -> do_inform1(Config) end).
+
+do_inform1(Config) ->
p("starting with Config: ~p~n", [Config]),
MgrNode = ?config(manager_node, Config),
@@ -4610,8 +4792,10 @@ inform1(Config) when is_list(Config) ->
inform2(suite) -> [];
inform2(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- put(tname, i2),
+ ?TC_TRY(inform2,
+ fun() -> do_inform2(Config) end).
+
+do_inform2(Config) ->
p("starting with Config: ~p~n", [Config]),
MgrNode = ?config(manager_node, Config),
@@ -4745,7 +4929,7 @@ inform2(Config) when is_list(Config) ->
"~n ~p", [Addr]),
ok;
{snmp_notification, inform2_tag1, {no_response, Addr}} ->
- p("<ERROR> received expected \"no response\" "
+ e("Received unexpected \"no response\" "
"notification from: "
"~n ~p", [Addr]),
{error, no_response}
@@ -4782,8 +4966,10 @@ inform2(Config) when is_list(Config) ->
inform3(suite) -> [];
inform3(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- put(tname,i3),
+ ?TC_TRY(inform3,
+ fun() -> do_inform3(Config) end).
+
+do_inform3(Config) ->
p("starting with Config: ~p~n", [Config]),
MgrNode = ?config(manager_node, Config),
@@ -4879,7 +5065,7 @@ inform3(Config) when is_list(Config) ->
"~n ~p", [Addr]),
ok;
{snmp_notification, inform3_tag1, {got_response, Addr}} ->
- p("<ERROR> received unexpected \"got response\" "
+ e("Received unexpected \"got response\" "
"notification from: "
"~n ~p",
[Addr]),
@@ -4918,8 +5104,10 @@ inform3(Config) when is_list(Config) ->
inform4(suite) -> [];
inform4(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- put(tname,i4),
+ ?TC_TRY(inform4,
+ fun() -> do_inform4(Config) end).
+
+do_inform4(Config) ->
p("starting with Config: ~p~n", [Config]),
MgrNode = ?config(manager_node, Config),
@@ -5038,8 +5226,10 @@ inform4(Config) when is_list(Config) ->
inform_swarm(suite) -> [];
inform_swarm(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- put(tname, is),
+ ?TC_TRY(inform_swarm,
+ fun() -> do_inform_swarm(Config) end).
+
+do_inform_swarm(Config) ->
p("starting with Config: ~p~n", [Config]),
MgrNode = ?config(manager_node, Config),
@@ -5166,7 +5356,7 @@ inform_swarm_collector(N, SentAckCnt, RecvCnt, RespCnt, Timeout) ->
inform_swarm_collector(N, SentAckCnt, RecvCnt+1, RespCnt,
Timeout);
{Err, Idx, VBs} ->
- p("<ERROR> unexpected error status: "
+ e("Unexpected error status: "
"~n Err: ~p"
"~n Idx: ~p"
"~n VBs: ~p", [Err, Idx, VBs]),
@@ -5185,7 +5375,7 @@ inform_swarm_collector(N, SentAckCnt, RecvCnt, RespCnt, Timeout) ->
%% The agent did not received ack from the manager in time
{snmp_notification, inform2_tag1, {no_response, Addr}} ->
- p("<ERROR> received expected \"no response\" notification "
+ e("Received expected \"no response\" notification "
"from: "
"~n ~p", [Addr]),
Reason = {no_response, Addr, {N, SentAckCnt, RecvCnt, RespCnt}},
@@ -5210,8 +5400,10 @@ report(Config) when is_list(Config) ->
otp8015_1(doc) -> ["OTP-8015:1 - testing the new api-function."];
otp8015_1(suite) -> [];
otp8015_1(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- put(tname, otp8015_1),
+ ?TC_TRY(otp8015_1,
+ fun() -> do_otp8015_1(Config) end).
+
+do_otp8015_1(Config) ->
p("starting with Config: ~p~n", [Config]),
ConfDir = ?config(manager_conf_dir, Config),
@@ -5258,8 +5450,10 @@ otp8015_1(Config) when is_list(Config) ->
otp8395_1(doc) -> ["OTP-8395:1 - simple get with ATL sequence numbering."];
otp8395_1(suite) -> [];
otp8395_1(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- put(tname, otp8395_1),
+ ?TC_TRY(otp8395_1,
+ fun() -> do_otp8395_1(Config) end).
+
+do_otp8395_1(Config) ->
do_simple_sync_get2(Config).
@@ -5362,10 +5556,10 @@ command_handler([{No, Desc, Cmd}|Cmds]) ->
p("command_handler -> ~w: ok",[No]),
command_handler(Cmds);
{error, Reason} ->
- p("<ERROR> command_handler -> ~w error: ~n~p",[No, Reason]),
+ e("Command_handler -> ~w error: ~n~p",[No, Reason]),
?line ?FAIL({command_failed, No, Reason});
Error ->
- p("<ERROR> command_handler -> ~w unexpected: ~n~p",[No, Error]),
+ e("Command_handler -> ~w unexpected: ~n~p",[No, Error]),
?line ?FAIL({unexpected_command_result, No, Error})
end.
@@ -5416,15 +5610,14 @@ init_manager(AutoInform, Config) ->
start_manager(Node, Vsns, Conf)
end
catch
- T:E ->
- StackTrace = ?STACK(),
+ C:E:S ->
p("Failure during manager start: "
- "~n Error Type: ~p"
- "~n Error: ~p"
- "~n StackTrace: ~p", [T, E, StackTrace]),
+ "~n Error Class: ~p"
+ "~n Error: ~p"
+ "~n StackTrace: ~p", [C, E, S]),
%% And now, *try* to cleanup
(catch stop_node(Node)),
- ?FAIL({failed_starting_manager, T, E, StackTrace})
+ ?FAIL({failed_starting_manager, C, E, S})
end.
fin_manager(Config) ->
@@ -5432,7 +5625,7 @@ fin_manager(Config) ->
StopMgrRes = stop_manager(Node),
StopCryptoRes = fin_crypto(Node),
StopNode = stop_node(Node),
- p("fin_agent -> stop apps and (mgr node ~p) node results: "
+ p("fin_manager -> stop apps and (mgr node ~p) node results: "
"~n SNMP Mgr: ~p"
"~n Crypto: ~p"
"~n Node: ~p",
@@ -5498,15 +5691,14 @@ init_agent(Config) ->
start_agent(Node, Vsns, Conf)
end
catch
- T:E ->
- StackTrace = ?STACK(),
+ C:E:S ->
p("Failure during agent start: "
- "~n Error Type: ~p"
- "~n Error: ~p"
- "~n StackTrace: ~p", [T, E, StackTrace]),
+ "~n Error Class: ~p"
+ "~n Error: ~p"
+ "~n StackTrace: ~p", [C, E, S]),
%% And now, *try* to cleanup
(catch stop_node(Node)),
- ?FAIL({failed_starting_agent, T, E, StackTrace})
+ ?FAIL({failed_starting_agent, C, E, S})
end.
@@ -6179,7 +6371,12 @@ start_agent(Node, Vsns, Conf0, _Opts) ->
{mib_server, [{verbosity, MSV}]},
{note_store, [{verbosity, NSV}]},
{stymbolic_store, [{verbosity, SSV}]},
- {net_if, [{verbosity, NIV}]},
+ {net_if, [{verbosity, NIV},
+ %% On some linux "they" add a 127.0.1.1 or somthing
+ %% similar, so if we don't specify bind_to
+ %% we don't know which address will be selected
+ %% (which will cause problems for some test cases).
+ {options, [{bind_to, true}]}]},
{multi_threaded, true}],
?line ok = set_agent_env(Node, Env),
@@ -6228,6 +6425,8 @@ start_manager_node() ->
start_node(snmp_manager).
start_node(Name) ->
+ start_node(Name, true).
+start_node(Name, Retry) ->
Pa = filename:dirname(code:which(?MODULE)),
Args = case init:get_argument('CC_TEST') of
{ok, [[]]} ->
@@ -6238,30 +6437,47 @@ start_node(Name) ->
""
end,
A = Args ++ " -pa " ++ Pa,
- case (catch ?START_NODE(Name, A)) of
+ try ?START_NODE(Name, A) of
{ok, Node} ->
Node;
- Else ->
- ?line ?FAIL(Else)
+ {error, timeout} ->
+ e("Failed starting node ~p: timeout", [Name]),
+ ?line ?FAIL({error_starting_node, Name, timeout});
+ {error, {already_running, Node}} when (Retry =:= true) ->
+ %% Ouch
+ %% Either we previously failed to (properly) stop the node
+ %% or it was a failed start, that reported failure (for instance
+ %% timeout) but actually succeeded. Regardless, we don't know
+ %% the state of this node, so (try) stop it and then (re-) try
+ %% start again.
+ e("Failed starting node ~p: Already Running - try stop", [Node]),
+ case ?STOP_NODE(Node) of
+ true ->
+ p("Successfully stopped old node ~p", [Node]),
+ start_node(Name, false);
+ false ->
+ e("Failed stop old node ~p", [Node]),
+ ?line ?FAIL({error_starting_node, Node, Retry, already_running})
+ end;
+ {error, {already_running, Node}} ->
+ e("Failed starting node ~p: Already Running", [Node]),
+ ?line ?FAIL({error_starting_node, Node, Retry, already_running});
+ {error, Reason} ->
+ e("Failed starting node ~p: ~p", [Name, Reason]),
+ ?line ?FAIL({error_starting_node, Name, Reason})
+ catch
+ exit:{suite_failed, Reason} ->
+ e("(suite) Failed starting node ~p: ~p", [Name, Reason]),
+ ?line ?FAIL({failed_starting_node, Name, Reason})
end.
-stop_node(Node) ->
- rpc:cast(Node, erlang, halt, []),
- await_stopped(Node, 5).
-await_stopped(Node, 0) ->
- p("await_stopped -> ~p still exist: giving up", [Node]),
- ok;
-await_stopped(Node, N) ->
- Nodes = erlang:nodes(),
- case lists:member(Node, Nodes) of
- true ->
- p("await_stopped -> ~p still exist: ~w", [Node, N]),
- ?SLEEP(1000),
- await_stopped(Node, N-1);
- false ->
- p("await_stopped -> ~p gone: ~w", [Node, N]),
- ok
+stop_node(Node) ->
+ case ?STOP_NODE(Node) of
+ true ->
+ ok;
+ false ->
+ ?line ?FAIL({failed_stop_node, Node})
end.
@@ -6506,12 +6722,15 @@ rcall(Node, Mod, Func, Args) ->
%% ------
+e(F, A) ->
+ p("<ERROR> " ++ F, A).
+
p(F) ->
p(F, []).
p(F, A) ->
p(get(tname), F, A).
-
+
p(TName, F, A) ->
io:format("*** [~w][~s] ***"
"~n " ++ F ++ "~n", [TName, formated_timestamp()|A]).
diff --git a/lib/snmp/test/snmp_test_global_sys_monitor.erl b/lib/snmp/test/snmp_test_global_sys_monitor.erl
new file mode 100644
index 0000000000..eafb96621a
--- /dev/null
+++ b/lib/snmp/test/snmp_test_global_sys_monitor.erl
@@ -0,0 +1,214 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(snmp_test_global_sys_monitor).
+
+-export([start/0, stop/0,
+ reset_events/0,
+ events/0,
+ log/1]).
+-export([init/1]).
+
+-define(NAME, ?MODULE).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+start() ->
+ Parent = self(),
+ proc_lib:start(?MODULE, init, [Parent]).
+
+stop() ->
+ cast(stop).
+
+%% This does not reset the global counter but the "collector"
+%% See events for more info.
+reset_events() ->
+ cast(reset_events).
+
+events() ->
+ call(events).
+
+log(Event) ->
+ cast({node(), Event}).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+init(Parent) ->
+ process_flag(priority, high),
+ case global:register_name(?NAME, self()) of
+ yes ->
+ info_msg("Starting", []),
+ proc_lib:init_ack(Parent, {ok, self()}),
+ loop(#{parent => Parent, ev_cnt => 0, evs => []});
+ no ->
+ warning_msg("Already started", []),
+ proc_lib:init_ack(Parent, {error, already_started}),
+ exit(normal)
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+loop(State) ->
+ receive
+ {?MODULE, stop} ->
+ warning_msg("Stopping with ~w events counted",
+ [maps:get(ev_cnt, State)]),
+ exit(normal);
+
+ {?MODULE, reset_events} ->
+ loop(State#{evs => []});
+
+ {?MODULE, Ref, From, events} ->
+ Evs = maps:get(evs, State),
+ From ! {?MODULE, Ref, lists:reverse(Evs)},
+ loop(State);
+
+ {?MODULE, {Node, Event}} ->
+ State2 = process_event(State, Node, Event),
+ loop(State2);
+
+ {nodedown = Event, Node} ->
+ State2 = process_event(State, Node, Event),
+ loop(State2);
+
+ _ ->
+ loop(State)
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+process_event(State, Node, {Pid, TS, Tag, Info}) ->
+ process_system_event(State, Node, Pid, TS, Tag, Info);
+
+process_event(State, Node, {TS, starting}) ->
+ FTS = snmp_misc:format_timestamp(TS),
+ info_msg("System Monitor on node ~p starting at ~s", [Node, FTS]),
+ if
+ (Node =/= node()) ->
+ erlang:monitor_node(Node, true);
+ true ->
+ ok
+ end,
+ State;
+
+process_event(State, Node, {TS, already_started}) ->
+ FTS = snmp_misc:format_timestamp(TS),
+ info_msg("System Monitor on node ~p already started", [Node, FTS]),
+ State;
+
+process_event(State, Node, nodedown) ->
+ info_msg("Node ~p down", [Node]),
+ State;
+
+process_event(State, Node, Event) ->
+ warning_msg("Received unknown event from node ~p:"
+ "~n ~p", [Node, Event]),
+ State.
+
+
+%% System Monitor events
+%% We only *count* system events
+process_system_event(#{ev_cnt := Cnt, evs := Evs} = State,
+ Node, Pid, TS, long_gc = Ev, Info) ->
+ print_system_event("Long GC", Node, Pid, TS, Info),
+ State#{ev_cnt => Cnt + 1, evs => [{Node, Ev} | Evs]};
+process_system_event(#{ev_cnt := Cnt, evs := Evs} = State,
+ Node, Pid, TS, long_schedule = Ev, Info) ->
+ print_system_event("Long Schedule", Node, Pid, TS, Info),
+ State#{ev_cnt => Cnt + 1, evs => [{Node, Ev} | Evs]};
+process_system_event(#{ev_cnt := Cnt, evs := Evs} = State,
+ Node, Pid, TS, large_heap = Ev, Info) ->
+ print_system_event("Large Heap", Node, Pid, TS, Info),
+ State#{ev_cnt => Cnt + 1, evs => [{Node, Ev} | Evs]};
+process_system_event(#{ev_cnt := Cnt, evs := Evs} = State,
+ Node, Pid, TS, busy_port = Ev, Info) ->
+ print_system_event("Busy port", Node, Pid, TS, Info),
+ State#{ev_cnt => Cnt + 1, evs => [{Node, Ev} | Evs]};
+process_system_event(#{ev_cnt := Cnt, evs := Evs} = State,
+ Node, Pid, TS, busy_dist_port = Ev, Info) ->
+ print_system_event("Busy dist port", Node, Pid, TS, Info),
+ State#{ev_cnt => Cnt + 1, evs => [{Node, Ev} | Evs]};
+
+%% And everything else
+process_system_event(State, Node, Pid, TS, Tag, Info) ->
+ Pre = f("Unknown Event '~p'", [Tag]),
+ print_system_event(Pre, Node, Pid, TS, Info),
+ State.
+
+
+print_system_event(Pre, Node, Pid, TS, Info) ->
+ FTS = snmp_misc:format_timestamp(TS),
+ warning_msg("~s from ~p (~p) at ~s:"
+ "~n ~p", [Pre, Node, Pid, FTS, Info]).
+
+f(F, A) ->
+ lists:flatten(io_lib:format(F, A)).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+cast(Msg) ->
+ try global:send(?NAME, {?MODULE, Msg}) of
+ Pid when is_pid(Pid) ->
+ ok
+ catch
+ C:E:_ ->
+ {error, {catched, C, E}}
+ end.
+
+call(Req) ->
+ call(Req, infinity).
+
+call(Req, Timeout) ->
+ Ref = make_ref(),
+ try global:send(?NAME, {?MODULE, Ref, self(), Req}) of
+ Pid when is_pid(Pid) ->
+ receive
+ {?MODULE, Ref, Rep} ->
+ Rep
+ after Timeout ->
+ {error, timeout}
+ end
+ catch
+ C:E:_ ->
+ {error, {catched, C, E}}
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+info_msg(F, A) ->
+ error_logger:info_msg(format_msg(F, A), []).
+
+warning_msg(F, A) ->
+ error_logger:warning_msg(format_msg(F, A), []).
+
+
+format_msg(F, A) ->
+ f("~n" ++
+ "****** SNMP TEST GLOBAL SYSTEM MONITOR ******~n~n" ++
+ F ++
+ "~n~n",
+ A).
+
diff --git a/lib/snmp/test/snmp_test_lib.erl b/lib/snmp/test/snmp_test_lib.erl
index 290f1bc31a..26b68501e2 100644
--- a/lib/snmp/test/snmp_test_lib.erl
+++ b/lib/snmp/test/snmp_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -23,9 +23,12 @@
-include_lib("kernel/include/file.hrl").
+-export([tc_try/2, tc_try/3]).
-export([hostname/0, hostname/1, localhost/0, localhost/1, os_type/0, sz/1,
display_suite_info/1]).
--export([non_pc_tc_maybe_skip/4, os_based_skip/1]).
+-export([non_pc_tc_maybe_skip/4, os_based_skip/1,
+ has_support_ipv6/0, has_support_ipv6/1,
+ is_ipv6_host/0, is_ipv6_host/1]).
-export([fix_data_dir/1,
init_suite_top_dir/2, init_group_top_dir/2, init_testcase_top_dir/2,
lookup/2,
@@ -34,17 +37,114 @@
-export([hours/1, minutes/1, seconds/1, sleep/1]).
-export([flush_mqueue/0, trap_exit/0, trap_exit/1]).
-export([ping/1, local_nodes/0, nodes_on/1]).
--export([start_node/2]).
+-export([start_node/2, stop_node/1]).
-export([is_app_running/1,
is_crypto_running/0, is_mnesia_running/0, is_snmp_running/0]).
-export([crypto_start/0, crypto_support/0]).
-export([watchdog/3, watchdog_start/1, watchdog_start/2, watchdog_stop/1]).
-export([del_dir/1]).
-export([cover/1]).
--export([p/2, print/5, formated_timestamp/0]).
+-export([f/2, p/2, print1/2, print2/2, print/5, formated_timestamp/0]).
%% ----------------------------------------------------------------------
+%% Run test-case
+%%
+
+%% *** tc_try/2,3 ***
+%% Case: Basically the test case name
+%% TCCondFun: A fun that is evaluated before the actual test case
+%% The point of this is that it can performs checks to
+%% see if we shall run the test case at all.
+%% For instance, the test case may only work in specific
+%% conditions.
+%% FCFun: The test case fun
+tc_try(Case, TCFun) ->
+ tc_try(Case, fun() -> ok end, TCFun).
+
+tc_try(Case, TCCondFun, TCFun)
+ when is_atom(Case) andalso
+ is_function(TCCondFun, 0) andalso
+ is_function(TCFun, 0) ->
+ tc_begin(Case),
+ try TCCondFun() of
+ ok ->
+ try
+ begin
+ TCFun(),
+ sleep(seconds(1)),
+ tc_end("ok")
+ end
+ catch
+ C:{skip, _} = SKIP when ((C =:= throw) orelse (C =:= exit)) ->
+ tc_end( f("skipping(catched,~w,tc)", [C]) ),
+ SKIP;
+ C:E:S ->
+ tc_end( f("failed(catched,~w,tc)", [C]) ),
+ erlang:raise(C, E, S)
+ end;
+ {skip, _} = SKIP ->
+ tc_end("skipping(tc)"),
+ SKIP;
+ {error, Reason} ->
+ tc_end("failed(tc)"),
+ exit({tc_cond_failed, Reason})
+ catch
+ C:{skip, _} = SKIP when ((C =:= throw) orelse (C =:= exit)) ->
+ tc_end( f("skipping(catched,~w,cond)", [C]) ),
+ SKIP;
+ C:E:S ->
+ tc_end( f("failed(catched,~w,cond)", [C]) ),
+ erlang:raise(C, E, S)
+ end.
+
+
+tc_set_name(N) when is_atom(N) ->
+ tc_set_name(atom_to_list(N));
+tc_set_name(N) when is_list(N) ->
+ put(tc_name, N).
+
+tc_get_name() ->
+ get(tc_name).
+
+tc_begin(TC) ->
+ OldVal = process_flag(trap_exit, true),
+ put(old_trap_exit, OldVal),
+ tc_set_name(TC),
+ tc_print("begin ***",
+ "~n----------------------------------------------------~n", "").
+
+tc_end(Result) when is_list(Result) ->
+ OldVal = erase(old_trap_exit),
+ process_flag(trap_exit, OldVal),
+ tc_print("done: ~s", [Result],
+ "", "----------------------------------------------------~n~n"),
+ ok.
+
+tc_print(F, Before, After) ->
+ tc_print(F, [], Before, After).
+
+tc_print(F, A, Before, After) ->
+ Name = tc_which_name(),
+ FStr = f("*** [~s][~s][~p] " ++ F ++ "~n",
+ [formated_timestamp(),Name,self()|A]),
+ io:format(user, Before ++ FStr ++ After, []).
+
+tc_which_name() ->
+ case tc_get_name() of
+ undefined ->
+ case get(sname) of
+ undefined ->
+ "";
+ SName when is_list(SName) ->
+ SName
+ end;
+ Name when is_list(Name) ->
+ Name
+ end.
+
+
+%% ----------------------------------------------------------------------
%% Misc functions
%%
@@ -52,18 +152,76 @@ hostname() ->
hostname(node()).
hostname(Node) ->
- from($@, atom_to_list(Node)).
+ case string:tokens(atom_to_list(Node), [$@]) of
+ [_, Host] ->
+ Host;
+ _ ->
+ []
+ end.
-from(H, [H | T]) -> T;
-from(H, [_ | T]) -> from(H, T);
-from(_H, []) -> [].
+%% localhost() ->
+%% {ok, Ip} = snmp_misc:ip(net_adm:localhost()),
+%% Ip.
+%% localhost(Family) ->
+%% {ok, Ip} = snmp_misc:ip(net_adm:localhost(), Family),
+%% Ip.
localhost() ->
- {ok, Ip} = snmp_misc:ip(net_adm:localhost()),
- Ip.
+ localhost(inet).
+
localhost(Family) ->
- {ok, Ip} = snmp_misc:ip(net_adm:localhost(), Family),
- Ip.
+ case inet:getaddr(net_adm:localhost(), Family) of
+ {ok, {127, _, _, _}} when (Family =:= inet) ->
+ %% Ouch, we need to use something else
+ case inet:getifaddrs() of
+ {ok, IfList} ->
+ which_addr(Family, IfList);
+ {error, Reason1} ->
+ fail({getifaddrs, Reason1}, ?MODULE, ?LINE)
+ end;
+ {ok, {A1, _, _, _, _, _, _, _}} when (Family =:= inet6) andalso
+ ((A1 =:= 0) orelse
+ (A1 =:= 16#fe80)) ->
+ %% Ouch, we need to use something else
+ case inet:getifaddrs() of
+ {ok, IfList} ->
+ which_addr(Family, IfList);
+ {error, Reason1} ->
+ fail({getifaddrs, Reason1}, ?MODULE, ?LINE)
+ end;
+ {ok, Addr} ->
+ Addr;
+ {error, Reason2} ->
+ fail({getaddr, Reason2}, ?MODULE, ?LINE)
+ end.
+
+which_addr(_Family, []) ->
+ fail(no_valid_addr, ?MODULE, ?LINE);
+which_addr(Family, [{"lo", _} | IfList]) ->
+ which_addr(Family, IfList);
+which_addr(Family, [{"docker" ++ _, _} | IfList]) ->
+ which_addr(Family, IfList);
+which_addr(Family, [{"br-" ++ _, _} | IfList]) ->
+ which_addr(Family, IfList);
+which_addr(Family, [{_Name, IfOpts} | IfList]) ->
+ case which_addr2(Family, IfOpts) of
+ {ok, Addr} ->
+ Addr;
+ {error, _} ->
+ which_addr(Family, IfList)
+ end.
+
+which_addr2(_Family, []) ->
+ {error, not_found};
+which_addr2(Family, [{addr, Addr}|_])
+ when (Family =:= inet) andalso (size(Addr) =:= 4) ->
+ {ok, Addr};
+which_addr2(Family, [{addr, Addr}|_])
+ when (Family =:= inet6) andalso (size(Addr) =:= 8) ->
+ {ok, Addr};
+which_addr2(Family, [_|IfOpts]) ->
+ which_addr2(Family, IfOpts).
+
sz(L) when is_list(L) ->
length(L);
@@ -142,63 +300,121 @@ non_pc_tc_maybe_skip(Config, Condition, File, Line)
%% test-server...
ok;
_ ->
- case Condition() of
+ try Condition() of
true ->
skip(non_pc_testcase, File, Line);
false ->
ok
+ catch
+ C:E:S ->
+ skip({condition, C, E, S}, File, Line)
end
end
end.
+%% The type and spec'ing is just to increase readability
+-type os_family() :: win32 | unix.
+-type os_name() :: atom().
+-type os_version() :: string() | {non_neg_integer(),
+ non_neg_integer(),
+ non_neg_integer()}.
+-type os_skip_check() :: fun(() -> boolean()) |
+ fun((os_version()) -> boolean()).
+-type skippable() :: any | [os_family() |
+ {os_family(), os_name() |
+ [os_name() | {os_name(),
+ os_skip_check()}]}].
+
+-spec os_based_skip(skippable()) -> boolean().
+
os_based_skip(any) ->
- io:format("os_based_skip(any) -> entry"
- "~n", []),
true;
os_based_skip(Skippable) when is_list(Skippable) ->
- io:format("os_based_skip -> entry with"
- "~n Skippable: ~p"
- "~n", [Skippable]),
- {OsFam, OsName} =
- case os:type() of
- {_Fam, _Name} = FamAndName ->
- FamAndName;
- Fam ->
- {Fam, undefined}
- end,
- io:format("os_based_skip -> os-type: "
- "~n OsFam: ~p"
- "~n OsName: ~p"
- "~n", [OsFam, OsName]),
+ os_base_skip(Skippable, os:type());
+os_based_skip(_Crap) ->
+ false.
+
+os_base_skip(Skippable, {OsFam, OsName}) ->
+ os_base_skip(Skippable, OsFam, OsName);
+os_base_skip(Skippable, OsFam) ->
+ os_base_skip(Skippable, OsFam, undefined).
+
+os_base_skip(Skippable, OsFam, OsName) ->
+ %% Check if the entire family is to be skipped
+ %% Example: [win32, unix]
case lists:member(OsFam, Skippable) of
true ->
true;
false ->
- case lists:keysearch(OsFam, 1, Skippable) of
- {value, {OsFam, OsName}} ->
- true;
- {value, {OsFam, OsNames}} when is_list(OsNames) ->
+ %% Example: [{unix, freebsd}] | [{unix, [freebsd, darwin]}]
+ case lists:keysearch(OsFam, 1, Skippable) of
+ {value, {OsFam, OsName}} ->
+ true;
+ {value, {OsFam, OsNames}} when is_list(OsNames) ->
+ %% OsNames is a list of:
+ %% [atom()|{atom(), function/0 | function/1}]
case lists:member(OsName, OsNames) of
true ->
true;
false ->
- case lists:keymember(OsName, 1, OsNames) of
- {value, {OsName, Check}} when is_function(Check) ->
- Check();
- _ ->
- false
- end
+ os_based_skip_check(OsName, OsNames)
end;
- _ ->
- false
- end
- end;
-os_based_skip(_Crap) ->
- io:format("os_based_skip -> entry with"
- "~n _Crap: ~p"
- "~n", [_Crap]),
- false.
+ _ ->
+ false
+ end
+ end.
+
+%% Performs a check via a provided fun with arity 0 or 1.
+%% The argument is the result of os:version().
+os_based_skip_check(OsName, OsNames) ->
+ case lists:keysearch(OsName, 1, OsNames) of
+ {value, {OsName, Check}} when is_function(Check, 0) ->
+ Check();
+ {value, {OsName, Check}} when is_function(Check, 1) ->
+ Check(os:version());
+ _ ->
+ false
+ end.
+
+
+%% A basic test to check if current host supports IPv6
+has_support_ipv6() ->
+ case inet:gethostname() of
+ {ok, Hostname} ->
+ has_support_ipv6(Hostname);
+ _ ->
+ false
+ end.
+
+has_support_ipv6(Hostname) ->
+ case inet:getaddr(Hostname, inet6) of
+ {ok, Addr} when (size(Addr) =:= 8) andalso
+ (element(1, Addr) =/= 0) andalso
+ (element(1, Addr) =/= 16#fe80) ->
+ true;
+ {ok, _} ->
+ false;
+ {error, _} ->
+ false
+ end.
+
+
+is_ipv6_host() ->
+ case inet:gethostname() of
+ {ok, Hostname} ->
+ is_ipv6_host(Hostname);
+ {error, _} ->
+ false
+ end.
+
+is_ipv6_host(Hostname) ->
+ case ct:require(ipv6_hosts) of
+ ok ->
+ lists:member(list_to_atom(Hostname), ct:get_config(ipv6_hosts));
+ _ ->
+ false
+ end.
%% ----------------------------------------------------------------
@@ -397,10 +613,14 @@ nodes_on(Host) when is_list(Host) ->
start_node(Name, Args) ->
- Opts = [{cleanup,false}, {args,Args}],
+ Opts = [{cleanup, false}, {args, Args}],
test_server:start_node(Name, slave, Opts).
+stop_node(Node) ->
+ test_server:stop_node(Node).
+
+
%% ----------------------------------------------------------------
%% Application and Crypto utility functions
%%
@@ -593,6 +813,9 @@ cover([Suite, Case] = Args) when is_atom(Suite) andalso is_atom(Case) ->
%% (debug) Print functions
%%
+f(F, A) ->
+ lists:flatten(io_lib:format(F, A)).
+
p(Mod, Case) when is_atom(Mod) andalso is_atom(Case) ->
case get(test_case) of
undefined ->
@@ -605,19 +828,30 @@ p(Mod, Case) when is_atom(Mod) andalso is_atom(Case) ->
p(F, A) when is_list(F) andalso is_list(A) ->
io:format(user, F ++ "~n", A).
+%% This is just a bog standard printout, with a (formatted) timestamp
+%% prefix and a newline after.
+%% print1 - prints to both standard_io and user.
+%% print2 - prints to just standard_io.
+
+print_format(F, A) ->
+ FTS = snmp_test_lib:formated_timestamp(),
+ io_lib:format("[~s] " ++ F ++ "~n", [FTS | A]).
+
+print1(F, A) ->
+ S = print_format(F, A),
+ io:format("~s", [S]),
+ io:format(user, "~s", [S]).
+
+print2(F, A) ->
+ S = print_format(F, A),
+ io:format("~s", [S]).
+
+
print(Prefix, Module, Line, Format, Args) ->
io:format("*** [~s] ~s ~p ~p ~p:~p *** " ++ Format ++ "~n",
[formated_timestamp(),
Prefix, node(), self(), Module, Line|Args]).
formated_timestamp() ->
- format_timestamp(os:timestamp()).
-
-format_timestamp({_N1, _N2, N3} = Now) ->
- {Date, Time} = calendar:now_to_datetime(Now),
- {YYYY,MM,DD} = Date,
- {Hour,Min,Sec} = Time,
- FormatDate =
- io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w ~w",
- [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
- lists:flatten(FormatDate).
+ snmp_misc:formated_timestamp().
+
diff --git a/lib/snmp/test/snmp_test_lib.hrl b/lib/snmp/test/snmp_test_lib.hrl
index 7acebee1f1..f077f15d3e 100644
--- a/lib/snmp/test/snmp_test_lib.hrl
+++ b/lib/snmp/test/snmp_test_lib.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,15 +18,11 @@
%% The Initial Developer of the Original Code is Ericsson AB.
%% %CopyrightEnd%
%%
+
%%----------------------------------------------------------------------
-%% Purpose: Define common macros for testing
+%% Purpose: Define common macros for (the snmp) testing
%%----------------------------------------------------------------------
-%% - (some of the) Macros stolen from the test server -
-
-%% -define(line,put(test_server_loc,{?MODULE,?LINE}),).
-
-
%% - Misc macros -
-ifndef(APPLICATION).
@@ -45,12 +41,18 @@
%% - Test case macros -
+-define(TC_TRY(C, TC), snmp_test_lib:tc_try(C, TC)).
+-define(TC_TRY(C, TCCond, TC), snmp_test_lib:tc_try(C, TCCond, TC)).
-define(OS_BASED_SKIP(Skippable),
snmp_test_lib:os_based_skip(Skippable)).
-define(NON_PC_TC_MAYBE_SKIP(Config, Condition),
snmp_test_lib:non_pc_tc_maybe_skip(Config, Condition, ?MODULE, ?LINE)).
--define(SKIP(Reason), snmp_test_lib:skip(Reason, ?MODULE, ?LINE)).
--define(FAIL(Reason), snmp_test_lib:fail(Reason, ?MODULE, ?LINE)).
+-define(SKIP(Reason), snmp_test_lib:skip(Reason, ?MODULE, ?LINE)).
+-define(FAIL(Reason), snmp_test_lib:fail(Reason, ?MODULE, ?LINE)).
+-define(IS_IPV6_HOST(), snmp_test_lib:is_ipv6_host()).
+-define(IS_IPV6_HOST(H), snmp_test_lib:is_ipv6_host(H)).
+-define(HAS_SUPPORT_IPV6(), snmp_test_lib:has_support_ipv6()).
+-define(HAS_SUPPORT_IPV6(H), snmp_test_lib:has_support_ipv6(H)).
%% - Time macros -
@@ -88,6 +90,7 @@
-define(LNODES(), snmp_test_lib:local_nodes()).
-define(NODES(H), snmp_test_lib:nodes_on(H)).
-define(START_NODE(N,A), snmp_test_lib:start_node(N,A)).
+-define(STOP_NODE(N), snmp_test_lib:stop_node(N)).
%% - Application and Crypto utility macros -
@@ -127,24 +130,33 @@
-endif.
-ifdef(snmp_debug).
--define(DBG(F,A),?PRINT("DBG",F,A)).
+-define(DBG(F,A), ?PRINT("DBG", F, A)).
-else.
--define(DBG(F,A),ok).
+-define(DBG(F,A), ok).
-endif.
-ifdef(snmp_log).
--define(LOG(F,A),?PRINT("LOG",F,A)).
+-define(LOG(F,A), ?PRINT("LOG", F, A)).
-else.
--define(LOG(F,A),ok).
+-define(LOG(F,A), ok).
-endif.
-ifdef(snmp_error).
--define(ERR(F,A),?PRINT("ERR",F,A)).
+-define(ERR(F,A), ?PRINT("ERR", F, A)).
-else.
--define(ERR(F,A),ok).
+-define(ERR(F,A), ok).
-endif.
--define(INF(F,A),?PRINT("INF",F,A)).
+-define(INF(F,A), ?PRINT("INF", F, A)).
-define(PRINT(P,F,A),
- snmp_test_lib:print(P,?MODULE,?LINE,F,A)).
+ snmp_test_lib:print(P, ?MODULE, ?LINE, F, A)).
+
+-define(PRINT1(F, A), snmp_test_lib:print1(F, A)).
+-define(PRINT1(F), ?PRINT1(F, [])).
+-define(EPRINT1(F, A), ?PRINT1("<ERROR> " ++ F, A)).
+
+-define(PRINT2(F, A), snmp_test_lib:print2(F, A)).
+-define(PRINT2(F), ?PRINT2(F, [])).
+-define(EPRINT2(F, A), ?PRINT2("<ERROR> " ++ F, A)).
+
diff --git a/lib/snmp/test/snmp_test_mgr.erl b/lib/snmp/test/snmp_test_mgr.erl
index 36637d5cf4..9d6be65088 100644
--- a/lib/snmp/test/snmp_test_mgr.erl
+++ b/lib/snmp/test/snmp_test_mgr.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -20,8 +20,10 @@
-module(snmp_test_mgr).
+
%%----------------------------------------------------------------------
-%% This module implements a simple SNMP manager for Erlang.
+%% This module implements a simple SNMP manager for Erlang. Its used
+%% during by the agent test suite.
%%----------------------------------------------------------------------
%% c(snmp_test_mgr).
@@ -49,16 +51,18 @@
-include_lib("snmp/include/snmp_types.hrl").
-include_lib("snmp/include/STANDARD-MIB.hrl").
-
--record(state,{dbg = true,
- quiet,
- parent,
- timeout = 3500,
- print_traps = true,
- mini_mib,
- packet_server,
- last_sent_pdu,
- last_received_pdu}).
+-include("snmp_test_lib.hrl").
+-include_lib("snmp/src/app/snmp_internal.hrl").
+
+-record(state, {dbg = true,
+ quiet,
+ parent,
+ timeout = 3500,
+ print_traps = true,
+ mini_mib,
+ packet_server,
+ last_sent_pdu,
+ last_received_pdu}).
-define(SERVER, ?MODULE).
-define(PACK_SERV, snmp_test_mgr_misc).
@@ -189,35 +193,38 @@ receive_trap(Timeout) ->
init({Options, CallerPid}) ->
put(sname, mgr),
put(verbosity, debug),
- random:seed(erlang:phash2([node()]),
- erlang:monotonic_time(),
- erlang:unique_integer()),
+ ?SNMP_RAND_SEED(),
+ %% rand:seed(exrop,
+ %% {erlang:phash2([node()]),
+ %% erlang:monotonic_time(),
+ %% erlang:unique_integer()}),
case (catch is_options_ok(Options)) of
true ->
put(debug, get_value(debug, Options, false)),
d("init -> (~p) extract options",[self()]),
PacksDbg = get_value(packet_server_debug, Options, false),
- io:format("[~w] ~p -> PacksDbg: ~p~n", [?MODULE, self(), PacksDbg]),
+ print("[~w] ~p -> PacksDbg: ~p~n", [?MODULE, self(), PacksDbg]),
RecBufSz = get_value(recbuf, Options, 1024),
- io:format("[~w] ~p -> RecBufSz: ~p~n", [?MODULE, self(), RecBufSz]),
+ print("[~w] ~p -> RecBufSz: ~p~n", [?MODULE, self(), RecBufSz]),
Mibs = get_value(mibs, Options, []),
- io:format("[~w] ~p -> Mibs: ~p~n", [?MODULE, self(), Mibs]),
+ print("[~w] ~p -> Mibs: ~p~n", [?MODULE, self(), Mibs]),
Udp = get_value(agent_udp, Options, 4000),
- io:format("[~w] ~p -> Udp: ~p~n", [?MODULE, self(), Udp]),
+ print("[~w] ~p -> Udp: ~p~n", [?MODULE, self(), Udp]),
User = get_value(user, Options, "initial"),
- io:format("[~w] ~p -> User: ~p~n", [?MODULE, self(), User]),
+ print("[~w] ~p -> User: ~p~n", [?MODULE, self(), User]),
EngineId = get_value(engine_id, Options, "agentEngine"),
- io:format("[~w] ~p -> EngineId: ~p~n", [?MODULE, self(), EngineId]),
+ print("[~w] ~p -> EngineId: ~p~n", [?MODULE, self(), EngineId]),
CtxEngineId = get_value(context_engine_id, Options, EngineId),
- io:format("[~w] ~p -> CtxEngineId: ~p~n", [?MODULE, self(), CtxEngineId]),
+ print("[~w] ~p -> CtxEngineId: ~p~n", [?MODULE, self(), CtxEngineId]),
TrapUdp = get_value(trap_udp, Options, 5000),
- io:format("[~w] ~p -> TrapUdp: ~p~n", [?MODULE, self(), TrapUdp]),
+ print("[~w] ~p -> TrapUdp: ~p~n", [?MODULE, self(), TrapUdp]),
Dir = get_value(dir, Options, "."),
- io:format("[~w] ~p -> Dir: ~p~n", [?MODULE, self(), Dir]),
+ print("[~w] ~p -> Dir: ~p~n", [?MODULE, self(), Dir]),
SecLevel = get_value(sec_level, Options, noAuthNoPriv),
- io:format("[~w] ~p -> SecLevel: ~p~n", [?MODULE, self(), SecLevel]),
+ print("[~w] ~p -> SecLevel: ~p~n", [?MODULE, self(), SecLevel]),
MiniMIB = snmp_mini_mib:create(Mibs),
- io:format("[~w] ~p -> MiniMIB: ~p~n", [?MODULE, self(), MiniMIB]),
+ d("[~w] ~p -> MiniMIB: "
+ "~n ~p", [?MODULE, self(), MiniMIB]),
Version = case lists:member(v2, Options) of
true -> 'version-2';
false ->
@@ -226,30 +233,41 @@ init({Options, CallerPid}) ->
false -> 'version-1'
end
end,
- io:format("[~w] ~p -> Version: ~p~n", [?MODULE, self(), Version]),
+ print("[~w] ~p -> Version: ~p~n", [?MODULE, self(), Version]),
Com = case Version of
'version-3' ->
get_value(context, Options, "");
_ ->
get_value(community, Options, "public")
end,
- io:format("[~w] ~p -> Com: ~p~n", [?MODULE, self(), Com]),
+ print("[~w] ~p -> Com: ~p~n", [?MODULE, self(), Com]),
VsnHdrD =
{Com, User, EngineId, CtxEngineId, mk_seclevel(SecLevel)},
- io:format("[~w] ~p -> VsnHdrD: ~p~n", [?MODULE, self(), VsnHdrD]),
+ print("[~w] ~p -> VsnHdrD: ~p~n", [?MODULE, self(), VsnHdrD]),
IpFamily = get_value(ipfamily, Options, inet),
- io:format("[~w] ~p -> IpFamily: ~p~n", [?MODULE, self(), IpFamily]),
+ print("[~w] ~p -> IpFamily: ~p~n", [?MODULE, self(), IpFamily]),
AgIp = case snmp_misc:assq(agent, Options) of
- {value, Tuple4} when is_tuple(Tuple4) andalso
- (size(Tuple4) =:= 4) ->
- Tuple4;
+ {value, Addr} when is_tuple(Addr) andalso
+ (size(Addr) =:= 4) andalso
+ (IpFamily =:= inet) ->
+ print("[~w] ~p -> Addr: ~p~n",
+ [?MODULE, self(), Addr]),
+ Addr;
+ {value, Addr} when is_tuple(Addr) andalso
+ (size(Addr) =:= 8) andalso
+ (IpFamily =:= inet6) ->
+ print("[~w] ~p -> Addr: ~p~n",
+ [?MODULE, self(), Addr]),
+ Addr;
{value, Host} when is_list(Host) ->
+ print("[~w] ~p -> Host: ~p~n",
+ [?MODULE, self(), Host]),
{ok, Ip} = snmp_misc:ip(Host, IpFamily),
Ip
end,
- io:format("[~w] ~p -> AgIp: ~p~n", [?MODULE, self(), AgIp]),
+ print("[~w] ~p -> AgIp: ~p~n", [?MODULE, self(), AgIp]),
Quiet = lists:member(quiet, Options),
- io:format("[~w] ~p -> Quiet: ~p~n", [?MODULE, self(), Quiet]),
+ print("[~w] ~p -> Quiet: ~p~n", [?MODULE, self(), Quiet]),
PackServ =
start_packet_server(
Quiet, Options, CallerPid, AgIp, Udp, TrapUdp,
@@ -443,7 +461,8 @@ handle_cast({bulk, Args}, State) ->
{noreply, execute_request(bulk, Args, State)};
handle_cast({response, RespPdu}, State) ->
- d("handle_cast -> response request with ~p", [RespPdu]),
+ d("handle_cast -> response request with "
+ "~n ~p", [RespPdu]),
?PACK_SERV:send_pdu(RespPdu, State#state.packet_server),
{noreply, State};
@@ -663,7 +682,6 @@ make_vb(Oid) ->
#varbind{oid = Oid, variabletype = 'NULL', value = 'NULL'}.
make_request_id() ->
- %% random:uniform(16#FFFFFFF-1).
snmp_test_mgr_counter_server:increment(mgr_request_id, 1, 1, 2147483647).
echo_pdu(PDU, MiniMIB) ->
@@ -1126,14 +1144,15 @@ sizeOf(L) when is_list(L) ->
sizeOf(B) when is_binary(B) ->
size(B).
-d(F,A) -> d(get(debug),F,A).
+d(F, A) -> d(get(debug), F, A).
-d(true,F,A) ->
- io:format("*** [~s] MGR_DBG *** " ++ F ++ "~n",
- [formated_timestamp()|A]);
+d(true, F, A) ->
+ print(F, A);
d(_,_F,_A) ->
ok.
+print(F, A) ->
+ ?PRINT2("MGR " ++ F, A).
-formated_timestamp() ->
- snmp_test_lib:formated_timestamp().
+%% formated_timestamp() ->
+%% snmp_test_lib:formated_timestamp().
diff --git a/lib/snmp/test/snmp_test_mgr_misc.erl b/lib/snmp/test/snmp_test_mgr_misc.erl
index 274fb5be26..6608a88c00 100644
--- a/lib/snmp/test/snmp_test_mgr_misc.erl
+++ b/lib/snmp/test/snmp_test_mgr_misc.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -38,11 +38,14 @@
-define(SNMP_USE_V3, true).
-include_lib("snmp/include/snmp_types.hrl").
+-include_lib("snmp/src/misc/snmp_verbosity.hrl").
+-include("snmp_test_lib.hrl").
%%----------------------------------------------------------------------
%% The InHandler process will receive messages on the form {snmp_pdu, Pdu}.
%%----------------------------------------------------------------------
+
start_link_packet(
InHandler, AgentIp, UdpPort, TrapUdp, VsnHdr, Version, Dir, BufSz) ->
start_link_packet(
@@ -101,11 +104,11 @@ init_packet(
DbgOptions, IpFamily) ->
put(sname, mgr_misc),
init_debug(DbgOptions),
- {ok, UdpId} =
- gen_udp:open(TrapUdp, [{recbuf,BufSz}, {reuseaddr, true}, IpFamily]),
+ UdpOpts = [{recbuf,BufSz}, {reuseaddr, true}, IpFamily],
+ {ok, UdpId} = gen_udp:open(TrapUdp, UdpOpts),
put(msg_id, 1),
- proc_lib:init_ack(Parent, self()),
init_usm(Version, Dir),
+ proc_lib:init_ack(Parent, self()),
packet_loop(SnmpMgr, UdpId, AgentIp, UdpPort, VsnHdr, Version, []).
init_debug(Dbg) when is_atom(Dbg) ->
@@ -200,86 +203,24 @@ packet_loop(SnmpMgr, UdpId, AgentIp, UdpPort, VsnHdr, Version, MsgData) ->
handle_udp_packet(_V, undefined,
UdpId, Ip, UdpPort,
Bytes, SnmpMgr, AgentIp) ->
- M = (catch snmp_pdus:dec_message_only(Bytes)),
- MsgData3 =
- case M of
- Message when Message#message.version =:= 'version-3' ->
- d("handle_udp_packet -> version 3"),
- case catch handle_v3_msg(Bytes, Message) of
- {ok, NewData, MsgData2} ->
- Msg = Message#message{data = NewData},
- case SnmpMgr of
- {pdu, Pid} ->
- Pdu = get_pdu(Msg),
- d("packet_loop -> "
- "send pdu to manager (~w): ~p", [Pid, Pdu]),
- Pid ! {snmp_pdu, Pdu};
- {msg, Pid} ->
- d("packet_loop -> "
- "send msg to manager (~w): ~p", [Pid, Msg]),
- Pid ! {snmp_msg, Msg, Ip, UdpPort}
- end,
- MsgData2;
- {error, Reason, B} ->
- udp_send(UdpId, AgentIp, UdpPort, B),
- error("Decoding error. Auto-sending Report.\n"
- "Reason: ~w "
- "(UDPport: ~w, Ip: ~w)",
- [Reason, UdpPort, Ip]),
- [];
- {error, Reason} ->
- error("Decoding error. "
- "Bytes: ~w ~n Reason: ~w "
- "(UDPport: ~w, Ip: ~w)",
- [Bytes, Reason, UdpPort, Ip]),
- []
- end;
- Message when is_record(Message, message) ->
- %% v1 or v2c
- d("handle_udp_packet -> version v1 or v2c"),
- case catch snmp_pdus:dec_pdu(Message#message.data) of
- Pdu when is_record(Pdu, pdu) ->
- case SnmpMgr of
- {pdu, Pid} ->
- d("handle_udp_packet -> "
- "send pdu to manager (~w): ~p",
- [Pid, Pdu]),
- Pid ! {snmp_pdu, Pdu};
- {msg, Pid} ->
- d("handle_udp_packet -> "
- "send pdu-msg to manager (~w): ~p",
- [Pid, Pdu]),
- Msg = Message#message{data = Pdu},
- Pid ! {snmp_msg, Msg, Ip, UdpPort}
- end;
- Pdu when is_record(Pdu, trappdu) ->
- case SnmpMgr of
- {pdu, Pid} ->
- d("handle_udp_packet -> "
- "send trap to manager (~w): ~p",
- [Pid, Pdu]),
- Pid ! {snmp_pdu, Pdu};
- {msg, Pid} ->
- d("handle_udp_packet -> "
- "send trap-msg to manager (~w): ~p",
- [Pid, Pdu]),
- Msg = Message#message{data = Pdu},
- Pid ! {snmp_msg, Msg, Ip, UdpPort}
- end;
- Reason ->
- error("Decoding error. "
- "Bytes: ~w ~n Reason: ~w "
- "(UDPport: ~w, Ip: ~w)",
- [Bytes, Reason, UdpPort, Ip])
- end,
- [];
- Reason ->
- error("Decoding error. Bytes: ~w ~n Reason: ~w "
- "(UDPport: ~w, Ip: ~w)",
- [Bytes, Reason, UdpPort, Ip]),
- []
- end,
- MsgData3;
+ try snmp_pdus:dec_message_only(Bytes) of
+ Message when Message#message.version =:= 'version-3' ->
+ d("handle_udp_packet -> version 3"),
+ handle_v3_message(SnmpMgr, UdpId, Ip, UdpPort, AgentIp,
+ Bytes, Message);
+
+ Message when is_record(Message, message) ->
+ d("handle_udp_packet -> version 1 or 2"),
+ handle_v1_or_v2_message(SnmpMgr, UdpId, Ip, UdpPort, AgentIp,
+ Bytes, Message)
+
+ catch
+ Class:Error:_ ->
+ error("Decoding error (~w). Bytes: ~w ~n Error: ~w "
+ "(UDPport: ~w, Ip: ~w)",
+ [Class, Bytes, Error, UdpPort, Ip]),
+ []
+ end;
handle_udp_packet(V, {DiscoReqMsg, From}, _UdpId, _Ip, _UdpPort,
Bytes, _, _AgentIp) ->
DiscoRspMsg = (catch snmp_pdus:dec_message(Bytes)),
@@ -297,6 +238,88 @@ handle_udp_packet(V, {DiscoReqMsg, From}, _UdpId, _Ip, _UdpPort,
[]
end.
+handle_v3_message(Mgr, UdpId, Ip, UdpPort, AgentIp,
+ Bytes, Message) ->
+ try handle_v3_msg(Bytes, Message) of
+ {ok, NewData, MsgData} ->
+ Msg = Message#message{data = NewData},
+ case Mgr of
+ {pdu, Pid} ->
+ Pdu = get_pdu(Msg),
+ d("handle_v3_message -> send pdu to manager (~p): "
+ "~n ~p", [Pid, Pdu]),
+ Pid ! {snmp_pdu, Pdu};
+ {msg, Pid} ->
+ d("handle_v3_message -> send msg to manager (~p): "
+ "~n ~p", [Pid, Msg]),
+ Pid ! {snmp_msg, Msg, Ip, UdpPort}
+ end,
+ MsgData
+
+ catch
+ throw:{error, Reason, B}:_ ->
+ udp_send(UdpId, AgentIp, UdpPort, B),
+ error("Decoding (v3) error. Auto-sending Report.\n"
+ "~n Reason: ~w "
+ "(UDPport: ~w, Ip: ~w)",
+ [Reason, UdpPort, Ip]),
+ [];
+
+ throw:{error, Reason}:_ ->
+ error("Decoding (v3) error. "
+ "~n Bytes: ~w"
+ "~n Reason: ~w "
+ "(UDPport: ~w, Ip: ~w)",
+ [Bytes, Reason, UdpPort, Ip]),
+ [];
+
+ Class:Error:_ ->
+ error("Decoding (v3) error (~w). "
+ "~n Bytes: ~w"
+ "~n Error: ~w "
+ "(UDPport: ~w, Ip: ~w)",
+ [Class, Bytes, Error, UdpPort, Ip]),
+ []
+
+ end.
+
+handle_v1_or_v2_message(Mgr, _UdpId, Ip, UdpPort, _AgentIp,
+ Bytes, Message) ->
+ try snmp_pdus:dec_pdu(Message#message.data) of
+ Pdu when is_record(Pdu, pdu) ->
+ case Mgr of
+ {pdu, Pid} ->
+ d("handle_v1_or_v2_message -> send pdu to manager (~p): "
+ "~n ~p", [Pid, Pdu]),
+ Pid ! {snmp_pdu, Pdu};
+ {msg, Pid} ->
+ d("handle_v1_or_v2_message -> send msg to manager (~p): "
+ "~n ~p", [Pid, Pdu]),
+ Msg = Message#message{data = Pdu},
+ Pid ! {snmp_msg, Msg, Ip, UdpPort}
+ end;
+ Pdu when is_record(Pdu, trappdu) ->
+ case Mgr of
+ {pdu, Pid} ->
+ d("handle_v1_or_v2_message -> send trap-pdu to manager (~p): "
+ "~n ~p", [Pid, Pdu]),
+ Pid ! {snmp_pdu, Pdu};
+ {msg, Pid} ->
+ d("handle_v1_or_v2_message -> send trap-msg to manager (~p): "
+ "~n ~p", [Pid, Pdu]),
+ Msg = Message#message{data = Pdu},
+ Pid ! {snmp_msg, Msg, Ip, UdpPort}
+ end
+
+ catch
+ Class:Error:_ ->
+ error("Decoding (v1 or v2) error (~w): "
+ "~n Bytes: ~w"
+ "~n Error: ~w "
+ "(UDPport: ~w, Ip: ~w)",
+ [Class, Bytes, Error, UdpPort, Ip])
+ end.
+
%% This function assumes that the agent and the manager (thats us)
%% has the same version.
@@ -553,6 +576,7 @@ vsn('version-2') -> v2c.
udp_send(UdpId, AgentIp, UdpPort, B) ->
+ ?vlog("attempt send message (~w bytes) to ~p", [sz(B), {AgentIp, UdpPort}]),
case (catch gen_udp:send(UdpId, AgentIp, UdpPort, B)) of
{error,ErrorReason} ->
error("failed (error) sending message to ~p:~p: "
@@ -578,18 +602,100 @@ set_pdu(Msg, RePdu) ->
init_usm('version-3', Dir) ->
+ ?vlog("init_usm -> create (and init) fake \"agent\" table", []),
ets:new(snmp_agent_table, [set, public, named_table]),
ets:insert(snmp_agent_table, {agent_mib_storage, persistent}),
- snmpa_local_db:start_link(normal, Dir, [{verbosity,trace}]),
+ %% The local-db process may *still* be running (from a previous
+ %% test case), on the way down, but not yet dead.
+ %% Either way, before we start it, make sure its dead and *gone*!
+ %% How do we do that without getting hung up? Calling the stop
+ %% function, will not do since it uses Timeout=infinity.
+ ?vlog("init_usm -> ensure (old) fake local-db is dead", []),
+ ensure_local_db_dead(),
+ ?vlog("init_usm -> try start fake local-db", []),
+ case snmpa_local_db:start_link(normal, Dir,
+ [{sname, "MGR-LOCAL-DB"},
+ {verbosity, trace}]) of
+ {ok, Pid} ->
+ ?vlog("started: ~p"
+ "~n ~p", [Pid, process_info(Pid)]);
+ {error, {already_started, Pid}} ->
+ LDBInfo = process_info(Pid),
+ ?vlog("already started: ~p"
+ "~n ~p", [Pid, LDBInfo]),
+ ?FAIL({still_running, snmpa_local_db, LDBInfo});
+ {error, Reason} ->
+ ?FAIL({failed_starting, snmpa_local_db, Reason})
+ end,
NameDb = snmpa_agent:db(snmpEngineID),
+ ?vlog("init_usm -> try set manager engine-id", []),
R = snmp_generic:variable_set(NameDb, "mgrEngine"),
- io:format("~w:init_usm -> engine-id set result: ~p~n", [?MODULE,R]),
+ snmp_verbosity:print(info, info, "init_usm -> engine-id set result: ~p", [R]),
+ ?vlog("init_usm -> try set engine boots (framework-mib)", []),
snmp_framework_mib:set_engine_boots(1),
+ ?vlog("init_usm -> try set engine time (framework-mib)", []),
snmp_framework_mib:set_engine_time(1),
- snmp_user_based_sm_mib:reconfigure(Dir);
+ ?vlog("init_usm -> try usm (mib) reconfigure", []),
+ snmp_user_based_sm_mib:reconfigure(Dir),
+ ?vlog("init_usm -> done", []),
+ ok;
init_usm(_Vsn, _Dir) ->
ok.
+ensure_local_db_dead() ->
+ ensure_dead(whereis(snmpa_local_db), 2000).
+
+ensure_dead(Pid, Timeout) when is_pid(Pid) ->
+ MRef = erlang:monitor(process, Pid),
+ try
+ begin
+ ensure_dead_wait(Pid, MRef, Timeout),
+ ensure_dead_stop(Pid, MRef, Timeout),
+ ensure_dead_kill(Pid, MRef, Timeout),
+ exit(failed_stop_local_db)
+ end
+ catch
+ throw:ok ->
+ ok
+ end;
+ensure_dead(_, _) ->
+ ?vlog("ensure_dead -> already dead", []),
+ ok.
+
+ensure_dead_wait(Pid, MRef, Timeout) ->
+ receive
+ {'DOWN', MRef, process, Pid, _Info} ->
+ ?vlog("ensure_dead_wait -> died peacefully", []),
+ throw(ok)
+ after Timeout ->
+ ?vlog("ensure_dead_wait -> giving up", []),
+ ok
+ end.
+
+ensure_dead_stop(Pid, MRef, Timeout) ->
+ StopPid = spawn(fun() -> snmpa_local_db:stop() end),
+ receive
+ {'DOWN', MRef, process, Pid, _Info} ->
+ ?vlog("ensure_dead -> dead (stopped)", []),
+ throw(ok)
+ after Timeout ->
+ ?vlog("ensure_dead_stop -> giving up", []),
+ exit(StopPid, kill),
+ ok
+ end.
+
+ensure_dead_kill(Pid, MRef, Timeout) ->
+ exit(Pid, kill),
+ receive
+ {'DOWN', MRef, process, Pid, _Info} ->
+ ?vlog("ensure_dead -> dead (killed)", []),
+ throw(ok)
+ after Timeout ->
+ ?vlog("ensure_dead_kill -> giving up", []),
+ ok
+ end.
+
+
display_incomming_message(M) ->
display_message("Incomming",M).
@@ -775,20 +881,20 @@ display_prop_hdr(S) ->
%%----------------------------------------------------------------------
sz(L) when is_list(L) ->
- length(lists:flatten(L));
+ iolist_size(L);
sz(B) when is_binary(B) ->
size(B);
sz(O) ->
{unknown_size, O}.
d(F) -> d(F, []).
-d(F,A) -> d(get(debug),F,A).
+d(F,A) -> d(get(debug), F, A).
-d(true,F,A) ->
- io:format("*** [~s] MGR_PS_DBG *** " ++ F ++ "~n",
- [formated_timestamp()|A]);
+d(true, F, A) ->
+ print(F, A);
d(_,_F,_A) ->
ok.
-formated_timestamp() ->
- snmp_test_lib:formated_timestamp().
+print(F, A) ->
+ ?PRINT2("MGR_PS " ++ F, A).
+
diff --git a/lib/snmp/test/snmp_test_server.erl b/lib/snmp/test/snmp_test_server.erl
index a77bdc142c..ab7dbbbaa0 100644
--- a/lib/snmp/test/snmp_test_server.erl
+++ b/lib/snmp/test/snmp_test_server.erl
@@ -207,7 +207,7 @@ do_subcases(Mod, Fun, [{conf, Init, Cases, Finish}|SubCases], Config, Acc)
[{failed, {Mod, Fun}, Error}]
end,
do_subcases(Mod, Fun, SubCases, Config, [R|Acc]);
-do_subcases(Mod, Fun, [SubCase|SubCases], Config, Acc) when atom(SubCase) ->
+do_subcases(Mod, Fun, [SubCase|SubCases], Config, Acc) when is_atom(SubCase) ->
R = do_case(Mod, SubCase, Config),
do_subcases(Mod, Fun, SubCases,Config, [R|Acc]).
@@ -407,7 +407,7 @@ d(_, _, _, _) ->
ok.
timestamp() ->
- {Date, Time} = calendar:now_to_datetime( now() ),
+ {Date, Time} = calendar:now_to_datetime( erlang:timestamp() ),
{YYYY, MM, DD} = Date,
{Hour, Min, Sec} = Time,
FormatDate =
diff --git a/lib/snmp/test/snmp_test_sys_monitor.erl b/lib/snmp/test/snmp_test_sys_monitor.erl
new file mode 100644
index 0000000000..2291c6ca97
--- /dev/null
+++ b/lib/snmp/test/snmp_test_sys_monitor.erl
@@ -0,0 +1,86 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(snmp_test_sys_monitor).
+
+-export([start/0, stop/0,
+ init/1]).
+
+-define(NAME, ?MODULE).
+-define(GSM, snmp_test_global_sys_monitor).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+start() ->
+ Parent = self(),
+ proc_lib:start(?MODULE, init, [Parent]).
+
+stop() ->
+ case whereis(?NAME) of
+ Pid when is_pid(Pid) ->
+ Pid ! {?MODULE, stop},
+ ok;
+ _ ->
+ ok
+ end.
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+init(Parent) ->
+ process_flag(priority, high),
+ try register(?NAME, self()) of
+ true ->
+ global:sync(),
+ MonSettings = [
+ busy_port,
+ busy_dist_port,
+ {long_gc, 1000},
+ {long_schedule, 1000},
+ {large_heap, 8*1024*1024} % 8 MB
+ ],
+ erlang:system_monitor(self(), MonSettings),
+ ?GSM:log({erlang:timestamp(), starting}),
+ proc_lib:init_ack(Parent, {ok, self()}),
+ loop(#{parent => Parent})
+ catch
+ _:_:_ ->
+ ?GSM:log({erlang:timestamp(), already_started}),
+ proc_lib:init_ack(Parent, {error, already_started}),
+ exit(normal)
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+loop(State) ->
+ receive
+ {monitor, Pid, Tag, Info} ->
+ ?GSM:log({Pid, erlang:timestamp(), Tag, Info}),
+ loop(State);
+
+ _ ->
+ loop(State)
+ end.
+
+
+
diff --git a/lib/snmp/test/snmp_to_snmpnet_SUITE.erl b/lib/snmp/test/snmp_to_snmpnet_SUITE.erl
index b83c7461d1..b8bdb30271 100644
--- a/lib/snmp/test/snmp_to_snmpnet_SUITE.erl
+++ b/lib/snmp/test/snmp_to_snmpnet_SUITE.erl
@@ -247,9 +247,17 @@ erlang_agent_netsnmp_get(Config) when is_list(Config) ->
start_agent(Config),
Oid = ?sysDescr_instance,
Expected = expected(Oid, get),
- [Expected = snmpget(Oid, Transport, Config)
- || Transport <- Transports],
- ok.
+ try
+ begin
+ [Expected = snmpget(Oid, Transport, Config)
+ || Transport <- Transports],
+ ok
+ end
+ catch
+ throw:{skip, _} = SKIP ->
+ SKIP
+ end.
+
%%--------------------------------------------------------------------
erlang_manager_netsnmp_get() ->
@@ -260,29 +268,34 @@ erlang_manager_netsnmp_get(Config) when is_list(Config) ->
SysDescr = "Net-SNMP agent",
TargetName = "Target Net-SNMP agent",
Transports = ?config(transports, Config),
- ProgHandle = start_snmpd(Community, SysDescr, Config),
- start_manager(Config),
- snmp_manager_user:start_link(self(), test_user),
- [snmp_manager_user:register_agent(
- TargetName++domain_suffix(Domain),
- [{reg_type, target_name},
- {tdomain, Domain}, {taddress, Addr},
- {community, Community}, {engine_id, "EngineId"},
- {version, v2}, {sec_model, v2c}, {sec_level, noAuthNoPriv}])
- || {Domain, Addr} <- Transports],
- Results =
- [snmp_manager_user:sync_get(
- TargetName++domain_suffix(Domain),
- [?sysDescr_instance])
- || {Domain, _} <- Transports],
- ct:pal("sync_get -> ~p", [Results]),
- snmp_manager_user:stop(),
- stop_program(ProgHandle),
- [{ok,
- {noError, 0,
- [{varbind, ?sysDescr_instance, 'OCTET STRING', SysDescr,1}] },
- _} = R || R <- Results],
- ok.
+ case start_snmpd(Community, SysDescr, Config) of
+ {skip, _} = SKIP ->
+ SKIP;
+ ProgHandle ->
+ start_manager(Config),
+ snmp_manager_user:start_link(self(), test_user),
+ [snmp_manager_user:register_agent(
+ TargetName++domain_suffix(Domain),
+ [{reg_type, target_name},
+ {tdomain, Domain}, {taddress, Addr},
+ {community, Community}, {engine_id, "EngineId"},
+ {version, v2}, {sec_model, v2c}, {sec_level, noAuthNoPriv}])
+ || {Domain, Addr} <- Transports],
+ Results =
+ [snmp_manager_user:sync_get(
+ TargetName++domain_suffix(Domain),
+ [?sysDescr_instance])
+ || {Domain, _} <- Transports],
+ ct:pal("sync_get -> ~p", [Results]),
+ snmp_manager_user:stop(),
+ stop_program(ProgHandle),
+ [{ok,
+ {noError, 0,
+ [{varbind, ?sysDescr_instance, 'OCTET STRING', SysDescr,1}] },
+ _} = R || R <- Results],
+ ok
+ end.
+
%%--------------------------------------------------------------------
erlang_agent_netsnmp_inform(Config) when is_list(Config) ->
@@ -292,17 +305,19 @@ erlang_agent_netsnmp_inform(Config) when is_list(Config) ->
start_agent(Config),
ok = snmpa:load_mib(snmp_master_agent, filename:join(DataDir, Mib)),
- ProgHandle = start_snmptrapd(Mib, Config),
-
- snmpa:send_notification(
- snmp_master_agent, testTrapv22, {erlang_agent_test, self()}),
-
- receive
- {snmp_targets, erlang_agent_test, Addresses} ->
- ct:pal("Notification sent to: ~p~n", [Addresses]),
- erlang_agent_netsnmp_inform_responses(Addresses)
- end,
- stop_program(ProgHandle).
+ case start_snmptrapd(Mib, Config) of
+ {skip, _} = SKIP ->
+ SKIP;
+ ProgHandle ->
+ snmpa:send_notification(
+ snmp_master_agent, testTrapv22, {erlang_agent_test, self()}),
+ receive
+ {snmp_targets, erlang_agent_test, Addresses} ->
+ ct:pal("Notification sent to: ~p~n", [Addresses]),
+ erlang_agent_netsnmp_inform_responses(Addresses)
+ end,
+ stop_program(ProgHandle)
+ end.
erlang_agent_netsnmp_inform_responses([]) ->
receive
@@ -326,6 +341,7 @@ erlang_agent_netsnmp_inform_responses([Address | Addresses]) ->
%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
+
snmpget(Oid, Transport, Config) ->
Versions = ?config(snmp_versions, Config),
@@ -335,10 +351,14 @@ snmpget(Oid, Transport, Config) ->
"-Cf",
net_snmp_addr_str(Transport),
oid_str(Oid)],
- ProgHandle = start_program(snmpget, Args, none, Config),
- {_, line, Line} = get_program_output(ProgHandle),
- stop_program(ProgHandle),
- Line.
+ case start_program(snmpget, Args, none, Config) of
+ {skip, _} = SKIP ->
+ throw(SKIP);
+ ProgHandle ->
+ {_, line, Line} = get_program_output(ProgHandle),
+ stop_program(ProgHandle),
+ Line
+ end.
start_snmptrapd(Mibs, Config) ->
DataDir = ?config(data_dir, Config),
@@ -382,12 +402,13 @@ start_program(Prog, Args, StartCheckMP, Config) ->
DataDir = ?config(data_dir, Config),
StartWrapper = filename:join(DataDir, "start_stop_wrapper"),
Parent = self(),
- Pid =
- spawn_link(
+ %% process_flag(trap_exit, true),
+ {Pid, Mon} =
+ spawn_monitor(
fun () ->
run_program(Parent, StartWrapper, [Path | Args])
end),
- start_check(Pid, erlang:monitor(process, Pid), StartCheckMP).
+ start_check(Pid, Mon, StartCheckMP).
start_check(Pid, Mon, none) ->
{Pid, Mon};
@@ -400,6 +421,10 @@ start_check(Pid, Mon, StartCheckMP) ->
nomatch ->
start_check(Pid, Mon, StartCheckMP)
end;
+ {'DOWN', Mon, _, _Pid, {skip, Reason} = SKIP} ->
+ ct:pal("Received DOWN from ~p"
+ "~n Skip Reason: ~p", [_Pid, Reason]),
+ SKIP;
{'DOWN', Mon, _, _, Reason} ->
ct:fail("Prog ~p start failed: ~p", [Pid, Reason])
end.
@@ -446,14 +471,34 @@ run_program_loop(Parent, Port, Buf) ->
{Port, {data, {Flag, Data}}} ->
case Flag of
eol ->
- Line = iolist_to_binary(lists:reverse(Buf, Data)),
- ct:pal("Prog ~p output: ~s", [Port, Line]),
- Parent ! {self(), line, Line},
- run_program_loop(Parent, Port, []);
+ Line = iolist_to_binary(lists:reverse(Buf, Data)),
+ ct:pal("Prog ~p output: ~s", [Port, Line]),
+ %% There are potentially many different fail outputs,
+ %% but for now we test for just this one: illegal option
+ IOpt = "illegal option",
+ case string:find(binary_to_list(Line), IOpt) of
+ nomatch ->
+ Parent ! {self(), line, Line},
+ run_program_loop(Parent, Port, []);
+ Line2 ->
+ %% Try to extract the actual illegal option string
+ IOpt2 =
+ case string:take(
+ string:prefix(Line2, IOpt), [$-, $ ]) of
+ {_, Str} when length(Str) > 0 ->
+ Str;
+ _X ->
+ Line2
+ end,
+ ct:pal("Force program ~p stop", [Port]),
+ true = port_command(Port, <<"stop\n">>),
+ (catch port_close(Port)),
+ exit({skip, {illegal_option, IOpt2}})
+ end;
noeol ->
run_program_loop(Parent, Port, [Data | Buf])
end;
- {Port, {exit_status,ExitStatus}} ->
+ {Port, {exit_status, ExitStatus}} ->
ct:pal("Prog ~p exit: ~p", [Port, ExitStatus]),
catch port_close(Port),
Parent ! {self(), exit, ExitStatus};
diff --git a/lib/snmp/test/test-mibs/ALARM-MIB.mib b/lib/snmp/test/test-mibs/ALARM-MIB.mib
index 18e43d4b4b..10d2adbff9 100644
--- a/lib/snmp/test/test-mibs/ALARM-MIB.mib
+++ b/lib/snmp/test/test-mibs/ALARM-MIB.mib
@@ -330,7 +330,7 @@ alarmModelRowStatus OBJECT-TYPE
cannot be used as an alarm suppression mechanism. Entries
that are notInService will disappear as described in RFC2579.
- This row can not be modified while it is being
+ This row cannot be modified while it is being
referenced by a value of alarmActiveModelPointer. In these
cases, an error of `inconsistentValue' will be returned to
the manager.
diff --git a/lib/snmp/test/test-mibs/SNMPv2-TC.mib b/lib/snmp/test/test-mibs/SNMPv2-TC.mib
index fd6a728ab5..1d75c4bbd8 100644
--- a/lib/snmp/test/test-mibs/SNMPv2-TC.mib
+++ b/lib/snmp/test/test-mibs/SNMPv2-TC.mib
@@ -454,7 +454,7 @@ value | | see 1| ->C| ->D
associated with this column or that there is no
conceptual row for which this column would be
accessible in the MIB view used by the retrieval. As
- such, the management station can not issue any
+ such, the management station cannot issue any
management protocol set operations to create an
instance of this column.
@@ -576,7 +576,7 @@ value | | see 1| ->C| ->D
associated with this column or that there is no
conceptual row for which this column would be
accessible in the MIB view used by the retrieval. As
- such, the management station can not issue any
+ such, the management station cannot issue any
management protocol set operations to create an
instance of this column.
diff --git a/lib/snmp/vsn.mk b/lib/snmp/vsn.mk
index 4d5a0fbce8..f305497cd3 100644
--- a/lib/snmp/vsn.mk
+++ b/lib/snmp/vsn.mk
@@ -19,6 +19,6 @@
# %CopyrightEnd%
APPLICATION = snmp
-SNMP_VSN = 5.2.12
+SNMP_VSN = 5.3
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(SNMP_VSN)$(PRE_VSN)"