aboutsummaryrefslogtreecommitdiffstats
path: root/lib/snmp/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/snmp/src')
-rw-r--r--lib/snmp/src/Makefile23
-rw-r--r--lib/snmp/src/agent/Makefile37
-rw-r--r--lib/snmp/src/agent/depend.mk43
-rw-r--r--lib/snmp/src/agent/modules.mk37
-rw-r--r--lib/snmp/src/agent/snmp_community_mib.erl114
-rw-r--r--lib/snmp/src/agent/snmp_framework_mib.erl145
-rw-r--r--lib/snmp/src/agent/snmp_generic.erl51
-rw-r--r--lib/snmp/src/agent/snmp_generic_mnesia.erl23
-rw-r--r--lib/snmp/src/agent/snmp_index.erl23
-rw-r--r--lib/snmp/src/agent/snmp_notification_mib.erl48
-rw-r--r--lib/snmp/src/agent/snmp_shadow_table.erl30
-rw-r--r--lib/snmp/src/agent/snmp_standard_mib.erl59
-rw-r--r--lib/snmp/src/agent/snmp_target_mib.erl295
-rw-r--r--lib/snmp/src/agent/snmp_user_based_sm_mib.erl289
-rw-r--r--lib/snmp/src/agent/snmp_view_based_acm_mib.erl298
-rw-r--r--lib/snmp/src/agent/snmpa.erl326
-rw-r--r--lib/snmp/src/agent/snmpa_acm.erl27
-rw-r--r--lib/snmp/src/agent/snmpa_agent.erl259
-rw-r--r--lib/snmp/src/agent/snmpa_agent_sup.erl33
-rw-r--r--lib/snmp/src/agent/snmpa_app.erl23
-rw-r--r--lib/snmp/src/agent/snmpa_atl.hrl23
-rw-r--r--lib/snmp/src/agent/snmpa_authentication_service.erl23
-rw-r--r--lib/snmp/src/agent/snmpa_conf.erl634
-rw-r--r--lib/snmp/src/agent/snmpa_discovery_handler.erl23
-rw-r--r--lib/snmp/src/agent/snmpa_discovery_handler_default.erl23
-rw-r--r--lib/snmp/src/agent/snmpa_error.erl23
-rw-r--r--lib/snmp/src/agent/snmpa_error_io.erl23
-rw-r--r--lib/snmp/src/agent/snmpa_error_logger.erl23
-rw-r--r--lib/snmp/src/agent/snmpa_error_report.erl23
-rw-r--r--lib/snmp/src/agent/snmpa_general_db.erl21
-rw-r--r--lib/snmp/src/agent/snmpa_internal.hrl21
-rw-r--r--lib/snmp/src/agent/snmpa_local_db.erl37
-rw-r--r--lib/snmp/src/agent/snmpa_mib.erl273
-rw-r--r--lib/snmp/src/agent/snmpa_mib_data.erl1395
-rw-r--r--lib/snmp/src/agent/snmpa_mib_data_ttln.erl1403
-rw-r--r--lib/snmp/src/agent/snmpa_mib_data_tttn.erl1444
-rw-r--r--lib/snmp/src/agent/snmpa_mib_lib.erl23
-rw-r--r--lib/snmp/src/agent/snmpa_mib_storage.erl182
-rw-r--r--lib/snmp/src/agent/snmpa_mib_storage_dets.erl310
-rw-r--r--lib/snmp/src/agent/snmpa_mib_storage_ets.erl342
-rw-r--r--lib/snmp/src/agent/snmpa_mib_storage_mnesia.erl303
-rw-r--r--lib/snmp/src/agent/snmpa_misc_sup.erl23
-rw-r--r--lib/snmp/src/agent/snmpa_mpd.erl160
-rw-r--r--lib/snmp/src/agent/snmpa_net_if.erl1328
-rw-r--r--lib/snmp/src/agent/snmpa_net_if_filter.erl77
-rw-r--r--lib/snmp/src/agent/snmpa_network_interface.erl23
-rw-r--r--lib/snmp/src/agent/snmpa_network_interface_filter.erl34
-rw-r--r--lib/snmp/src/agent/snmpa_notification_delivery_info_receiver.erl23
-rw-r--r--lib/snmp/src/agent/snmpa_notification_filter.erl23
-rw-r--r--lib/snmp/src/agent/snmpa_set.erl23
-rw-r--r--lib/snmp/src/agent/snmpa_set_lib.erl98
-rw-r--r--lib/snmp/src/agent/snmpa_set_mechanism.erl23
-rw-r--r--lib/snmp/src/agent/snmpa_supervisor.erl130
-rw-r--r--lib/snmp/src/agent/snmpa_svbl.erl23
-rw-r--r--lib/snmp/src/agent/snmpa_symbolic_store.erl312
-rw-r--r--lib/snmp/src/agent/snmpa_target_cache.erl60
-rw-r--r--lib/snmp/src/agent/snmpa_trap.erl191
-rw-r--r--lib/snmp/src/agent/snmpa_usm.erl39
-rw-r--r--lib/snmp/src/agent/snmpa_vacm.erl30
-rw-r--r--lib/snmp/src/agent/snmpa_vacm.hrl23
-rw-r--r--lib/snmp/src/app/Makefile43
-rw-r--r--lib/snmp/src/app/depend.mk23
-rw-r--r--lib/snmp/src/app/modules.mk23
-rw-r--r--lib/snmp/src/app/snmp.app.src46
-rw-r--r--lib/snmp/src/app/snmp.appup.src395
-rw-r--r--lib/snmp/src/app/snmp.erl233
-rw-r--r--lib/snmp/src/app/snmp_app.erl37
-rw-r--r--lib/snmp/src/app/snmp_app_sup.erl23
-rw-r--r--lib/snmp/src/app/snmp_internal.hrl25
-rw-r--r--lib/snmp/src/compile/Makefile37
-rw-r--r--lib/snmp/src/compile/depend.mk27
-rw-r--r--lib/snmp/src/compile/modules.mk23
-rw-r--r--lib/snmp/src/compile/snmpc.erl106
-rw-r--r--lib/snmp/src/compile/snmpc.hrl23
-rw-r--r--lib/snmp/src/compile/snmpc.src36
-rw-r--r--lib/snmp/src/compile/snmpc_lib.erl94
-rw-r--r--lib/snmp/src/compile/snmpc_lib.hrl23
-rw-r--r--lib/snmp/src/compile/snmpc_mib_gram.yrl73
-rw-r--r--lib/snmp/src/compile/snmpc_mib_to_hrl.erl23
-rw-r--r--lib/snmp/src/compile/snmpc_misc.erl43
-rw-r--r--lib/snmp/src/compile/snmpc_misc.hrl23
-rw-r--r--lib/snmp/src/compile/snmpc_tok.erl23
-rw-r--r--lib/snmp/src/manager/Makefile37
-rw-r--r--lib/snmp/src/manager/depend.mk31
-rw-r--r--lib/snmp/src/manager/modules.mk24
-rw-r--r--lib/snmp/src/manager/snmpm.erl921
-rw-r--r--lib/snmp/src/manager/snmpm_atl.hrl23
-rw-r--r--lib/snmp/src/manager/snmpm_conf.erl276
-rw-r--r--lib/snmp/src/manager/snmpm_config.erl1374
-rw-r--r--lib/snmp/src/manager/snmpm_internal.hrl23
-rw-r--r--lib/snmp/src/manager/snmpm_misc_sup.erl23
-rw-r--r--lib/snmp/src/manager/snmpm_mpd.erl109
-rw-r--r--lib/snmp/src/manager/snmpm_net_if.erl1059
-rw-r--r--lib/snmp/src/manager/snmpm_net_if_filter.erl81
-rw-r--r--lib/snmp/src/manager/snmpm_net_if_mt.erl24
-rw-r--r--lib/snmp/src/manager/snmpm_network_interface.erl23
-rw-r--r--lib/snmp/src/manager/snmpm_network_interface_filter.erl23
-rw-r--r--lib/snmp/src/manager/snmpm_server.erl1025
-rw-r--r--lib/snmp/src/manager/snmpm_server_sup.erl23
-rw-r--r--lib/snmp/src/manager/snmpm_supervisor.erl23
-rw-r--r--lib/snmp/src/manager/snmpm_user.erl199
-rw-r--r--lib/snmp/src/manager/snmpm_user_default.erl41
-rw-r--r--lib/snmp/src/manager/snmpm_user_old.erl23
-rw-r--r--lib/snmp/src/manager/snmpm_usm.erl35
-rw-r--r--lib/snmp/src/manager/snmpm_usm.hrl23
-rw-r--r--lib/snmp/src/misc/Makefile37
-rw-r--r--lib/snmp/src/misc/depend.mk23
-rw-r--r--lib/snmp/src/misc/modules.mk23
-rw-r--r--lib/snmp/src/misc/snmp_conf.erl796
-rw-r--r--lib/snmp/src/misc/snmp_config.erl774
-rw-r--r--lib/snmp/src/misc/snmp_debug.hrl23
-rw-r--r--lib/snmp/src/misc/snmp_log.erl512
-rw-r--r--lib/snmp/src/misc/snmp_mini_mib.erl23
-rw-r--r--lib/snmp/src/misc/snmp_misc.erl61
-rw-r--r--lib/snmp/src/misc/snmp_note_store.erl23
-rw-r--r--lib/snmp/src/misc/snmp_pdus.erl135
-rw-r--r--lib/snmp/src/misc/snmp_usm.erl85
-rw-r--r--lib/snmp/src/misc/snmp_verbosity.erl32
-rw-r--r--lib/snmp/src/misc/snmp_verbosity.hrl23
-rw-r--r--lib/snmp/src/subdirs.mk23
120 files changed, 12860 insertions, 7976 deletions
diff --git a/lib/snmp/src/Makefile b/lib/snmp/src/Makefile
index 341107ce30..39ea5f74db 100644
--- a/lib/snmp/src/Makefile
+++ b/lib/snmp/src/Makefile
@@ -2,18 +2,19 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2009. All Rights Reserved.
+# Copyright Ericsson AB 2004-2016. All Rights Reserved.
#
-# The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved online at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
+# 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%
diff --git a/lib/snmp/src/agent/Makefile b/lib/snmp/src/agent/Makefile
index a67fe4d17c..2943a4d550 100644
--- a/lib/snmp/src/agent/Makefile
+++ b/lib/snmp/src/agent/Makefile
@@ -2,18 +2,19 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2009. All Rights Reserved.
+# Copyright Ericsson AB 1996-2016. All Rights Reserved.
#
-# The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved online at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
+# 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%
@@ -128,14 +129,14 @@ info:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/src/agent
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)/src/agent
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src/agent"
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)/src/agent"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
$(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) \
- $(RELSYSDIR)/ebin
-# $(INSTALL_DIR) $(RELSYSDIR)/include
-# $(INSTALL_DATA) $(EXT_HRL_FILES) $(RELSYSDIR)/include
+ "$(RELSYSDIR)/ebin"
+# $(INSTALL_DIR) "$(RELSYSDIR)/include"
+# $(INSTALL_DATA) $(EXT_HRL_FILES) "$(RELSYSDIR)/include"
release_docs_spec:
diff --git a/lib/snmp/src/agent/depend.mk b/lib/snmp/src/agent/depend.mk
index 078ef15821..8eba50fa3b 100644
--- a/lib/snmp/src/agent/depend.mk
+++ b/lib/snmp/src/agent/depend.mk
@@ -2,18 +2,19 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2009. All Rights Reserved.
+# Copyright Ericsson AB 2004-2016. All Rights Reserved.
#
-# The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved online at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
+# 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%
@@ -77,10 +78,6 @@ $(EBIN)/snmpa_error_logger.$(EMULATOR): \
snmpa_error_report.erl \
snmpa_error_logger.erl
-$(EBIN)/snmpa_general_db.$(EMULATOR): \
- snmpa_general_db.erl \
- ../misc/snmp_verbosity.hrl
-
$(EBIN)/snmpa_local_db.$(EMULATOR): \
snmpa_local_db.erl \
../misc/snmp_debug.hrl \
@@ -88,6 +85,18 @@ $(EBIN)/snmpa_local_db.$(EMULATOR): \
../../include/snmp_types.hrl \
../../include/STANDARD-MIB.hrl
+$(EBIN)/snmpa_mib_storage.$(EMULATOR): \
+ snmpa_mib_storage.erl
+
+$(EBIN)/snmpa_mib_storage_ets.$(EMULATOR): \
+ snmpa_mib_storage_ets.erl
+
+$(EBIN)/snmpa_mib_storage_dets.$(EMULATOR): \
+ snmpa_mib_storage_dets.erl
+
+$(EBIN)/snmpa_mib_storage_mnesia.$(EMULATOR): \
+ snmpa_mib_storage_mnesia.erl
+
$(EBIN)/snmpa_mib.$(EMULATOR): \
snmpa_mib.erl \
../misc/snmp_debug.hrl \
@@ -96,6 +105,10 @@ $(EBIN)/snmpa_mib.$(EMULATOR): \
$(EBIN)/snmpa_mib_data.$(EMULATOR): \
snmpa_mib_data.erl \
+ ../../include/snmp_types.hrl
+
+$(EBIN)/snmpa_mib_data_tttn.$(EMULATOR): \
+ snmpa_mib_data_tttn.erl \
../misc/snmp_debug.hrl \
../misc/snmp_verbosity.hrl \
../../include/snmp_types.hrl
diff --git a/lib/snmp/src/agent/modules.mk b/lib/snmp/src/agent/modules.mk
index 33ab41b434..0f8615588a 100644
--- a/lib/snmp/src/agent/modules.mk
+++ b/lib/snmp/src/agent/modules.mk
@@ -2,18 +2,19 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2009. All Rights Reserved.
+# Copyright Ericsson AB 2004-2016. All Rights Reserved.
#
-# The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved online at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
+# 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%
@@ -21,15 +22,21 @@ BEHAVIOUR_MODULES = \
snmpa_authentication_service \
snmpa_discovery_handler \
snmpa_error_report \
+ snmpa_mib_storage \
+ snmpa_mib_data \
snmpa_network_interface \
snmpa_network_interface_filter \
snmpa_notification_delivery_info_receiver \
snmpa_notification_filter \
snmpa_set_mechanism
+# 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...
+# snmpa_mib_data_ttln
MODULES = \
- $(BEHAVIOUR_MODULES) \
snmpa \
+ $(BEHAVIOUR_MODULES) \
snmpa_acm \
snmpa_agent \
snmpa_agent_sup \
@@ -39,10 +46,12 @@ MODULES = \
snmpa_error \
snmpa_error_io \
snmpa_error_logger \
- snmpa_general_db \
snmpa_local_db \
+ snmpa_mib_storage_ets \
+ snmpa_mib_storage_dets \
+ snmpa_mib_storage_mnesia \
snmpa_mib \
- snmpa_mib_data \
+ snmpa_mib_data_tttn \
snmpa_mib_lib \
snmpa_misc_sup \
snmpa_mpd \
diff --git a/lib/snmp/src/agent/snmp_community_mib.erl b/lib/snmp/src/agent/snmp_community_mib.erl
index 77307aa7ad..9fd7b30f9f 100644
--- a/lib/snmp/src/agent/snmp_community_mib.erl
+++ b/lib/snmp/src/agent/snmp_community_mib.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -28,8 +29,10 @@
-export([add_community/5, add_community/6, delete_community/1]).
-export([check_community/1]).
+-include("snmpa_internal.hrl").
-include("SNMP-COMMUNITY-MIB.hrl").
-include("SNMP-TARGET-MIB.hrl").
+-include("SNMPv2-TM.hrl").
-include("SNMPv2-TC.hrl").
-include("snmp_types.hrl").
@@ -120,11 +123,19 @@ init_tabs(Comms) ->
read_community_config_files(Dir) ->
?vdebug("read community config file",[]),
- Gen = fun(_) -> ok end,
- Filter = fun(Comms) -> Comms end,
- Check = fun(Entry) -> check_community(Entry) end,
- [Comms] =
- snmp_conf:read_files(Dir, [{Gen, Filter, Check, "community.conf"}]),
+ FileName = "community.conf",
+ Gen = fun(D, Reason) ->
+ warning_msg("failed reading config file ~s"
+ "~n Config Dir: ~s"
+ "~n Reason: ~p",
+ [FileName, D, Reason]),
+ ok
+ end,
+ Order = fun snmp_conf:no_order/2,
+ Filter = fun snmp_conf:no_filter/1,
+ Check = fun(Entry, State) -> {check_community(Entry), State} end,
+ [Comms] =
+ snmp_conf:read_files(Dir, [{FileName, Gen, Order, Check, Filter}]),
Comms.
check_community({Index, CommunityName, SecName, CtxName, TransportTag}) ->
@@ -184,7 +195,7 @@ add_community(Idx, CommName, SecName, EngineId, CtxName, TransportTag) ->
do_add_community(Community).
do_add_community(Community) ->
- case (catch check_community(Community)) of
+ try check_community(Community) of
{ok, Row} ->
Key = element(1, Row),
case table_cre_row(snmpCommunityTable, Key, Row) of
@@ -193,11 +204,12 @@ do_add_community(Community) ->
{ok, Key};
false ->
{error, create_failed}
- end;
+ end
+ catch
{error, Reason} ->
{error, Reason};
- Error ->
- {error, Error}
+ Class:Reason ->
+ {error, {Class, Reason, erlang:get_stacktrace()}}
end.
%% FIXME: does not work with mnesia
@@ -235,6 +247,10 @@ gc_tabs() ->
%%-----------------------------------------------------------------
community2vacm(Community, Addr) ->
Idxs = ets:lookup(snmp_community_cache, Community),
+ ?vtrace("community2vacm ->~n"
+ " Community: ~p~n"
+ " Addr: ~p~n"
+ " Idxs: ~p", [Community, Addr, Idxs]),
loop_c2v_rows(lists:keysort(2, Idxs), Addr).
loop_c2v_rows([{_, CommunityIndex} | T], Addr) ->
@@ -242,6 +258,9 @@ loop_c2v_rows([{_, CommunityIndex} | T], Addr) ->
"~n CommunityIndex: ~p", [CommunityIndex]),
case get_row(CommunityIndex) of
{_Community, VacmParams, Tag} ->
+ ?vtrace("loop_c2v_rows ->~n"
+ " VacmParams: ~p~n"
+ " Tag: ~p", [VacmParams, Tag]),
{TDomain, TAddr} = Addr,
case snmp_target_mib:is_valid_tag(Tag, TDomain, TAddr) of
true ->
@@ -498,7 +517,12 @@ snmpTargetAddrExtTable(get_next, RowIndex, Cols) ->
NCols = conv1(Cols),
conv2(next(snmpTargetAddrExtTable, RowIndex, NCols));
snmpTargetAddrExtTable(set, RowIndex, Cols0) ->
- case (catch verify_snmpTargetAddrExtTable_cols(Cols0, [])) of
+ case
+ (catch verify_snmpTargetAddrExtTable_cols(
+ Cols0,
+ get_snmpTargetAddrTDomain(RowIndex, Cols0),
+ []))
+ of
{ok, Cols} ->
NCols = conv3(Cols),
snmp_generic:table_func(set, RowIndex, NCols,
@@ -507,7 +531,11 @@ snmpTargetAddrExtTable(set, RowIndex, Cols0) ->
Error
end;
snmpTargetAddrExtTable(is_set_ok, RowIndex, Cols0) ->
- case (catch verify_snmpTargetAddrExtTable_cols(Cols0, [])) of
+ case (catch verify_snmpTargetAddrExtTable_cols(
+ Cols0,
+ get_snmpTargetAddrTDomain(RowIndex, Cols0),
+ []))
+ of
{ok, Cols} ->
NCols = conv3(Cols),
snmp_generic:table_func(is_set_ok, RowIndex, NCols,
@@ -517,29 +545,49 @@ snmpTargetAddrExtTable(is_set_ok, RowIndex, Cols0) ->
end.
-verify_snmpTargetAddrExtTable_cols([], Cols) ->
+
+get_snmpTargetAddrTDomain(RowIndex, Col) ->
+ case
+ get(
+ snmpTargetAddrTable, RowIndex,
+ [?snmpTargetAddrRowStatus,?snmpTargetAddrTDomain])
+ of
+ [{value,?snmpTargetAddrRowStatus_active},ValueTDomain] ->
+ case ValueTDomain of
+ {value,TDomain} ->
+ TDomain;
+ _ ->
+ ?snmpUDPDomain
+ end;
+ _ ->
+ wrongValue(Col)
+ end.
+
+
+
+verify_snmpTargetAddrExtTable_cols([], _TDomain, Cols) ->
{ok, lists:reverse(Cols)};
-verify_snmpTargetAddrExtTable_cols([{Col, Val0}|Cols], Acc) ->
- Val = verify_snmpTargetAddrExtTable_col(Col, Val0),
- verify_snmpTargetAddrExtTable_cols(Cols, [{Col, Val}|Acc]).
+verify_snmpTargetAddrExtTable_cols([{Col, Val0}|Cols], TDomain, Acc) ->
+ Val = verify_snmpTargetAddrExtTable_col(Col, TDomain, Val0),
+ verify_snmpTargetAddrExtTable_cols(Cols, TDomain, [{Col, Val}|Acc]).
-verify_snmpTargetAddrExtTable_col(?snmpTargetAddrTMask, []) ->
+verify_snmpTargetAddrExtTable_col(?snmpTargetAddrTMask, _TDomain, []) ->
[];
-verify_snmpTargetAddrExtTable_col(?snmpTargetAddrTMask, TMask) ->
- case (catch snmp_conf:check_taddress(TMask)) of
+verify_snmpTargetAddrExtTable_col(?snmpTargetAddrTMask, TDomain, TMask) ->
+ case (catch snmp_conf:check_taddress(TDomain, TMask)) of
ok ->
TMask;
_ ->
wrongValue(?snmpTargetAddrTMask)
end;
-verify_snmpTargetAddrExtTable_col(?snmpTargetAddrMMS, MMS) ->
+verify_snmpTargetAddrExtTable_col(?snmpTargetAddrMMS, _TDomain, MMS) ->
case (catch snmp_conf:check_packet_size(MMS)) of
ok ->
MMS;
_ ->
wrongValue(?snmpTargetAddrMMS)
end;
-verify_snmpTargetAddrExtTable_col(_, Val) ->
+verify_snmpTargetAddrExtTable_col(_, _TDomain, Val) ->
Val.
db(snmpTargetAddrExtTable) -> db(snmpTargetAddrTable);
@@ -575,6 +623,7 @@ conv3([{Idx, Val}|T]) -> [{Idx+10, Val} | conv3(T)];
conv3([]) -> [].
+
get(Name, RowIndex, Cols) ->
snmp_generic:handle_table_get(db(Name), RowIndex, Cols, foi(Name)).
@@ -601,5 +650,8 @@ set_sname(_) -> %% Keep it, if already set.
error(Reason) ->
throw({error, Reason}).
+warning_msg(F, A) ->
+ ?snmpa_warning("[COMMUNITY-MIB]: " ++ F, A).
+
config_err(F, A) ->
snmpa_error:config_err("[COMMUNITY-MIB]: " ++ F, A).
diff --git a/lib/snmp/src/agent/snmp_framework_mib.erl b/lib/snmp/src/agent/snmp_framework_mib.erl
index 0d7866d94d..7ea4f0ed97 100644
--- a/lib/snmp/src/agent/snmp_framework_mib.erl
+++ b/lib/snmp/src/agent/snmp_framework_mib.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -41,6 +42,7 @@
-compile({no_auto_import,[error/1]}).
-export([init/0, configure/1]).
-export([intContextTable/1, intContextTable/3,
+ intAgentTransportDomain/1, intAgentTransports/1,
intAgentUDPPort/1, intAgentIpAddress/1,
snmpEngineID/1,
snmpEngineBoots/1,
@@ -51,7 +53,7 @@
set_engine_boots/1, set_engine_time/1,
table_next/2, check_status/3]).
-export([add_context/1, delete_context/1]).
--export([check_agent/1, check_context/1]).
+-export([check_agent/2, check_context/1, order_agent/2]).
%%-----------------------------------------------------------------
@@ -115,45 +117,46 @@ do_configure(Dir) ->
read_internal_config_files(Dir) ->
?vdebug("read context config file",[]),
- Gen = fun(D) -> convert_context(D) end,
- Filter = fun(Contexts) -> Contexts end,
- Check = fun(Entry) -> check_context(Entry) end,
- [Ctxs] = snmp_conf:read_files(Dir, [{Gen, Filter, Check, "context.conf"}]),
+ Gen = fun gen_context/2,
+ Order = fun snmp_conf:no_order/2,
+ Filter = fun snmp_conf:no_filter/1,
+ Check = fun(Entry, State) -> {check_context(Entry), State} end,
+ [Ctxs] =
+ snmp_conf:read_files
+ (Dir, [{"context.conf", Gen, Order, Check, Filter}]),
Ctxs.
-
read_agent(Dir) ->
- ?vdebug("read agent config file",[]),
- Check = fun(Entry) -> check_agent(Entry) end,
- File = filename:join(Dir, "agent.conf"),
- Agent = snmp_conf:read(File, Check),
- sort_agent(Agent).
-
-
-%%-----------------------------------------------------------------
-%% Make sure that each mandatory agent attribute is present, and
-%% provide default values for the other non-present attributes.
-%%-----------------------------------------------------------------
-sort_agent(L) ->
- Mand = [{intAgentIpAddress, mandatory},
- {intAgentUDPPort, mandatory},
- {snmpEngineMaxMessageSize, mandatory},
- {snmpEngineID, mandatory}],
- {ok, L2} = snmp_conf:check_mandatory(L, Mand),
- lists:keysort(1, L2).
+ ?vdebug("read agent config file", []),
+ FileName = "agent.conf",
+ File = filename:join(Dir, FileName),
+ Conf0 =
+ try
+ snmp_conf:read(File, fun order_agent/2, fun check_agent/2)
+ catch
+ throw:{error, Reason} ->
+ error({failed_reading_config_file, Dir, FileName, Reason})
+ end,
+ Mand =
+ [{intAgentTransports, mandatory},
+ {snmpEngineMaxMessageSize, mandatory},
+ {snmpEngineID, mandatory}],
+ {ok, Conf} = snmp_conf:check_mandatory(Conf0, Mand),
+ Conf.
%%-----------------------------------------------------------------
%% Generate a context.conf file.
%%-----------------------------------------------------------------
-convert_context(Dir) ->
+gen_context(Dir, _Reason) ->
config_err("missing context.conf file => generating a default file", []),
- File = filename:join(Dir,"context.conf"),
+ File = filename:join(Dir, "context.conf"),
case file:open(File, [write]) of
{ok, Fid} ->
ok = io:format(Fid, "~s\n", [context_header()]),
ok = io:format(Fid, "%% The default context\n\"\".\n", []),
- file:close(Fid);
+ file:close(Fid),
+ [];
{error, Reason} ->
file:delete(File),
error({failed_creating_file, File, Reason})
@@ -165,7 +168,7 @@ context_header() ->
io_lib:format("%% This file was automatically generated by "
"snmp_config v~s ~w-~2.2.0w-~2.2.0w "
"~2.2.0w:~2.2.0w:~2.2.0w\n",
- [?version,Y,Mo,D,H,Mi,S]).
+ [?version, Y, Mo, D, H, Mi, S]).
%%-----------------------------------------------------------------
@@ -187,10 +190,50 @@ check_context(Context) ->
%% Agent
%% {Name, Value}.
%%-----------------------------------------------------------------
-check_agent({intAgentIpAddress, Value}) ->
- snmp_conf:check_ip(Value);
-check_agent({intAgentUDPPort, Value}) ->
- snmp_conf:check_integer(Value);
+check_agent(Entry, undefined) ->
+ check_agent(Entry, {snmp_target_mib:default_domain(), undefined});
+check_agent({intAgentTransportDomain, Domain}, {_, Port}) ->
+ {snmp_conf:check_domain(Domain), {Domain, Port}};
+check_agent({intAgentUDPPort, Port}, {Domain, _}) ->
+ ok = snmp_conf:check_port(Port),
+ {ok, {Domain, Port}};
+check_agent({intAgentIpAddress, _}, {_, undefined}) ->
+ error({missing_mandatory, intAgentUDPPort});
+check_agent({intAgentIpAddress = Tag, Ip} = Entry, {Domain, Port} = State) ->
+ {case snmp_conf:check_ip(Domain, Ip) of
+ ok ->
+ [Entry,
+ {intAgentTransports, [{Domain, {Ip, Port}}]}];
+ {ok, FixedIp} ->
+ [{Tag, FixedIp},
+ {intAgentTransports, [{Domain, {FixedIp, Port}}]}]
+ end, State};
+check_agent({intAgentTransports = Tag, Transports}, {_, Port} = State)
+ when is_list(Transports) ->
+ CheckedTransports =
+ [case Transport of
+ {Domain, Address} ->
+ case
+ case Port of
+ undefined ->
+ snmp_conf:check_address(Domain, Address);
+ _ ->
+ snmp_conf:check_address(Domain, Address, Port)
+ end
+ of
+ ok ->
+ Transport;
+ {ok, FixedAddress} ->
+ {Domain, FixedAddress}
+ end;
+ _ ->
+ error({bad_transport, Transport})
+ end
+ || Transport <- Transports],
+ {{ok, {Tag, CheckedTransports}}, State};
+check_agent(Entry, State) ->
+ {check_agent(Entry), State}.
+
%% This one is kept for backwards compatibility
check_agent({intAgentMaxPacketSize, Value}) ->
snmp_conf:check_packet_size(Value);
@@ -201,6 +244,14 @@ check_agent({snmpEngineID, Value}) ->
check_agent(X) ->
error({invalid_agent_attribute, X}).
+%% Ordering function to sort intAgentTransportDomain first
+%% hence before intAgentIpAddress. Sort other entries on the key.
+order_agent(EntryA, EntryB) ->
+ snmp_conf:keyorder(
+ 1, EntryA, EntryB,
+ [intAgentTransportDomain, intAgentUDPPort | sort]).
+
+
maybe_create_table(Name) ->
case snmpa_local_db:table_exists(db(Name)) of
@@ -373,6 +424,14 @@ intAgentUDPPort(Op) ->
intAgentIpAddress(Op) ->
snmp_generic:variable_func(Op, db(intAgentIpAddress)).
+intAgentTransportDomain(Op) ->
+ snmp_generic:variable_func(Op, db(intAgentTransportDomain)).
+
+intAgentTransports(Op) ->
+ snmp_generic:variable_func(Op, db(intAgentTransports)).
+
+
+
snmpEngineID(print) ->
VarAndValue = [{snmpEngineID, snmpEngineID(get)}],
snmpa_mib_lib:print_variables(VarAndValue);
diff --git a/lib/snmp/src/agent/snmp_generic.erl b/lib/snmp/src/agent/snmp_generic.erl
index 06afa68d96..fc23e16ef1 100644
--- a/lib/snmp/src/agent/snmp_generic.erl
+++ b/lib/snmp/src/agent/snmp_generic.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -414,7 +415,12 @@ table_check_status(NameDb, Col, ?'RowStatus_createAndGo', RowIndex, Cols) ->
% side effect free and we only use the result temporary.
case catch snmpa_local_db:table_construct_row(
NameDb, RowIndex, ?'RowStatus_createAndGo', Cols) of
- {'EXIT', _} ->
+ {'EXIT', _Reason} ->
+ ?vtrace(
+ "failed construct row (createAndGo): "
+ " n Reason: ~p"
+ " n Stack: ~p",
+ [_Reason, erlang:get_stacktrace()]),
{noCreation, Col}; % Bad RowIndex
Row ->
case lists:member(noinit, tuple_to_list(Row)) of
@@ -431,7 +437,12 @@ table_check_status(NameDb, Col, ?'RowStatus_createAndWait', RowIndex, Cols) ->
false ->
case catch snmpa_local_db:table_construct_row(
NameDb, RowIndex, ?'RowStatus_createAndGo', Cols) of
- {'EXIT', _} ->
+ {'EXIT', _Reason} ->
+ ?vtrace(
+ "failed construct row (createAndWait): "
+ " n Reason: ~p"
+ " n Stack: ~p",
+ [_Reason, erlang:get_stacktrace()]),
{noCreation, Col}; % Bad RowIndex
_Row ->
{noError, 0}
@@ -711,7 +722,19 @@ find_col(Col, [_H | T]) -> find_col(Col, T).
try_apply(nofunc, _) -> {noError, 0};
-try_apply(F, Args) -> apply(F, Args).
+try_apply(F, Args) -> maybe_verbose_apply(F, Args).
+
+maybe_verbose_apply(M, Args) ->
+ case get(verbosity) of
+ false ->
+ apply(M, Args);
+ _ ->
+ ?vlog("~n apply: ~w,~p~n", [M,Args]),
+ Res = apply(M,Args),
+ ?vlog("~n returned: ~p", [Res]),
+ Res
+ end.
+
table_info({Name, _Db}) ->
case snmpa_symbolic_store:table_info(Name) of
diff --git a/lib/snmp/src/agent/snmp_generic_mnesia.erl b/lib/snmp/src/agent/snmp_generic_mnesia.erl
index ce42af404b..131b9b0368 100644
--- a/lib/snmp/src/agent/snmp_generic_mnesia.erl
+++ b/lib/snmp/src/agent/snmp_generic_mnesia.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
diff --git a/lib/snmp/src/agent/snmp_index.erl b/lib/snmp/src/agent/snmp_index.erl
index 1902fe2613..38b39a9b7e 100644
--- a/lib/snmp/src/agent/snmp_index.erl
+++ b/lib/snmp/src/agent/snmp_index.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
diff --git a/lib/snmp/src/agent/snmp_notification_mib.erl b/lib/snmp/src/agent/snmp_notification_mib.erl
index 720ac749b8..3f1ba5d8b3 100644
--- a/lib/snmp/src/agent/snmp_notification_mib.erl
+++ b/lib/snmp/src/agent/snmp_notification_mib.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -27,6 +28,7 @@
-export([add_notify/3, delete_notify/1]).
-export([check_notify/1]).
+-include("snmpa_internal.hrl").
-include("SNMP-NOTIFICATION-MIB.hrl").
-include("SNMPv2-TC.hrl").
-include("snmp_tables.hrl").
@@ -104,15 +106,24 @@ do_reconfigure(Dir) ->
read_notify_config_files(Dir) ->
?vdebug("read notify config file",[]),
- Gen = fun(_) -> ok end,
- Filter = fun(Notifs) -> Notifs end,
- Check = fun(Entry) -> check_notify(Entry) end,
+ FileName = "notify.conf",
+ Gen =
+ fun (D, Reason) ->
+ info_msg("failed reading config file ~s"
+ "~n Config Dir: ~s"
+ "~n Reason: ~p",
+ [FileName, D, Reason]),
+ ok
+ end,
+ Order = fun snmp_conf:no_order/2,
+ Filter = fun snmp_conf:no_filter/1,
+ Check = fun (Entry, State) -> {check_notify(Entry), State} end,
[Notifs] =
- snmp_conf:read_files(Dir, [{Gen, Filter, Check, "notify.conf"}]),
+ snmp_conf:read_files(Dir, [{FileName, Gen, Order, Check, Filter}]),
Notifs.
check_notify({Name, Tag, Type}) ->
- snmp_conf:check_string(Name,{gt,0}),
+ snmp_conf:check_string(Name, {gt, 0}),
snmp_conf:check_string(Tag),
{ok, Val} = snmp_conf:check_atom(Type, [{trap, 1}, {inform, 2}]),
Notify = {Name, Tag, Val,
@@ -451,12 +462,15 @@ set_sname() ->
set_sname(get(sname)).
set_sname(undefined) ->
- put(sname,conf);
+ put(sname, conf);
set_sname(_) -> %% Keep it, if already set.
ok.
error(Reason) ->
throw({error, Reason}).
+info_msg(F, A) ->
+ ?snmpa_info("[NOTIFICATION-MIB]: " ++ F, A).
+
config_err(F, A) ->
snmpa_error:config_err("[NOTIFICATION-MIB]: " ++ F, A).
diff --git a/lib/snmp/src/agent/snmp_shadow_table.erl b/lib/snmp/src/agent/snmp_shadow_table.erl
index 34543d542b..f9181f70a7 100644
--- a/lib/snmp/src/agent/snmp_shadow_table.erl
+++ b/lib/snmp/src/agent/snmp_shadow_table.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2015. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -76,7 +77,7 @@ delete_time_stamp_table() ->
end.
update(Name, UpdateFunc, Interval) ->
- CurrentTime = get_time(),
+ CurrentTime = snmp_misc:now(ms),
case mnesia:dirty_read({time_stamp, Name}) of
[#time_stamp{data = Expire}] when CurrentTime =< Expire -> ok;
_ ->
@@ -117,9 +118,6 @@ table_func(Op, RowIndex, Cols,
update(Name, UpdateFunc, Interval),
snmp_generic:table_func(Op, RowIndex, Cols, {Name, mnesia}).
-get_time() ->
- {M,S,U} = erlang:now(),
- 1000000000 * M + 1000 * S + (U div 1000).
%%-----------------------------------------------------------------
%% Urrk.
@@ -183,5 +181,3 @@ delete_table(Tab) ->
error_msg(F, A) ->
?snmpa_error(F, A).
-
-
diff --git a/lib/snmp/src/agent/snmp_standard_mib.erl b/lib/snmp/src/agent/snmp_standard_mib.erl
index b6834d278c..bfe471178d 100644
--- a/lib/snmp/src/agent/snmp_standard_mib.erl
+++ b/lib/snmp/src/agent/snmp_standard_mib.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2015. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -143,20 +144,38 @@ do_reconfigure(Dir) ->
%% Func: read_standard/1
%% Args: Dir is the directory with trailing dir_separator where
%% the configuration files can be found.
-%% Purpose: Reads th standard configuration file.
+%% Purpose: Reads the standard configuration file.
%% Returns: A list of standard variables
%% Fails: If an error occurs, the process will die with Reason
%% configuration_error.
+%% This file is mandatory, as it contains mandatory
+%% config options for which there are no default values.
%%-----------------------------------------------------------------
read_standard(Dir) ->
?vdebug("check standard config file",[]),
- Gen = fun(_) -> ok end,
- Filter = fun(Standard) -> sort_standard(Standard) end,
- Check = fun(Entry) -> check_standard(Entry) end,
+ FileName = "standard.conf",
+ Gen =
+ fun (D, Reason) ->
+ throw(
+ {error,
+ {failed_reading_config_file,
+ D, FileName, list_dir(Dir), Reason}})
+ end,
+ Order = fun snmp_conf:no_order/2,
+ Check = fun (Entry, State) -> {check_standard(Entry), State} end,
+ Filter = fun sort_standard/1,
[Standard] =
- snmp_conf:read_files(Dir, [{Gen, Filter, Check, "standard.conf"}]),
+ snmp_conf:read_files(Dir, [{FileName, Gen, Order, Check, Filter}]),
Standard.
+list_dir(Dir) ->
+ case file:list_dir(Dir) of
+ {ok, Files} ->
+ Files;
+ Error ->
+ Error
+ end.
+
%%-----------------------------------------------------------------
%% Make sure that each mandatory standard attribute is present, and
@@ -528,8 +547,9 @@ dummy(_Op) -> ok.
%%-----------------------------------------------------------------
snmp_set_serial_no(new) ->
snmp_generic:variable_func(new, {snmpSetSerialNo, volatile}),
- {A1,A2,A3} = erlang:now(),
- random:seed(A1,A2,A3),
+ random:seed(erlang:phash2([node()]),
+ erlang:monotonic_time(),
+ erlang:unique_integer()),
Val = random:uniform(2147483648) - 1,
snmp_generic:variable_func(set, Val, {snmpSetSerialNo, volatile});
@@ -548,6 +568,7 @@ snmp_set_serial_no(set, NewVal) ->
snmp_generic:variable_func(set, (NewVal + 1) rem 2147483648,
{snmpSetSerialNo, volatile}).
+
%%-----------------------------------------------------------------
%% This is the instrumentation function for sysOrTable
%%-----------------------------------------------------------------
@@ -588,4 +609,4 @@ error(Reason) ->
throw({error, Reason}).
config_err(F, A) ->
- snmpa_error:config_err("[STANDARD-MIB]: " ++ F, A).
+ snmpa_error:config_err("[STANDARD-MIB] " ++ F, A).
diff --git a/lib/snmp/src/agent/snmp_target_mib.erl b/lib/snmp/src/agent/snmp_target_mib.erl
index a45db89c09..e65fa7f340 100644
--- a/lib/snmp/src/agent/snmp_target_mib.erl
+++ b/lib/snmp/src/agent/snmp_target_mib.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2015. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -132,19 +133,23 @@ do_reconfigure(Dir) ->
read_target_config_files(Dir) ->
- ?vdebug("check target address config file",[]),
- TAGen = fun(_D) -> ok end,
- TAFilter = fun(Addr) -> Addr end,
- TACheck = fun(Entry) -> check_target_addr(Entry) end,
+ ?vdebug("check target address and parameter config file(s)",[]),
+
+ TAName = "target_addr.conf",
+ TACheck = fun (Entry, State) -> {check_target_addr(Entry), State} end,
- TPGen = fun(_D) -> ok end,
- TPFilter = fun(Params) -> Params end,
- TPCheck = fun(Entry) -> check_target_params(Entry) end,
+ TPName = "target_params.conf",
+ TPCheck = fun (Entry, State) -> {check_target_params(Entry), State} end,
+
+ NoGen = fun snmp_conf:no_gen/2,
+ NoOrder = fun snmp_conf:no_order/2,
+ NoFilter = fun snmp_conf:no_filter/1,
[Addrs, Params] =
- snmp_conf:read_files(Dir,
- [{TAGen, TAFilter, TACheck, "target_addr.conf"},
- {TPGen, TPFilter, TPCheck, "target_params.conf"}]),
+ snmp_conf:read_files(
+ Dir,
+ [{TAName, NoGen, NoOrder, TACheck, NoFilter},
+ {TPName, NoGen, NoOrder, TPCheck, NoFilter}]),
{Addrs, Params}.
@@ -154,79 +159,173 @@ read_target_config_files(Dir) ->
%% TMask, MMS}
%%-----------------------------------------------------------------
-check_target_addr({Name, Domain, Ip, Udp, Timeout, RetryCount, TagList,
- Params, EngineId, TMask, MMS}) ->
+check_target_addr(
+ {Name, Domain, Ip, Udp, Timeout, RetryCount, TagList, Params,
+ EngineId, TMask, MMS}) -> % Arity 11
+ Address = {Ip, Udp},
+ check_target_addr(
+ Name, Domain, Address, Timeout, RetryCount, TagList, Params,
+ EngineId, TMask, MMS);
+check_target_addr(
+ {Name, Domain, Address, Timeout, RetryCount, TagList, Params,
+ EngineId, TMask, MMS}) % Arity 10
+ when is_atom(Domain) ->
+ check_target_addr(
+ Name, Domain, Address, Timeout, RetryCount, TagList, Params,
+ EngineId, TMask, MMS);
+check_target_addr(
+ {Name, Ip, Udp, Timeout, RetryCount, TagList, Params,
+ EngineId, TMask, MMS})
+ when is_integer(Udp) -> % Arity 10
+ Domain = default_domain(),
+ Address = {Ip, Udp},
+ check_target_addr(
+ Name, Domain, Address, Timeout, RetryCount, TagList, Params,
+ EngineId, TMask, MMS);
+check_target_addr(
+ {_Name, Domain, Address, _Timeout, _RetryCount, _TagList, _Params,
+ _EngineId, _TMask, _MMS}) -> % Arity 10
+ error({bad_address, {Domain, Address}});
+check_target_addr(
+ {Name, Domain, Address, Timeout, RetryCount, TagList, Params,
+ EngineId}) % Arity 8
+ when is_atom(Domain) ->
+ check_target_addr(
+ Name, Domain, Address, Timeout, RetryCount, TagList, Params,
+ EngineId);
+check_target_addr(
+ {Name, Ip, Udp, Timeout, RetryCount, TagList, Params,
+ EngineId}) % Arity 8
+ when is_integer(Udp) ->
+ Domain = default_domain(),
+ Address = {Ip, Udp},
+ check_target_addr(
+ Name, Domain, Address, Timeout, RetryCount, TagList, Params,
+ EngineId);
+check_target_addr(
+ {_Name, Domain, Address, _Timeout, _RetryCount, _TagList, _Params,
+ _EngineId}) ->% Arity 8
+ error({bad_address, {Domain, Address}});
+%% Use dummy engine id if the old style is found
+check_target_addr(
+ {Name, Domain, Address, Timeout, RetryCount, TagList, Params}) % Arity 7
+ when is_atom(Domain) ->
+ check_target_addr(
+ Name, Domain, Address, Timeout, RetryCount, TagList, Params);
+check_target_addr(
+ {Name, Ip, Udp, Timeout, RetryCount, TagList, Params}) % Arity 7
+ when is_integer(Udp) ->
+ Domain = default_domain(),
+ Address = {Ip, Udp},
+ check_target_addr(
+ Name, Domain, Address, Timeout, RetryCount, TagList, Params);
+check_target_addr(
+ {_Name, Domain, Address, _Timeout, _RetryCount, _TagList, _Params}) -> % Arity 7
+ error({bad_address, {Domain, Address}});
+%% Use dummy engine id if the old style is found
+check_target_addr(
+ {Name, Domain, Address, Timeout, RetryCount, TagList, Params,
+ TMask, MMS}) % Arity 9
+ when is_atom(Domain) ->
+ check_target_addr(
+ Name, Domain, Address, Timeout, RetryCount, TagList, Params, TMask, MMS);
+check_target_addr(
+ {Name, Ip, Udp, Timeout, RetryCount, TagList, Params,
+ TMask, MMS}) % Arity 9
+ when is_integer(Udp) ->
+ Domain = default_domain(),
+ Address = {Ip, Udp},
+ check_target_addr(
+ Name, Domain, Address, Timeout, RetryCount, TagList, Params, TMask, MMS);
+check_target_addr(
+ {_Name, Domain, Address, _Timeout, _RetryCount, _TagList, _Params,
+ _TMask, _MMS}) -> % Arity 9
+ error({bad_address, {Domain, Address}});
+check_target_addr(X) ->
+ error({invalid_target_addr, X}).
+
+check_target_addr(
+ Name, Domain, Address, Timeout, RetryCount, TagList, Params) -> % Arity 7
+ check_target_addr(
+ Name, Domain, Address, Timeout, RetryCount, TagList, Params,
+ "dummy").
+%%
+check_target_addr(
+ Name, Domain, Address, Timeout, RetryCount, TagList, Params,
+ EngineId) -> % Arity 8
+ check_target_addr(
+ Name, Domain, Address, Timeout, RetryCount, TagList, Params,
+ EngineId, [], 2048).
+%%
+check_target_addr(
+ Name, Domain, Address, Timeout, RetryCount, TagList, Params,
+ TMask, MMS) -> % Arity 9
+ check_target_addr(
+ Name, Domain, Address, Timeout, RetryCount, TagList, Params,
+ "dummy", TMask, MMS).
+%%
+check_target_addr(
+ Name, Domain, Address, Timeout, RetryCount, TagList, Params,
+ EngineId, Mask, MMS) -> % Arity 10
?vtrace("check target address with:"
"~n Name: ~s"
"~n Domain: ~p"
- "~n Ip: ~p"
- "~n Udp: ~p"
+ "~n Address: ~p"
"~n Timeout: ~p"
"~n RetryCount: ~p"
"~n TagList: ~p"
"~n Params: ~p"
"~n EngineId: ~p"
- "~n TMask: ~p"
+ "~n Mask: ~p"
"~n MMS: ~p",
- [Name,
- Domain, Ip, Udp,
+ [Name, Domain, Address,
Timeout, RetryCount,
- TagList, Params, EngineId, TMask, MMS]),
+ TagList, Params, EngineId, Mask, MMS]),
snmp_conf:check_string(Name,{gt,0}),
snmp_conf:check_domain(Domain),
- snmp_conf:check_ip(Domain, Ip),
- snmp_conf:check_integer(Udp, {gt, 0}),
+ NAddress = check_address(Domain, Address),
snmp_conf:check_integer(Timeout, {gte, 0}),
snmp_conf:check_integer(RetryCount, {gte,0}),
snmp_conf:check_string(TagList),
snmp_conf:check_string(Params),
check_engine_id(EngineId),
- TAddress = snmp_conf:mk_taddress(Domain, Ip, Udp),
+ NMask = check_mask(Domain, Mask),
TDomain = snmp_conf:mk_tdomain(Domain),
- check_tmask(TDomain, TMask, TAddress),
+ TAddress = snmp_conf:mk_taddress(Domain, NAddress),
+ TMask = snmp_conf:mk_taddress(Domain, NMask),
snmp_conf:check_packet_size(MMS),
?vtrace("check target address done",[]),
Addr = {Name, TDomain, TAddress, Timeout,
RetryCount, TagList, Params,
?'StorageType_nonVolatile', ?'RowStatus_active', EngineId,
TMask, MMS}, % Values for Augmenting table in SNMP-COMMUNITY-MIB
- {ok, Addr};
-check_target_addr({Name, Ip, Udp, Timeout, RetryCount, TagList,
- Params, EngineId, TMask, MMS}) ->
- Domain = default_domain(),
- check_target_addr({Name,
- Domain, Ip, Udp,
- Timeout, RetryCount, TagList,
- Params, EngineId, TMask, MMS});
-check_target_addr({Name, Ip, Udp, Timeout, RetryCount, TagList, Params,
- EngineId}) ->
- check_target_addr({Name, Ip, Udp, Timeout, RetryCount, TagList,
- Params, EngineId, [], 2048});
-%% Use dummy engine id if the old style is found
-check_target_addr({Name, Ip, Udp, Timeout, RetryCount, TagList, Params}) ->
- check_target_addr({Name, Ip, Udp, Timeout, RetryCount, TagList,
- Params, "dummy", [], 2048});
-%% Use dummy engine id if the old style is found
-check_target_addr({Name, Ip, Udp, Timeout, RetryCount, TagList, Params,
- TMask, MMS}) ->
- check_target_addr({Name, Ip, Udp, Timeout, RetryCount, TagList,
- Params, "dummy", TMask, MMS});
-check_target_addr(X) ->
- error({invalid_target_addr, X}).
-
+ {ok, Addr}.
check_engine_id(discovery) ->
ok;
check_engine_id(EngineId) ->
snmp_conf:check_string(EngineId).
+check_address(Domain, Address) ->
+ case snmp_conf:check_address(Domain, Address, 162) of
+ ok ->
+ Address;
+ {ok, NAddress} ->
+ NAddress
+ end.
-check_tmask(_TDomain, [], _TAddress) ->
- ok;
-check_tmask(TDomain, TMask, TAddress) when length(TMask) =:= length(TAddress) ->
- snmp_conf:check_taddress(TDomain, TMask);
-check_tmask(_TDomain, TMask, _TAddr) ->
- throw({error, {invalid_tmask, TMask}}).
+check_mask(_Domain, [] = Mask) ->
+ Mask;
+check_mask(Domain, Mask) ->
+ try snmp_conf:check_address(Domain, Mask) of
+ ok ->
+ Mask;
+ {ok, NMask} ->
+ NMask
+ catch
+ {error, {bad_address, Info}} ->
+ error({bad_mask, Info})
+ end.
%%-----------------------------------------------------------------
@@ -248,13 +347,6 @@ check_target_params(X) ->
error({invalid_target_params, X}).
-
-%% maybe_create_table(Name) ->
-%% case snmpa_local_db:table_exists(db(Name)) of
-%% true -> ok;
-%% _ -> snmpa_local_db:table_create(db(Name))
-%% end.
-
init_tabs(Addrs, Params) ->
?vdebug("create target address table",[]),
AddrDB = db(snmpTargetAddrTable),
@@ -286,16 +378,21 @@ table_del_row(Tab, Key) ->
snmpa_mib_lib:table_del_row(db(Tab), Key).
-add_addr(Name, Ip, Port, Timeout, Retry, TagList,
- Params, EngineId, TMask, MMS) ->
- Domain = default_domain(),
- add_addr(Name, Domain, Ip, Port, Timeout, Retry, TagList,
- Params, EngineId, TMask, MMS).
-
-add_addr(Name, Domain, Ip, Port, Timeout, Retry, TagList,
- Params, EngineId, TMask, MMS) ->
- Addr = {Name, Domain, Ip, Port, Timeout, Retry, TagList,
- Params, EngineId, TMask, MMS},
+add_addr(
+ Name, Domain_or_Ip, Addr_or_Port, Timeout, Retry, TagList, Params,
+ EngineId, TMask, MMS) ->
+ add_addr(
+ {Name, Domain_or_Ip, Addr_or_Port, Timeout, Retry, TagList, Params,
+ EngineId, TMask, MMS}).
+%%
+add_addr(
+ Name, Domain, Ip, Port, Timeout, Retry, TagList, Params,
+ EngineId, TMask, MMS) ->
+ add_addr(
+ {Name, Domain, Ip, Port, Timeout, Retry, TagList, Params,
+ EngineId, TMask, MMS}).
+%%
+add_addr(Addr) ->
case (catch check_target_addr(Addr)) of
{ok, Row} ->
Key = element(1, Row),
@@ -576,8 +673,9 @@ snmpTargetSpinLock(print) ->
snmpTargetSpinLock(new) ->
snmp_generic:variable_func(new, {snmpTargetSpinLock, volatile}),
- {A1,A2,A3} = erlang:now(),
- random:seed(A1,A2,A3),
+ random:seed(erlang:phash2([node()]),
+ erlang:monotonic_time(),
+ erlang:unique_integer()),
Val = random:uniform(2147483648) - 1,
snmp_generic:variable_func(set, Val, {snmpTargetSpinLock, volatile});
@@ -604,6 +702,20 @@ snmpTargetAddrTable(print) ->
FOI = foi(Table),
PrintRow =
fun(Prefix, Row) ->
+ TDomain = element(?snmpTargetAddrTDomain, Row),
+ Domain =
+ try snmp_conf:tdomain_to_domain(TDomain)
+ catch
+ {error, {bad_tdomain, _}} ->
+ undefined
+ end,
+ TAddress = element(?snmpTargetAddrTAddress, Row),
+ AddrString =
+ try snmp_conf:mk_addr_string({Domain, TAddress})
+ catch
+ {error, {bad_address, _}} ->
+ "-"
+ end,
lists:flatten(
io_lib:format("~sName: ~p"
"~n~sTDomain: ~p (~w)"
@@ -618,21 +730,8 @@ snmpTargetAddrTable(print) ->
"~n~s[Ext] TMask: ~p"
"~n~s[Ext] MMS: ~p",
[Prefix, element(?snmpTargetAddrName, Row),
- Prefix, element(?snmpTargetAddrTDomain, Row),
- case element(?snmpTargetAddrTDomain, Row) of
- ?snmpUDPDomain -> snmpUDPDomain;
- ?transportDomainUdpIpv4 -> transportDomainUdpIpv4;
- ?transportDomainUdpIpv6 -> transportDomainUdpIpv6;
- _ -> undefined
- end,
- Prefix, element(?snmpTargetAddrTAddress, Row),
- case element(?snmpTargetAddrTAddress, Row) of
- [A,B,C,D,U1,U2] ->
- lists:flatten(
- io_lib:format("~w.~w.~w.~w:~w",
- [A, B, C, D, U1 bsl 8 + U2]));
- _ -> "-"
- end,
+ Prefix, TDomain, Domain,
+ Prefix, TAddress, AddrString,
Prefix, element(?snmpTargetAddrTimeout, Row),
Prefix, element(?snmpTargetAddrRetryCount, Row),
Prefix, element(?snmpTargetAddrTagList, Row),
@@ -976,5 +1075,3 @@ error(Reason) ->
config_err(F, A) ->
snmpa_error:config_err("[TARGET-MIB]: " ++ F, A).
-
-
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 69cebc858b..f6e4fd3951 100644
--- a/lib/snmp/src/agent/snmp_user_based_sm_mib.erl
+++ b/lib/snmp/src/agent/snmp_user_based_sm_mib.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2015. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -54,6 +55,7 @@
%% Columns not accessible via SNMP
-define(usmUserAuthKey, 14).
-define(usmUserPrivKey, 15).
+-define(is_cloning, 16).
%%%-----------------------------------------------------------------
@@ -136,18 +138,20 @@ do_reconfigure(Dir) ->
read_usm_config_files(Dir) ->
?vdebug("read usm config file",[]),
- Gen = fun(D) -> generate_usm(D) end,
- Filter = fun(Usms) -> Usms end,
- Check = fun(Entry) -> check_usm(Entry) end,
+ Gen = fun (D, Reason) -> generate_usm(D, Reason) end,
+ Order = fun snmp_conf:no_order/2,
+ Check = fun (Entry, State) -> {check_usm(Entry), State} end,
+ Filter = fun snmp_conf:no_filter/1,
[Usms] =
- snmp_conf:read_files(Dir, [{Gen, Filter, Check, "usm.conf"}]),
+ snmp_conf:read_files(Dir, [{"usm.conf", Gen, Order, Check, Filter}]),
Usms.
-generate_usm(Dir) ->
+generate_usm(Dir, _Reason) ->
info_msg("Incomplete configuration. Generating empty usm.conf.", []),
USMFile = filename:join(Dir, "usm.conf"),
- ok = file:write_file(USMFile, list_to_binary([])).
+ ok = file:write_file(USMFile, list_to_binary([])),
+ [].
check_usm({EngineID, Name, SecName, Clone, AuthP, AuthKeyC, OwnAuthKeyC,
@@ -213,12 +217,12 @@ check_user(User) ->
case element(?usmUserAuthProtocol, User) of
?usmNoAuthProtocol -> ok;
?usmHMACMD5AuthProtocol ->
- case is_crypto_supported(md5_mac_96) of
+ case is_crypto_supported(md5) of
true -> ok;
false -> exit({unsupported_crypto, md5_mac_96})
end;
?usmHMACSHAAuthProtocol ->
- case is_crypto_supported(sha_mac_96) of
+ case is_crypto_supported(sha) of
true -> ok;
false -> exit({unsupported_crypto, sha_mac_96})
end
@@ -226,14 +230,14 @@ check_user(User) ->
case element(?usmUserPrivProtocol, User) of
?usmNoPrivProtocol -> ok;
?usmDESPrivProtocol ->
- case is_crypto_supported(des_cbc_decrypt) of
+ case is_crypto_supported(des_cbc) of
true -> ok;
- false -> exit({unsupported_crypto, des_cbc_decrypt})
+ false -> exit({unsupported_crypto, des_cbc})
end;
?usmAesCfb128Protocol ->
- case is_crypto_supported(aes_cfb_128_decrypt) of
+ case is_crypto_supported(aes_cfb128) of
true -> ok;
- false -> exit({unsupported_crypto, aes_cfb_128_decrypt})
+ false -> exit({unsupported_crypto, aes_cfb128})
end
end.
@@ -436,8 +440,9 @@ usmUserSpinLock(print) ->
usmUserSpinLock(new) ->
snmp_generic:variable_func(new, {usmUserSpinLock, volatile}),
- {A1,A2,A3} = erlang:now(),
- random:seed(A1,A2,A3),
+ random:seed(erlang:phash2([node()]),
+ erlang:monotonic_time(),
+ erlang:unique_integer()),
Val = random:uniform(2147483648) - 1,
snmp_generic:variable_func(set, Val, {usmUserSpinLock, volatile});
@@ -564,7 +569,9 @@ usmUserTable(set, RowIndex, Cols0) ->
{ok, Cols} ->
?vtrace("usmUserTable(set) -> verified"
"~n Cols: ~p", [Cols]),
- NCols = pre_set(RowIndex, Cols),
+ % check whether we're cloning. if so, get cloned params and add a few
+ % defaults that might be needed.
+ NCols = pre_set(RowIndex, validate_clone_from(RowIndex, Cols)),
?vtrace("usmUserTable(set) -> pre-set: "
"~n NCols: ~p", [NCols]),
%% NOTE: The NCols parameter is sent to snmp_generic, but not to
@@ -730,30 +737,40 @@ validate_is_set_ok(Error, _RowIndex, _Cols) ->
Error.
do_validate_is_set_ok(RowIndex, Cols) ->
- validate_clone_from(RowIndex, Cols),
- validate_auth_protocol(RowIndex, Cols),
- validate_auth_key_change(RowIndex, Cols),
- validate_own_auth_key_change(RowIndex, Cols),
- validate_priv_protocol(RowIndex, Cols),
- validate_priv_key_change(RowIndex, Cols),
- validate_own_priv_key_change(RowIndex, Cols),
+ NCols = validate_clone_from(RowIndex, Cols),
+ validate_auth_protocol(RowIndex, NCols),
+ validate_auth_key_change(RowIndex, NCols),
+ validate_own_auth_key_change(RowIndex, NCols),
+ validate_priv_protocol(RowIndex, NCols),
+ validate_priv_key_change(RowIndex, NCols),
+ validate_own_priv_key_change(RowIndex, NCols),
ok.
pre_set(RowIndex, Cols) ->
+ %% Remove the ?is_cloning member again; it must no longer be
+ %% present.
+ Cols0 = key1delete(?is_cloning, Cols),
%% Possibly initialize the usmUserSecurityName and privacy keys
case snmp_generic:table_row_exists(db(usmUserTable), RowIndex) of
- true -> Cols;
+ true -> Cols0;
false ->
SecName = get_user_name(RowIndex),
- [{?usmUserSecurityName, SecName} | Cols] ++
- [{?usmUserAuthKey, ""},
- {?usmUserPrivKey, ""}]
+ Cols1 = [{?usmUserSecurityName, SecName} | Cols0],
+ case proplists:get_value(?is_cloning, Cols) of
+ true ->
+ % the row is just being cloned. the cloned user's
+ % passwords are already present in Cols and must
+ % not be overwritten.
+ Cols1;
+ _ ->
+ Cols1 ++ [{?usmUserAuthKey, ""},
+ {?usmUserPrivKey, ""}]
+ end
end.
validate_set({noError, 0}, RowIndex, Cols) ->
%% Now, all is_set_ok validation steps have been executed. So
%% everything is ready for the set.
- set_clone_from(RowIndex, Cols),
set_auth_key_change(RowIndex, Cols),
set_own_auth_key_change(RowIndex, Cols),
set_priv_key_change(RowIndex, Cols),
@@ -769,7 +786,7 @@ validate_set(Error, _RowIndex, _Cols) ->
%% no further checks.
%%-----------------------------------------------------------------
validate_clone_from(RowIndex, Cols) ->
- case lists:keysearch(?usmUserCloneFrom, 1, Cols) of
+ case key1search(?usmUserCloneFrom, Cols) of
{value, {_Col, RowPointer}} ->
RowIndex2 = extract_row(RowPointer),
OldCloneFrom = snmp_generic:table_get_element(db(usmUserTable),
@@ -778,35 +795,63 @@ validate_clone_from(RowIndex, Cols) ->
case OldCloneFrom of
{value, Val} when Val /= noinit ->
%% This means that the cloning is already done...
- ok;
+ no_cloning(Cols);
_ ->
- %% Otherwise, we must check the CloneFrom value
- case snmp_generic:table_get_element(db(usmUserTable),
- RowIndex2,
- ?usmUserStatus) of
- {value, ?'RowStatus_active'} -> ok;
- _ -> inconsistentName(?usmUserCloneFrom)
- end
+ %% Otherwise, we must check the CloneFrom value. It
+ %% must relate to a usmUserEntry that exists and is active.
+ case snmp_generic:table_get_row(db(usmUserTable), RowIndex2) of
+ CloneFromRow when is_tuple(CloneFromRow) ->
+ case element(?usmUserStatus, CloneFromRow) of
+ ?'RowStatus_active' ->
+ get_cloned_cols(CloneFromRow, Cols);
+ _ ->
+ inconsistentName(?usmUserCloneFrom)
+ end;
+ undefined ->
+ inconsistentName(?usmUserCloneFrom)
+ end
end;
false ->
- ok
+ % no ?usmUserCloneFrom specified, don't modify columns
+ no_cloning(Cols)
end.
+get_cloned_cols(CloneFromRow, Cols) ->
+ % initialize cloned columns with data from CloneFromRow
+ % and overwrite that again with data found in Cols
+ AuthP = element(?usmUserAuthProtocol, CloneFromRow),
+ PrivP = element(?usmUserPrivProtocol, CloneFromRow),
+ AuthK = element(?usmUserAuthKey, CloneFromRow),
+ PrivK = element(?usmUserPrivKey, CloneFromRow),
+ ClonedCols = [{?usmUserAuthProtocol, AuthP},
+ {?usmUserPrivProtocol, PrivP},
+ {?usmUserAuthKey, AuthK},
+ {?usmUserPrivKey, PrivK},
+ {?is_cloning, true}
+ ],
+ Func = fun({Col, _} = Item, NCols) ->
+ key1store(Col, NCols, Item)
+ end,
+ Cols1 = lists:foldl(Func, ClonedCols, Cols),
+ key1sort(Cols1).
+
+no_cloning(Cols0) ->
+ Cols1 = key1delete(?usmUserCloneFrom, Cols0),
+ key1delete(?is_cloning, Cols1).
+
validate_auth_protocol(RowIndex, Cols) ->
- case lists:keysearch(?usmUserAuthProtocol, 1, Cols) of
+ case key1search(?usmUserAuthProtocol, Cols) of
{value, {_Col, AuthProtocol}} ->
- %% Check if the row has been cloned; we can't check the
+ %% Check if the row is being cloned; we can't check the
%% old value of authProtocol, because if the row was
%% createAndWaited, the default value would have been
%% written (usmNoAuthProtocol).
- OldCloneFrom = snmp_generic:table_get_element(db(usmUserTable),
- RowIndex,
- ?usmUserCloneFrom),
- case OldCloneFrom of
- {value, Val} when Val /= noinit ->
- %% This means that the cloning is already done; set is ok
- %% if new protocol is usmNoAuthProtocol
+ IsCloning = proplists:get_value(?is_cloning, Cols, false),
+ if
+ not IsCloning ->
+ %% This means that the row is not being cloned right
+ %% now; set is ok if new protocol is usmNoAuthProtocol
case AuthProtocol of
?usmNoAuthProtocol ->
%% Check that the Priv protocl is noPriv
@@ -821,7 +866,7 @@ validate_auth_protocol(RowIndex, Cols) ->
_ ->
wrongValue(?usmUserAuthProtocol)
end;
- _ ->
+ true ->
%% Otherwise, check that the new protocol is known,
%% and that the system we're running supports the
%% hash function.
@@ -833,13 +878,13 @@ validate_auth_protocol(RowIndex, Cols) ->
_ -> inconsistentValue(?usmUserAuthProtocol)
end;
?usmHMACMD5AuthProtocol ->
- case is_crypto_supported(md5_mac_96) of
+ case is_crypto_supported(md5) of
true -> ok;
false ->
wrongValue(?usmUserAuthProtocol)
end;
?usmHMACSHAAuthProtocol ->
- case is_crypto_supported(sha_mac_96) of
+ case is_crypto_supported(sha) of
true -> ok;
false ->
wrongValue(?usmUserAuthProtocol)
@@ -867,7 +912,7 @@ validate_own_priv_key_change(RowIndex, Cols) ->
%% Check that the requesting user is the same as the modified user
validate_requester(RowIndex, Cols, KeyChangeCol) ->
- case lists:keysearch(KeyChangeCol, 1, Cols) of
+ case key1search(KeyChangeCol, Cols) of
{value, _} ->
case get(sec_model) of % Check the securityModel in the request
?SEC_USM -> ok;
@@ -890,17 +935,14 @@ validate_requester(RowIndex, Cols, KeyChangeCol) ->
end.
validate_key_change(RowIndex, Cols, KeyChangeCol, Type) ->
- case lists:keysearch(KeyChangeCol, 1, Cols) of
+ case key1search(KeyChangeCol, Cols) of
{value, {_Col, KeyC}} ->
%% Check if the row has been cloned; or if it is cloned in
%% this set-operation.
OldCloneFrom = snmp_generic:table_get_element(db(usmUserTable),
RowIndex,
?usmUserCloneFrom),
- IsClonePresent = case lists:keysearch(?usmUserCloneFrom, 1, Cols) of
- {value, _} -> true;
- false -> false
- end,
+ IsClonePresent = proplists:get_value(?is_cloning, Cols, false),
%% Set is ok if 1) the user already is created, 2) this is
%% a new user, which has been cloned, or is about to be
%% cloned.
@@ -912,7 +954,7 @@ validate_key_change(RowIndex, Cols, KeyChangeCol, Type) ->
%% The user is cloned in this operation
ok;
_ ->
- %% The user doen't exist, or hasn't been cloned,
+ %% The user doesn't exist, or hasn't been cloned,
%% and is not cloned in this operation.
inconsistentName(KeyChangeCol)
end,
@@ -939,17 +981,15 @@ validate_key_change(RowIndex, Cols, KeyChangeCol, Type) ->
end.
validate_priv_protocol(RowIndex, Cols) ->
- case lists:keysearch(?usmUserPrivProtocol, 1, Cols) of
+ case key1search(?usmUserPrivProtocol, Cols) of
{value, {_Col, PrivProtocol}} ->
%% Check if the row has been cloned; we can't check the
%% old value of privhProtocol, because if the row was
%% createAndWaited, the default value would have been
%% written (usmNoPrivProtocol).
- OldCloneFrom = snmp_generic:table_get_element(db(usmUserTable),
- RowIndex,
- ?usmUserCloneFrom),
- case OldCloneFrom of
- {value, Val} when Val /= noinit ->
+ IsCloning = proplists:get_value(?is_cloning, Cols, false),
+ if
+ not IsCloning ->
%% This means that the cloning is already done; set is ok
%% if new protocol is usmNoPrivProtocol
case PrivProtocol of
@@ -962,7 +1002,7 @@ validate_priv_protocol(RowIndex, Cols) ->
_ ->
wrongValue(?usmUserPrivProtocol)
end;
- _ ->
+ true ->
%% Otherwise, check that the new protocol is known,
%% and that the system we're running supports the
%% crypto function.
@@ -972,7 +1012,7 @@ validate_priv_protocol(RowIndex, Cols) ->
?usmDESPrivProtocol ->
%% The 'catch' handles the case when 'crypto' is
%% not present in the system.
- case is_crypto_supported(des_cbc_decrypt) of
+ case is_crypto_supported(des_cbc) of
true ->
case get_auth_proto(RowIndex, Cols) of
?usmNoAuthProtocol ->
@@ -986,7 +1026,7 @@ validate_priv_protocol(RowIndex, Cols) ->
?usmAesCfb128Protocol ->
%% The 'catch' handles the case when 'crypto' is
%% not present in the system.
- case is_crypto_supported(aes_cfb_128_decrypt) of
+ case is_crypto_supported(aes_cfb128) of
true ->
case get_auth_proto(RowIndex, Cols) of
?usmNoAuthProtocol ->
@@ -1005,31 +1045,6 @@ validate_priv_protocol(RowIndex, Cols) ->
end.
-set_clone_from(RowIndex, Cols) ->
- %% If CloneFrom is modified, do the cloning.
- case lists:keysearch(?usmUserCloneFrom, 1, Cols) of
- {value, {_Col, RowPointer}} ->
- RowIndex2 = extract_row(RowPointer), % won't fail
- CloneRow = snmp_generic:table_get_row(db(usmUserTable), RowIndex2,
- foi(usmUserTable)),
- AuthP = element(?usmUserAuthProtocol, CloneRow),
- PrivP = element(?usmUserPrivProtocol, CloneRow),
- AuthK = element(?usmUserAuthKey, CloneRow),
- PrivK = element(?usmUserPrivKey, CloneRow),
- SCols = [{?usmUserAuthProtocol, AuthP},
- {?usmUserPrivProtocol, PrivP},
- {?usmUserAuthKey, AuthK},
- {?usmUserPrivKey, PrivK}],
- case snmp_generic:table_set_elements(db(usmUserTable),
- RowIndex,
- SCols) of
- true -> ok;
- false -> {commitFailed, ?usmUserCloneFrom}
- end;
- false ->
- ok
- end.
-
set_auth_key_change(RowIndex, Cols) ->
set_key_change(RowIndex, Cols, ?usmUserAuthKeyChange, auth).
@@ -1043,7 +1058,7 @@ set_own_priv_key_change(RowIndex, Cols) ->
set_key_change(RowIndex, Cols, ?usmUserOwnPrivKeyChange, priv).
set_key_change(RowIndex, Cols, KeyChangeCol, Type) ->
- case lists:keysearch(KeyChangeCol, 1, Cols) of
+ case key1search(KeyChangeCol, Cols) of
{value, {_Col, KeyChange}} ->
KeyCol = case Type of
auth -> ?usmUserAuthKey;
@@ -1071,11 +1086,11 @@ extract_row([H | T], [H | T2]) -> extract_row(T, T2);
extract_row([], [?usmUserSecurityName | T]) -> T;
extract_row(_, _) -> wrongValue(?usmUserCloneFrom).
-%% Pre: the user exixt
+%% Pre: the user exists or is being cloned in this operation
get_auth_proto(RowIndex, Cols) ->
- %% The protocol can be chanegd by the request too, otherwise,
+ %% The protocol can be changed by the request too, otherwise,
%% check the stored protocol.
- case lists:keysearch(?usmUserAuthProtocol, 1, Cols) of
+ case key1search(?usmUserAuthProtocol, Cols) of
{value, {_, Protocol}} ->
Protocol;
false ->
@@ -1090,11 +1105,11 @@ get_auth_proto(RowIndex, Cols) ->
end
end.
-%% Pre: the user exixt
+%% Pre: the user exists or is being cloned in this operation
get_priv_proto(RowIndex, Cols) ->
- %% The protocol can be chanegd by the request too, otherwise,
+ %% The protocol can be changed by the request too, otherwise,
%% check the stored protocol.
- case lists:keysearch(?usmUserPrivProtocol, 1, Cols) of
+ case key1search(?usmUserPrivProtocol, Cols) of
{value, {_, Protocol}} ->
Protocol;
false ->
@@ -1153,7 +1168,7 @@ mk_key_change(Hash, OldKey, NewKey) ->
%% case in the standard where Random is pre-defined.
mk_key_change(Alg, OldKey, NewKey, KeyLen, Random) ->
%% OldKey and Random is of length KeyLen...
- Digest = lists:sublist(binary_to_list(crypto:Alg(OldKey++Random)), KeyLen),
+ Digest = lists:sublist(binary_to_list(crypto:hash(Alg, OldKey++Random)), KeyLen),
%% ... and so is Digest
Delta = snmp_misc:str_xor(Digest, NewKey),
Random ++ Delta.
@@ -1170,7 +1185,7 @@ extract_new_key(Hash, OldKey, KeyChange) ->
sha -> sha
end,
{Random, Delta} = split(KeyLen, KeyChange, []),
- Digest = lists:sublist(binary_to_list(crypto:Alg(OldKey++Random)), KeyLen),
+ Digest = lists:sublist(binary_to_list(crypto:hash(Alg, OldKey++Random)), KeyLen),
NewKey = snmp_misc:str_xor(Digest, Delta),
NewKey.
@@ -1178,29 +1193,7 @@ extract_new_key(Hash, OldKey, KeyChange) ->
-define(i8(Int), Int band 255).
mk_random(Len) when Len =< 20 ->
- %% Use of yield():
- %% This will either schedule another process, or fail and invoke
- %% the error_handler (in old versions). In either case, it is
- %% safe to assume that now, reductions and garbage_collection have
- %% changed in a non-deterministically way.
- {_,_,A} = erlang:now(),
- catch erlang:yield(),
- {_,_,B} = erlang:now(),
- catch erlang:yield(),
- {_,_,C} = erlang:now(),
- {D,_} = erlang:statistics(reductions),
- {E,_} = erlang:statistics(runtime),
- {F,_} = erlang:statistics(wall_clock),
- {G,H,_} = erlang:statistics(garbage_collection),
- catch erlang:yield(),
- {_,_,C2} = erlang:now(),
- {D2,_} = erlang:statistics(reductions),
- {_,H2,_} = erlang:statistics(garbage_collection),
- %% X(N) means we can use N bits from variable X:
- %% A(16) B(16) C(16) D(16) E(8) F(16) G(8) H(16)
- Rnd20 = [?i16(A),?i16(B),?i16(C),?i16(D),?i8(E),?i16(F),
- ?i8(G),?i16(H),?i16(C2),?i16(D2),?i16(H2)],
- lists:sublist(Rnd20, Len).
+ binary_to_list(crypto:strong_rand_bytes(Len)).
split(0, Rest, FirstRev) ->
{lists:reverse(FirstRev), Rest};
@@ -1208,13 +1201,10 @@ split(N, [H | T], FirstRev) when N > 0 ->
split(N-1, T, [H | FirstRev]).
+-compile({inline, [{is_crypto_supported,1}]}).
is_crypto_supported(Func) ->
- %% The 'catch' handles the case when 'crypto' is
- %% not present in the system (or not started).
- case catch lists:member(Func, crypto:info()) of
- true -> true;
- _ -> false
- end.
+ snmp_misc:is_crypto_supported(Func).
+
inconsistentValue(V) -> throw({inconsistentValue, V}).
inconsistentName(N) -> throw({inconsistentName, N}).
@@ -1232,6 +1222,27 @@ set_sname(_) -> %% Keep it, if already set.
error(Reason) ->
throw({error, Reason}).
+
+%%-----------------------------------------------------------------
+%% lists key-function(s) wrappers
+
+-compile({inline,key1delete/2}).
+key1delete(Key, List) ->
+ lists:keydelete(Key, 1, List).
+
+-compile({inline,key1search/2}).
+key1search(Key, List) ->
+ lists:keysearch(Key, 1, List).
+
+-compile({inline,key1store/3}).
+key1store(Key, List, Elem) ->
+ lists:keystore(Key, 1, List, Elem).
+
+-compile({inline,key1sort/1}).
+key1sort(List) ->
+ lists:keysort(1, List).
+
+
%%-----------------------------------------------------------------
info_msg(F, A) ->
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 2cee91b081..02415e8036 100644
--- a/lib/snmp/src/agent/snmp_view_based_acm_mib.erl
+++ b/lib/snmp/src/agent/snmp_view_based_acm_mib.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -33,6 +34,8 @@
%% Internal exports
-export([check_vacm/1]).
+%%
+-export([emask2imask/1]).
-include("snmp_types.hrl").
@@ -49,6 +52,14 @@
-endif.
+-type internal_view_mask() :: null | [internal_view_mask_element()].
+-type internal_view_mask_element() :: 0 | 1.
+
+-type external_view_mask() :: octet_string(). % At most length of 16 octet
+-type octet_string() :: [octet()].
+-type octet() :: byte().
+
+
%%-----------------------------------------------------------------
%% Func: configure/1
%% Args: Dir is the directory where the configuration files are found.
@@ -115,15 +126,18 @@ do_reconfigure(Dir) ->
read_vacm_config_files(Dir) ->
?vdebug("read vacm config file",[]),
- Gen = fun(_) -> ok end,
- Filter = fun(Vacms) ->
- Sec2Group = [X || {vacmSecurityToGroup, X} <- Vacms],
- Access = [X || {vacmAccess, X} <- Vacms],
- View = [X || {vacmViewTreeFamily, X} <- Vacms],
- {Sec2Group, Access, View}
- end,
- Check = fun(Entry) -> check_vacm(Entry) end,
- [Vacms] = snmp_conf:read_files(Dir, [{Gen, Filter, Check, "vacm.conf"}]),
+ Gen = fun snmp_conf:no_gen/2,
+ Order = fun snmp_conf:no_order/2,
+ Check = fun (Entry, State) -> {check_vacm(Entry), State} end,
+ Filter =
+ fun (Vacms) ->
+ Sec2Group = [X || {vacmSecurityToGroup, X} <- Vacms],
+ Access = [X || {vacmAccess, X} <- Vacms],
+ View = [X || {vacmViewTreeFamily, X} <- Vacms],
+ {Sec2Group, Access, View}
+ end,
+ [Vacms] =
+ snmp_conf:read_files(Dir, [{"vacm.conf", Gen, Order, Check, Filter}]),
Vacms.
%%-----------------------------------------------------------------
@@ -160,14 +174,7 @@ check_vacm({vacmViewTreeFamily, ViewName, Tree, Type, Mask}) ->
{ok, TypeVal} =
snmp_conf:check_atom(Type, [{included, ?view_included},
{excluded, ?view_excluded}]),
- MaskVal =
- case (catch snmp_conf:check_atom(Mask, [{null, []}])) of
- {error, _} ->
- snmp_conf:check_oid(Mask),
- Mask;
- {ok, X} ->
- X
- end,
+ {ok, MaskVal} = snmp_conf:check_imask(Mask),
Vacm = {ViewName, Tree, MaskVal, TypeVal,
?'StorageType_nonVolatile', ?'RowStatus_active'},
{ok, {vacmViewTreeFamily, Vacm}};
@@ -194,8 +201,8 @@ init_tabs(Sec2Group, Access, View) ->
ok.
init_sec2group_table([Row | T]) ->
-%% ?vtrace("init security-to-group table: "
-%% "~n Row: ~p",[Row]),
+ %% ?vtrace("init security-to-group table: "
+ %% "~n Row: ~p",[Row]),
Key1 = element(1, Row),
Key2 = element(2, Row),
Key = [Key1, length(Key2) | Key2],
@@ -496,7 +503,7 @@ verify_vacmSecurityToGroupTable_col(_, Val) ->
%%
%%-----------------------------------------------------------------
vacmAccessTable(print) ->
- %% M�ste jag g�ra om alla entrien till {RowIdx, Row}?
+ %% Do I need to turn all entries into {RowIdx, Row}?
TableInfo = get_table(vacmAccessTable),
PrintRow =
fun(Prefix, Row) ->
@@ -565,45 +572,85 @@ vacmAccessTable(is_set_ok, RowIndex, Cols0) ->
case (catch verify_vacmAccessTable_cols(Cols0, [])) of
{ok, Cols} ->
IsValidKey = is_valid_key(RowIndex),
- case lists:keysearch(?vacmAccessStatus, 1, Cols) of
- %% Ok, if contextMatch is init
- {value, {Col, ?'RowStatus_active'}} ->
- {ok, Row} = snmpa_vacm:get_row(RowIndex),
- case element(?vacmAContextMatch, Row) of
- noinit -> {inconsistentValue, Col};
- _ -> {noError, 0}
+ StatusCol = lists:keyfind(?vacmAccessStatus, 1, Cols),
+ MaybeRow = snmpa_vacm:get_row(RowIndex),
+ case {StatusCol, MaybeRow} of
+ {{Col, ?'RowStatus_active'}, false} ->
+ %% row does not yet exist => inconsistentValue
+ %% (see SNMPv2-TC.mib, RowStatus textual convention)
+ {inconsistentValue, Col};
+ {{Col, ?'RowStatus_active'}, {ok, Row}} ->
+ %% Ok, if contextMatch is init
+ case element(?vacmAContextMatch, Row) of
+ noinit ->
+ %% check whether ContextMatch is being set in
+ %% the same operation
+ case proplists:get_value(?vacmAccessContextMatch,
+ Cols) of
+ undefined ->
+ %% no, we can't make this row active yet
+ {inconsistentValue, Col};
+ _ ->
+ %% ok, activate the row
+ {noError, 0}
+ end;
+ _ ->
+ {noError, 0}
end;
- {value, {Col, ?'RowStatus_notInService'}} -> % Ok, if not notReady
- {ok, Row} = snmpa_vacm:get_row(RowIndex),
+ {{Col, ?'RowStatus_notInService'}, false} ->
+ %% row does not yet exist => inconsistentValue
+ %% (see SNMPv2-TC.mib, RowStatus textual convention)
+ {inconsistentValue, Col};
+ {{Col, ?'RowStatus_notInService'}, {ok, Row}} ->
+ %% Ok, if not notReady
case element(?vacmAStatus, Row) of
- ?'RowStatus_notReady' -> {inconsistentValue, Col};
- _ -> {noError, 0}
+ ?'RowStatus_notReady' ->
+ {inconsistentValue, Col};
+ _ ->
+ {noError, 0}
end;
- {value, {Col, ?'RowStatus_notReady'}} -> % never ok!
+ {{Col, ?'RowStatus_notReady'}, _} ->
+ %% never ok!
{inconsistentValue, Col};
- {value, {Col, ?'RowStatus_createAndGo'}} -> % ok, if it doesn't exist
+ {{Col, ?'RowStatus_createAndGo'}, false} ->
+ %% ok, if it doesn't exist
Res = lists:keysearch(?vacmAccessContextMatch, 1, Cols),
- case snmpa_vacm:get_row(RowIndex) of
- false when (IsValidKey =:= true) andalso
- is_tuple(Res) -> {noError, 0};
- false -> {noCreation, Col}; % Bad RowIndex
- _ -> {inconsistentValue, Col}
+ if
+ IsValidKey =/= true ->
+ %% bad RowIndex => noCreation
+ {noCreation, Col};
+ is_tuple(Res) ->
+ %% required field is present => noError
+ {noError, 0};
+ true ->
+ %% required field is missing => inconsistentValue
+ {inconsistentValue, Col}
end;
- {value, {Col, ?'RowStatus_createAndWait'}} -> % ok, if it doesn't exist
- case snmpa_vacm:get_row(RowIndex) of
- false when (IsValidKey =:= true) -> {noError, 0};
- false -> {noCreation, Col}; % Bad RowIndex
- _ -> {inconsistentValue, Col}
+ {{Col, ?'RowStatus_createAndGo'}, _} ->
+ %% row already exists => inconsistentValue
+ {inconsistentValue, Col};
+ {{Col, ?'RowStatus_createAndWait'}, false} ->
+ %% ok, if it doesn't exist
+ if
+ IsValidKey =:= true ->
+ %% RowIndex is valid => noError
+ {noError, 0};
+ true ->
+ {noCreation, Col}
end;
- {value, {_Col, ?'RowStatus_destroy'}} -> % always ok!
+ {{Col, ?'RowStatus_createAndWait'}, _} ->
+ %% Row already exists => inconsistentValue
+ {inconsistentValue, Col};
+ {value, {_Col, ?'RowStatus_destroy'}} ->
+ %% always ok!
{noError, 0};
- _ -> % otherwise, it's a change; it must exist
- case snmpa_vacm:get_row(RowIndex) of
- {ok, _} ->
- {noError, 0};
- false ->
- {inconsistentName, element(1, hd(Cols))}
- end
+ {_, false} ->
+ %% otherwise, it's a row change;
+ %% row does not exist => inconsistentName
+ {inconsistentName, element(1, hd(Cols))};
+ _ ->
+ %% row change and row exists => noError
+ {noError, 0}
end;
Error ->
Error
@@ -734,10 +781,15 @@ do_vacmAccessTable_set(RowIndex, Cols) ->
%% Cols are sorted, and all columns are > 3.
+do_get_next(_RowIndex, []) ->
+ % Cols can be empty because we're called for each
+ % output of split_cols(); and one of that may well
+ % be empty.
+ [];
do_get_next(RowIndex, Cols) ->
case snmpa_vacm:get_next_row(RowIndex) of
{NextIndex, Row} ->
- F1 = fun(Col) when Col < ?vacmAccessStatus ->
+ F1 = fun(Col) when Col =< ?vacmAccessStatus ->
{[Col | NextIndex], element(Col-3, Row)};
(_) ->
endOfTable
@@ -745,9 +797,9 @@ do_get_next(RowIndex, Cols) ->
lists:map(F1, Cols);
false ->
case snmpa_vacm:get_next_row([]) of
- {_NextIndex, Row} ->
+ {NextIndex2, Row} ->
F2 = fun(Col) when Col < ?vacmAccessStatus ->
- {[Col+1 | RowIndex], element(Col-2, Row)};
+ {[Col+1 | NextIndex2], element(Col-2, Row)};
(_) ->
endOfTable
end,
@@ -796,8 +848,9 @@ vacmViewSpinLock(print) ->
vacmViewSpinLock(new) ->
snmp_generic:variable_func(new, volatile_db(vacmViewSpinLock)),
- {A1,A2,A3} = erlang:now(),
- random:seed(A1,A2,A3),
+ random:seed(erlang:phash2([node()]),
+ erlang:monotonic_time(),
+ erlang:unique_integer()),
Val = random:uniform(2147483648) - 1,
snmp_generic:variable_func(set, Val, volatile_db(vacmViewSpinLock));
@@ -908,13 +961,23 @@ verify_vacmViewTreeFamilyTable_col(?vacmViewTreeFamilySubtree, Tree) ->
wrongValue(?vacmViewTreeFamilySubtree)
end;
verify_vacmViewTreeFamilyTable_col(?vacmViewTreeFamilyMask, Mask) ->
+ %% Mask here is in the "external" format. That is, according
+ %% to the MIB, which means that its an OCTET STRING of max 16
+ %% octets.
+ %% We however store the mask as a list of 1's (exact) and
+ %% 0's (wildcard), which means we have to convert the mask.
case Mask of
- null -> [];
- [] -> [];
+ %% The Mask can only have this value if the vacmViewTreeFamilyTable
+ %% is called locally!
+ null ->
+ [];
+ [] ->
+ [];
_ ->
- case (catch snmp_conf:check_oid(Mask)) of
- ok ->
- Mask;
+ %% Check and convert to our internal format
+ case check_mask(Mask) of
+ {ok, IMask} ->
+ IMask;
_ ->
wrongValue(?vacmViewTreeFamilyMask)
end
@@ -932,6 +995,60 @@ verify_vacmViewTreeFamilyTable_col(_, Val) ->
Val.
+check_mask(Mask) when is_list(Mask) andalso (length(Mask) =< 16) ->
+ try
+ begin
+ {ok, emask2imask(Mask)}
+ end
+ catch
+ throw:{error, _} ->
+ {error, {bad_mask, Mask}};
+ T:E ->
+ {error, {bad_mask, Mask, T, E}}
+ end;
+check_mask(BadMask) ->
+ {error, {bad_mask, BadMask}}.
+
+-spec emask2imask(EMask :: external_view_mask()) ->
+ IMask :: internal_view_mask().
+
+%% Convert an External Mask (OCTET STRING) to Internal Mask (list of 0 or 1)
+emask2imask(EMask) ->
+ lists:flatten([octet2bits(Octet) || Octet <- EMask]).
+
+octet2bits(Octet)
+ when is_integer(Octet) andalso (Octet >= 16#00) andalso (16#FF >= Octet) ->
+ <<A:1, B:1, C:1, D:1, E:1, F:1, G:1, H:1>> = <<Octet>>,
+ [A, B, C, D, E, F, G, H];
+octet2bits(BadOctet) ->
+ throw({error, {bad_octet, BadOctet}}).
+
+-spec imask2emask(IMask :: internal_view_mask()) ->
+ EMask :: external_view_mask().
+
+%% Convert an Internal Mask (list of 0 or 1) to External Mask (OCTET STRING)
+imask2emask(IMask) ->
+ imask2emask(IMask, []).
+
+imask2emask([], EMask) ->
+ lists:reverse(EMask);
+imask2emask(IMask, EMask) ->
+ %% Make sure we have atleast 8 bits
+ %% (maybe extend with 1's)
+ IMask2 =
+ case length(IMask) of
+ Small when Small < 8 ->
+ IMask ++ lists:duplicate(8-Small, 1);
+ _ ->
+ IMask
+ end,
+ %% Extract 8 bits
+ [A, B, C, D, E, F, G, H | IMaskRest] = IMask2,
+ <<Octet:8>> = <<A:1, B:1, C:1, D:1, E:1, F:1, G:1, H:1>>,
+ imask2emask(IMaskRest, [Octet | EMask]).
+
+
+
table_next(Name, RestOid) ->
snmp_generic:table_next(db(Name), RestOid).
@@ -969,11 +1086,41 @@ stc(vacmSecurityToGroupTable) -> ?vacmSecurityToGroupStorageType;
stc(vacmViewTreeFamilyTable) -> ?vacmViewTreeFamilyStorageType.
next(Name, RowIndex, Cols) ->
- snmp_generic:handle_table_next(db(Name), RowIndex, Cols,
- fa(Name), foi(Name), noc(Name)).
+ Result = snmp_generic:handle_table_next(db(Name), RowIndex, Cols,
+ fa(Name), foi(Name), noc(Name)),
+ externalize_next(Name, Result).
get(Name, RowIndex, Cols) ->
- snmp_generic:handle_table_get(db(Name), RowIndex, Cols, foi(Name)).
+ Result = snmp_generic:handle_table_get(db(Name), RowIndex, Cols,
+ foi(Name)),
+ externalize_get(Name, Cols, Result).
+
+
+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.
+
+
+externalize_get(Name, Cols, Result) when is_list(Result) ->
+ %% Patch returned values
+ F = fun({Col, {value, Val}}) -> {value, externalize(Name, Col, Val)};
+ ({_, Other}) -> Other
+ 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.
+
+externalize(vacmViewTreeFamilyTable, ?vacmViewTreeFamilyMask, Val) ->
+ imask2emask(Val);
+externalize(_, _, Val) ->
+ Val.
+
wrongValue(V) -> throw({wrongValue, V}).
@@ -990,4 +1137,3 @@ error(Reason) ->
config_err(F, A) ->
snmpa_error:config_err("[VIEW-BASED-ACM-MIB]: " ++ F, A).
-
diff --git a/lib/snmp/src/agent/snmpa.erl b/lib/snmp/src/agent/snmpa.erl
index c400aaddf7..ff7be54283 100644
--- a/lib/snmp/src/agent/snmpa.erl
+++ b/lib/snmp/src/agent/snmpa.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
+%% 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
%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -39,8 +40,10 @@
enum_to_int/2, enum_to_int/3,
info/0, info/1, old_info_format/1,
- load_mibs/1, load_mibs/2,
- unload_mibs/1, unload_mibs/2,
+ load_mib/1, load_mib/2,
+ load_mibs/1, load_mibs/2, load_mibs/3,
+ unload_mib/1, unload_mib/2,
+ unload_mibs/1, unload_mibs/2, unload_mibs/3,
which_mibs/0, which_mibs/1,
whereis_mib/1, whereis_mib/2,
dump_mibs/0, dump_mibs/1,
@@ -83,8 +86,10 @@
-export([add_agent_caps/2, del_agent_caps/1, get_agent_caps/0]).
%% Audit Trail Log functions
--export([log_to_txt/2, log_to_txt/3, log_to_txt/4,
- log_to_txt/5, log_to_txt/6, log_to_txt/7,
+-export([log_to_txt/1, log_to_txt/2, log_to_txt/3, log_to_txt/4,
+ log_to_txt/5, log_to_txt/6, log_to_txt/7, log_to_txt/8,
+ log_to_io/1, log_to_io/2, log_to_io/3, log_to_io/4,
+ log_to_io/5, log_to_io/6, log_to_io/7,
log_info/0,
change_log_size/1,
get_log_type/0, get_log_type/1,
@@ -108,10 +113,42 @@
-export([print_mib_info/0, print_mib_tables/0, print_mib_variables/0]).
+-export_type([
+ me/0,
+
+ %% Agent config types
+ mib_storage/0,
+ mib_storage_opt/0,
+ mib_storage_module/0,
+ mib_storage_options/0
+ ]).
+
+-deprecated([{old_info_format, 1, next_major_release}]).
+
+
-include("snmpa_atl.hrl").
-include("snmpa_internal.hrl").
+-include_lib("snmp/include/snmp_types.hrl"). % type of me needed.
+
+-define(DISCO_EXTRA_INFO, undefined).
+-define(ATL_BLOCK_DEFAULT, true).
+
--define(DISCO_EXTRA_INFO, undefined).
+%%-----------------------------------------------------------------
+%% Types
+%%-----------------------------------------------------------------
+
+-type me() :: #me{}.
+
+%% Agent config types
+-type mib_storage() :: [mib_storage_opt()].
+-type mib_storage_opt() :: {module, mib_storage_module()} |
+ {options, mib_storage_options()}.
+
+%% Module implementing the snmpa_mib_storage behaviour
+-type mib_storage_module() :: atom().
+%% Options specific to the above module
+-type mib_storage_options() :: list().
%%-----------------------------------------------------------------
@@ -266,19 +303,75 @@ backup(Agent, BackupDir) ->
dump_mibs() -> snmpa_agent:dump_mibs(snmp_master_agent).
dump_mibs(File) -> snmpa_agent:dump_mibs(snmp_master_agent, File).
+
+load_mib(Mib) ->
+ load_mib(snmp_master_agent, Mib).
+
+-spec load_mib(Agent :: pid() | atom(), Mib :: string()) ->
+ ok | {error, Reason :: already_loaded | term()}.
+
+load_mib(Agent, Mib) ->
+ case load_mibs(Agent, [Mib]) of
+ {error, {'load aborted at', Mib, Reason}} ->
+ {error, Reason};
+ Else ->
+ Else
+ end.
+
load_mibs(Mibs) ->
- load_mibs(snmp_master_agent, Mibs).
+ load_mibs(snmp_master_agent, Mibs, false).
load_mibs(Agent, Mibs) when is_list(Mibs) ->
- snmpa_agent:load_mibs(Agent, Mibs).
+ snmpa_agent:load_mibs(Agent, Mibs, false);
+load_mibs(Mibs, Force)
+ when is_list(Mibs) andalso ((Force =:= true) orelse (Force =:= false)) ->
+ load_mibs(snmp_master_agent, Mibs, Force).
+
+-spec load_mibs(Agent :: pid() | atom(),
+ Mibs :: [MibName :: string()],
+ Force :: boolean()) ->
+ ok | {error, {'load aborted at', MibName :: string(), InternalReason :: already_loaded | term()}}.
+
+load_mibs(Agent, Mibs, Force)
+ when is_list(Mibs) andalso ((Force =:= true) orelse (Force =:= false)) ->
+ snmpa_agent:load_mibs(Agent, Mibs, Force).
+
+
+unload_mib(Mib) ->
+ unload_mib(snmp_master_agent, Mib).
+
+-spec unload_mib(Agent :: pid() | atom(), Mib :: string()) ->
+ ok | {error, Reason :: not_loaded | term()}.
+
+unload_mib(Agent, Mib) ->
+ case unload_mibs(Agent, [Mib]) of
+ {error, {'unload aborted at', Mib, Reason}} ->
+ {error, Reason};
+ Else ->
+ Else
+ end.
unload_mibs(Mibs) ->
- unload_mibs(snmp_master_agent, Mibs).
+ unload_mibs(snmp_master_agent, Mibs, false).
unload_mibs(Agent, Mibs) when is_list(Mibs) ->
- snmpa_agent:unload_mibs(Agent, Mibs).
+ snmpa_agent:unload_mibs(Agent, Mibs);
+unload_mibs(Mibs, Force)
+ when is_list(Mibs) andalso ((Force =:= true) orelse (Force =:= false)) ->
+ unload_mibs(snmp_master_agent, Mibs, Force).
+
+-spec unload_mibs(Agent :: pid() | atom(),
+ Mibs :: [MibName :: string()],
+ Force :: boolean()) ->
+ ok | {error, {'unload aborted at', MibName :: string(), InternalReason :: not_loaded | term()}}.
+
+unload_mibs(Agent, Mibs, Force)
+ when is_list(Mibs) andalso ((Force =:= true) orelse (Force =:= false)) ->
+ snmpa_agent:unload_mibs(Agent, Mibs, Force).
+
which_mibs() -> which_mibs(snmp_master_agent).
which_mibs(Agent) -> snmpa_agent:which_mibs(Agent).
+
whereis_mib(Mib) ->
whereis_mib(snmp_master_agent, Mib).
whereis_mib(Agent, Mib) when is_atom(Mib) ->
@@ -780,24 +873,207 @@ get_agent_caps() ->
%%% Audit Trail Log functions
%%%-----------------------------------------------------------------
+-spec log_to_txt(LogDir :: snmp:dir()) ->
+ snmp:void().
+
+log_to_txt(LogDir) ->
+ log_to_txt(LogDir, []).
+
+-spec log_to_txt(LogDir :: snmp:dir(),
+ Block :: boolean()) ->
+ snmp:void();
+ (LogDir :: snmp:dir(),
+ Mibs :: [snmp:mib_name()]) ->
+ snmp:void().
+
+log_to_txt(LogDir, Block)
+ when ((Block =:= true) orelse (Block =:= false)) ->
+ Mibs = [],
+ OutFile = "snmpa_log.txt",
+ LogName = ?audit_trail_log_name,
+ LogFile = ?audit_trail_log_file,
+ snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block);
+
log_to_txt(LogDir, Mibs) ->
+ Block = ?ATL_BLOCK_DEFAULT,
OutFile = "snmpa_log.txt",
LogName = ?audit_trail_log_name,
LogFile = ?audit_trail_log_file,
- snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile).
+ snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block).
+
+-spec log_to_txt(LogDir :: snmp:dir(),
+ Mibs :: [snmp:mib_name()],
+ Block :: boolean()) ->
+ snmp:void();
+ (LogDir :: snmp:dir(),
+ Mibs :: [snmp:mib_name()],
+ OutFile :: file:filename()) ->
+ snmp:void().
+
+log_to_txt(LogDir, Mibs, Block)
+ when ((Block =:= true) orelse (Block =:= false)) ->
+ OutFile = "snmpa_log.txt",
+ LogName = ?audit_trail_log_name,
+ LogFile = ?audit_trail_log_file,
+ snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block);
log_to_txt(LogDir, Mibs, OutFile) ->
+ Block = ?ATL_BLOCK_DEFAULT,
+ LogName = ?audit_trail_log_name,
+ LogFile = ?audit_trail_log_file,
+ snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block).
+
+-spec log_to_txt(LogDir :: snmp:dir(),
+ Mibs :: [snmp:mib_name()],
+ OutFile :: file:filename(),
+ Block :: boolean()) ->
+ snmp:void();
+ (LogDir :: snmp:dir(),
+ Mibs :: [snmp:mib_name()],
+ OutFile :: file:filename(),
+ LogName :: string()) ->
+ snmp:void().
+
+log_to_txt(LogDir, Mibs, OutFile, Block)
+ when ((Block =:= true) orelse (Block =:= false)) ->
LogName = ?audit_trail_log_name,
LogFile = ?audit_trail_log_file,
- snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile).
+ snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block);
log_to_txt(LogDir, Mibs, OutFile, LogName) ->
+ Block = ?ATL_BLOCK_DEFAULT,
LogFile = ?audit_trail_log_file,
- snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile).
+ snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block).
+
+-spec log_to_txt(LogDir :: snmp:dir(),
+ Mibs :: [snmp:mib_name()],
+ OutFile :: file:filename(),
+ LogName :: string(),
+ Block :: boolean()) ->
+ snmp:void();
+ (LogDir :: snmp:dir(),
+ Mibs :: [snmp:mib_name()],
+ OutFile :: file:filename(),
+ LogName :: string(),
+ LogFile :: string()) ->
+ snmp:void().
+
+log_to_txt(LogDir, Mibs, OutFile, LogName, Block)
+ when ((Block =:= true) orelse (Block =:= false)) ->
+ LogFile = ?audit_trail_log_file,
+ snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block);
log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile) ->
- snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile).
+ Block = ?ATL_BLOCK_DEFAULT,
+ snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block).
+
+-spec log_to_txt(LogDir :: snmp:dir(),
+ Mibs :: [snmp:mib_name()],
+ OutFile :: file:filename(),
+ LogName :: string(),
+ LogFile :: string(),
+ Block :: boolean()) ->
+ snmp:void();
+ (LogDir :: snmp:dir(),
+ Mibs :: [snmp:mib_name()],
+ OutFile :: file:filename(),
+ LogName :: string(),
+ LogFile :: string(),
+ Start :: snmp_log:log_time()) ->
+ snmp:void().
+
+log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block)
+ when ((Block =:= true) orelse (Block =:= false)) ->
+ snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block);
log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start) ->
- snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start).
+ Block = ?ATL_BLOCK_DEFAULT,
+ snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start).
+
+-spec log_to_txt(LogDir :: snmp:dir(),
+ Mibs :: [snmp:mib_name()],
+ OutFile :: file:filename(),
+ LogName :: string(),
+ LogFile :: string(),
+ Block :: boolean(),
+ Start :: snmp_log:log_time()) ->
+ snmp:void();
+ (LogDir :: snmp:dir(),
+ Mibs :: [snmp:mib_name()],
+ OutFile :: file:filename(),
+ LogName :: string(),
+ LogFile :: string(),
+ Start :: snmp_log:log_time(),
+ Stop :: snmp_log:log_time()) ->
+ snmp:void().
+
+log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start)
+ when ((Block =:= true) orelse (Block =:= false)) ->
+ snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start);
+
log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) ->
- snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop).
+ Block = ?ATL_BLOCK_DEFAULT,
+ snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop).
+
+-spec log_to_txt(LogDir :: snmp:dir(),
+ Mibs :: [snmp:mib_name()],
+ OutFile :: file:filename(),
+ LogName :: string(),
+ LogFile :: string(),
+ Block :: boolean(),
+ Start :: snmp_log:log_time(),
+ Stop :: snmp_log:log_time()) ->
+ snmp:void().
+
+log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop) ->
+ snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop).
+
+
+log_to_io(LogDir) ->
+ log_to_io(LogDir, []).
+
+log_to_io(LogDir, Block)
+ when ((Block =:= true) orelse (Block =:= false)) ->
+ Mibs = [],
+ LogName = ?audit_trail_log_name,
+ LogFile = ?audit_trail_log_file,
+ snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block);
+log_to_io(LogDir, Mibs) ->
+ Block = ?ATL_BLOCK_DEFAULT,
+ LogName = ?audit_trail_log_name,
+ LogFile = ?audit_trail_log_file,
+ snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block).
+
+log_to_io(LogDir, Mibs, Block)
+ when ((Block =:= true) orelse (Block =:= false)) ->
+ LogName = ?audit_trail_log_name,
+ LogFile = ?audit_trail_log_file,
+ snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block);
+log_to_io(LogDir, Mibs, LogName) ->
+ Block = ?ATL_BLOCK_DEFAULT,
+ LogFile = ?audit_trail_log_file,
+ snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block).
+
+log_to_io(LogDir, Mibs, LogName, Block)
+ when ((Block =:= true) orelse (Block =:= false)) ->
+ LogFile = ?audit_trail_log_file,
+ snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block);
+log_to_io(LogDir, Mibs, LogName, LogFile) ->
+ Block = ?ATL_BLOCK_DEFAULT,
+ snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block).
+
+log_to_io(LogDir, Mibs, LogName, LogFile, Block)
+ when ((Block =:= true) orelse (Block =:= false)) ->
+ snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block);
+log_to_io(LogDir, Mibs, LogName, LogFile, Start) ->
+ Block = ?ATL_BLOCK_DEFAULT,
+ snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start).
+
+log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start)
+ when ((Block =:= true) orelse (Block =:= false)) ->
+ snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start);
+log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop) ->
+ Block = ?ATL_BLOCK_DEFAULT,
+ snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop).
+
+log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop) ->
+ snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop).
log_info() ->
diff --git a/lib/snmp/src/agent/snmpa_acm.erl b/lib/snmp/src/agent/snmpa_acm.erl
index 42a0d4d6a3..de67df8a06 100644
--- a/lib/snmp/src/agent/snmpa_acm.erl
+++ b/lib/snmp/src/agent/snmpa_acm.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -279,7 +280,7 @@ validate_mib_view(Oid, MibView) ->
end.
get_largest_family([{SubTree, Mask, Type} | T], Oid, Res) ->
- case check_mask(Oid, SubTree, Mask) of
+ case check_mask(Oid, SubTree, snmp_view_based_acm_mib:emask2imask(Mask)) of
true -> get_largest_family(T, Oid, add_res(length(SubTree), SubTree,
Type, Res));
false -> get_largest_family(T, Oid, Res)
@@ -344,7 +345,7 @@ validate_all_mib_view([], _MibView) ->
%% intelligent.
%%-----------------------------------------------------------------
is_definitely_not_in_mib_view(Oid, [{SubTree, Mask,?view_included}|T]) ->
- case check_maybe_mask(Oid, SubTree, Mask) of
+ case check_maybe_mask(Oid, SubTree, snmp_view_based_acm_mib:emask2imask(Mask)) of
true -> false;
false -> is_definitely_not_in_mib_view(Oid, T)
end;
diff --git a/lib/snmp/src/agent/snmpa_agent.erl b/lib/snmp/src/agent/snmpa_agent.erl
index 9cc986cf47..458b88359b 100644
--- a/lib/snmp/src/agent/snmpa_agent.erl
+++ b/lib/snmp/src/agent/snmpa_agent.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
+%% 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
%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -28,7 +29,8 @@
%% External exports
-export([start_link/4, start_link/5, stop/1]).
-export([subagent_set/2,
- load_mibs/2, unload_mibs/2, which_mibs/1, whereis_mib/2, info/1,
+ load_mibs/3, unload_mibs/3,
+ which_mibs/1, whereis_mib/2, info/1,
register_subagent/3, unregister_subagent/2,
send_notification/3,
register_notification_filter/5,
@@ -71,7 +73,8 @@
handle_pdu/8, worker/2, worker_loop/1,
do_send_trap/7, do_send_trap/8]).
%% <BACKWARD-COMPAT>
--export([handle_pdu/7]).
+-export([handle_pdu/7,
+ load_mibs/2, unload_mibs/2]).
%% </BACKWARD-COMPAT>
-include("snmpa_internal.hrl").
@@ -159,12 +162,15 @@
%% it is sent to the worker, and the worker is marked as busy.
%% If a request is received when the worker is busy, a new temporary
%% worker is spawned.
+%%
%% Code change
%% ===========
%% Note that the worker(s) execute the same module as the master
%% agent. For code change we have two options - ignore the workers,
%% or send them a code change message.
+%%
%%-----------------------------------------------------------------
+
-record(state, {type,
parent,
worker,
@@ -219,22 +225,19 @@
%%-----------------------------------------------------------------
start_link(Prio, Parent, Ref, Options) ->
?d("start_link -> entry with"
- "~n Prio: ~p"
- "~n Parent: ~p"
- "~n Ref: ~p"
- "~n Options: ~p", [Prio, Parent, Ref, Options]),
- %% gen_server:start_link(?MODULE, [Prio, Parent, Ref, Options], []).
+ "~n Prio: ~p"
+ "~n Parent: ~p"
+ "~n Ref: ~p"
+ "~n Options: ~p", [Prio, Parent, Ref, Options]),
?GS_START_LINK3(Prio, Parent, Ref, Options).
start_link(Prio, Name, Parent, Ref, Options) ->
?d("start_link -> entry with"
- "~n Prio: ~p"
- "~n Name: ~p"
- "~n Parent: ~p"
- "~n Ref: ~p"
- "~n Options: ~p", [Prio, Name, Parent, Ref, Options]),
-% gen_server:start_link({local, Name}, ?MODULE,
-% [Prio, Parent, Ref, Options], []).
+ "~n Prio: ~p"
+ "~n Name: ~p"
+ "~n Parent: ~p"
+ "~n Ref: ~p"
+ "~n Options: ~p", [Prio, Name, Parent, Ref, Options]),
?GS_START_LINK4(Prio, Name, Parent, Ref, Options).
stop(Agent) -> call(Agent, stop).
@@ -335,10 +338,10 @@ increment_counter(Counter, Initial, Max) ->
init([Prio, Parent, Ref, Options]) ->
?d("init -> entry with"
- "~n Prio: ~p"
- "~n Parent: ~p"
- "~n Ref: ~p"
- "~n Options: ~p", [Prio, Parent, Ref, Options]),
+ "~n Prio: ~p"
+ "~n Parent: ~p"
+ "~n Ref: ~p"
+ "~n Options: ~p", [Prio, Parent, Ref, Options]),
case (catch do_init(Prio, Parent, Ref, Options)) of
{ok, State} ->
?vdebug("started",[]),
@@ -528,12 +531,22 @@ subagent_set(SubAgent, Arguments) ->
%% Called by administrator (not agent; deadlock would occur)
+%% <BACKWARD-COMPAT>
load_mibs(Agent, Mibs) ->
- call(Agent, {load_mibs, Mibs}).
+ load_mibs(Agent, Mibs, false).
+%% </BACKWARD-COMPAT>
+
+load_mibs(Agent, Mibs, Force) ->
+ call(Agent, {load_mibs, Mibs, Force}).
%% Called by administrator (not agent; deadlock would occur)
+%% <BACKWARD-COMPAT>
unload_mibs(Agent, Mibs) ->
- call(Agent, {unload_mibs, Mibs}).
+ unload_mibs(Agent, Mibs, false).
+%% </BACKWARD-COMPAT>
+
+unload_mibs(Agent, Mibs, Force) ->
+ call(Agent, {unload_mibs, Mibs, Force}).
which_mibs(Agent) ->
call(Agent, which_mibs).
@@ -1134,7 +1147,7 @@ handle_call({get, Vars, Context}, _From, S) ->
"~n Vars: ~p"
"~n Context: ~p", [Vars, Context]),
put_pdu_data({undefined, undefined, undefined, undefined, Context}),
- case catch mapfoldl({?MODULE, tr_var}, [], 1, Vars) of
+ case catch mapfoldl(fun ?MODULE:tr_var/2, [], 1, Vars) of
{error, Reason} -> {reply, {error, Reason}, S};
{_, Varbinds} ->
?vdebug("Varbinds: ~p",[Varbinds]),
@@ -1155,7 +1168,7 @@ handle_call({get_next, Vars, Context}, _From, S) ->
"~n Vars: ~p"
"~n Context: ~p",[Vars, Context]),
put_pdu_data({undefined, undefined, undefined, undefined, Context}),
- case catch mapfoldl({?MODULE, tr_var}, [], 1, Vars) of
+ case catch mapfoldl(fun ?MODULE:tr_var/2, [], 1, Vars) of
{error, Reason} -> {reply, {error, Reason}, S};
{_, Varbinds} ->
?vdebug("Varbinds: ~p",[Varbinds]),
@@ -1216,13 +1229,25 @@ handle_call({unregister_subagent, SubTreeOid}, _From, S) ->
end,
{reply, Reply, S};
+%% <BACKWARD-COMPAT>
handle_call({load_mibs, Mibs}, _From, S) ->
?vlog("load mibs ~p", [Mibs]),
{reply, snmpa_mib:load_mibs(get(mibserver), Mibs), S};
+%% </BACKWARD-COMPAT>
+handle_call({load_mibs, Mibs, Force}, _From, S) ->
+ ?vlog("[~w] load mibs ~p", [Force, Mibs]),
+ {reply, snmpa_mib:load_mibs(get(mibserver), Mibs, Force), S};
+
+%% <BACKWARD-COMPAT>
handle_call({unload_mibs, Mibs}, _From, S) ->
?vlog("unload mibs ~p", [Mibs]),
{reply, snmpa_mib:unload_mibs(get(mibserver), Mibs), S};
+%% </BACKWARD-COMPAT>
+
+handle_call({unload_mibs, Mibs, Force}, _From, S) ->
+ ?vlog("[~w] unload mibs ~p", [Force, Mibs]),
+ {reply, snmpa_mib:unload_mibs(get(mibserver), Mibs, Force), S};
handle_call(which_mibs, _From, S) ->
?vlog("which mibs", []),
@@ -1281,7 +1306,7 @@ handle_call({backup, BackupDir}, From, #state{backup = undefined} = S) ->
?vtrace("backup server: ~p", [BackupServer]),
{noreply, S#state{backup = {BackupServer, From}}};
-handle_call({backup, _BackupDir}, From, #state{backup = Backup} = S) ->
+handle_call({backup, _BackupDir}, _From, #state{backup = Backup} = S) ->
?vinfo("backup already in progress: ~p", [Backup]),
{reply, {error, backup_in_progress}, S};
@@ -1457,80 +1482,80 @@ handle_mibs_cache_request(MibServer, Req) ->
%% Downgrade
%%
-code_change({down, _Vsn}, S1, downgrade_to_pre_4_17_3) ->
- #state{type = Type,
- parent = Parent,
- worker = Worker,
- worker_state = WorkerState,
- set_worker = SetWorker,
- multi_threaded = MT,
- ref = Ref,
- vsns = Vsns,
- nfilters = NF,
- note_store = NoteStore,
- mib_server = MS,
- net_if = NetIf,
- net_if_mod = NetIfMod,
- backup = Backup,
- disco = Disco,
- mibs_cache_request = MCR} = S1,
- S2 = {state,
- type = Type,
- parent = Parent,
- worker = Worker,
- worker_state = WorkerState,
- set_worker = SetWorker,
- multi_threaded = MT,
- ref = Ref,
- vsns = Vsns,
- nfilters = NF,
- note_store = NoteStore,
- mib_server = MS,
- net_if = NetIf,
- net_if_mod = NetIfMod,
- backup = Backup,
- disco = Disco,
- mibs_cache_request = MCR},
- {ok, S2};
-
-%% Upgrade
-%%
-code_change(_Vsn, S1, upgrade_from_pre_4_17_3) ->
- {state,
- type = Type,
- parent = Parent,
- worker = Worker,
- worker_state = WorkerState,
- set_worker = SetWorker,
- multi_threaded = MT,
- ref = Ref,
- vsns = Vsns,
- nfilters = NF,
- note_store = NoteStore,
- mib_server = MS,
- net_if = NetIf,
- net_if_mod = NetIfMod,
- backup = Backup,
- disco = Disco,
- mibs_cache_request = MCR} = S1,
- S2 = #state{type = Type,
- parent = Parent,
- worker = Worker,
- worker_state = WorkerState,
- set_worker = SetWorker,
- multi_threaded = MT,
- ref = Ref,
- vsns = Vsns,
- nfilters = NF,
- note_store = NoteStore,
- mib_server = MS,
- net_if = NetIf,
- net_if_mod = NetIfMod,
- backup = Backup,
- disco = Disco,
- mibs_cache_request = MCR,
- gb_max_vbs = ?DEFAULT_GB_MAX_VBS},
- {ok, S2};
+%% code_change({down, _Vsn}, S1, downgrade_to_pre_4_17_3) ->
+%% #state{type = Type,
+%% parent = Parent,
+%% worker = Worker,
+%% worker_state = WorkerState,
+%% set_worker = SetWorker,
+%% multi_threaded = MT,
+%% ref = Ref,
+%% vsns = Vsns,
+%% nfilters = NF,
+%% note_store = NoteStore,
+%% mib_server = MS,
+%% net_if = NetIf,
+%% net_if_mod = NetIfMod,
+%% backup = Backup,
+%% disco = Disco,
+%% mibs_cache_request = MCR} = S1,
+%% S2 = {state,
+%% type = Type,
+%% parent = Parent,
+%% worker = Worker,
+%% worker_state = WorkerState,
+%% set_worker = SetWorker,
+%% multi_threaded = MT,
+%% ref = Ref,
+%% vsns = Vsns,
+%% nfilters = NF,
+%% note_store = NoteStore,
+%% mib_server = MS,
+%% net_if = NetIf,
+%% net_if_mod = NetIfMod,
+%% backup = Backup,
+%% disco = Disco,
+%% mibs_cache_request = MCR},
+%% {ok, S2};
+
+%% %% Upgrade
+%% %%
+%% code_change(_Vsn, S1, upgrade_from_pre_4_17_3) ->
+%% {state,
+%% type = Type,
+%% parent = Parent,
+%% worker = Worker,
+%% worker_state = WorkerState,
+%% set_worker = SetWorker,
+%% multi_threaded = MT,
+%% ref = Ref,
+%% vsns = Vsns,
+%% nfilters = NF,
+%% note_store = NoteStore,
+%% mib_server = MS,
+%% net_if = NetIf,
+%% net_if_mod = NetIfMod,
+%% backup = Backup,
+%% disco = Disco,
+%% mibs_cache_request = MCR} = S1,
+%% S2 = #state{type = Type,
+%% parent = Parent,
+%% worker = Worker,
+%% worker_state = WorkerState,
+%% set_worker = SetWorker,
+%% multi_threaded = MT,
+%% ref = Ref,
+%% vsns = Vsns,
+%% nfilters = NF,
+%% note_store = NoteStore,
+%% mib_server = MS,
+%% net_if = NetIf,
+%% net_if_mod = NetIfMod,
+%% backup = Backup,
+%% disco = Disco,
+%% mibs_cache_request = MCR,
+%% gb_max_vbs = ?DEFAULT_GB_MAX_VBS},
+%% {ok, S2};
code_change(_Vsn, S, _Extra) ->
{ok, S}.
@@ -2488,10 +2513,19 @@ handle_mib_of(MibServer, Oid) ->
%% Func: process_msg/7
%% Returns: RePdu
%%-----------------------------------------------------------------
-process_msg(MibView, Vsn, Pdu, PduMS, Community, {Ip, Udp}, ContextName,
- GbMaxVBs) ->
+process_msg(
+ MibView, Vsn, Pdu, PduMS, Community,
+ SourceAddress, ContextName, GbMaxVBs) ->
#pdu{request_id = ReqId} = Pdu,
- put(snmp_address, {tuple_to_list(Ip), Udp}),
+ put(
+ snmp_address,
+ case SourceAddress of
+ {Domain, _} when is_atom(Domain) ->
+ SourceAddress;
+ {Ip, Port} when is_integer(Port) ->
+ %% Legacy transport domain
+ {tuple_to_list(Ip), Port}
+ end),
put(snmp_request_id, ReqId),
put(snmp_community, Community),
put(snmp_context, ContextName),
@@ -4411,7 +4445,7 @@ get_mibs(Opts) ->
get_option(mibs, Opts, []).
get_mib_storage(Opts) ->
- get_option(mib_storage, Opts, ets).
+ get_option(mib_storage, Opts).
get_set_mechanism(Opts) ->
get_option(set_mechanism, Opts, snmpa_set).
@@ -4450,6 +4484,9 @@ net_if_verbosity(_Pid,_Verbosity) ->
ok.
+get_option(Key, Opts) ->
+ snmp_misc:get_option(Key, Opts).
+
get_option(Key, Opts, Default) ->
snmp_misc:get_option(Key, Opts, Default).
diff --git a/lib/snmp/src/agent/snmpa_agent_sup.erl b/lib/snmp/src/agent/snmpa_agent_sup.erl
index 9b8c4d12a6..0a5116b2d0 100644
--- a/lib/snmp/src/agent/snmpa_agent_sup.erl
+++ b/lib/snmp/src/agent/snmpa_agent_sup.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -29,10 +30,12 @@
-export([init/1]).
-define(SERVER, ?MODULE).
+%% Always use plain ets for sub-agents
-ifdef(snmp_debug).
--define(DEFAULT_OPTS, [{verbosity, trace}]).
+-define(DEFAULT_SA_OPTS, [{mib_storage, [{module, snmpa_mib_storage_ets}]},
+ {verbosity, trace}]).
-else.
--define(DEFAULT_OPTS, []).
+-define(DEFAULT_SA_OPTS, [{mib_storage, [{module, snmpa_mib_storage_ets}]}]).
-endif.
@@ -63,8 +66,8 @@ start_subagent(ParentAgent, Subtree, Mibs) ->
Ref = make_ref(),
?d("start_subagent -> Ref: ~p", [Ref]),
Options = [{priority, Prio},
- {mibs, Mibs},
- {misc_sup, snmpa_misc_sup} | ?DEFAULT_OPTS],
+ {mibs, Mibs},
+ {misc_sup, snmpa_misc_sup} | ?DEFAULT_SA_OPTS],
Agent = {{sub_agent, Max},
{snmpa_agent, start_link,
[Prio, ParentAgent, Ref, Options]},
diff --git a/lib/snmp/src/agent/snmpa_app.erl b/lib/snmp/src/agent/snmpa_app.erl
index 4e65e8e283..86ff145e93 100644
--- a/lib/snmp/src/agent/snmpa_app.erl
+++ b/lib/snmp/src/agent/snmpa_app.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
diff --git a/lib/snmp/src/agent/snmpa_atl.hrl b/lib/snmp/src/agent/snmpa_atl.hrl
index ec6beb3542..d07c850891 100644
--- a/lib/snmp/src/agent/snmpa_atl.hrl
+++ b/lib/snmp/src/agent/snmpa_atl.hrl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
diff --git a/lib/snmp/src/agent/snmpa_authentication_service.erl b/lib/snmp/src/agent/snmpa_authentication_service.erl
index b5ff8460c6..e4238a8384 100644
--- a/lib/snmp/src/agent/snmpa_authentication_service.erl
+++ b/lib/snmp/src/agent/snmpa_authentication_service.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
diff --git a/lib/snmp/src/agent/snmpa_conf.erl b/lib/snmp/src/agent/snmpa_conf.erl
index c17a6abbd7..fc5116dac9 100644
--- a/lib/snmp/src/agent/snmpa_conf.erl
+++ b/lib/snmp/src/agent/snmpa_conf.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -47,7 +48,7 @@
read_standard_config/1,
%% target_addr.conf
- target_addr_entry/5, target_addr_entry/6,
+ target_addr_entry/5, target_addr_entry/6, target_addr_entry/7,
target_addr_entry/8, target_addr_entry/10, target_addr_entry/11,
write_target_addr_config/2, write_target_addr_config/3,
append_target_addr_config/2,
@@ -108,36 +109,25 @@ write_agent_config(Dir, Conf) ->
Hdr = header() ++ Comment,
write_agent_config(Dir, Hdr, Conf).
-write_agent_config(Dir, Hdr, Conf)
+write_agent_config(Dir, Hdr, Conf)
when is_list(Dir) and is_list(Hdr) and is_list(Conf) ->
- Verify = fun() -> verify_agent_conf(Conf) end,
- Write = fun(Fd) -> write_agent_conf(Fd, Hdr, Conf) end,
- write_config_file(Dir, "agent.conf", Verify, Write).
-
+ Order = fun snmp_framework_mib:order_agent/2,
+ Check = fun snmp_framework_mib:check_agent/2,
+ Write = fun (Fd, Entries) -> write_agent_conf(Fd, Hdr, Entries) end,
+ write_config_file(Dir, "agent.conf", Order, Check, Write, Conf).
-append_agent_config(Dir, Conf)
+append_agent_config(Dir, Conf)
when is_list(Dir) and is_list(Conf) ->
- Verify = fun() -> verify_agent_conf(Conf) end,
- Write = fun(Fd) -> write_agent_conf(Fd, Conf) end,
- append_config_file(Dir, "agent.conf", Verify, Write).
-
+ Order = fun snmp_framework_mib:order_agent/2,
+ Check = fun snmp_framework_mib:check_agent/2,
+ Write = fun write_agent_conf/2,
+ append_config_file(Dir, "agent.conf", Order, Check, Write, Conf).
read_agent_config(Dir) ->
- Verify = fun(Entry) -> verify_agent_conf_entry(Entry) end,
- read_config_file(Dir, "agent.conf", Verify).
+ Order = fun snmp_framework_mib:order_agent/2,
+ Check = fun snmp_framework_mib:check_agent/2,
+ read_config_file(Dir, "agent.conf", Order, Check).
-
-verify_agent_conf([]) ->
- ok;
-verify_agent_conf([H|T]) ->
- verify_agent_conf_entry(H),
- verify_agent_conf(T);
-verify_agent_conf(X) ->
- error({bad_agent_config, X}).
-
-verify_agent_conf_entry(Entry) ->
- ok = snmp_framework_mib:check_agent(Entry),
- ok.
write_agent_conf(Fd, "", Conf) ->
write_agent_conf(Fd, Conf);
@@ -151,6 +141,10 @@ write_agent_conf(Fd, [H|T]) ->
do_write_agent_conf(Fd, H),
write_agent_conf(Fd, T).
+do_write_agent_conf(Fd, {intAgentTransports = Tag, Val}) ->
+ io:format(Fd, "{~w, ~w}.~n", [Tag, Val]);
+do_write_agent_conf(Fd, {intAgentTransportDomain = Tag, Val}) ->
+ io:format(Fd, "{~w, ~w}.~n", [Tag, Val]);
do_write_agent_conf(Fd, {intAgentIpAddress = Tag, Val}) ->
io:format(Fd, "{~w, ~w}.~n", [Tag, Val]);
do_write_agent_conf(Fd, {intAgentUDPPort = Tag, Val} ) ->
@@ -160,7 +154,7 @@ do_write_agent_conf(Fd, {intAgentMaxPacketSize = Tag, Val} ) ->
do_write_agent_conf(Fd, {snmpEngineMaxMessageSize = Tag, Val} ) ->
io:format(Fd, "{~w, ~w}.~n", [Tag, Val]);
do_write_agent_conf(Fd, {snmpEngineID = Tag, Val} ) ->
- io:format(Fd, "{~w, \"~s\"}.~n", [Tag, Val]);
+ io:format(Fd, "{~w, ~p}.~n", [Tag, Val]);
do_write_agent_conf(_Fd, Crap) ->
error({bad_agent_config, Crap}).
@@ -191,34 +185,27 @@ write_context_config(Dir, Conf) ->
write_context_config(Dir, Hdr, Conf)
when is_list(Dir) and is_list(Hdr) and is_list(Conf) ->
- Verify = fun() -> verify_context_conf(Conf) end,
- Write = fun(Fd) -> write_context_conf(Fd, Hdr, Conf) end,
- write_config_file(Dir, "context.conf", Verify, Write).
-
+ Order = fun snmp_conf:no_order/2,
+ Check = fun check_context/2,
+ Write = fun (Fd, Entries) -> write_context_conf(Fd, Hdr, Entries) end,
+ write_config_file(Dir, "context.conf", Order, Check, Write, Conf).
-append_context_config(Dir, Conf)
+append_context_config(Dir, Conf)
when is_list(Dir) and is_list(Conf) ->
- Verify = fun() -> verify_context_conf(Conf) end,
- Write = fun(Fd) -> write_context_conf(Fd, Conf) end,
- append_config_file(Dir, "context.conf", Verify, Write).
-
+ Order = fun snmp_conf:no_order/2,
+ Check = fun check_context/2,
+ Write = fun write_context_conf/2,
+ append_config_file(Dir, "context.conf", Order, Check, Write, Conf).
read_context_config(Dir) ->
- Verify = fun(Entry) -> verify_context_conf_entry(Entry) end,
- read_config_file(Dir, "context.conf", Verify).
+ Order = fun snmp_conf:no_order/2,
+ Check = fun check_context/2,
+ read_config_file(Dir, "context.conf", Order, Check).
-
-verify_context_conf([]) ->
- ok;
-verify_context_conf([H|T]) ->
- verify_context_conf_entry(H),
- verify_context_conf(T);
-verify_context_conf(X) ->
- error({error_context_config, X}).
-
-verify_context_conf_entry(Context) ->
- {ok, _} = snmp_framework_mib:check_context(Context),
- ok.
+
+check_context(Entry, State) ->
+ {check_ok(snmp_framework_mib:check_context(Entry)),
+ State}.
write_context_conf(Fd, "", Conf) ->
write_context_conf(Fd, Conf);
@@ -271,36 +258,29 @@ write_community_config(Dir, Conf) ->
Hdr = header() ++ Comment,
write_community_config(Dir, Hdr, Conf).
-write_community_config(Dir, Hdr, Conf)
+write_community_config(Dir, Hdr, Conf)
when is_list(Dir) and is_list(Hdr) and is_list(Conf) ->
- Verify = fun() -> verify_community_conf(Conf) end,
- Write = fun(Fd) -> write_community_conf(Fd, Hdr, Conf) end,
- write_config_file(Dir, "community.conf", Verify, Write).
-
+ Order = fun snmp_conf:no_order/2,
+ Check = fun check_community/2,
+ Write = fun (Fd, Entries) -> write_community_conf(Fd, Hdr, Entries) end,
+ write_config_file(Dir, "community.conf", Order, Check, Write, Conf).
-append_community_config(Dir, Conf)
+append_community_config(Dir, Conf)
when is_list(Dir) and is_list(Conf) ->
- Verify = fun() -> verify_community_conf(Conf) end,
- Write = fun(Fd) -> write_community_conf(Fd, Conf) end,
- append_config_file(Dir, "community.conf", Verify, Write).
-
+ Order = fun snmp_conf:no_order/2,
+ Check = fun check_community/2,
+ Write = fun write_community_conf/2,
+ append_config_file(Dir, "community.conf", Order, Check, Write, Conf).
read_community_config(Dir) ->
- Verify = fun(Entry) -> verify_community_conf_entry(Entry) end,
- read_config_file(Dir, "community.conf", Verify).
+ Order = fun snmp_conf:no_order/2,
+ Check = fun check_community/2,
+ read_config_file(Dir, "community.conf", Order, Check).
-
-verify_community_conf([]) ->
- ok;
-verify_community_conf([H|T]) ->
- verify_community_conf_entry(H),
- verify_community_conf(T);
-verify_community_conf(X) ->
- error({invalid_community_config, X}).
-
-verify_community_conf_entry(Context) ->
- {ok, _} = snmp_community_mib:check_community(Context),
- ok.
+
+check_community(Entry, State) ->
+ {check_ok(snmp_community_mib:check_community(Entry)),
+ State}.
write_community_conf(Fd, "", Conf) ->
write_community_conf(Fd, Conf);
@@ -309,14 +289,17 @@ write_community_conf(Fd, Hdr, Conf) ->
write_community_conf(Fd, Conf).
write_community_conf(Fd, Conf) ->
- Fun = fun({Idx, Name, SecName, CtxName, TranspTag}) ->
- io:format(Fd, "{\"~s\", \"~s\", \"~s\", \"~s\", \"~s\"}.~n",
- [Idx, Name, SecName, CtxName, TranspTag]);
+ Fun =
+ fun({Idx, Name, SecName, CtxName, TranspTag}) ->
+ io:format(
+ Fd,
+ "{\"~s\", \"~s\", \"~s\", \"~s\", \"~s\"}.~n",
+ [Idx, Name, SecName, CtxName, TranspTag]);
(Crap) ->
- error({bad_community_config, Crap})
+ error({bad_community_config, Crap})
end,
lists:foreach(Fun, Conf).
-
+
%%
%% ------ standard.conf ------
@@ -343,40 +326,29 @@ write_standard_config(Dir, Conf) ->
Hdr = header() ++ Comment,
write_standard_config(Dir, Hdr, Conf).
-write_standard_config(Dir, Hdr, Conf)
+write_standard_config(Dir, Hdr, Conf)
when is_list(Dir) and is_list(Hdr) and is_list(Conf) ->
- Verify = fun() -> verify_standard_conf(Conf) end,
- Write = fun(Fd) -> write_standard_conf(Fd, Hdr, Conf) end,
- write_config_file(Dir, "standard.conf", Verify, Write).
+ Order = fun snmp_conf:no_order/2,
+ Check = fun check_standard/2,
+ Write = fun (Fd, Entries) -> write_standard_conf(Fd, Hdr, Entries) end,
+ write_config_file(Dir, "standard.conf", Order, Check, Write, Conf).
-
-append_standard_config(Dir, Conf)
+append_standard_config(Dir, Conf)
when is_list(Dir) and is_list(Conf) ->
- Verify = fun() -> verify_standard_conf(Conf) end,
- Write = fun(Fd) -> write_standard_conf(Fd, Conf) end,
- append_config_file(Dir, "standard.conf", Verify, Write).
-
+ Order = fun snmp_conf:no_order/2,
+ Check = fun check_standard/2,
+ Write = fun write_standard_conf/2,
+ append_config_file(Dir, "standard.conf", Order, Check, Write, Conf).
read_standard_config(Dir) ->
- Verify = fun(Entry) -> verify_standard_conf_entry(Entry) end,
- read_config_file(Dir, "standard.conf", Verify).
+ Order = fun snmp_conf:no_order/2,
+ Check = fun check_standard/2,
+ read_config_file(Dir, "standard.conf", Order, Check).
-
-verify_standard_conf([]) ->
- ok;
-verify_standard_conf([H|T]) ->
- verify_standard_conf_entry(H),
- verify_standard_conf(T);
-verify_standard_conf(X) ->
- error({bad_standard_config, X}).
-
-verify_standard_conf_entry(Std) ->
- case snmp_standard_mib:check_standard(Std) of
- ok ->
- ok;
- {ok, _} ->
- ok
- end.
+
+check_standard(Entry, State) ->
+ {check_ok(snmp_standard_mib:check_standard(Entry)),
+ State}.
write_standard_conf(Fd, "", Conf) ->
write_standard_conf(Fd, Conf);
@@ -410,72 +382,48 @@ do_write_standard_conf(_Fd, Tag, Val) ->
%% ------ target_addr.conf ------
%%
-target_addr_entry(Name,
- Ip,
- TagList,
- ParamsName,
- EngineId) ->
+target_addr_entry(
+ Name, Ip, TagList, ParamsName, EngineId) ->
target_addr_entry(Name, Ip, TagList, ParamsName, EngineId, []).
-target_addr_entry(Name,
- Ip,
- TagList,
- ParamsName,
- EngineId,
- TMask) ->
- target_addr_entry(Name, Ip, 162, TagList,
- ParamsName, EngineId,
- TMask, 2048).
-
-target_addr_entry(Name,
- Ip,
- Udp,
- TagList,
- ParamsName,
- EngineId,
- TMask,
- MaxMessageSize) ->
- target_addr_entry(Name, Ip, Udp, 1500, 3, TagList,
- ParamsName, EngineId,
- TMask, MaxMessageSize).
-
-target_addr_entry(Name,
- Ip,
- Udp,
- Timeout,
- RetryCount,
- TagList,
- ParamsName,
- EngineId,
- TMask,
- MaxMessageSize) ->
- target_addr_entry(Name, snmp_target_mib:default_domain(), Ip, Udp,
- Timeout, RetryCount, TagList,
- ParamsName, EngineId,
- TMask, MaxMessageSize).
-
-target_addr_entry(Name,
- Domain,
- Ip,
- Udp,
- Timeout,
- RetryCount,
- TagList,
- ParamsName,
- EngineId,
- TMask,
- MaxMessageSize) ->
- {Name,
- Domain,
- Ip,
- Udp,
- Timeout,
- RetryCount,
- TagList,
- ParamsName,
- EngineId,
- TMask,
- MaxMessageSize}.
+target_addr_entry(
+ Name, Domain, Addr, TagList,
+ ParamsName, EngineId) when is_atom(Domain) ->
+ target_addr_entry(
+ Name, Domain, Addr, TagList,
+ ParamsName, EngineId, []);
+target_addr_entry(
+ Name, Ip, TagList, ParamsName,
+ EngineId, TMask) ->
+ target_addr_entry(
+ Name, Ip, 162, TagList, ParamsName,
+ EngineId, TMask, 2048).
+
+target_addr_entry(
+ Name, Domain_or_Ip, Addr_or_Port, TagList,
+ ParamsName, EngineId, TMask) ->
+ target_addr_entry(
+ Name, Domain_or_Ip, Addr_or_Port, TagList,
+ ParamsName, EngineId, TMask, 2048).
+
+target_addr_entry(
+ Name, Domain_or_Ip, Addr_or_Port, TagList,
+ ParamsName, EngineId, TMask, MaxMessageSize) ->
+ target_addr_entry(
+ Name, Domain_or_Ip, Addr_or_Port, 1500, 3, TagList,
+ ParamsName, EngineId, TMask, MaxMessageSize).
+
+target_addr_entry(
+ Name, Domain_or_Ip, Addr_or_Port, Timeout, RetryCount, TagList,
+ ParamsName, EngineId, TMask, MaxMessageSize) ->
+ {Name, Domain_or_Ip, Addr_or_Port, Timeout, RetryCount, TagList,
+ ParamsName, EngineId, TMask, MaxMessageSize}.
+
+target_addr_entry(
+ Name, Domain, Ip, Udp, Timeout, RetryCount, TagList,
+ ParamsName, EngineId,TMask, MaxMessageSize) ->
+ {Name, Domain, Ip, Udp, Timeout, RetryCount, TagList,
+ ParamsName, EngineId, TMask, MaxMessageSize}.
write_target_addr_config(Dir, Conf) ->
@@ -504,37 +452,29 @@ write_target_addr_config(Dir, Conf) ->
Hdr = header() ++ Comment,
write_target_addr_config(Dir, Hdr, Conf).
-write_target_addr_config(Dir, Hdr, Conf)
+write_target_addr_config(Dir, Hdr, Conf)
when is_list(Dir) and is_list(Hdr) and is_list(Conf) ->
- Verify = fun() -> verify_target_addr_conf(Conf) end,
- Write = fun(Fd) -> write_target_addr_conf(Fd, Hdr, Conf) end,
- write_config_file(Dir, "target_addr.conf", Verify, Write).
-
-
+ Order = fun snmp_conf:no_order/2,
+ Check = fun check_target_addr/2,
+ Write = fun (Fd, Entries) -> write_target_addr_conf(Fd, Hdr, Entries) end,
+ write_config_file(Dir, "target_addr.conf", Order, Check, Write, Conf).
-append_target_addr_config(Dir, Conf)
+append_target_addr_config(Dir, Conf)
when is_list(Dir) and is_list(Conf) ->
- Verify = fun() -> verify_target_addr_conf(Conf) end,
- Write = fun(Fd) -> write_target_addr_conf(Fd, Conf) end,
- append_config_file(Dir, "target_addr.conf", Verify, Write).
-
+ Order = fun snmp_conf:no_order/2,
+ Check = fun check_target_addr/2,
+ Write = fun write_target_addr_conf/2,
+ append_config_file(Dir, "target_addr.conf", Order, Check, Write, Conf).
read_target_addr_config(Dir) ->
- Verify = fun(Entry) -> verify_target_addr_conf_entry(Entry) end,
- read_config_file(Dir, "target_addr.conf", Verify).
+ Order = fun snmp_conf:no_order/2,
+ Check = fun check_target_addr/2,
+ read_config_file(Dir, "target_addr.conf", Order, Check).
-
-verify_target_addr_conf([]) ->
- ok;
-verify_target_addr_conf([H|T]) ->
- verify_target_addr_conf_entry(H),
- verify_target_addr_conf(T);
-verify_target_addr_conf(X) ->
- error({bad_target_addr_config, X}).
-
-verify_target_addr_conf_entry(Entry) ->
- {ok, _} = snmp_target_mib:check_target_addr(Entry),
- ok.
+
+check_target_addr(Entry, State) ->
+ {check_ok(snmp_target_mib:check_target_addr(Entry)),
+ State}.
write_target_addr_conf(Fd, "", Conf) ->
write_target_addr_conf(Fd, Conf);
@@ -547,29 +487,41 @@ write_target_addr_conf(Fd, Conf) ->
lists:foreach(Fun, Conf),
ok.
-do_write_target_addr_conf(Fd,
- {Name,
- Ip, Udp,
- Timeout, RetryCount, TagList,
- ParamsName, EngineId,
- TMask, MaxMessageSize}) ->
- Domain = snmp_target_mib:default_domain(),
- do_write_target_addr_conf(Fd,
- {Name,
- Domain, Ip, Udp,
- Timeout, RetryCount, TagList,
- ParamsName, EngineId,
- TMask, MaxMessageSize});
-do_write_target_addr_conf(Fd,
- {Name,
- Domain, Ip, Udp,
- Timeout, RetryCount, TagList,
- ParamsName, EngineId,
- TMask, MaxMessageSize}) ->
- io:format(Fd,
- "{\"~s\", ~w, ~w, ~w, ~w, ~w, \"~s\", \"~s\", \"~s\", ~w, ~w}.~n",
- [Name, Domain, Ip, Udp, Timeout, RetryCount, TagList,
- ParamsName, EngineId, TMask, MaxMessageSize]);
+do_write_target_addr_conf(
+ Fd,
+ {Name, Domain, Address, Timeout, RetryCount, TagList,
+ ParamsName, EngineId, TMask, MaxMessageSize})
+ when is_atom(Domain) ->
+ io:format(
+ Fd,
+ "{\"~s\", ~w, ~w, ~w, ~w, \"~s\", \"~s\", \"~s\", ~w, ~w}.~n",
+ [Name, Domain, Address, Timeout, RetryCount, TagList,
+ ParamsName, EngineId, TMask, MaxMessageSize]);
+do_write_target_addr_conf(
+ Fd,
+ {Name, Ip, Udp, Timeout, RetryCount, TagList,
+ ParamsName, EngineId, TMask, MaxMessageSize})
+ when is_integer(Udp) ->
+ Domain = snmp_target_mib:default_domain(),
+ Address = {Ip, Udp},
+ do_write_target_addr_conf(
+ Fd,
+ {Name, Domain, Address, Timeout, RetryCount, TagList,
+ ParamsName, EngineId, TMask, MaxMessageSize});
+do_write_target_addr_conf(
+ _Fd,
+ {_Name, Domain, Address, _Timeout, _RetryCount, _TagList,
+ _ParamsName, _EngineId, _TMask, _MaxMessageSize}) ->
+ error({bad_address, {Domain, Address}});
+do_write_target_addr_conf(
+ Fd,
+ {Name, Domain, Ip, Udp, Timeout, RetryCount, TagList,
+ ParamsName, EngineId, TMask, MaxMessageSize}) ->
+ Address = {Ip, Udp},
+ do_write_target_addr_conf(
+ Fd,
+ {Name, Domain, Address, Timeout, RetryCount, TagList,
+ ParamsName, EngineId, TMask, MaxMessageSize});
do_write_target_addr_conf(_Fd, Crap) ->
error({bad_target_addr_config, Crap}).
@@ -613,34 +565,27 @@ write_target_params_config(Dir, Conf) ->
write_target_params_config(Dir, Hdr, Conf)
when is_list(Dir) and is_list(Hdr) and is_list(Conf) ->
- Verify = fun() -> verify_target_params_conf(Conf) end,
- Write = fun(Fd) -> write_target_params_conf(Fd, Hdr, Conf) end,
- write_config_file(Dir, "target_params.conf", Verify, Write).
-
+ Order = fun snmp_conf:no_order/2,
+ Check = fun check_target_params/2,
+ Write = fun (Fd, Entries) -> write_target_params_conf(Fd, Hdr, Entries) end,
+ write_config_file(Dir, "target_params.conf", Order, Check, Write, Conf).
append_target_params_config(Dir, Conf)
when is_list(Dir) and is_list(Conf) ->
- Verify = fun() -> verify_target_params_conf(Conf) end,
- Write = fun(Fd) -> write_target_params_conf(Fd, Conf) end,
- append_config_file(Dir, "target_params.conf", Verify, Write).
-
+ Order = fun snmp_conf:no_order/2,
+ Check = fun check_target_params/2,
+ Write = fun write_target_params_conf/2,
+ append_config_file(Dir, "target_params.conf", Order, Check, Write, Conf).
read_target_params_config(Dir) ->
- Verify = fun(Entry) -> verify_target_params_conf_entry(Entry) end,
- read_config_file(Dir, "target_params.conf", Verify).
+ Order = fun snmp_conf:no_order/2,
+ Check = fun check_target_params/2,
+ read_config_file(Dir, "target_params.conf", Order, Check).
-verify_target_params_conf([]) ->
- ok;
-verify_target_params_conf([H|T]) ->
- verify_target_params_conf_entry(H),
- verify_target_params_conf(T);
-verify_target_params_conf(X) ->
- error({bad_target_params_config, X}).
-
-verify_target_params_conf_entry(Entry) ->
- {ok, _} = snmp_target_mib:check_target_params(Entry),
- ok.
+check_target_params(Entry, State) ->
+ {check_ok(snmp_target_mib:check_target_params(Entry)),
+ State}.
write_target_params_conf(Fd, "", Conf) ->
write_target_params_conf(Fd, Conf);
@@ -685,34 +630,27 @@ write_notify_config(Dir, Conf) ->
write_notify_config(Dir, Hdr, Conf)
when is_list(Dir) and is_list(Hdr) and is_list(Conf) ->
- Verify = fun() -> verify_notify_conf(Conf) end,
- Write = fun(Fd) -> write_notify_conf(Fd, Hdr, Conf) end,
- write_config_file(Dir, "notify.conf", Verify, Write).
-
+ Order = fun snmp_conf:no_order/2,
+ Check = fun check_notify/2,
+ Write = fun (Fd, Entries) -> write_notify_conf(Fd, Hdr, Entries) end,
+ write_config_file(Dir, "notify.conf", Order, Check, Write, Conf).
append_notify_config(Dir, Conf)
when is_list(Dir) and is_list(Conf) ->
- Verify = fun() -> verify_notify_conf(Conf) end,
- Write = fun(Fd) -> write_notify_conf(Fd, Conf) end,
- append_config_file(Dir, "notify.conf", Verify, Write).
-
+ Order = fun snmp_conf:no_order/2,
+ Check = fun check_notify/2,
+ Write = fun write_notify_conf/2,
+ append_config_file(Dir, "notify.conf", Order, Check, Write, Conf).
read_notify_config(Dir) ->
- Verify = fun(Entry) -> verify_notify_conf_entry(Entry) end,
- read_config_file(Dir, "notify.conf", Verify).
+ Order = fun snmp_conf:no_order/2,
+ Check = fun check_notify/2,
+ read_config_file(Dir, "notify.conf", Order, Check).
-verify_notify_conf([]) ->
- ok;
-verify_notify_conf([H|T]) ->
- verify_notify_conf_entry(H),
- verify_notify_conf(T);
-verify_notify_conf(X) ->
- error({bad_notify_config, X}).
-
-verify_notify_conf_entry(Entry) ->
- {ok, _} = snmp_notification_mib:check_notify(Entry),
- ok.
+check_notify(Entry, State) ->
+ {check_ok(snmp_notification_mib:check_notify(Entry)),
+ State}.
write_notify_conf(Fd, "", Conf) ->
write_notify_conf(Fd, Conf);
@@ -781,34 +719,27 @@ write_usm_config(Dir, Conf) ->
write_usm_config(Dir, Hdr, Conf)
when is_list(Dir) and is_list(Hdr) and is_list(Conf) ->
- Verify = fun() -> verify_usm_conf(Conf) end,
- Write = fun(Fd) -> write_usm_conf(Fd, Hdr, Conf) end,
- write_config_file(Dir, "usm.conf", Verify, Write).
-
+ Order = fun snmp_conf:no_order/2,
+ Check = fun check_usm/2,
+ Write = fun (Fd, Entries) -> write_usm_conf(Fd, Hdr, Entries) end,
+ write_config_file(Dir, "usm.conf", Order, Check, Write, Conf).
append_usm_config(Dir, Conf)
when is_list(Dir) and is_list(Conf) ->
- Verify = fun() -> verify_usm_conf(Conf) end,
- Write = fun(Fd) -> write_usm_conf(Fd, Conf) end,
- append_config_file(Dir, "usm.conf", Verify, Write).
-
+ Order = fun snmp_conf:no_order/2,
+ Check = fun check_usm/2,
+ Write = fun write_usm_conf/2,
+ append_config_file(Dir, "usm.conf", Order, Check, Write, Conf).
read_usm_config(Dir) ->
- Verify = fun(Entry) -> verify_usm_conf_entry(Entry) end,
- read_config_file(Dir, "usm.conf", Verify).
+ Order = fun snmp_conf:no_order/2,
+ Check = fun check_usm/2,
+ read_config_file(Dir, "usm.conf", Order, Check).
-verify_usm_conf([]) ->
- ok;
-verify_usm_conf([H|T]) ->
- verify_usm_conf_entry(H),
- verify_usm_conf(T);
-verify_usm_conf(X) ->
- error({bad_usm_conf, X}).
-
-verify_usm_conf_entry(Entry) ->
- {ok, _} = snmp_user_based_sm_mib:check_usm(Entry),
- ok.
+check_usm(Entry, State) ->
+ {check_ok(snmp_user_based_sm_mib:check_usm(Entry)),
+ State}.
write_usm_conf(Fd, "", Conf) ->
write_usm_conf(Fd, Conf);
@@ -820,15 +751,16 @@ write_usm_conf(Fd, Conf) ->
Fun = fun(Entry) -> do_write_usm_conf(Fd, Entry) end,
lists:foreach(Fun, Conf).
-do_write_usm_conf(Fd,
- {EngineID, UserName, SecName, Clone,
- AuthP, AuthKeyC, OwnAuthKeyC,
- PrivP, PrivKeyC, OwnPrivKeyC,
- Public, AuthKey, PrivKey}) ->
+do_write_usm_conf(
+ Fd,
+ {EngineID, UserName, SecName, Clone,
+ AuthP, AuthKeyC, OwnAuthKeyC,
+ PrivP, PrivKeyC, OwnPrivKeyC,
+ Public, AuthKey, PrivKey}) ->
io:format(Fd, "{", []),
- io:format(Fd, "\"~s\", ", [EngineID]),
- io:format(Fd, "\"~s\", ", [UserName]),
- io:format(Fd, "\"~s\", ", [SecName]),
+ io:format(Fd, "~p, ", [EngineID]),
+ io:format(Fd, "~p, ", [UserName]),
+ io:format(Fd, "~p, ", [SecName]),
io:format(Fd, "~w, ", [Clone]),
io:format(Fd, "~w, ", [AuthP]),
do_write_usm2(Fd, AuthKeyC, ", "),
@@ -890,34 +822,27 @@ write_vacm_config(Dir, Conf) ->
write_vacm_config(Dir, Hdr, Conf)
when is_list(Dir) and is_list(Hdr) and is_list(Conf) ->
- Verify = fun() -> verify_vacm_conf(Conf) end,
- Write = fun(Fd) -> write_vacm_conf(Fd, Hdr, Conf) end,
- write_config_file(Dir, "vacm.conf", Verify, Write).
-
+ Order = fun snmp_conf:no_order/2,
+ Check = fun check_vacm/2,
+ Write = fun (Fd, Entries) -> write_vacm_conf(Fd, Hdr, Entries) end,
+ write_config_file(Dir, "vacm.conf", Order, Check, Write, Conf).
append_vacm_config(Dir, Conf)
when is_list(Dir) and is_list(Conf) ->
- Verify = fun() -> verify_vacm_conf(Conf) end,
- Write = fun(Fd) -> write_vacm_conf(Fd, Conf) end,
- append_config_file(Dir, "vacm.conf", Verify, Write).
-
+ Order = fun snmp_conf:no_order/2,
+ Check = fun check_vacm/2,
+ Write = fun write_vacm_conf/2,
+ append_config_file(Dir, "vacm.conf", Order, Check, Write, Conf).
read_vacm_config(Dir) ->
- Verify = fun(Entry) -> verify_vacm_conf_entry(Entry) end,
- read_config_file(Dir, "vacm.conf", Verify).
+ Order = fun snmp_conf:no_order/2,
+ Check = fun check_vacm/2,
+ read_config_file(Dir, "vacm.conf", Order, Check).
-verify_vacm_conf([]) ->
- ok;
-verify_vacm_conf([H|T]) ->
- verify_vacm_conf_entry(H),
- verify_vacm_conf(T);
-verify_vacm_conf(X) ->
- error({bad_vacm_conf, X}).
-
-verify_vacm_conf_entry(Entry) ->
- {ok, _} = snmp_view_based_acm_mib:check_vacm(Entry),
- ok.
+check_vacm(Entry, State) ->
+ {check_ok(snmp_view_based_acm_mib:check_vacm(Entry)),
+ State}.
write_vacm_conf(Fd, "", Conf) ->
write_vacm_conf(Fd, Conf);
@@ -929,49 +854,60 @@ write_vacm_conf(Fd, Conf) ->
Fun = fun(Entry) -> do_write_vacm_conf(Fd, Entry) end,
lists:foreach(Fun, Conf).
-do_write_vacm_conf(Fd,
- {vacmSecurityToGroup,
- SecModel, SecName, GroupName}) ->
- io:format(Fd, "{vacmSecurityToGroup, ~w, \"~s\", \"~s\"}.~n",
- [SecModel, SecName, GroupName]);
-do_write_vacm_conf(Fd,
- {vacmAccess,
- GroupName, Prefix, SecModel, SecLevel, Match, RV, WV, NV}) ->
- io:format(Fd, "{vacmAccess, \"~s\", \"~s\", ~w, ~w, ~w, "
- "\"~s\", \"~s\", \"~s\"}.~n",
- [GroupName, Prefix, SecModel, SecLevel,
- Match, RV, WV, NV]);
-do_write_vacm_conf(Fd,
- {vacmViewTreeFamily,
- ViewIndex, ViewSubtree, ViewStatus, ViewMask}) ->
- io:format(Fd, "{vacmViewTreeFamily, \"~s\", ~w, ~w, ~w}.~n",
- [ViewIndex, ViewSubtree, ViewStatus, ViewMask]);
+do_write_vacm_conf(
+ Fd,
+ {vacmSecurityToGroup,
+ SecModel, SecName, GroupName}) ->
+ io:format(
+ Fd, "{vacmSecurityToGroup, ~w, ~p, ~p}.~n",
+ [SecModel, SecName, GroupName]);
+do_write_vacm_conf(
+ Fd,
+ {vacmAccess,
+ GroupName, Prefix, SecModel, SecLevel, Match, RV, WV, NV}) ->
+ io:format(
+ Fd, "{vacmAccess, ~p, ~p, ~w, ~w, ~w, "
+ "~p, ~p, ~p}.~n",
+ [GroupName, Prefix, SecModel, SecLevel,
+ Match, RV, WV, NV]);
+do_write_vacm_conf(
+ Fd,
+ {vacmViewTreeFamily,
+ ViewIndex, ViewSubtree, ViewStatus, ViewMask}) ->
+ io:format(
+ Fd, "{vacmViewTreeFamily, ~p, ~w, ~w, ~w}.~n",
+ [ViewIndex, ViewSubtree, ViewStatus, ViewMask]);
do_write_vacm_conf(_Fd, Crap) ->
error({bad_vacm_config, Crap}).
%% ---- config file wrapper functions ----
-write_config_file(Dir, File, Verify, Write) ->
- snmp_config:write_config_file(Dir, File, Verify, Write).
+write_config_file(Dir, File, Order, Check, Write, Conf) ->
+ snmp_config:write_config_file(Dir, File, Order, Check, Write, Conf).
-append_config_file(Dir, File, Verify, Write) ->
- snmp_config:append_config_file(Dir, File, Verify, Write).
+append_config_file(Dir, File, Order, Check, Write, Conf) ->
+ snmp_config:append_config_file(Dir, File, Order, Check, Write, Conf).
-read_config_file(Dir, File, Verify) ->
- snmp_config:read_config_file(Dir, File, Verify).
+read_config_file(Dir, File, Order, Check) ->
+ snmp_config:read_config_file(Dir, File, Order, Check).
%% ---- config file utility functions ----
+check_ok(ok) ->
+ ok;
+check_ok({ok, _}) ->
+ ok.
+
header() ->
{Y,Mo,D} = date(),
{H,Mi,S} = time(),
- io_lib:format("%% This file was generated by "
- "~w (version-~s) ~w-~2.2.0w-~2.2.0w "
- "~2.2.0w:~2.2.0w:~2.2.0w\n",
- [?MODULE, ?version, Y, Mo, D, H, Mi, S]).
-
+ io_lib:format(
+ "%% This file was generated by "
+ "~w (version-~s) ~w-~2.2.0w-~2.2.0w "
+ "~2.2.0w:~2.2.0w:~2.2.0w\n",
+ [?MODULE, ?version, Y, Mo, D, H, Mi, S]).
error(R) ->
throw({error, R}).
diff --git a/lib/snmp/src/agent/snmpa_discovery_handler.erl b/lib/snmp/src/agent/snmpa_discovery_handler.erl
index cf38583054..ffdd6aca1e 100644
--- a/lib/snmp/src/agent/snmpa_discovery_handler.erl
+++ b/lib/snmp/src/agent/snmpa_discovery_handler.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
diff --git a/lib/snmp/src/agent/snmpa_discovery_handler_default.erl b/lib/snmp/src/agent/snmpa_discovery_handler_default.erl
index 12a27993ab..8bd8d1973e 100644
--- a/lib/snmp/src/agent/snmpa_discovery_handler_default.erl
+++ b/lib/snmp/src/agent/snmpa_discovery_handler_default.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
diff --git a/lib/snmp/src/agent/snmpa_error.erl b/lib/snmp/src/agent/snmpa_error.erl
index db2b8d0178..804c850593 100644
--- a/lib/snmp/src/agent/snmpa_error.erl
+++ b/lib/snmp/src/agent/snmpa_error.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
diff --git a/lib/snmp/src/agent/snmpa_error_io.erl b/lib/snmp/src/agent/snmpa_error_io.erl
index 54cdb6baac..e961d4b525 100644
--- a/lib/snmp/src/agent/snmpa_error_io.erl
+++ b/lib/snmp/src/agent/snmpa_error_io.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
diff --git a/lib/snmp/src/agent/snmpa_error_logger.erl b/lib/snmp/src/agent/snmpa_error_logger.erl
index b1124fd728..d52a3e48ac 100644
--- a/lib/snmp/src/agent/snmpa_error_logger.erl
+++ b/lib/snmp/src/agent/snmpa_error_logger.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
diff --git a/lib/snmp/src/agent/snmpa_error_report.erl b/lib/snmp/src/agent/snmpa_error_report.erl
index 35c02edcab..8f28eac653 100644
--- a/lib/snmp/src/agent/snmpa_error_report.erl
+++ b/lib/snmp/src/agent/snmpa_error_report.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
diff --git a/lib/snmp/src/agent/snmpa_general_db.erl b/lib/snmp/src/agent/snmpa_general_db.erl
index a06604c9cf..431302b6cc 100644
--- a/lib/snmp/src/agent/snmpa_general_db.erl
+++ b/lib/snmp/src/agent/snmpa_general_db.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
+%% 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
%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
diff --git a/lib/snmp/src/agent/snmpa_internal.hrl b/lib/snmp/src/agent/snmpa_internal.hrl
index c435b519d9..fe3ba9f39e 100644
--- a/lib/snmp/src/agent/snmpa_internal.hrl
+++ b/lib/snmp/src/agent/snmpa_internal.hrl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
+%% 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
%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
diff --git a/lib/snmp/src/agent/snmpa_local_db.erl b/lib/snmp/src/agent/snmpa_local_db.erl
index ab277fc3e9..eb67b9cd6f 100644
--- a/lib/snmp/src/agent/snmpa_local_db.erl
+++ b/lib/snmp/src/agent/snmpa_local_db.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -191,6 +192,12 @@ dets_open(DbDir, DbInitError, Opts) ->
end
end;
_ ->
+ case DbInitError of
+ create_db_and_dir ->
+ ok = filelib:ensure_dir(Filename);
+ _ ->
+ ok
+ end,
case do_dets_open(Name, Filename, Opts) of
{ok, Dets} ->
?vdebug("dets open done",[]),
@@ -515,7 +522,7 @@ handle_call({backup, BackupDir}, From,
{reply, Error, State}
end;
-handle_call({backup, _BackupDir}, From, #state{backup = Backup} = S) ->
+handle_call({backup, _BackupDir}, _From, #state{backup = Backup} = S) ->
?vinfo("backup already in progress: ~p", [Backup]),
{reply, {error, backup_in_progress}, S};
@@ -583,7 +590,7 @@ handle_cast({variable_inc, Name, Db, N}, State) ->
{value, Val} -> Val;
_ -> 0
end,
- insert(Db, Name, M+N rem 4294967296, State),
+ insert(Db, Name, (M+N) rem 4294967296, State),
{noreply, State};
handle_cast({verbosity,Verbosity}, State) ->
@@ -1005,6 +1012,10 @@ table_construct_row(Name, RowIndex, Status, Cols) ->
defvals = Defs, status_col = StatusCol,
first_own_index = FirstOwnIndex, not_accessible = NoAccs} =
snmp_generic:table_info(Name),
+ ?vtrace(
+ "table_construct_row Indexes: ~p~n"
+ " RowIndex: ~p",
+ [Indexes, RowIndex]),
Keys = snmp_generic:split_index_to_keys(Indexes, RowIndex),
OwnKeys = snmp_generic:get_own_indexes(FirstOwnIndex, Keys),
Row = OwnKeys ++ snmp_generic:table_create_rest(length(OwnKeys) + 1,
diff --git a/lib/snmp/src/agent/snmpa_mib.erl b/lib/snmp/src/agent/snmpa_mib.erl
index 574467d38f..ab1098514c 100644
--- a/lib/snmp/src/agent/snmpa_mib.erl
+++ b/lib/snmp/src/agent/snmpa_mib.erl
@@ -1,24 +1,24 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
+%% 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
%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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_mib).
-%% c(snmpa_mib).
%%%-----------------------------------------------------------------
%%% This module implements a MIB server.
@@ -27,7 +27,7 @@
%% External exports
-export([start_link/3, stop/1,
lookup/2, next/3, which_mib/2, which_mibs/1, whereis_mib/2,
- load_mibs/2, unload_mibs/2,
+ load_mibs/3, unload_mibs/3,
register_subagent/3, unregister_subagent/2, info/1, info/2,
verbosity/2, dump/1, dump/2,
backup/2,
@@ -40,6 +40,10 @@
which_cache_size/1
]).
+%% <BACKWARD-COMPAT>
+-export([load_mibs/2, unload_mibs/2]).
+%% </BACKWARD-COMPAT>
+
%% Internal exports
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
code_change/3]).
@@ -75,12 +79,14 @@
%% Internal Data structures
%%
%% State
-%% data - is the MIB data (defined in snmpa_mib_data)
+%% data - is the MIB data (defined in mib_data module)
%% meo - mib entry override
%% teo - trap (notification) entry override
%%-----------------------------------------------------------------
--record(state, {data, meo, teo, backup,
- cache, cache_tmr, cache_autogc, cache_gclimit, cache_age}).
+-record(state,
+ {data, meo, teo, backup,
+ cache, cache_tmr, cache_autogc, cache_gclimit, cache_age,
+ data_mod}).
@@ -181,19 +187,32 @@ next(MibServer, Oid, MibView) ->
%%----------------------------------------------------------------------
%% Purpose: Loads mibs into the mib process.
%% Args: Mibs is a list of Filenames (compiled mibs).
+%% Force is a boolean
%% Returns: ok | {error, Reason}
%%----------------------------------------------------------------------
+
+%% <BACKWARD-COMPAT>
load_mibs(MibServer, Mibs) ->
- call(MibServer, {load_mibs, Mibs}).
+ load_mibs(MibServer, Mibs, false).
+%% </BACKWARD-COMPAT>
+
+load_mibs(MibServer, Mibs, Force) ->
+ call(MibServer, {load_mibs, Mibs, Force}).
%%----------------------------------------------------------------------
%% Purpose: Loads mibs into the mib process.
%% Args: Mibs is a list of Filenames (compiled mibs).
+%% Force is a boolean
%% Returns: ok | {error, Reason}
%%----------------------------------------------------------------------
+%% <BACKWARD-COMPAT>
unload_mibs(MibServer, Mibs) ->
- call(MibServer, {unload_mibs, Mibs}).
+ unload_mibs(MibServer, Mibs, false).
+%% </BACKWARD-COMPAT>
+
+unload_mibs(MibServer, Mibs, Force) ->
+ call(MibServer, {unload_mibs, Mibs, Force}).
%%----------------------------------------------------------------------
@@ -224,9 +243,9 @@ info(MibServer, Type) ->
call(MibServer, {info, Type}).
dump(MibServer) ->
- call(MibServer, dump).
+ dump(MibServer, io).
-dump(MibServer, File) when is_list(File) ->
+dump(MibServer, File) when (File =:= io) orelse is_list(File) ->
call(MibServer, {dump, File}).
backup(MibServer, BackupDir) when is_list(BackupDir) ->
@@ -256,7 +275,7 @@ init([Prio, Mibs, Opts]) ->
do_init(Prio, Mibs, Opts) ->
process_flag(priority, Prio),
process_flag(trap_exit, true),
- put(sname,ms),
+ put(sname, ms),
put(verbosity, ?vvalidate(get_verbosity(Opts))),
?vlog("starting",[]),
@@ -289,13 +308,19 @@ do_init(Prio, Mibs, Opts) ->
MeOverride = get_me_override(Opts),
TeOverride = get_te_override(Opts),
MibStorage = get_mib_storage(Opts),
- Data = snmpa_mib_data:new(MibStorage),
- ?vtrace("init -> mib data created",[]),
- case (catch mib_operations(load_mib, Mibs, Data,
+ MibDataMod = get_data_mod(Opts),
+ ?vtrace("init -> try create mib data with"
+ "~n MeOverride: ~p"
+ "~n TeOverride: ~p"
+ "~n MibStorage: ~p", [MeOverride, TeOverride, MibStorage]),
+ Data = MibDataMod:new(MibStorage),
+ ?vdebug("init -> mib data created", []),
+ case (catch mib_operations(MibDataMod,
+ load_mib, Mibs, Data,
MeOverride, TeOverride, true)) of
{ok, Data2} ->
?vdebug("started",[]),
- snmpa_mib_data:sync(Data2),
+ MibDataMod:sync(Data2),
?vdebug("mib data synced",[]),
{ok, #state{data = Data2,
teo = TeOverride,
@@ -304,7 +329,8 @@ do_init(Prio, Mibs, Opts) ->
cache_tmr = CacheGcTimer,
cache_autogc = CacheAutoGC,
cache_gclimit = CacheGcLimit,
- cache_age = CacheAge}};
+ cache_age = CacheAge,
+ data_mod = MibDataMod}};
{'aborted at', Mib, _NewData, Reason} ->
?vinfo("failed loading mib ~p: ~p",[Mib,Reason]),
{error, {Mib, Reason}}
@@ -315,32 +341,30 @@ do_init(Prio, Mibs, Opts) ->
%% Returns: {ok, NewMibData} | {'aborted at', Mib, NewData, Reason}
%% Args: Operation is load_mib | unload_mib.
%%----------------------------------------------------------------------
-mib_operations(Operation, Mibs, Data, MeOverride, TeOverride) ->
- mib_operations(Operation, Mibs, Data, MeOverride, TeOverride, false).
-
-
-mib_operations(_Operation, [], Data, _MeOverride, _TeOverride, _Force) ->
+mib_operations(_Mod, _Operation, [], Data, _MeOverride, _TeOverride, _Force) ->
{ok, Data};
-mib_operations(Operation, [Mib|Mibs], Data0, MeOverride, TeOverride, Force) ->
+mib_operations(Mod, Operation, [Mib|Mibs], Data0, MeOverride, TeOverride, Force) ->
?vtrace("mib operations ~p on"
- "~n Mibs: ~p"
- "~n with "
- "~n MeOverride: ~p"
- "~n TeOverride: ~p"
- "~n Force: ~p", [Operation,Mibs,MeOverride,TeOverride,Force]),
- Data = mib_operation(Operation, Mib, Data0, MeOverride, TeOverride, Force),
- mib_operations(Operation, Mibs, Data, MeOverride, TeOverride, Force).
-
-mib_operation(Operation, Mib, Data0, MeOverride, TeOverride, Force)
+ "~n Mibs: ~p"
+ "~n with "
+ "~n MeOverride: ~p"
+ "~n TeOverride: ~p"
+ "~n Force: ~p",
+ [Operation, Mibs, MeOverride, TeOverride, Force]),
+ Data = mib_operation(Mod,
+ Operation, Mib, Data0, MeOverride, TeOverride, Force),
+ mib_operations(Mod, Operation, Mibs, Data, MeOverride, TeOverride, Force).
+
+mib_operation(Mod, Operation, Mib, Data0, MeOverride, TeOverride, Force)
when is_list(Mib) ->
?vtrace("mib operation on mib ~p", [Mib]),
- case apply(snmpa_mib_data, Operation, [Data0,Mib,MeOverride,TeOverride]) of
- {error, 'already loaded'} when (Operation =:= load_mib) andalso
+ case apply(Mod, Operation, [Data0, Mib, MeOverride, TeOverride]) of
+ {error, already_loaded} when (Operation =:= load_mib) andalso
(Force =:= true) ->
?vlog("ignore mib ~p -> already loaded", [Mib]),
Data0;
- {error, 'not loaded'} when (Operation =:= unload_mib) andalso
- (Force =:= true) ->
+ {error, not_loaded} when (Operation =:= unload_mib) andalso
+ (Force =:= true) ->
?vlog("ignore mib ~p -> not loaded", [Mib]),
Data0;
{error, Reason} ->
@@ -350,7 +374,7 @@ mib_operation(Operation, Mib, Data0, MeOverride, TeOverride, Force)
{ok, Data} ->
Data
end;
-mib_operation(_Op, Mib, Data, _MeOverride, _TeOverride, _Force) ->
+mib_operation(_Mod, _Op, Mib, Data, _MeOverride, _TeOverride, _Force) ->
throw({'aborted at', Mib, Data, bad_mibname}).
@@ -395,15 +419,15 @@ handle_call({update_cache_opts, Key, Value}, _From, State) ->
{reply, Result, NewState};
handle_call({lookup, Oid}, _From,
- #state{data = Data, cache = Cache} = State) ->
+ #state{data = Data, cache = Cache, data_mod = Mod} = State) ->
?vlog("lookup ~p", [Oid]),
Key = {lookup, Oid},
{Reply, NewState} =
case maybe_cache_lookup(Cache, Key) of
?NO_CACHE ->
- {snmpa_mib_data:lookup(Data, Oid), State};
+ {Mod:lookup(Data, Oid), State};
[] ->
- Rep = snmpa_mib_data:lookup(Data, Oid),
+ Rep = Mod:lookup(Data, Oid),
ets:insert(Cache, {Key, Rep, timestamp()}),
{Rep, maybe_start_cache_gc_timer(State)};
[{Key, Rep, _}] ->
@@ -414,22 +438,23 @@ handle_call({lookup, Oid}, _From,
?vdebug("lookup -> Reply: ~p", [Reply]),
{reply, Reply, NewState};
-handle_call({which_mib, Oid}, _From, #state{data = Data} = State) ->
+handle_call({which_mib, Oid}, _From,
+ #state{data = Data, data_mod = Mod} = State) ->
?vlog("which_mib ~p",[Oid]),
- Reply = snmpa_mib_data:which_mib(Data, Oid),
+ Reply = Mod:which_mib(Data, Oid),
?vdebug("which_mib: ~p",[Reply]),
{reply, Reply, State};
handle_call({next, Oid, MibView}, _From,
- #state{data = Data, cache = Cache} = State) ->
+ #state{data = Data, cache = Cache, data_mod = Mod} = State) ->
?vlog("next ~p [~p]", [Oid, MibView]),
Key = {next, Oid, MibView},
{Reply, NewState} =
case maybe_cache_lookup(Cache, Key) of
?NO_CACHE ->
- {snmpa_mib_data:next(Data, Oid, MibView), State};
+ {Mod:next(Data, Oid, MibView), State};
[] ->
- Rep = snmpa_mib_data:next(Data, Oid, MibView),
+ Rep = Mod:next(Data, Oid, MibView),
ets:insert(Cache, {Key, Rep, timestamp()}),
{Rep, maybe_start_cache_gc_timer(State)};
[{Key, Rep, _}] ->
@@ -440,90 +465,110 @@ handle_call({next, Oid, MibView}, _From,
?vdebug("next -> Reply: ~p", [Reply]),
{reply, Reply, NewState};
-handle_call({load_mibs, Mibs}, _From,
- #state{data = Data,
- teo = TeOverride,
- meo = MeOverride,
- cache = Cache} = State) ->
- ?vlog("load mibs ~p",[Mibs]),
+%% <BACKWARD-COMPAT>
+handle_call({load_mibs, Mibs}, From, State) ->
+ handle_call({load_mibs, Mibs, false}, From, State);
+%% </BACKWARD-COMPAT>
+
+handle_call({load_mibs, Mibs, Force}, _From,
+ #state{data = Data,
+ teo = TeOverride,
+ meo = MeOverride,
+ cache = Cache,
+ data_mod = Mod} = State) ->
+ ?vlog("[~w] load mibs ~p", [Force, Mibs]),
%% Invalidate cache
NewCache = maybe_invalidate_cache(Cache),
- {NData,Reply} =
- case (catch mib_operations(load_mib, Mibs, Data,
- MeOverride, TeOverride)) of
+ {NData, Reply} =
+ case (catch mib_operations(Mod, load_mib, Mibs, Data,
+ MeOverride, TeOverride, Force)) of
{'aborted at', Mib, NewData, Reason} ->
?vlog("aborted at ~p for reason ~p",[Mib,Reason]),
- {NewData,{error, {'load aborted at', Mib, Reason}}};
+ {NewData, {error, {'load aborted at', Mib, Reason}}};
{ok, NewData} ->
- {NewData,ok}
+ {NewData, ok}
end,
- snmpa_mib_data:sync(NData),
+ Mod:sync(NData),
{reply, Reply, State#state{data = NData, cache = NewCache}};
-handle_call({unload_mibs, Mibs}, _From,
- #state{data = Data,
- teo = TeOverride,
- meo = MeOverride,
- cache = Cache} = State) ->
- ?vlog("unload mibs ~p",[Mibs]),
+%% <BACKWARD-COMPAT>
+handle_call({unload_mibs, Mibs}, From, State) ->
+ handle_call({unload_mibs, Mibs, false}, From, State);
+%% </BACKWARD-COMPAT>
+
+handle_call({unload_mibs, Mibs, Force}, _From,
+ #state{data = Data,
+ teo = TeOverride,
+ meo = MeOverride,
+ cache = Cache,
+ data_mod = Mod} = State) ->
+ ?vlog("[~w] unload mibs ~p", [Force, Mibs]),
%% Invalidate cache
NewCache = maybe_invalidate_cache(Cache),
%% Unload mib(s)
- {NData,Reply} =
- case (catch mib_operations(unload_mib, Mibs, Data,
- MeOverride, TeOverride)) of
+ {NData, Reply} =
+ case (catch mib_operations(Mod, unload_mib, Mibs, Data,
+ MeOverride, TeOverride, Force)) of
{'aborted at', Mib, NewData, Reason} ->
- ?vlog("aborted at ~p for reason ~p",[Mib,Reason]),
+ ?vlog("aborted at ~p for reason ~p", [Mib,Reason]),
{NewData, {error, {'unload aborted at', Mib, Reason}}};
{ok, NewData} ->
- {NewData,ok}
+ {NewData, ok}
end,
- snmpa_mib_data:sync(NData),
+ Mod:sync(NData),
{reply, Reply, State#state{data = NData, cache = NewCache}};
-handle_call(which_mibs, _From, #state{data = Data} = State) ->
+handle_call(which_mibs, _From, #state{data = Data, data_mod = Mod} = State) ->
?vlog("which mibs",[]),
- Reply = snmpa_mib_data:which_mibs(Data),
+ Reply = Mod:which_mibs(Data),
{reply, Reply, State};
-handle_call({whereis_mib, Mib}, _From, #state{data = Data} = State) ->
+handle_call({whereis_mib, Mib}, _From,
+ #state{data = Data,
+ data_mod = Mod} = State) ->
?vlog("whereis mib: ~p",[Mib]),
- Reply = snmpa_mib_data:whereis_mib(Data, Mib),
+ Reply = Mod:whereis_mib(Data, Mib),
{reply, Reply, State};
handle_call({register_subagent, Oid, Pid}, _From,
- #state{data = Data, cache = Cache} = State) ->
+ #state{data = Data,
+ cache = Cache,
+ data_mod = Mod} = State) ->
?vlog("register subagent ~p, ~p",[Oid,Pid]),
%% Invalidate cache
NewCache = maybe_invalidate_cache(Cache),
- case snmpa_mib_data:register_subagent(Data, Oid, Pid) of
+ case Mod:register_subagent(Data, Oid, Pid) of
{error, Reason} ->
?vlog("registration failed: ~p",[Reason]),
{reply, {error, Reason}, State#state{cache = NewCache}};
- NewData ->
+ {ok, NewData} ->
{reply, ok, State#state{data = NewData, cache = NewCache}}
end;
handle_call({unregister_subagent, OidOrPid}, _From,
- #state{data = Data, cache = Cache} = State) ->
+ #state{data = Data,
+ cache = Cache,
+ data_mod = Mod} = State) ->
?vlog("unregister subagent ~p",[OidOrPid]),
%% Invalidate cache
NewCache = maybe_invalidate_cache(Cache),
- case snmpa_mib_data:unregister_subagent(Data, OidOrPid) of
+ case Mod:unregister_subagent(Data, OidOrPid) of
+ {ok, NewData} ->
+ {reply, ok, State#state{data = NewData, cache = NewCache}};
{ok, NewData, DeletedSubagentPid} ->
{reply, {ok, DeletedSubagentPid}, State#state{data = NewData,
cache = NewCache}};
{error, Reason} ->
?vlog("unregistration failed: ~p",[Reason]),
- {reply, {error, Reason}, State#state{cache = NewCache}};
- NewData ->
- {reply, ok, State#state{data = NewData, cache = NewCache}}
+ {reply, {error, Reason}, State#state{cache = NewCache}}
end;
-handle_call(info, _From, #state{data = Data, cache = Cache} = State) ->
+handle_call(info, _From, #state{data = Data,
+ cache = Cache,
+ data_mod = Mod} = State) ->
?vlog("info",[]),
Reply =
- case (catch snmpa_mib_data:info(Data)) of
+ case (catch Mod:info(Data)) of
Info when is_list(Info) ->
[{cache, size_cache(Cache)} | Info];
E ->
@@ -531,10 +576,12 @@ handle_call(info, _From, #state{data = Data, cache = Cache} = State) ->
end,
{reply, Reply, State};
-handle_call({info, Type}, _From, #state{data = Data} = State) ->
+handle_call({info, Type}, _From,
+ #state{data = Data,
+ data_mod = Mod} = State) ->
?vlog("info ~p",[Type]),
Reply =
- case (catch snmpa_mib_data:info(Data, Type)) of
+ case (catch Mod:info(Data, Type)) of
Info when is_list(Info) ->
Info;
E ->
@@ -542,21 +589,19 @@ handle_call({info, Type}, _From, #state{data = Data} = State) ->
end,
{reply, Reply, State};
-handle_call(dump, _From, State) ->
- ?vlog("dump",[]),
- Reply = snmpa_mib_data:dump(State#state.data),
- {reply, Reply, State};
-
-handle_call({dump, File}, _From, #state{data = Data} = State) ->
+handle_call({dump, File}, _From,
+ #state{data = Data, data_mod = Mod} = State) ->
?vlog("dump on ~s",[File]),
- Reply = snmpa_mib_data:dump(Data, File),
+ Reply = Mod:dump(Data, File),
{reply, Reply, State};
%% This check (that there is no backup already in progress) is also
%% done in the master agent process, but just in case a user issues
%% a backup call to this process directly, we add a similar check here.
handle_call({backup, BackupDir}, From,
- #state{backup = undefined, data = Data} = State) ->
+ #state{backup = undefined,
+ data = Data,
+ data_mod = Mod} = State) ->
?vlog("backup to ~s", [BackupDir]),
Pid = self(),
V = get(verbosity),
@@ -568,7 +613,7 @@ handle_call({backup, BackupDir}, From,
put(sname, ambs),
put(verbosity, V),
Dir = filename:join([BackupDir]),
- Reply = snmpa_mib_data:backup(Data, Dir),
+ Reply = Mod:backup(Data, Dir),
Pid ! {backup_done, Reply},
unlink(Pid)
end),
@@ -580,7 +625,7 @@ handle_call({backup, BackupDir}, From,
{reply, Error, State}
end;
-handle_call({backup, _BackupDir}, From, #state{backup = Backup} = S) ->
+handle_call({backup, _BackupDir}, _From, #state{backup = Backup} = S) ->
?vinfo("backup already in progress: ~p", [Backup]),
{reply, {error, backup_in_progress}, S};
@@ -637,8 +682,8 @@ handle_info(Info, State) ->
warning_msg("received unknown info: ~n~p", [Info]),
{noreply, State}.
-terminate(_Reason, #state{data = Data}) ->
- catch snmpa_mib_data:close(Data),
+terminate(_Reason, #state{data = Data, data_mod = Mod}) ->
+ catch Mod:close(Data),
ok.
@@ -655,6 +700,11 @@ terminate(_Reason, #state{data = Data}) ->
%% S2 = {state, Data, MEO, TEO, B},
%% {ok, S2};
+code_change({down, Vsn}, #state{data = Data0, data_mod = Mod} = State, Extra) ->
+ Data = Mod:code_change(down, Vsn, Extra, Data0),
+ {ok, State#state{data = Data}};
+
+
%% %% upgrade
%% %%
%% code_change(_Vsn, S1, upgrade_from_pre_4_12) ->
@@ -663,8 +713,9 @@ terminate(_Reason, #state{data = Data}) ->
%% S2 = #state{data = Data, meo = MEO, teo = TEO, backup = B, cache = Cache},
%% {ok, S2};
-code_change(_Vsn, State, _Extra) ->
- {ok, State}.
+code_change(Vsn, #state{data = Data0, data_mod = Mod} = State, Extra) ->
+ Data = Mod:code_change(up, Vsn, Extra, Data0),
+ {ok, State#state{data = Data}}.
%%-----------------------------------------------------------------
@@ -681,7 +732,10 @@ get_te_override(Options) ->
get_opt(trapentry_override, Options, false).
get_mib_storage(Options) ->
- get_opt(mib_storage, Options, ets).
+ get_opt(mib_storage, Options).
+
+get_data_mod(Options) ->
+ get_opt(data_module, Options, snmpa_mib_data_tttn).
get_cacheopt_autogc(Cache, CacheOpts) ->
IsValid = fun(AutoGC) when ((AutoGC =:= true) orelse
@@ -868,6 +922,9 @@ timestamp() ->
%% ----------------------------------------------------------------
+get_opt(Key, Options) ->
+ snmp_misc:get_option(Key, Options).
+
get_opt(Key, Options, Default) ->
snmp_misc:get_option(Key, Options, Default).
diff --git a/lib/snmp/src/agent/snmpa_mib_data.erl b/lib/snmp/src/agent/snmpa_mib_data.erl
index b80d85d2ee..fcbc0465c8 100644
--- a/lib/snmp/src/agent/snmpa_mib_data.erl
+++ b/lib/snmp/src/agent/snmpa_mib_data.erl
@@ -1,1355 +1,110 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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_mib_data).
-%%%-----------------------------------------------------------------
-%%% This module implements the MIB internal data structures.
-%%% An MIB Data Structure consists of three items; an ets-table,
-%%% a tree and a list of registered subagents.
-%%% The subagent information is consequently duplicated. It resides
-%%% both in the tree and in the list.
-%%% The ets-table contains all data associated with each variable,
-%%% table, tableentry and tablecolumn in the MIB.
-%%% The tree contains information of the Oids in the MIB.
-%%%
-%%% When a mib is loaded, the tree is built from the plain list
-%%% in the binary file.
-%%%-----------------------------------------------------------------
--include("snmp_types.hrl").
--include("snmp_debug.hrl").
-
--define(VMODULE,"MDATA").
--include("snmp_verbosity.hrl").
-
--define(MIB_DATA,snmpa_mib_data).
--define(MIB_NODE,snmpa_mib_node).
--define(MIB_TREE,snmpa_mib_tree).
--define(DUMMY_TREE_GENERATION,1).
--define(DEFAULT_TREE,{tree,{undefined_node},internal}).
-%%-define(DUMMY_TREE_DB,dummy_tree_db).
-%%-define(DUMMY_TREE_DB_INIT,{?DUMMY_TREE_DB,?DEFAULT_TREE}).
-
+-include_lib("snmp/include/snmp_types.hrl").
%%%-----------------------------------------------------------------
-%%% Table of contents
-%%% =================
-%%% 1. Interface
-%%% 2. Implementation of tree access
-%%% 3. Tree building functions
-%%% 4. Tree merging
-%%% 5. Tree deletion routines
-%%% 6. Functions for subagent handling
-%%% 7. Misc functions
+%%% This is the behaviour for the MIB server backend internal
+%%% data storage.
%%%-----------------------------------------------------------------
+%% These types should really be defined elsewhere...
+-export_type([
+ mib_view/0,
+ mib_view_elem/0,
+ mib_view_mask/0,
+ mib_view_inclusion/0
+ ]).
-%%----------------------------------------------------------------------
-%% data_db is an database containing loaded mibs as:
-%% {MibName = atom(), Symbolic = ?, FullFileName = string()}
-%% it is either ets or mnesia
-%% tree_db is a database containing _one_ record with the tree!
-%% (the reason for this is part to get replication and part out of convenience)
-%% ref_tree is the root node, without any subagent.
-%% tree is the root node (same as ref_tree but with the subagents added).
-%% subagents is a list of {SAPid, Oid}
-%%----------------------------------------------------------------------
--record(mib_data, {mib_db, % table of #mib_info
- node_db, % table of #node_info
- tree_db, % table of #tree
- tree, % The actual tree
- subagents = []}).
-
--record(mib_info, {name, symbolic, file_name}).
--record(node_info, {oid, mib_name, me}).
-
-
-%% API
--export([new/0, new/1, sync/1, close/1,
- load_mib/4, unload_mib/4, which_mibs/1, whereis_mib/2,
- info/1, info/2,
- dump/1, dump/2,
- backup/2,
- lookup/2, next/3, which_mib/2,
- register_subagent/3, unregister_subagent/2]).
-
-%% Internal exports
--export([code_change/2]).
-
-
-%%-----------------------------------------------------------------
-%% A tree is represented as a N-tuple, where each element is a
-%% node. A node is:
-%% 1) {tree, Tree, Info} where Info can be {table, Id}, {table_entry, Id}
-%% or perhaps 'internal'
-%% 2) undefined_node (memory optimization (instead of {node, undefined}))
-%% 3) {node, Info} where Info can be {subagent, Pid}, {variable, Id},
-%% {table_column, Id}
-%% Id is {MibName, MibEntry}
-%% The over all root is represented as {tree, Tree, internal}.
-%%
-%% tree() = {tree, nodes(), tree_info()}
-%% nodes() = {tree() | node() | undefined_node, ...}
-%% node() = {node, node_info()}
-%% tree_info() = {table, Id} | {table_entry, Id} | internal
-%% node_info() = {subagent, Pid} | {variable, Id} | {table_colum, Id}
-%%-----------------------------------------------------------------
-
-%% This record is what is stored in the database. The 'tree' part
-%% is described above...
--record(tree,{generation = ?DUMMY_TREE_GENERATION, root = ?DEFAULT_TREE}).
-
-
-%%%======================================================================
-%%% 1. Interface
-%%%======================================================================
-
-%%-----------------------------------------------------------------
-%% Func: new/0, new/1
-%% Returns: A representation of mib data.
-%%-----------------------------------------------------------------
-new() ->
- new(ets).
-
-%% Where -> A list of nodes where the tables will be created
-new(Storage) ->
- %% First we must check if there is already something to read
- %% If a database already exists, then the tree structure has to be read
- ?vtrace("open (mib) database",[]),
- MibDb = snmpa_general_db:open(Storage, ?MIB_DATA,
- mib_info,
- record_info(fields,mib_info), set),
- ?vtrace("open (mib) node database",[]),
- NodeDb = snmpa_general_db:open(Storage, ?MIB_NODE,
- node_info,
- record_info(fields,node_info), set),
- ?vtrace("open (mib) tree database",[]),
- TreeDb = snmpa_general_db:open(Storage, ?MIB_TREE,
- tree,
- record_info(fields,tree), set),
- Tree =
- case snmpa_general_db:read(TreeDb, ?DUMMY_TREE_GENERATION) of
- false ->
- T = #tree{},
- snmpa_general_db:write(TreeDb, T),
- T;
- {value, T} ->
- T
- end,
- install_mibs(MibDb, NodeDb),
- #mib_data{mib_db = MibDb,
- node_db = NodeDb,
- tree_db = TreeDb,
- tree = Tree}.
-
-
-%%----------------------------------------------------------------------
-%% Returns: new mib data | {error, Reason}
-%%----------------------------------------------------------------------
-load_mib(MibData,FileName,MeOverride,TeOverride)
- when is_record(MibData,mib_data) andalso is_list(FileName) ->
- ?vlog("load mib file: ~p",[FileName]),
- ActualFileName = filename:rootname(FileName, ".bin") ++ ".bin",
- MibName = list_to_atom(filename:basename(FileName, ".bin")),
- (catch do_load_mib(MibData, ActualFileName, MibName,
- MeOverride, TeOverride)).
-
-do_load_mib(MibData, ActualFileName, MibName, MeOverride, TeOverride) ->
- ?vtrace("do_load_mib -> entry with"
- "~n ActualFileName: ~s"
- "~n MibName: ~p",[ActualFileName, MibName]),
- #mib_data{mib_db = MibDb,
- node_db = NodeDb,
- %% tree_db = TreeDb,
- tree = Tree} = MibData,
- verify_not_loaded(MibDb, MibName),
- ?vtrace("do_load_mib -> already loaded mibs:"
- "~n ~p",[loaded(MibDb)]),
- Mib = do_read_mib(ActualFileName),
- ?vtrace("do_load_mib -> read mib ~s",[Mib#mib.name]),
- NonInternalMes =
- lists:filter(fun(ME) -> maybe_drop_me(ME) end, Mib#mib.mes),
- OldRoot = Tree#tree.root,
- T = build_tree(NonInternalMes, MibName),
- ?d("load_mib -> "
- "~n OldRoot: ~p"
- "~n T: ~p", [OldRoot, T]),
- case (catch merge_nodes(T, OldRoot)) of
- {error_merge_nodes, Node1, Node2} ->
- ?vlog("error merging nodes:"
- "~n~p~nand~n~p", [Node1,Node2]),
- {error, oid_conflict};
- NewRoot when is_tuple(NewRoot) andalso (element(1,NewRoot) =:= tree) ->
- ?d("load_mib -> "
- "~n NewRoot: ~p", [NewRoot]),
- Symbolic = not lists:member(no_symbolic_info, Mib#mib.misc),
- case (catch check_notif_and_mes(TeOverride, MeOverride, Symbolic,
- Mib#mib.traps, NonInternalMes)) of
- true ->
- install_mes(NodeDb, MibName, NonInternalMes),
- install_mib(MibDb, Symbolic, Mib,
- MibName, ActualFileName, NonInternalMes),
- ?vtrace("installed mib ~s", [Mib#mib.name]),
- Tree2 = Tree#tree{root = NewRoot},
- %% snmpa_general_db:write(TreeDb, Tree2), %% Store later?
- {ok, MibData#mib_data{tree = Tree2}};
- Else ->
- Else
- end
- end.
-
-
-verify_not_loaded(Db, Name) ->
- case snmpa_general_db:read(Db, Name) of
- {value, #mib_info{name = Name}} ->
- throw({error, 'already loaded'});
- false ->
- ok
- end.
-
-do_read_mib(ActualFileName) ->
- case snmp_misc:read_mib(ActualFileName) of
- {error, Reason} ->
- ?vlog("Failed reading mib file ~p with reason: ~p",
- [ActualFileName,Reason]),
- throw({error, Reason});
- {ok, Mib} ->
- Mib
- end.
-
-%% The Tree DB is handled in a special way since it can be very large.
-sync(#mib_data{mib_db = M,
- node_db = N,
- tree_db = T, tree = Tree, subagents = []}) ->
- snmpa_general_db:sync(M),
- snmpa_general_db:sync(N),
- snmpa_general_db:write(T, Tree),
- snmpa_general_db:sync(T);
-sync(#mib_data{mib_db = M,
- node_db = N,
- tree_db = T, tree = Tree, subagents = SAs}) ->
-
- snmpa_general_db:sync(M),
- snmpa_general_db:sync(N),
-
- %% Ouch. Since the subagent info is dynamic we do not
- %% want to store the tree containing subagent info. So, we
- %% have to create a tmp tree without those and store it.
-
- case delete_subagents(Tree, SAs) of
- {ok, TreeWithoutSAs} ->
- snmpa_general_db:write(T, TreeWithoutSAs),
- snmpa_general_db:sync(T);
- Error ->
- Error
- end.
-
-delete_subagents(Tree, []) ->
- {ok, Tree};
-delete_subagents(Tree0, [{_, Oid}|SAs]) ->
- case (catch delete_subagent(Tree0, Oid)) of
- {tree, _Tree, _Info} = Tree1 ->
- delete_subagents(Tree1, SAs);
- _Error ->
- {error, {'invalid oid', Oid}}
- end.
-
-%%----------------------------------------------------------------------
-%% (OTP-3601)
-%%----------------------------------------------------------------------
-check_notif_and_mes(TeOverride,MeOverride,Symbolic,Traps,MEs) ->
- ?vtrace("check notifications and mib entries",[]),
- check_notifications(TeOverride,Symbolic,Traps),
- check_mes(MeOverride,MEs).
-
-check_notifications(true, _Symbolic, _Traps) ->
- ?vtrace("trapentry override = true => skip check",[]),
- true;
-check_notifications(_, Symbolic, Traps) ->
- check_notifications(Symbolic, Traps).
-
-check_notifications(true, Traps) ->
- check_notifications(Traps);
-check_notifications(_, _) -> true.
-
-check_notifications([]) -> true;
-check_notifications([#trap{trapname = Key} = Trap | Traps]) ->
- ?vtrace("check notification [trap] with Key: ~p",[Key]),
- case snmpa_symbolic_store:get_notification(Key) of
- {value, Trap} -> check_notifications(Traps);
- {value, _} -> throw({error, {'trap already defined', Key}});
- undefined -> check_notifications(Traps)
- end;
-check_notifications([#notification{trapname = Key} = Notif | Traps]) ->
- ?vtrace("check notification [notification] with Key: ~p",[Key]),
- case snmpa_symbolic_store:get_notification(Key) of
- {value, Notif} ->
- check_notifications(Traps);
- {value, _} ->
- throw({error, {'notification already defined', Key}});
- undefined ->
- check_notifications(Traps)
- end;
-check_notifications([Crap | Traps]) ->
- ?vlog("skipped check of: ~n~p",[Crap]),
- check_notifications(Traps).
-
-check_mes(true,_) ->
- ?vtrace("mibentry override = true => skip check",[]),
- true;
-check_mes(_,MEs) ->
- check_mes(MEs).
-
-check_mes([]) -> true;
-check_mes([#me{aliasname = Name, oid = Oid1} | MEs]) ->
- ?vtrace("check mib entries with aliasname: ~p",[Name]),
- case snmpa_symbolic_store:aliasname_to_oid(Name) of
- {value, Oid1} ->
- check_mes(MEs);
- {value, Oid2} ->
- ?vinfo("~n expecting '~p'~n but found '~p'",[Oid1, Oid2]),
- throw({error, {'mibentry already defined', Name}});
- false ->
- check_mes(MEs)
- end;
-check_mes([Crap | MEs]) ->
- ?vlog("skipped check of: ~n~p",[Crap]),
- check_mes(MEs).
-
-
-
-%%----------------------------------------------------------------------
-%% Returns: new mib data | {error, Reason}
-%%----------------------------------------------------------------------
-unload_mib(MibData, FileName, _, _) when is_list(FileName) ->
- MibName = list_to_atom(filename:basename(FileName, ".bin")),
- (catch do_unload_mib(MibData, MibName)).
-
-do_unload_mib(MibData, MibName) ->
- ?vtrace("do_unload_mib -> entry with"
- "~n MibName: ~p", [MibName]),
- #mib_data{mib_db = MibDb,
- node_db = NodeDb,
- %% tree_db = TreeDb,
- tree = Tree} = MibData,
- #mib_info{symbolic = Symbolic} = verify_loaded(MibDb, MibName),
- NewRoot = delete_mib_from_tree(MibName, Tree#tree.root),
- MEs = uninstall_mes(NodeDb, MibName),
- uninstall_mib(MibDb, Symbolic, MibName, MEs),
- NewMibData = MibData#mib_data{tree = Tree#tree{root = NewRoot}},
- {ok, NewMibData}.
-
-verify_loaded(Db, Name) ->
- case snmpa_general_db:read(Db, Name) of
- {value, MibInfo} ->
- MibInfo;
- false ->
- throw({error, 'not loaded'})
- end.
-
-
-close(#mib_data{mib_db = MibDb, node_db = NodeDb, tree_db = TreeDb}) ->
- snmpa_general_db:close(MibDb),
- snmpa_general_db:close(NodeDb),
- snmpa_general_db:close(TreeDb),
- ok.
-
-register_subagent(#mib_data{tree = T} = MibData, Oid, Pid) ->
- case insert_subagent(Oid, T#tree.root) of
- {error, Reason} ->
- {error, Reason};
- NewRootTree ->
- SAs = [{Pid, Oid} | MibData#mib_data.subagents],
- T2 = T#tree{root = NewRootTree},
- MibData#mib_data{tree = T2, subagents = SAs}
- end.
-
-
-%%----------------------------------------------------------------------
-%% Purpose: Get a list of all loaded mibs
-%% Returns: [{Name, File}]
-%%----------------------------------------------------------------------
-
-which_mibs(#mib_data{mib_db = Db}) ->
- Mibs = snmpa_general_db:tab2list(Db),
- [{Name, File} || #mib_info{name = Name, file_name = File} <- Mibs].
-
-
-%%----------------------------------------------------------------------
-%% Purpose: Get a list of all loaded mibs
-%% Returns: [{Name, File}]
-%%----------------------------------------------------------------------
-
-whereis_mib(#mib_data{mib_db = Db}, Name) ->
- case snmpa_general_db:read(Db, Name) of
- {value, #mib_info{file_name = File}} ->
- {ok, File};
- false ->
- {error, not_found}
- end.
-
-
-%%----------------------------------------------------------------------
-%% Purpose: Deletes SA with Pid from all subtrees it handles.
-%% Returns: NewMibData.
-%%----------------------------------------------------------------------
-unregister_subagent(MibData, Pid) when is_pid(Pid) ->
- SAs = MibData#mib_data.subagents,
- case lists:keysearch(Pid, 1, SAs) of
- false -> MibData;
- {value, {Pid, Oid}} ->
- % we should never get an error since Oid is found in MibData.
- {ok, NewMibData, _DeletedSA} = unregister_subagent(MibData, Oid),
- % continue if the same Pid handles other mib subtrees.
- unregister_subagent(NewMibData, Pid)
- end;
-
-%%----------------------------------------------------------------------
-%% Purpose: Deletes one unique subagent.
-%% Returns: {error, Reason} | {ok, NewMibData, DeletedSubagentPid}
-%%----------------------------------------------------------------------
-unregister_subagent(#mib_data{tree = T} = MibData, Oid) when is_list(Oid) ->
- case catch delete_subagent(T#tree.root, Oid) of
- {tree, Tree, Info} ->
- OldSAs = MibData#mib_data.subagents,
- {value, {Pid, _Oid}} = lists:keysearch(Oid, 2, OldSAs),
- SAs = lists:keydelete(Oid, 2, OldSAs),
- T2 = T#tree{root = {tree, Tree, Info}},
- {ok,
- MibData#mib_data{tree = T2, subagents = SAs},
- Pid};
- _ ->
- {error, {'invalid oid', Oid}}
- end.
-
-%%----------------------------------------------------------------------
-%% Purpose: To inpect memory usage, loaded mibs, registered subagents
-%%----------------------------------------------------------------------
-info(MibData) ->
- ?vtrace("retrieve info",[]),
- #mib_data{mib_db = MibDb, node_db = NodeDb, tree_db = TreeDb,
- tree = Tree, subagents = SAs} = MibData,
- LoadedMibs = old_format(snmpa_general_db:tab2list(MibDb)),
- TreeSize = snmp_misc:mem_size(Tree),
- {memory, ProcSize} = erlang:process_info(self(),memory),
- MibDbSize = snmpa_general_db:info(MibDb, memory),
- NodeDbSize = snmpa_general_db:info(NodeDb, memory),
- TreeDbSize = snmpa_general_db:info(TreeDb, memory),
- [{loaded_mibs, LoadedMibs}, {subagents, SAs}, {tree_size_bytes, TreeSize},
- {process_memory, ProcSize},
- {db_memory, [{mib,MibDbSize},{node,NodeDbSize},{tree,TreeDbSize}]}].
-
-info(#mib_data{mib_db = MibDb}, loaded_mibs) ->
- Mibs = snmpa_general_db:tab2list(MibDb),
- [filename:rootname(FN, ".bin") || #mib_info{file_name = FN} <- Mibs];
-info(#mib_data{tree = Tree}, tree_size_bytes) ->
- snmp_misc:mem_size(Tree);
-info(_, process_memory) ->
- {memory, ProcSize} = erlang:process_info(self(),memory),
- ProcSize;
-info(#mib_data{mib_db = MibDb, node_db = NodeDb, tree_db = TreeDb},
- db_memory) ->
- MibDbSize = snmpa_general_db:info(MibDb, memory),
- NodeDbSize = snmpa_general_db:info(NodeDb, memory),
- TreeDbSize = snmpa_general_db:info(TreeDb, memory),
- [{mib,MibDbSize},{node,NodeDbSize},{tree,TreeDbSize}];
-info(#mib_data{subagents = SAs}, subagents) ->
- SAs.
-
-old_format(LoadedMibs) ->
- ?vtrace("convert mib info to old format",[]),
- [{N,S,F} || #mib_info{name=N,symbolic=S,file_name=F} <- LoadedMibs].
-
-
-%%----------------------------------------------------------------------
-%% A total dump for debugging.
-%%----------------------------------------------------------------------
-dump(#mib_data{mib_db = MibDb, node_db = NodeDb, tree = Tree}) ->
- (catch io:format("MIB-tables:~n~p~n~n",
- [snmpa_general_db:tab2list(MibDb)])),
- (catch io:format("MIB-entries:~n~p~n~n",
- [snmpa_general_db:tab2list(NodeDb)])),
- (catch io:format("Tree:~n~p~n", [Tree])), % good luck reading it!
- ok.
-
-dump(#mib_data{mib_db = MibDb, node_db = NodeDb, tree = Tree}, File) ->
- case file:open(File,[write]) of
- {ok, Fd} ->
- io:format(Fd,"~s~n",
- [snmp:date_and_time_to_string(snmp:date_and_time())]),
- (catch io:format(Fd,"MIB-tables:~n~p~n~n",
- [snmpa_general_db:tab2list(MibDb)])),
- (catch io:format(Fd, "MIB-entries:~n~p~n~n",
- [snmpa_general_db:tab2list(NodeDb)])),
- io:format(Fd,"Tree:~n~p~n", [Tree]), % good luck reading it!
- file:close(Fd),
- ok;
- {error,Reason} ->
- ?vinfo("~n Failed opening file '~s' for reason ~p",
- [File,Reason]),
- {error,Reason}
- end.
-
-
-backup(#mib_data{mib_db = M, node_db = N, tree_db = T}, BackupDir) ->
- MRes = snmpa_general_db:backup(M, BackupDir),
- NRes = snmpa_general_db:backup(N, BackupDir),
- TRes = snmpa_general_db:backup(T, BackupDir),
- handle_backup_res([{mib_db, MRes}, {node_db, NRes}, {tree_db, TRes}]).
-
-handle_backup_res(Res) ->
- handle_backup_res(Res, []).
-
-handle_backup_res([], []) ->
- ok;
-handle_backup_res([], Err) ->
- {error, lists:reverse(Err)};
-handle_backup_res([{_, ok}|Res], Err) ->
- handle_backup_res(Res, Err);
-handle_backup_res([{Tag, {error, Reason}}|Res], Err) ->
- handle_backup_res(Res, [{Tag, Reason}|Err]);
-handle_backup_res([{Tag, Error}|Res], Err) ->
- handle_backup_res(Res, [{Tag, Error}|Err]).
-
-
-%%%======================================================================
-%%% 2. Implementation of tree access
-%%% lookup and next.
-%%%======================================================================
-
-
-which_mib(#mib_data{tree = T} = D, Oid) ->
- ?vtrace("which_mib -> entry with"
- "~n Oid: ~p",[Oid]),
- case (catch find_node(D, T#tree.root, Oid, [])) of
- {variable, _ME, Mib} ->
- ?vtrace("which_mib -> variable:"
- "~n Mib: ~p", [Mib]),
- {ok, Mib};
- {table, _EntryME, _, Mib} ->
- ?vtrace("which_mib -> table:"
- "~n Mib: ~p", [Mib]),
- {ok, Mib};
- {subagent, SubAgentPid, _SANextOid} ->
- ?vtrace("which_mib -> subagent:"
- "~n SubAgentPid: ~p", [SubAgentPid]),
- {error, {subagent, SubAgentPid}};
- {false, ErrorCode} ->
- ?vtrace("which_mib -> false:"
- "~n ErrorCode: ~p",[ErrorCode]),
- {error, ErrorCode};
- false ->
- ?vtrace("which_mib -> false",[]),
- {error, noSuchObject};
- {'EXIT', R} ->
- ?vtrace("which_mib -> exit:"
- "~n R: ~p",[R]),
- {error, noSuchObject}
- end.
-
-
-%%-----------------------------------------------------------------
-%% Func: lookup/2
-%% Purpose: Finds the mib entry corresponding to the Oid. If it is a
-%% variable, the Oid must be <Oid for var>.0 and if it is
-%% a table, Oid must be <table>.<entry>.<col>.<any>
-%% Returns: {variable, MibEntry} |
-%% {table_column, MibEntry, TableEntryOid} |
-%% {subagent, SubAgentPid, SAOid} |
-%% {false, Reason}
-%%-----------------------------------------------------------------
-lookup(#mib_data{tree = T} = D, Oid) ->
- ?vtrace("lookup -> entry with"
- "~n Oid: ~p",[Oid]),
- case (catch find_node(D, T#tree.root, Oid, [])) of
- {variable, ME, _Mib} when is_record(ME, me) ->
- ?vtrace("lookup -> variable:"
- "~n ME: ~p",[ME]),
- {variable, ME};
- {table, EntryME, {ColME, TableEntryOid}, _Mib} ->
- ?vtrace("lookup -> table:"
- "~n EntryME: ~p"
- "~n ColME: ~p"
- "~n RevTableEntryOid: ~p",
- [EntryME, ColME, TableEntryOid]),
- MFA = EntryME#me.mfa,
- RetME = ColME#me{mfa = MFA},
- {table_column, RetME, TableEntryOid};
- {subagent, SubAgentPid, SANextOid} ->
- ?vtrace("lookup -> subagent:"
- "~n SubAgentPid: ~p"
- "~n SANextOid: ~p", [SubAgentPid, SANextOid]),
- {subagent, SubAgentPid, SANextOid};
- {false, ErrorCode} ->
- ?vtrace("lookup -> false:"
- "~n ErrorCode: ~p",[ErrorCode]),
- {false, ErrorCode};
- false ->
- ?vtrace("lookup -> false",[]),
- {false, noSuchObject};
- {'EXIT', R} ->
- ?vtrace("lookup -> exit:"
- "~n R: ~p",[R]),
- {false, noSuchObject}
- end.
-
-
-find_node(D, {tree, Tree, {table, _}}, RestOfOid, RevOid) ->
- ?vtrace("find_node(tree,table) -> entry with"
- "~n RestOfOid: ~p"
- "~n RevOid: ~p",[RestOfOid, RevOid]),
- find_node(D, {tree, Tree, internal}, RestOfOid, RevOid);
-find_node(D, {tree, Tree, {table_entry, _}}, RestOfOid, RevOid) ->
- ?vtrace("find_node(tree,table_entry) -> entry with"
- "~n RestOfOid: ~p"
- "~n RevOid: ~p",[RestOfOid, RevOid]),
- #mib_data{node_db = Db} = D,
- Oid = lists:reverse(RevOid),
- case snmpa_general_db:read(Db, Oid) of
- {value, #node_info{me = ME, mib_name = Mib}} ->
- case find_node(D, {tree, Tree, internal}, RestOfOid, RevOid) of
- {false, ErrorCode} -> {false, ErrorCode};
- Val -> {table, ME, Val, Mib}
- end;
- false ->
- ?vinfo("find_node -> could not find table_entry ME with"
- "~n RevOid: ~p"
- "~n when"
- "~n RestOfOid: ~p",
- [RevOid, RestOfOid]),
- false
- end;
-find_node(D, {tree, Tree, _Internal}, [Int | RestOfOid], RevOid) ->
- ?vtrace("find_node(tree) -> entry with"
- "~n Int: ~p"
- "~n RestOfOid: ~p"
- "~n RevOid: ~p",[Int, RestOfOid, RevOid]),
- find_node(D, element(Int+1, Tree), RestOfOid, [Int | RevOid]);
-find_node(D, {node, {table_column, _}}, RestOfOid, [ColInt | RevOid]) ->
- ?vtrace("find_node(tree,table_column) -> entry with"
- "~n RestOfOid: ~p"
- "~n ColInt: ~p"
- "~n RevOid: ~p",[RestOfOid, ColInt, RevOid]),
- #mib_data{node_db = Db} = D,
- Oid = lists:reverse([ColInt | RevOid]),
- case snmpa_general_db:read(Db, Oid) of
- {value, #node_info{me = ME}} ->
- {ME, lists:reverse(RevOid)};
- false ->
- X = snmpa_general_db:read(Db, lists:reverse([ColInt | RevOid])),
- ?vinfo("find_node -> could not find table_column ME with"
- "~n RevOid: ~p"
- "~n trying [~p|~p]"
- "~n X: ~p",
- [RevOid, [ColInt | RevOid], X]),
- false
- end;
-find_node(D, {node, {variable, _MibName}}, [0], RevOid) ->
- ?vtrace("find_node(tree,variable,[0]) -> entry with"
- "~n RevOid: ~p",[RevOid]),
- #mib_data{node_db = Db} = D,
- Oid = lists:reverse(RevOid),
- %% {value, #node_info{me = ME}} = snmpa_general_db:read(Db, Oid),
- case snmpa_general_db:read(Db, Oid) of
- {value, #node_info{me = ME, mib_name = Mib}} ->
- {variable, ME, Mib};
- false ->
- ?vinfo("find_node -> could not find variable ME with"
- "~n RevOid: ~p", [RevOid]),
- false
- end;
-find_node(_D, {node, {variable, _MibName}}, [], _RevOid) ->
- ?vtrace("find_node(tree,variable,[]) -> entry",[]),
- {false, noSuchObject};
-find_node(_D, {node, {variable, _MibName}}, _, _RevOid) ->
- ?vtrace("find_node(tree,variable) -> entry",[]),
- {false, noSuchInstance};
-find_node(D, {node, subagent}, _RestOfOid, SARevOid) ->
- ?vtrace("find_node(tree,subagent) -> entry with"
- "~n SARevOid: ~p",[SARevOid]),
- #mib_data{subagents = SAs} = D,
- SAOid = lists:reverse(SARevOid),
- case lists:keysearch(SAOid, 2, SAs) of
- {value, {SubAgentPid, SAOid}} ->
- {subagent, SubAgentPid, SAOid};
- false ->
- ?vinfo("find_node -> could not find subagent with"
- "~n SAOid: ~p"
- "~n SAs: ~p", [SAOid, SAs]),
- false
- end;
-find_node(_D, Node, _RestOfOid, _RevOid) ->
- ?vtrace("find_node -> failed:~n~p",[Node]),
- {false, noSuchObject}.
-
-
-%%-----------------------------------------------------------------
-%% Func: next/3
-%% Purpose: Finds the lexicographically next oid.
-%% Returns: endOfMibView |
-%% {subagent, SubAgentPid, SAOid} |
-%% {variable, MibEntry, VarOid} |
-%% {table, TableOid, TableRestOid, MibEntry}
-%% If a variable is returnes, it is in the MibView.
-%% If a table or subagent is returned, it *may* be in the MibView.
-%%-----------------------------------------------------------------
-next(#mib_data{tree = T} = D, Oid, MibView) ->
- case catch next_node(D, T#tree.root, Oid, [], MibView) of
- false -> endOfMibView;
- Else -> Else
- end.
-
-%%-----------------------------------------------------------------
-%% This function is used as long as we have any Oid left. Take
-%% one integer at a time from the Oid, and traverse the tree
-%% accordingly. When the Oid is empty, call find_next.
-%% Returns: {subagent, SubAgentPid, SAOid} |
-%% false |
-%% {variable, MibEntry, VarOid} |
-%% {table, TableOid, TableRestOid, MibEntry}
-%%-----------------------------------------------------------------
-next_node(_D, undefined_node, _Oid, _RevOidSoFar, _MibView) ->
- ?vtrace("next_node(undefined_node) -> entry", []),
- false;
-
-next_node(_D, {tree, Tree, {table_entry, _Id}}, [Int | _Oid],
- _RevOidSoFar, _MibView)
- when Int+1 > size(Tree) ->
- ?vtrace("next_node(tree,table_entry) -> entry when not found whith"
- "~n Int: ~p"
- "~n size(Tree): ~p", [Int, size(Tree)]),
- false;
-next_node(D, {tree, Tree, {table_entry, _MibName}},
- Oid, RevOidSoFar, MibView) ->
- ?vtrace("next_node(tree,table_entry) -> entry when"
- "~n size(Tree): ~p"
- "~n Oid: ~p"
- "~n RevOidSoFar: ~p"
- "~n MibView: ~p", [size(Tree), Oid, RevOidSoFar, MibView]),
- OidSoFar = lists:reverse(RevOidSoFar),
- case snmpa_acm:is_definitely_not_in_mib_view(OidSoFar, MibView) of
- true ->
- ?vdebug("next_node(tree,table_entry) -> not in mib view",[]),
- false;
- _ ->
- #mib_data{node_db = Db} = D,
- case snmpa_general_db:read(Db, OidSoFar) of
- false ->
- ?vinfo("next_node -> could not find table_entry with"
- "~n OidSoFar: ~p", [OidSoFar]),
- false;
- {value, #node_info{me = ME}} ->
- ?vtrace("next_node(tree,table_entry) -> found: ~n ~p",
- [ME]),
- {table, OidSoFar, Oid, ME}
- end
- end;
-
-next_node(D, {tree, Tree, _Info}, [Int | RestOfOid], RevOidSoFar, MibView)
- when (Int < size(Tree)) andalso (Int >= 0) ->
- ?vtrace("next_node(tree) -> entry when"
- "~n size(Tree): ~p"
- "~n Int: ~p"
- "~n RestOfOid: ~p"
- "~n RevOidSoFar: ~p"
- "~n MibView: ~p",
- [size(Tree), Int, RestOfOid, RevOidSoFar, MibView]),
- case next_node(D, element(Int+1,Tree),
- RestOfOid, [Int|RevOidSoFar], MibView) of
- false ->
- find_next(D, {tree, Tree, _Info}, Int+1, RevOidSoFar, MibView);
- Else ->
- Else
- end;
-%% no solution
-next_node(D, {tree, Tree, _Info}, [], RevOidSoFar, MibView) ->
- ?vtrace("next_node(tree,[]) -> entry when"
- "~n size(Tree): ~p"
- "~n RevOidSoFar: ~p"
- "~n MibView: ~p",
- [size(Tree), RevOidSoFar, MibView]),
- find_next(D, {tree, Tree, _Info}, 0, RevOidSoFar, MibView);
-next_node(_D, {tree, Tree, _Info}, _RestOfOid, _RevOidSoFar, _MibView) ->
- ?vtrace("next_node(tree) -> entry when"
- "~n size(Tree): ~p", [size(Tree)]),
- false;
-
-next_node(D, {node, subagent}, Oid, RevOidSoFar, MibView) ->
- ?vtrace("next_node(node,subagent) -> entry when"
- "~n Oid: ~p"
- "~n RevOidSoFar: ~p"
- "~n MibView: ~p",
- [Oid, RevOidSoFar, MibView]),
- OidSoFar = lists:reverse(RevOidSoFar),
- case snmpa_acm:is_definitely_not_in_mib_view(OidSoFar, MibView) of
- true ->
- false;
- _ ->
- #mib_data{subagents = SAs} = D,
- case lists:keysearch(OidSoFar, 2, SAs) of
- {value, {SubAgentPid, OidSoFar}} ->
- {subagent, SubAgentPid, OidSoFar};
- _ ->
- ?vinfo("next_node -> could not find subagent with"
- "~n OidSoFar: ~p"
- "~n SAs: ~p", [OidSoFar, SAs]),
- false
- end
- end;
-
-next_node(D, {node, {variable, _MibName}}, [], RevOidSoFar, MibView) ->
- ?vtrace("next_node(node,variable,[]) -> entry when"
- "~n RevOidSoFar: ~p"
- "~n MibView: ~p",
- [RevOidSoFar, MibView]),
- OidSoFar = lists:reverse([0 | RevOidSoFar]),
- case snmpa_acm:validate_mib_view(OidSoFar, MibView) of
- true ->
- #mib_data{node_db = Db} = D,
- case snmpa_general_db:read(Db, lists:reverse(RevOidSoFar)) of
- false ->
- ?vinfo("next_node -> could not find variable with"
- "~n RevOidSoFar: ~p", [RevOidSoFar]),
- false;
- {value, #node_info{me = ME}} ->
- {variable, ME, OidSoFar}
- end;
- _ ->
- false
- end;
-
-next_node(_D, {node, {variable, _MibName}}, _Oid, _RevOidSoFar, _MibView) ->
- ?vtrace("next_node(node,variable) -> entry", []),
- false.
-
-%%-----------------------------------------------------------------
-%% This function is used to find the first leaf from where we
-%% are.
-%% Returns: {subagent, SubAgentPid, SAOid} |
-%% false |
-%% {variable, MibEntry, VarOid} |
-%% {table, TableOid, TableRestOid, MibEntry}
-%% PRE: This function must always be called with a {internal, Tree}
-%% node.
-%%-----------------------------------------------------------------
-find_next(D, {tree, Tree, internal}, Idx, RevOidSoFar, MibView)
- when Idx < size(Tree) ->
- case find_next(D, element(Idx+1, Tree), 0, [Idx| RevOidSoFar], MibView) of
- false ->
- find_next(D, {tree, Tree, internal}, Idx+1, RevOidSoFar, MibView);
- Other ->
- Other
- end;
-find_next(_D, {tree, _Tree, internal}, _Idx, _RevOidSoFar, _MibView) ->
- false;
-find_next(_D, undefined_node, _Idx, _RevOidSoFar, _MibView) ->
- false;
-find_next(D, {tree, Tree, {table, _MibName}}, Idx, RevOidSoFar, MibView) ->
- find_next(D, {tree, Tree, internal}, Idx, RevOidSoFar, MibView);
-find_next(D, {tree, _Tree, {table_entry, _MibName}}, _Index,
- RevOidSoFar, MibView) ->
- OidSoFar = lists:reverse(RevOidSoFar),
- case snmpa_acm:is_definitely_not_in_mib_view(OidSoFar, MibView) of
- true ->
- false;
- _ ->
- #mib_data{node_db = Db} = D,
- case snmpa_general_db:read(Db, OidSoFar) of
- false ->
- ?vinfo("find_next -> could not find table_entry ME with"
- "~n OidSoFar: ~p", [OidSoFar]),
- false;
- {value, #node_info{me = ME}} ->
- {table, OidSoFar, [], ME}
- end
- end;
-find_next(D, {node, {variable, _MibName}}, _Idx, RevOidSoFar, MibView) ->
- OidSoFar = lists:reverse([0 | RevOidSoFar]),
- case snmpa_acm:validate_mib_view(OidSoFar, MibView) of
- true ->
- #mib_data{node_db = Db} = D,
- case snmpa_general_db:read(Db, lists:reverse(RevOidSoFar)) of
- false ->
- ?vinfo("find_next -> could not find variable with"
- "~n RevOidSoFar: ~p", [RevOidSoFar]),
- false;
- {value, #node_info{me = ME}} ->
- {variable, ME, OidSoFar}
- end;
- _ ->
- false
- end;
-find_next(D, {node, subagent}, _Idx, RevOidSoFar, MibView) ->
- OidSoFar = lists:reverse(RevOidSoFar),
- case snmpa_acm:is_definitely_not_in_mib_view(OidSoFar, MibView) of
- true ->
- false;
- _ ->
- #mib_data{subagents = SAs} = D,
- case lists:keysearch(OidSoFar, 2, SAs) of
- {value, {SubAgentPid, OidSoFar}} ->
- {subagent, SubAgentPid, OidSoFar};
- false ->
- ?vinfo("find_node -> could not find subagent with"
- "~n OidSoFar: ~p"
- "~n SAs: ~p", [OidSoFar, SAs]),
- false
- end
- end.
-
-%%%======================================================================
-%%% 3. Tree building functions
-%%% Used when loading mibs.
-%%%======================================================================
-
-build_tree(Mes, MibName) ->
- ?d("build_tree -> "
- "~n Mes: ~p", [Mes]),
- {ListTree, []} = build_subtree([], Mes, MibName),
- {tree, convert_tree(ListTree), internal}.
-
-%%----------------------------------------------------------------------
-%% Purpose: Builds the tree where all oids have prefix equal to LevelPrefix.
-%% Returns: {Tree, RestMes}
-%% RestMes are Mes that should not be in this subtree.
-%% The Tree is a temporary and simplified data structure that is easy to
-%% convert to the final tuple tree used by the MIB process.
-%% A Node is represented as in the final tree.
-%% The tree is not represented as a N-tuple, but as an Index-list.
-%% Example: Temporary: [{1, Node1}, {3, Node3}]
-%% Final: {Node1, undefined_node, Node3}
-%% Pre: Mes are sorted on oid.
-%%----------------------------------------------------------------------
-build_subtree(LevelPrefix, [Me | Mes], MibName) ->
- ?vtrace("build subtree -> ~n"
- " oid: ~p~n"
- " LevelPrefix: ~p~n"
- " MibName: ~p", [Me#me.oid, LevelPrefix, MibName]),
- EType = Me#me.entrytype,
- ?vtrace("build subtree -> EType = ~p",[EType]),
- case in_subtree(LevelPrefix, Me) of
- above ->
- ?vtrace("build subtree -> above",[]),
- {[], [Me|Mes]};
- {node, Index} ->
- ?vtrace("build subtree -> node at ~p",[Index]),
- {Tree, RestMes} = build_subtree(LevelPrefix, Mes, MibName),
- {[{Index, {node, {EType, MibName}}} | Tree], RestMes};
- {subtree, Index, NewLevelPrefix} ->
- ?vtrace("build subtree -> subtree at"
- "~n ~w with ~w",
- [Index, NewLevelPrefix]),
- {BelowTree, RestMes} =
- build_subtree(NewLevelPrefix, Mes, MibName),
- {CurTree, RestMes2} =
- build_subtree(LevelPrefix, RestMes, MibName),
- {[{Index, {tree, BelowTree, {EType,MibName}}}| CurTree], RestMes2};
- {internal_subtree, Index, NewLevelPrefix} ->
- ?vtrace("build subtree -> internal_subtree at"
- "~n ~w with ~w",
- [Index,NewLevelPrefix]),
- {BelowTree, RestMes} =
- build_subtree(NewLevelPrefix, [Me | Mes], MibName),
- {CurTree, RestMes2} =
- build_subtree(LevelPrefix, RestMes, MibName),
- {[{Index, {tree, BelowTree, internal}} | CurTree], RestMes2}
- end;
-
-build_subtree(_LevelPrefix, [], _MibName) ->
- ?vtrace("build subtree -> done", []),
- {[], []}.
-
-%%--------------------------------------------------
-%% Purpose: Determine how/if/where Me should be inserted in subtree
-%% with LevelPrefix. This function does not build any tree, only
-%% determinses what should be done (by build subtree).
-%% Returns:
-%% above - Indicating that this ME should _not_ be in this subtree.
-%% {node, Index} - yes, construct a node with index Index on this level
-%% {internal_subtree, Index, NewLevelPrefix} - yes, there should be an
-%% internal subtree at this index.
-%% {subtree, Index, NewLevelPrefix} - yes, construct a subtree with
-%% NewLevelPrefix and insert this on current level in position Index.
-%%--------------------------------------------------
-in_subtree(LevelPrefix, Me) ->
- case lists:prefix(LevelPrefix, Me#me.oid) of
- true when length(Me#me.oid) > length(LevelPrefix) ->
- classify_how_in_subtree(LevelPrefix, Me);
- _ ->
- above
- end.
-
-%%--------------------------------------------------
-%% See comment about in_subtree/2. This function takes care of all cases
-%% where the ME really should be in _this_ subtree (not above).
-%%--------------------------------------------------
-classify_how_in_subtree(LevelPrefix, Me)
- when (length(Me#me.oid) =:= (length(LevelPrefix) + 1)) ->
- Oid = Me#me.oid,
- case node_or_subtree(Me#me.entrytype) of
- subtree ->
- {subtree, lists:last(Oid), Oid};
- node ->
- {node, lists:last(Oid)}
- end;
-
-classify_how_in_subtree(LevelPrefix, Me)
- when (length(Me#me.oid) > (length(LevelPrefix) + 1)) ->
- L1 = length(LevelPrefix) + 1,
- Oid = Me#me.oid,
- {internal_subtree, lists:nth(L1, Oid), lists:sublist(Oid, 1, L1)}.
-
-%%--------------------------------------------------
-%% Determines how to treat different kinds om MEs in the tree building process.
-%% Pre: all internal nodes have been removed.
-%%--------------------------------------------------
-node_or_subtree(table) -> subtree;
-node_or_subtree(table_entry) -> subtree;
-node_or_subtree(variable) -> node;
-node_or_subtree(table_column) -> node.
-
-%%--------------------------------------------------
-%% Purpose: (Recursively) Converts a temporary tree (see above) to a final tree.
-%% If input is a ListTree, output is a TupleTree.
-%% If input is a Node, output is the same Node.
-%% Pre: All Indexes are >= 0.
-%%--------------------------------------------------
-convert_tree({Index, {tree, Tree, Info}}) when Index >= 0 ->
- L = lists:map(fun convert_tree/1, Tree),
- {Index, {tree, dict_list_to_tuple(L), Info}};
-convert_tree({Index, {node, Info}}) when Index >= 0 ->
- {Index, {node, Info}};
-convert_tree(Tree) when is_list(Tree) ->
- L = lists:map(fun convert_tree/1, Tree),
- dict_list_to_tuple(L).
-
-%%----------------------------------------------------------------------
-%% Purpose: Converts a single level (that is non-recursively) from
-%% the temporary indexlist to the N-tuple.
-%% Input: A list of {Index, Data}.
-%% Output: A tuple where element Index is Data.
-%%----------------------------------------------------------------------
-dict_list_to_tuple(L) ->
- L2 = lists:keysort(1, L),
- list_to_tuple(integrate_indexes(0, L2)).
-
-%%----------------------------------------------------------------------
-%% Purpose: Helper function for dict_list_to_tuple/1.
-%% Converts an indexlist to a N-list.
-%% Input: A list of {Index, Data}.
-%% Output: A (usually longer, never shorter) list where element Index is Data.
-%% Example: [{1,hej}, {3, sven}] will give output
-%% [undefined_node, hej, undefined_node, sven].
-%% Initially CurIndex should be 0.
-%%----------------------------------------------------------------------
-integrate_indexes(CurIndex, [{CurIndex, Data} | T]) ->
- [Data | integrate_indexes(CurIndex + 1, T)];
-integrate_indexes(_Index, []) ->
- [];
-integrate_indexes(CurIndex, L) ->
- [undefined_node | integrate_indexes(CurIndex + 1, L)].
-
-%%%======================================================================
-%%% 4. Tree merging
-%%% Used by: load mib, insert subagent.
-%%%======================================================================
-
-%%----------------------------------------------------------------------
-%% Arg: Two root nodes (that is to be merged).
-%% Returns: A new root node where the nodes have been merger to one.
-%%----------------------------------------------------------------------
-merge_nodes(Same, Same) ->
- Same;
-merge_nodes(Node, undefined_node) ->
- Node;
-merge_nodes(undefined_node, Node) ->
- Node;
-merge_nodes({tree, Tree1, internal}, {tree, Tree2, internal}) ->
- {tree, merge_levels(tuple_to_list(Tree1),tuple_to_list(Tree2)), internal};
-merge_nodes(Node1, Node2) ->
- throw({error_merge_nodes, Node1, Node2}).
-
-%%----------------------------------------------------------------------
-%% Arg: Two levels to be merged.
-%% Here, a level is represented as a list of nodes. A list is easier
-%% to extend than a tuple.
-%% Returns: The resulting, merged level tuple.
-%%----------------------------------------------------------------------
-merge_levels(Level1, Level2) when length(Level1) =:= length(Level2) ->
- MergeNodes = fun(N1, N2) -> merge_nodes(N1, N2) end,
- list_to_tuple(snmp_misc:multi_map(MergeNodes, [Level1, Level2]));
-merge_levels(Level1, Level2) when length(Level1) > length(Level2) ->
- merge_levels(Level1, Level2 ++
- undefined_nodes_list(length(Level1) - length(Level2)));
-merge_levels(Level1, Level2) when length(Level1) < length(Level2) ->
- merge_levels(Level2, Level1).
-
-undefined_nodes_list(N) -> lists:duplicate(N, undefined_node).
-
-
-%%%======================================================================
-%%% 5. Tree deletion routines
-%%% (for unload mib)
-%%%======================================================================
-
-%%----------------------------------------------------------------------
-%% Purpose: Actually kicks of the tree reconstruction.
-%% Returns: {list of removed MEs, NewTree}
-%%----------------------------------------------------------------------
-delete_mib_from_tree(MibName, {tree, Tree, internal}) ->
- case delete_tree(Tree, MibName) of
- [] ->
- {tree, {undefined_node}, internal}; % reduce
- LevelList ->
- {tree, list_to_tuple(LevelList), internal}
- end.
-
-%%----------------------------------------------------------------------
-%% Purpose: Deletes all nodes associated to MibName from this level and
-%% all levels below.
-%% If the new level does not contain information (that is, no
-%% other mibs use it) anymore the empty list is returned.
-%% Returns: {MEs, The new level represented as a list}
-%%----------------------------------------------------------------------
-delete_tree(Tree, MibName) when is_tuple(Tree) ->
- NewLevel = delete_nodes(tuple_to_list(Tree), MibName, []),
- case lists:filter(fun drop_undefined_nodes/1,NewLevel) of
- [] -> [];
- _A_perhaps_shorted_list ->
- NewLevel % some other mib needs this level
- end.
-
-%%----------------------------------------------------------------------
-%% Purpose: Nodes belonging to MibName are removed from the tree.
-%% Recursively deletes sub trees to this node.
-%% Returns: {MEs, NewNodesList}
-%%----------------------------------------------------------------------
-delete_nodes([], _MibName, AccNodes) ->
- lists:reverse(AccNodes);
-
-delete_nodes([{node, {variable, MibName}}|T], MibName, AccNodes) ->
- delete_nodes(T, MibName, [undefined_node | AccNodes]);
-
-delete_nodes([{node, {table_column, MibName}}|T], MibName, AccNodes) ->
- delete_nodes(T, MibName, [undefined_node | AccNodes]);
-
-delete_nodes([{tree, _Tree, {table, MibName}}|T], MibName, AccNodes) ->
- delete_nodes(T, MibName, [undefined_node | AccNodes]);
-
-delete_nodes([{tree, _Tree, {table_entry, MibName}}|T], MibName, AccNodes) ->
- delete_nodes(T, MibName, [undefined_node | AccNodes]);
-
-delete_nodes([{tree, Tree, Info}|T], MibName, AccNodes) ->
- case delete_tree(Tree, MibName) of
- [] -> % tree completely deleted
- delete_nodes(T, MibName, [undefined_node | AccNodes]);
- LevelList ->
- delete_nodes(T, MibName,
- [{tree, list_to_tuple(LevelList), Info} | AccNodes])
- end;
-
-delete_nodes([NodeToKeep|T], MibName, AccNodes) ->
- delete_nodes(T, MibName, [NodeToKeep | AccNodes]).
-
-drop_undefined_nodes(undefined_node) -> false;
-drop_undefined_nodes(_) -> true.
-
-
-%%%======================================================================
-%%% 6. Functions for subagent handling
-%%%======================================================================
-
-%%----------------------------------------------------------------------
-%% Returns: A new Root|{error, reason}
-%%----------------------------------------------------------------------
-insert_subagent(Oid, OldRoot) ->
- ListTree = build_tree_for_subagent(Oid),
- case catch convert_tree(ListTree) of
- {'EXIT', _Reason} ->
- {error, 'cannot construct tree from oid'};
- Level when is_tuple(Level) ->
- T = {tree, Level, internal},
- case catch merge_nodes(T, OldRoot) of
- {error_merge_nodes, _Node1, _Node2} ->
- {error, oid_conflict};
- NewRoot when is_tuple(NewRoot) andalso
- (element(1, NewRoot) =:= tree) ->
- NewRoot
- end
- end.
-
-build_tree_for_subagent([Index]) ->
- [{Index, {node, subagent}}];
-
-build_tree_for_subagent([Index | T]) ->
- [{Index, {tree, build_tree_for_subagent(T), internal}}].
+-type mib_view() :: [mib_view_elem()].
+-type mib_view_elem() :: {SubTree :: snmp:oid(),
+ Mask :: [non_neg_integer()],
+ Inclusion :: mib_view_inclusion()}.
+-type mib_view_mask() :: [non_neg_integer()].
+-type mib_view_inclusion() :: 1 | 2. % 1 = included, 2 = excluded
-%%----------------------------------------------------------------------
-%% Returns: A new tree where the subagent at Oid (2nd arg) has been deleted.
-%%----------------------------------------------------------------------
-delete_subagent({tree, Tree, Info}, [Index]) ->
- {node, subagent} = element(Index+1, Tree),
- {tree, setelement(Index+1, Tree, undefined_node), Info};
-delete_subagent({tree, Tree, Info}, [Index | TI]) ->
- {tree, setelement(Index+1, Tree,
- delete_subagent(element(Index+1, Tree), TI)), Info}.
+-type filename() :: file:filename().
-%%%======================================================================
-%%% 7. Misc functions
-%%%======================================================================
-%%----------------------------------------------------------------------
-%% Installs the mibs found in the database when starting the agent.
-%% Basically calls the instrumentation functions for all non-internal
-%% mib-entries
-%%----------------------------------------------------------------------
-install_mibs(MibDb, NodeDb) ->
- MibNames = loaded(MibDb),
- ?vtrace("install_mibs -> found following mibs in database: ~n"
- "~p", [MibNames]),
- install_mibs2(NodeDb, MibNames).
+-callback new(MibStorage :: snmpa:mib_storage()) -> State :: term().
-install_mibs2(_, []) ->
- ok;
-install_mibs2(NodeDb, [MibName|MibNames]) ->
- Pattern = #node_info{oid = '_', mib_name = MibName, me = '_'},
- Nodes = snmpa_general_db:match_object(NodeDb, Pattern),
- MEs = [ME || #node_info{me = ME} <- Nodes],
- ?vtrace("install_mibs2 -> installing ~p MEs for mib ~p",
- [length(MEs),MibName]),
- NewF = fun(ME) -> call_instrumentation(ME, new) end,
- lists:foreach(NewF, MEs),
- install_mibs2(NodeDb, MibNames).
-
-
-%%----------------------------------------------------------------------
-%% Does all side effect stuff during load_mib.
-%%----------------------------------------------------------------------
-install_mib(Db, Symbolic, Mib, MibName, FileName, NonInternalMes) ->
- ?vdebug("install_mib -> entry with"
- "~n Symbolic: ~p"
- "~n MibName: ~p"
- "~n FileName: ~p", [Symbolic, MibName, FileName]),
- Rec = #mib_info{name = MibName, symbolic = Symbolic, file_name = FileName},
- snmpa_general_db:write(Db, Rec),
- install_mib2(Symbolic, MibName, Mib),
- NewF = fun(ME) -> call_instrumentation(ME, new) end,
- lists:foreach(NewF, NonInternalMes).
+-callback close(State :: term()) -> ok.
-install_mib2(true, MibName, Mib) ->
- #mib{table_infos = TabInfos,
- variable_infos = VarInfos,
- mes = MEs,
- asn1_types = ASN1Types,
- traps = Traps} = Mib,
- snmpa_symbolic_store:add_table_infos(MibName, TabInfos),
- snmpa_symbolic_store:add_variable_infos(MibName, VarInfos),
- snmpa_symbolic_store:add_aliasnames(MibName, MEs),
- snmpa_symbolic_store:add_types(MibName, ASN1Types),
- SetF = fun(Trap) ->
- snmpa_symbolic_store:set_notification(Trap, MibName)
- end,
- lists:foreach(SetF, Traps);
-install_mib2(_, _, _) ->
- ok.
+-callback sync(State :: term()) -> ok.
-install_mes(_Db, _MibName, []) ->
- ok;
-install_mes(Db, MibName, [ME|MEs]) ->
- Node = #node_info{oid = ME#me.oid, mib_name = MibName, me = ME},
- snmpa_general_db:write(Db, Node),
- install_mes(Db, MibName, MEs).
+-callback load_mib(State :: term(), FileName :: string(),
+ MeOverride :: boolean(),
+ TeOverride :: boolean()) ->
+ {ok, NewState :: term()} | {error, Reason :: already_loaded | term()}.
+-callback unload_mib(State :: term(), FileName :: string(),
+ MeOverride :: boolean(),
+ TeOverride :: boolean()) ->
+ {ok, NewState :: term()} | {error, Reason :: not_loaded | term()}.
-%%----------------------------------------------------------------------
-%% Does all side effect stuff during unload_mib.
-%%----------------------------------------------------------------------
-uninstall_mib(Db, Symbolic, MibName, MEs) ->
- ?vtrace("uninstall_mib -> entry with"
- "~n Db: ~p"
- "~n Symbolic: ~p"
- "~n MibName: ~p", [Db, Symbolic, MibName]),
- Res = snmpa_general_db:delete(Db, MibName),
- ?vtrace("uninstall_mib -> (mib) db delete result: ~p", [Res]),
- uninstall_mib2(Symbolic, MibName),
- DelF = fun(ME) -> call_instrumentation(ME, delete) end,
- lists:foreach(DelF, MEs).
+-callback lookup(State :: term(), Oid :: snmp:oid()) ->
+ {false, Reason :: term()} |
+ {variable, MibEntry :: snmpa:me()} |
+ {table_column, MibEntry :: snmpa:me(), TableEntryOid :: snmp:oid()} |
+ {subagent, SubAgentPid :: pid(), SAOid :: snmp:oid()}.
-uninstall_mib2(true, MibName) ->
- snmpa_symbolic_store:delete_table_infos(MibName),
- snmpa_symbolic_store:delete_variable_infos(MibName),
- snmpa_symbolic_store:delete_aliasnames(MibName),
- snmpa_symbolic_store:delete_types(MibName),
- snmpa_symbolic_store:delete_notifications(MibName);
-uninstall_mib2(_, _) ->
- ok.
+-callback next(State :: term(), Oid :: snmp:oid(), MibView :: mib_view()) ->
+ endOfView | false |
+ {subagent, SubAgentPid :: pid(), SAOid :: snmp:oid()} |
+ {variable, MibEntry :: snmpa:me(), VarOid :: snmp:oid()} |
+ {table, TableOid :: snmp:oid(), TableRestOid :: snmp:oid(), MibEntry :: snmpa:me()}.
-uninstall_mes(Db, MibName) ->
- Pattern = #node_info{oid = '_', mib_name = MibName, me = '_'},
- snmpa_general_db:match_delete(Db, Pattern).
+-callback register_subagent(State :: term(),
+ Oid :: snmp:oid(),
+ Pid :: pid()) ->
+ {ok, NewState :: term()} | {error, Reason :: term()}.
+-callback unregister_subagent(State :: term(),
+ PidOrOid :: pid() | snmp:oid()) ->
+ {ok, NewState :: term()} | % When second arg was a pid()
+ {ok, NewState :: term(), Pid :: pid()} | % When second arg was a oid()
+ {error, Reason :: term()}.
-%%----------------------------------------------------------------------
-%% Create a list of the names of all the loaded mibs
-%%----------------------------------------------------------------------
-loaded(Db) ->
- [N || #mib_info{name = N} <- snmpa_general_db:tab2list(Db)].
-
+-callback dump(State :: term(), Destination :: io | filename()) ->
+ ok | {error, Reason :: term()}.
-%%----------------------------------------------------------------------
-%% Calls MFA-instrumentation with 'new' or 'delete' operation.
-%%----------------------------------------------------------------------
-call_instrumentation(#me{entrytype = variable, mfa={M,F,A}}, Operation) ->
- ?vtrace("call instrumentation with"
- "~n entrytype: variable"
- "~n MFA: {~p,~p,~p}"
- "~n Operation: ~p",
- [M,F,A,Operation]),
- catch apply(M, F, [Operation | A]);
-call_instrumentation(#me{entrytype = table_entry, mfa={M,F,A}}, Operation) ->
- ?vtrace("call instrumentation with"
- "~n entrytype: table_entry"
- "~n MFA: {~p,~p,~p}"
- "~n Operation: ~p",
- [M,F,A,Operation]),
- catch apply(M, F, [Operation | A]);
-call_instrumentation(_ShitME, _Operation) ->
- done.
+-callback which_mib(State :: term(), Oid :: snmp:oid()) ->
+ {ok, Mib :: string()} | {error, Reason :: term()}.
+-callback which_mibs(State :: term()) ->
+ [{MibName :: atom(), Filename :: string()}].
-maybe_drop_me(#me{entrytype = internal}) -> false;
-maybe_drop_me(#me{entrytype = group}) -> false;
-maybe_drop_me(#me{imported = true}) -> false;
-maybe_drop_me(_) -> true.
+-callback whereis_mib(State :: term(), MibName :: atom()) ->
+ {ok, Filename :: string()} | {error, Reason :: term()}.
+-callback info(State :: term()) -> list().
-%%----------------------------------------------------------------------
-%% Code change functions
-%%----------------------------------------------------------------------
+-callback backup(State :: term(), BackupDir :: string()) ->
+ ok | {error, Reason :: term()}.
-code_change(down, State) ->
- ?d("code_change(down) -> entry",[]),
- State;
+-callback code_change(Direction :: up | down,
+ Vsn :: term(),
+ Extra :: term(),
+ State :: term()) ->
+ NewState :: term().
-code_change(up, State) ->
- ?d("code_change(up)",[]),
- State;
-code_change(_Vsn, State) ->
- State.
diff --git a/lib/snmp/src/agent/snmpa_mib_data_ttln.erl b/lib/snmp/src/agent/snmpa_mib_data_ttln.erl
new file mode 100644
index 0000000000..959230b1dd
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_mib_data_ttln.erl
@@ -0,0 +1,1403 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013-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%
+%%
+
+-module(snmpa_mib_data_ttln).
+
+%%%-----------------------------------------------------------------
+%%%
+%%% THIS FILE IS JUST A PLACE HOLDER - IGNORE
+%%%
+%%%-----------------------------------------------------------------
+
+
+%%%-----------------------------------------------------------------
+%%%
+%%% TTLN - TupleTreeListNodes
+%%%
+%%% This module implements the MIB internal data structures.
+%%% An MIB Data Structure consists of three items; an ets-table,
+%%% a tree and a list of registered subagents.
+%%% The subagent information is consequently duplicated. It resides
+%%% both in the tree and in the list.
+%%% The ets-table contains all data associated with each variable,
+%%% table, tableentry and tablecolumn in the MIB.
+%%% The tree contains information of the Oids in the MIB.
+%%%
+%%% When a mib is loaded, the tree is built from the plain list
+%%% in the binary file.
+%%%
+%%%-----------------------------------------------------------------
+
+-include("snmp_types.hrl").
+-include("snmp_debug.hrl").
+
+-define(VMODULE,"MDATA_TTLN").
+-include("snmp_verbosity.hrl").
+
+-behaviour(snmpa_mib_data).
+
+-define(MIB_DATA, snmpa_mib_data).
+-define(MIB_NODE, snmpa_mib_node).
+-define(MIB_TREE, snmpa_mib_tree).
+-define(DUMMY_TREE_GENERATION, 1).
+-define(DEFAULT_TREE, {tree,{undefined_node},internal}).
+
+
+%%%-----------------------------------------------------------------
+%%% Table of contents
+%%% =================
+%%% 1. Interface
+%%% 2. Implementation of tree access
+%%% 3. Tree building functions
+%%% 4. Tree merging
+%%% 5. Tree deletion routines
+%%% 6. Functions for subagent handling
+%%% 7. Misc functions
+%%%-----------------------------------------------------------------
+
+
+%%----------------------------------------------------------------------
+%% data_db is an database containing loaded mibs as:
+%% {MibName = atom(), Symbolic = ?, FullFileName = string()}
+%% it is either ets or mnesia
+%% tree_db is a database containing _one_ record with the tree!
+%% (the reason for this is part to get replication and part out of convenience)
+%% ref_tree is the root node, without any subagent.
+%% tree is the root node (same as ref_tree but with the subagents added).
+%% subagents is a list of {SAPid, Oid}
+%%----------------------------------------------------------------------
+-record(mib_data, {mib_db, % table of #mib_info
+ node_db, % table of #node_info
+ tree_db, % table of #tree
+ tree, % The actual tree
+ subagents = []}).
+
+-record(mib_info, {name, symbolic, file_name}).
+-record(node_info, {oid, mib_name, me}).
+
+
+%% API
+-export([new/0, new/1, sync/1, close/1,
+ load_mib/4, unload_mib/4, which_mibs/1, whereis_mib/2,
+ info/1, info/2,
+ dump/1, dump/2,
+ backup/2,
+ lookup/2, next/3, which_mib/2,
+ register_subagent/3, unregister_subagent/2]).
+
+%% Internal exports
+-export([code_change/2]).
+
+
+%%-----------------------------------------------------------------
+%% A tree is represented as a N-tuple, where each element is a
+%% node. A node is:
+%% 1) {tree, Tree, Info} where Info can be {table, Id}, {table_entry, Id}
+%% or perhaps 'internal'
+%% 2) undefined_node (memory optimization (instead of {node, undefined}))
+%% 3) {node, Info} where Info can be {subagent, Pid}, {variable, Id},
+%% {table_column, Id}
+%% Id is {MibName, MibEntry}
+%% The over all root is represented as {tree, Tree, internal}.
+%%
+%% tree() = {tree, nodes(), tree_info()}
+%% nodes() = [tree() | node() | undefined_node]
+%% node() = {node, node_info()}
+%% tree_info() = {table, Id} | {table_entry, Id} | internal
+%% node_info() = {subagent, Pid} | {variable, Id} | {table_colum, Id}
+%%-----------------------------------------------------------------
+
+-type tree_generation() :: non_neg_integer().
+-type tree() :: #tree{}.
+-type tree_nodes() :: [tree_node()].
+-type tree_node() :: tree() |
+ tree_node_elem() |
+ tree_node_empty().
+-type tree_node_elem() :: {node, tree_node_info()}.
+-type tree_node_info() :: {subagent, Pid :: pid()} |
+ {variable, Id :: non_neg_integer()} |
+ {table_column, Id :: non_neg_integer()}.
+-type tree_node_empty() :: {undefined_node, N :: pos_integer()}.
+-type tree_info() :: {table, Id :: non_neg_integer()} |
+ {table_entry, Id :: non_neg_integer()} |
+ internal.
+
+
+%% This record is what is stored in the database. The 'tree' part
+%% is described above...
+-record(mtree,
+ {
+ generation = ?DUMMY_TREE_GENERATION :: tree_generation(),
+ root = ?DEFAULT_TREE :: tree()
+ }).
+
+-record(tree,
+ {
+ %% The number of nodes is *not* actually the length of the
+ %% nodes list. Since the undefined-node(s) can be collapsed
+ %% into {undefined_node, N} we need to keep track of the
+ %% actual size some other way (so that we dont have the
+ %% traverse the nodes every time we want to check an index).
+ num_nodes :: non_neg_integer(),
+ nodes :: tree_nodes(),
+ tree_info :: tree_info()
+ }).
+
+
+
+
+%%%======================================================================
+%%% 1. Interface
+%%%======================================================================
+
+%%-----------------------------------------------------------------
+%% Func: new/0, new/1
+%% Returns: A representation of mib data.
+%%-----------------------------------------------------------------
+new() ->
+ new(ets).
+
+%% Where -> A list of nodes where the tables will be created
+new(Storage) ->
+ %% First we must check if there is already something to read
+ %% If a database already exists, then the tree structure has to be read
+ ?vtrace("open (mib) database",[]),
+ MibDb = snmpa_general_db:open(Storage, ?MIB_DATA,
+ mib_info,
+ record_info(fields, mib_info), set),
+ ?vtrace("open (mib) node database",[]),
+ NodeDb = snmpa_general_db:open(Storage, ?MIB_NODE,
+ node_info,
+ record_info(fields, node_info), set),
+ ?vtrace("open (mib) tree database",[]),
+ TreeDb = snmpa_general_db:open(Storage, ?MIB_TREE,
+ tree,
+ record_info(fields, mtree), set),
+ MTree =
+ case snmpa_general_db:read(TreeDb, ?DUMMY_TREE_GENERATION) of
+ false ->
+ T = #mtree{},
+ snmpa_general_db:write(TreeDb, T),
+ T;
+ {value, T} ->
+ T
+ end,
+ install_mibs(MibDb, NodeDb),
+ #mib_data{mib_db = MibDb,
+ node_db = NodeDb,
+ tree_db = TreeDb,
+ mtree = MTree}.
+
+
+%%----------------------------------------------------------------------
+%% Returns: new mib data | {error, Reason}
+%%----------------------------------------------------------------------
+load_mib(MibData,FileName,MeOverride,TeOverride)
+ when is_record(MibData,mib_data) andalso is_list(FileName) ->
+ ?vlog("load mib file: ~p",[FileName]),
+ ActualFileName = filename:rootname(FileName, ".bin") ++ ".bin",
+ MibName = list_to_atom(filename:basename(FileName, ".bin")),
+ (catch do_load_mib(MibData, ActualFileName, MibName,
+ MeOverride, TeOverride)).
+
+do_load_mib(MibData, ActualFileName, MibName, MeOverride, TeOverride) ->
+ ?vtrace("do_load_mib -> entry with"
+ "~n ActualFileName: ~s"
+ "~n MibName: ~p",[ActualFileName, MibName]),
+ #mib_data{mib_db = MibDb,
+ node_db = NodeDb,
+ %% tree_db = TreeDb,
+ tree = Tree} = MibData,
+ verify_not_loaded(MibDb, MibName),
+ ?vtrace("do_load_mib -> already loaded mibs:"
+ "~n ~p",[loaded(MibDb)]),
+ Mib = do_read_mib(ActualFileName),
+ ?vtrace("do_load_mib -> read mib ~s",[Mib#mib.name]),
+ NonInternalMes =
+ lists:filter(fun(ME) -> maybe_drop_me(ME) end, Mib#mib.mes),
+ OldRoot = Tree#tree.root,
+ T = build_tree(NonInternalMes, MibName),
+ ?d("load_mib -> "
+ "~n OldRoot: ~p"
+ "~n T: ~p", [OldRoot, T]),
+ case (catch merge_nodes(T, OldRoot)) of
+ {error_merge_nodes, Node1, Node2} ->
+ ?vlog("error merging nodes:"
+ "~n~p~nand~n~p", [Node1,Node2]),
+ {error, oid_conflict};
+ NewRoot when is_tuple(NewRoot) andalso (element(1,NewRoot) =:= tree) ->
+ ?d("load_mib -> "
+ "~n NewRoot: ~p", [NewRoot]),
+ Symbolic = not lists:member(no_symbolic_info, Mib#mib.misc),
+ case (catch check_notif_and_mes(TeOverride, MeOverride, Symbolic,
+ Mib#mib.traps, NonInternalMes)) of
+ true ->
+ install_mes(NodeDb, MibName, NonInternalMes),
+ install_mib(MibDb, Symbolic, Mib,
+ MibName, ActualFileName, NonInternalMes),
+ ?vtrace("installed mib ~s", [Mib#mib.name]),
+ Tree2 = Tree#tree{root = NewRoot},
+ %% snmpa_general_db:write(TreeDb, Tree2), %% Store later?
+ {ok, MibData#mib_data{tree = Tree2}};
+ Else ->
+ Else
+ end
+ end.
+
+
+verify_not_loaded(Db, Name) ->
+ case snmpa_general_db:read(Db, Name) of
+ {value, #mib_info{name = Name}} ->
+ throw({error, 'already loaded'});
+ false ->
+ ok
+ end.
+
+do_read_mib(ActualFileName) ->
+ case snmp_misc:read_mib(ActualFileName) of
+ {error, Reason} ->
+ ?vlog("Failed reading mib file ~p with reason: ~p",
+ [ActualFileName,Reason]),
+ throw({error, Reason});
+ {ok, Mib} ->
+ Mib
+ end.
+
+%% The Tree DB is handled in a special way since it can be very large.
+sync(#mib_data{mib_db = M,
+ node_db = N,
+ tree_db = T, tree = Tree, subagents = []}) ->
+ snmpa_general_db:sync(M),
+ snmpa_general_db:sync(N),
+ snmpa_general_db:write(T, Tree),
+ snmpa_general_db:sync(T);
+sync(#mib_data{mib_db = M,
+ node_db = N,
+ tree_db = T, tree = Tree, subagents = SAs}) ->
+
+ snmpa_general_db:sync(M),
+ snmpa_general_db:sync(N),
+
+ %% Ouch. Since the subagent info is dynamic we do not
+ %% want to store the tree containing subagent info. So, we
+ %% have to create a tmp tree without those and store it.
+
+ case delete_subagents(Tree, SAs) of
+ {ok, TreeWithoutSAs} ->
+ snmpa_general_db:write(T, TreeWithoutSAs),
+ snmpa_general_db:sync(T);
+ Error ->
+ Error
+ end.
+
+delete_subagents(Tree, []) ->
+ {ok, Tree};
+delete_subagents(Tree0, [{_, Oid}|SAs]) ->
+ case (catch delete_subagent(Tree0, Oid)) of
+ {tree, _Tree, _Info} = Tree1 ->
+ delete_subagents(Tree1, SAs);
+ _Error ->
+ {error, {'invalid oid', Oid}}
+ end.
+
+%%----------------------------------------------------------------------
+%% (OTP-3601)
+%%----------------------------------------------------------------------
+check_notif_and_mes(TeOverride,MeOverride,Symbolic,Traps,MEs) ->
+ ?vtrace("check notifications and mib entries",[]),
+ check_notifications(TeOverride,Symbolic,Traps),
+ check_mes(MeOverride,MEs).
+
+check_notifications(true, _Symbolic, _Traps) ->
+ ?vtrace("trapentry override = true => skip check",[]),
+ true;
+check_notifications(_, Symbolic, Traps) ->
+ check_notifications(Symbolic, Traps).
+
+check_notifications(true, Traps) ->
+ check_notifications(Traps);
+check_notifications(_, _) -> true.
+
+check_notifications([]) -> true;
+check_notifications([#trap{trapname = Key} = Trap | Traps]) ->
+ ?vtrace("check notification [trap] with Key: ~p",[Key]),
+ case snmpa_symbolic_store:get_notification(Key) of
+ {value, Trap} -> check_notifications(Traps);
+ {value, _} -> throw({error, {'trap already defined', Key}});
+ undefined -> check_notifications(Traps)
+ end;
+check_notifications([#notification{trapname = Key} = Notif | Traps]) ->
+ ?vtrace("check notification [notification] with Key: ~p",[Key]),
+ case snmpa_symbolic_store:get_notification(Key) of
+ {value, Notif} ->
+ check_notifications(Traps);
+ {value, _} ->
+ throw({error, {'notification already defined', Key}});
+ undefined ->
+ check_notifications(Traps)
+ end;
+check_notifications([Crap | Traps]) ->
+ ?vlog("skipped check of: ~n~p",[Crap]),
+ check_notifications(Traps).
+
+check_mes(true,_) ->
+ ?vtrace("mibentry override = true => skip check",[]),
+ true;
+check_mes(_,MEs) ->
+ check_mes(MEs).
+
+check_mes([]) -> true;
+check_mes([#me{aliasname = Name, oid = Oid1} | MEs]) ->
+ ?vtrace("check mib entries with aliasname: ~p",[Name]),
+ case snmpa_symbolic_store:aliasname_to_oid(Name) of
+ {value, Oid1} ->
+ check_mes(MEs);
+ {value, Oid2} ->
+ ?vinfo("~n expecting '~p'~n but found '~p'",[Oid1, Oid2]),
+ throw({error, {'mibentry already defined', Name}});
+ false ->
+ check_mes(MEs)
+ end;
+check_mes([Crap | MEs]) ->
+ ?vlog("skipped check of: ~n~p",[Crap]),
+ check_mes(MEs).
+
+
+
+%%----------------------------------------------------------------------
+%% Returns: new mib data | {error, Reason}
+%%----------------------------------------------------------------------
+unload_mib(MibData, FileName, _, _) when is_list(FileName) ->
+ MibName = list_to_atom(filename:basename(FileName, ".bin")),
+ (catch do_unload_mib(MibData, MibName)).
+
+do_unload_mib(MibData, MibName) ->
+ ?vtrace("do_unload_mib -> entry with"
+ "~n MibName: ~p", [MibName]),
+ #mib_data{mib_db = MibDb,
+ node_db = NodeDb,
+ %% tree_db = TreeDb,
+ tree = Tree} = MibData,
+ #mib_info{symbolic = Symbolic} = verify_loaded(MibDb, MibName),
+ NewRoot = delete_mib_from_tree(MibName, Tree#tree.root),
+ MEs = uninstall_mes(NodeDb, MibName),
+ uninstall_mib(MibDb, Symbolic, MibName, MEs),
+ NewMibData = MibData#mib_data{tree = Tree#tree{root = NewRoot}},
+ {ok, NewMibData}.
+
+verify_loaded(Db, Name) ->
+ case snmpa_general_db:read(Db, Name) of
+ {value, MibInfo} ->
+ MibInfo;
+ false ->
+ throw({error, 'not loaded'})
+ end.
+
+
+close(#mib_data{mib_db = MibDb, node_db = NodeDb, tree_db = TreeDb}) ->
+ snmpa_general_db:close(MibDb),
+ snmpa_general_db:close(NodeDb),
+ snmpa_general_db:close(TreeDb),
+ ok.
+
+register_subagent(#mib_data{tree = T} = MibData, Oid, Pid) ->
+ case insert_subagent(Oid, T#tree.root) of
+ {error, Reason} ->
+ {error, Reason};
+ NewRootTree ->
+ SAs = [{Pid, Oid} | MibData#mib_data.subagents],
+ T2 = T#tree{root = NewRootTree},
+ MibData#mib_data{tree = T2, subagents = SAs}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Purpose: Get a list of all loaded mibs
+%% Returns: [{Name, File}]
+%%----------------------------------------------------------------------
+
+which_mibs(#mib_data{mib_db = Db}) ->
+ Mibs = snmpa_general_db:tab2list(Db),
+ [{Name, File} || #mib_info{name = Name, file_name = File} <- Mibs].
+
+
+%%----------------------------------------------------------------------
+%% Purpose: Get a list of all loaded mibs
+%% Returns: [{Name, File}]
+%%----------------------------------------------------------------------
+
+whereis_mib(#mib_data{mib_db = Db}, Name) ->
+ case snmpa_general_db:read(Db, Name) of
+ {value, #mib_info{file_name = File}} ->
+ {ok, File};
+ false ->
+ {error, not_found}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Purpose: Deletes SA with Pid from all subtrees it handles.
+%% Returns: NewMibData.
+%%----------------------------------------------------------------------
+unregister_subagent(MibData, Pid) when is_pid(Pid) ->
+ SAs = MibData#mib_data.subagents,
+ case lists:keysearch(Pid, 1, SAs) of
+ false -> MibData;
+ {value, {Pid, Oid}} ->
+ % we should never get an error since Oid is found in MibData.
+ {ok, NewMibData, _DeletedSA} = unregister_subagent(MibData, Oid),
+ % continue if the same Pid handles other mib subtrees.
+ unregister_subagent(NewMibData, Pid)
+ end;
+
+%%----------------------------------------------------------------------
+%% Purpose: Deletes one unique subagent.
+%% Returns: {error, Reason} | {ok, NewMibData, DeletedSubagentPid}
+%%----------------------------------------------------------------------
+unregister_subagent(#mib_data{tree = T} = MibData, Oid) when is_list(Oid) ->
+ case catch delete_subagent(T#tree.root, Oid) of
+ {tree, Tree, Info} ->
+ OldSAs = MibData#mib_data.subagents,
+ {value, {Pid, _Oid}} = lists:keysearch(Oid, 2, OldSAs),
+ SAs = lists:keydelete(Oid, 2, OldSAs),
+ T2 = T#tree{root = {tree, Tree, Info}},
+ {ok,
+ MibData#mib_data{tree = T2, subagents = SAs},
+ Pid};
+ _ ->
+ {error, {'invalid oid', Oid}}
+ end.
+
+%%----------------------------------------------------------------------
+%% Purpose: To inpect memory usage, loaded mibs, registered subagents
+%%----------------------------------------------------------------------
+info(MibData) ->
+ ?vtrace("retrieve info",[]),
+ #mib_data{mib_db = MibDb, node_db = NodeDb, tree_db = TreeDb,
+ tree = Tree, subagents = SAs} = MibData,
+ LoadedMibs = old_format(snmpa_general_db:tab2list(MibDb)),
+ TreeSize = snmp_misc:mem_size(Tree),
+ {memory, ProcSize} = erlang:process_info(self(),memory),
+ MibDbSize = snmpa_general_db:info(MibDb, memory),
+ NodeDbSize = snmpa_general_db:info(NodeDb, memory),
+ TreeDbSize = snmpa_general_db:info(TreeDb, memory),
+ [{loaded_mibs, LoadedMibs}, {subagents, SAs}, {tree_size_bytes, TreeSize},
+ {process_memory, ProcSize},
+ {db_memory, [{mib,MibDbSize},{node,NodeDbSize},{tree,TreeDbSize}]}].
+
+info(#mib_data{mib_db = MibDb}, loaded_mibs) ->
+ Mibs = snmpa_general_db:tab2list(MibDb),
+ [filename:rootname(FN, ".bin") || #mib_info{file_name = FN} <- Mibs];
+info(#mib_data{tree = Tree}, tree_size_bytes) ->
+ snmp_misc:mem_size(Tree);
+info(_, process_memory) ->
+ {memory, ProcSize} = erlang:process_info(self(),memory),
+ ProcSize;
+info(#mib_data{mib_db = MibDb, node_db = NodeDb, tree_db = TreeDb},
+ db_memory) ->
+ MibDbSize = snmpa_general_db:info(MibDb, memory),
+ NodeDbSize = snmpa_general_db:info(NodeDb, memory),
+ TreeDbSize = snmpa_general_db:info(TreeDb, memory),
+ [{mib,MibDbSize},{node,NodeDbSize},{tree,TreeDbSize}];
+info(#mib_data{subagents = SAs}, subagents) ->
+ SAs.
+
+old_format(LoadedMibs) ->
+ ?vtrace("convert mib info to old format",[]),
+ [{N,S,F} || #mib_info{name=N,symbolic=S,file_name=F} <- LoadedMibs].
+
+
+%%----------------------------------------------------------------------
+%% A total dump for debugging.
+%%----------------------------------------------------------------------
+dump(#mib_data{mib_db = MibDb, node_db = NodeDb, tree = Tree}) ->
+ (catch io:format("MIB-tables:~n~p~n~n",
+ [snmpa_general_db:tab2list(MibDb)])),
+ (catch io:format("MIB-entries:~n~p~n~n",
+ [snmpa_general_db:tab2list(NodeDb)])),
+ (catch io:format("Tree:~n~p~n", [Tree])), % good luck reading it!
+ ok.
+
+dump(#mib_data{mib_db = MibDb, node_db = NodeDb, tree = Tree}, File) ->
+ case file:open(File,[write]) of
+ {ok, Fd} ->
+ io:format(Fd,"~s~n",
+ [snmp:date_and_time_to_string(snmp:date_and_time())]),
+ (catch io:format(Fd,"MIB-tables:~n~p~n~n",
+ [snmpa_general_db:tab2list(MibDb)])),
+ (catch io:format(Fd, "MIB-entries:~n~p~n~n",
+ [snmpa_general_db:tab2list(NodeDb)])),
+ io:format(Fd,"Tree:~n~p~n", [Tree]), % good luck reading it!
+ file:close(Fd),
+ ok;
+ {error,Reason} ->
+ ?vinfo("~n Failed opening file '~s' for reason ~p",
+ [File,Reason]),
+ {error,Reason}
+ end.
+
+
+backup(#mib_data{mib_db = M, node_db = N, tree_db = T}, BackupDir) ->
+ MRes = snmpa_general_db:backup(M, BackupDir),
+ NRes = snmpa_general_db:backup(N, BackupDir),
+ TRes = snmpa_general_db:backup(T, BackupDir),
+ handle_backup_res([{mib_db, MRes}, {node_db, NRes}, {tree_db, TRes}]).
+
+handle_backup_res(Res) ->
+ handle_backup_res(Res, []).
+
+handle_backup_res([], []) ->
+ ok;
+handle_backup_res([], Err) ->
+ {error, lists:reverse(Err)};
+handle_backup_res([{_, ok}|Res], Err) ->
+ handle_backup_res(Res, Err);
+handle_backup_res([{Tag, {error, Reason}}|Res], Err) ->
+ handle_backup_res(Res, [{Tag, Reason}|Err]);
+handle_backup_res([{Tag, Error}|Res], Err) ->
+ handle_backup_res(Res, [{Tag, Error}|Err]).
+
+
+%%%======================================================================
+%%% 2. Implementation of tree access
+%%% lookup and next.
+%%%======================================================================
+
+
+which_mib(#mib_data{tree = T} = D, Oid) ->
+ ?vtrace("which_mib -> entry with"
+ "~n Oid: ~p",[Oid]),
+ case (catch find_node(D, T#tree.root, Oid, [])) of
+ {variable, _ME, Mib} ->
+ ?vtrace("which_mib -> variable:"
+ "~n Mib: ~p", [Mib]),
+ {ok, Mib};
+ {table, _EntryME, _, Mib} ->
+ ?vtrace("which_mib -> table:"
+ "~n Mib: ~p", [Mib]),
+ {ok, Mib};
+ {subagent, SubAgentPid, _SANextOid} ->
+ ?vtrace("which_mib -> subagent:"
+ "~n SubAgentPid: ~p", [SubAgentPid]),
+ {error, {subagent, SubAgentPid}};
+ {false, ErrorCode} ->
+ ?vtrace("which_mib -> false:"
+ "~n ErrorCode: ~p",[ErrorCode]),
+ {error, ErrorCode};
+ false ->
+ ?vtrace("which_mib -> false",[]),
+ {error, noSuchObject};
+ {'EXIT', R} ->
+ ?vtrace("which_mib -> exit:"
+ "~n R: ~p",[R]),
+ {error, noSuchObject}
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Func: lookup/2
+%% Purpose: Finds the mib entry corresponding to the Oid. If it is a
+%% variable, the Oid must be <Oid for var>.0 and if it is
+%% a table, Oid must be <table>.<entry>.<col>.<any>
+%% Returns: {variable, MibEntry} |
+%% {table_column, MibEntry, TableEntryOid} |
+%% {subagent, SubAgentPid, SAOid} |
+%% {false, Reason}
+%%-----------------------------------------------------------------
+lookup(#mib_data{tree = T} = D, Oid) ->
+ ?vtrace("lookup -> entry with"
+ "~n Oid: ~p",[Oid]),
+ case (catch find_node(D, T#tree.root, Oid, [])) of
+ {variable, ME, _Mib} when is_record(ME, me) ->
+ ?vtrace("lookup -> variable:"
+ "~n ME: ~p",[ME]),
+ {variable, ME};
+ {table, EntryME, {ColME, TableEntryOid}, _Mib} ->
+ ?vtrace("lookup -> table:"
+ "~n EntryME: ~p"
+ "~n ColME: ~p"
+ "~n RevTableEntryOid: ~p",
+ [EntryME, ColME, TableEntryOid]),
+ MFA = EntryME#me.mfa,
+ RetME = ColME#me{mfa = MFA},
+ {table_column, RetME, TableEntryOid};
+ {subagent, SubAgentPid, SANextOid} ->
+ ?vtrace("lookup -> subagent:"
+ "~n SubAgentPid: ~p"
+ "~n SANextOid: ~p", [SubAgentPid, SANextOid]),
+ {subagent, SubAgentPid, SANextOid};
+ {false, ErrorCode} ->
+ ?vtrace("lookup -> false:"
+ "~n ErrorCode: ~p",[ErrorCode]),
+ {false, ErrorCode};
+ false ->
+ ?vtrace("lookup -> false",[]),
+ {false, noSuchObject};
+ {'EXIT', R} ->
+ ?vtrace("lookup -> exit:"
+ "~n R: ~p",[R]),
+ {false, noSuchObject}
+ end.
+
+
+find_node(D, {tree, Tree, {table, _}}, RestOfOid, RevOid) ->
+ ?vtrace("find_node(tree,table) -> entry with"
+ "~n RestOfOid: ~p"
+ "~n RevOid: ~p",[RestOfOid, RevOid]),
+ find_node(D, {tree, Tree, internal}, RestOfOid, RevOid);
+find_node(D, {tree, Tree, {table_entry, _}}, RestOfOid, RevOid) ->
+ ?vtrace("find_node(tree,table_entry) -> entry with"
+ "~n RestOfOid: ~p"
+ "~n RevOid: ~p",[RestOfOid, RevOid]),
+ #mib_data{node_db = Db} = D,
+ Oid = lists:reverse(RevOid),
+ case snmpa_general_db:read(Db, Oid) of
+ {value, #node_info{me = ME, mib_name = Mib}} ->
+ case find_node(D, {tree, Tree, internal}, RestOfOid, RevOid) of
+ {false, ErrorCode} -> {false, ErrorCode};
+ Val -> {table, ME, Val, Mib}
+ end;
+ false ->
+ ?vinfo("find_node -> could not find table_entry ME with"
+ "~n RevOid: ~p"
+ "~n when"
+ "~n RestOfOid: ~p",
+ [RevOid, RestOfOid]),
+ false
+ end;
+find_node(D, {tree, Tree, _Internal}, [Int | RestOfOid], RevOid) ->
+ ?vtrace("find_node(tree) -> entry with"
+ "~n Int: ~p"
+ "~n RestOfOid: ~p"
+ "~n RevOid: ~p",[Int, RestOfOid, RevOid]),
+ find_node(D, element(Int+1, Tree), RestOfOid, [Int | RevOid]);
+find_node(D, {node, {table_column, _}}, RestOfOid, [ColInt | RevOid]) ->
+ ?vtrace("find_node(tree,table_column) -> entry with"
+ "~n RestOfOid: ~p"
+ "~n ColInt: ~p"
+ "~n RevOid: ~p",[RestOfOid, ColInt, RevOid]),
+ #mib_data{node_db = Db} = D,
+ Oid = lists:reverse([ColInt | RevOid]),
+ case snmpa_general_db:read(Db, Oid) of
+ {value, #node_info{me = ME}} ->
+ {ME, lists:reverse(RevOid)};
+ false ->
+ X = snmpa_general_db:read(Db, lists:reverse([ColInt | RevOid])),
+ ?vinfo("find_node -> could not find table_column ME with"
+ "~n RevOid: ~p"
+ "~n trying [~p|~p]"
+ "~n X: ~p",
+ [RevOid, [ColInt | RevOid], X]),
+ false
+ end;
+find_node(D, {node, {variable, _MibName}}, [0], RevOid) ->
+ ?vtrace("find_node(tree,variable,[0]) -> entry with"
+ "~n RevOid: ~p",[RevOid]),
+ #mib_data{node_db = Db} = D,
+ Oid = lists:reverse(RevOid),
+ %% {value, #node_info{me = ME}} = snmpa_general_db:read(Db, Oid),
+ case snmpa_general_db:read(Db, Oid) of
+ {value, #node_info{me = ME, mib_name = Mib}} ->
+ {variable, ME, Mib};
+ false ->
+ ?vinfo("find_node -> could not find variable ME with"
+ "~n RevOid: ~p", [RevOid]),
+ false
+ end;
+find_node(_D, {node, {variable, _MibName}}, [], _RevOid) ->
+ ?vtrace("find_node(tree,variable,[]) -> entry",[]),
+ {false, noSuchObject};
+find_node(_D, {node, {variable, _MibName}}, _, _RevOid) ->
+ ?vtrace("find_node(tree,variable) -> entry",[]),
+ {false, noSuchInstance};
+find_node(D, {node, subagent}, _RestOfOid, SARevOid) ->
+ ?vtrace("find_node(tree,subagent) -> entry with"
+ "~n SARevOid: ~p",[SARevOid]),
+ #mib_data{subagents = SAs} = D,
+ SAOid = lists:reverse(SARevOid),
+ case lists:keysearch(SAOid, 2, SAs) of
+ {value, {SubAgentPid, SAOid}} ->
+ {subagent, SubAgentPid, SAOid};
+ false ->
+ ?vinfo("find_node -> could not find subagent with"
+ "~n SAOid: ~p"
+ "~n SAs: ~p", [SAOid, SAs]),
+ false
+ end;
+find_node(_D, Node, _RestOfOid, _RevOid) ->
+ ?vtrace("find_node -> failed:~n~p",[Node]),
+ {false, noSuchObject}.
+
+
+%%-----------------------------------------------------------------
+%% Func: next/3
+%% Purpose: Finds the lexicographically next oid.
+%% Returns: endOfMibView |
+%% {subagent, SubAgentPid, SAOid} |
+%% {variable, MibEntry, VarOid} |
+%% {table, TableOid, TableRestOid, MibEntry}
+%% If a variable is returnes, it is in the MibView.
+%% If a table or subagent is returned, it *may* be in the MibView.
+%%-----------------------------------------------------------------
+next(#mib_data{tree = T} = D, Oid, MibView) ->
+ case catch next_node(D, T#tree.root, Oid, [], MibView) of
+ false -> endOfMibView;
+ Else -> Else
+ end.
+
+%%-----------------------------------------------------------------
+%% This function is used as long as we have any Oid left. Take
+%% one integer at a time from the Oid, and traverse the tree
+%% accordingly. When the Oid is empty, call find_next.
+%% Returns: {subagent, SubAgentPid, SAOid} |
+%% false |
+%% {variable, MibEntry, VarOid} |
+%% {table, TableOid, TableRestOid, MibEntry}
+%%-----------------------------------------------------------------
+next_node(_D, undefined_node, _Oid, _RevOidSoFar, _MibView) ->
+ ?vtrace("next_node(undefined_node) -> entry", []),
+ false;
+
+next_node(_D, {tree, Tree, {table_entry, _Id}}, [Int | _Oid],
+ _RevOidSoFar, _MibView)
+ when Int+1 > size(Tree) ->
+ ?vtrace("next_node(tree,table_entry) -> entry when not found whith"
+ "~n Int: ~p"
+ "~n size(Tree): ~p", [Int, size(Tree)]),
+ false;
+next_node(D, {tree, Tree, {table_entry, _MibName}},
+ Oid, RevOidSoFar, MibView) ->
+ ?vtrace("next_node(tree,table_entry) -> entry when"
+ "~n size(Tree): ~p"
+ "~n Oid: ~p"
+ "~n RevOidSoFar: ~p"
+ "~n MibView: ~p", [size(Tree), Oid, RevOidSoFar, MibView]),
+ OidSoFar = lists:reverse(RevOidSoFar),
+ case snmpa_acm:is_definitely_not_in_mib_view(OidSoFar, MibView) of
+ true ->
+ ?vdebug("next_node(tree,table_entry) -> not in mib view",[]),
+ false;
+ _ ->
+ #mib_data{node_db = Db} = D,
+ case snmpa_general_db:read(Db, OidSoFar) of
+ false ->
+ ?vinfo("next_node -> could not find table_entry with"
+ "~n OidSoFar: ~p", [OidSoFar]),
+ false;
+ {value, #node_info{me = ME}} ->
+ ?vtrace("next_node(tree,table_entry) -> found: ~n ~p",
+ [ME]),
+ {table, OidSoFar, Oid, ME}
+ end
+ end;
+
+next_node(D, {tree, Tree, _Info}, [Int | RestOfOid], RevOidSoFar, MibView)
+ when (Int < size(Tree)) andalso (Int >= 0) ->
+ ?vtrace("next_node(tree) -> entry when"
+ "~n size(Tree): ~p"
+ "~n Int: ~p"
+ "~n RestOfOid: ~p"
+ "~n RevOidSoFar: ~p"
+ "~n MibView: ~p",
+ [size(Tree), Int, RestOfOid, RevOidSoFar, MibView]),
+ case next_node(D, element(Int+1,Tree),
+ RestOfOid, [Int|RevOidSoFar], MibView) of
+ false ->
+ find_next(D, {tree, Tree, _Info}, Int+1, RevOidSoFar, MibView);
+ Else ->
+ Else
+ end;
+%% no solution
+next_node(D, {tree, Tree, _Info}, [], RevOidSoFar, MibView) ->
+ ?vtrace("next_node(tree,[]) -> entry when"
+ "~n size(Tree): ~p"
+ "~n RevOidSoFar: ~p"
+ "~n MibView: ~p",
+ [size(Tree), RevOidSoFar, MibView]),
+ find_next(D, {tree, Tree, _Info}, 0, RevOidSoFar, MibView);
+next_node(_D, {tree, Tree, _Info}, _RestOfOid, _RevOidSoFar, _MibView) ->
+ ?vtrace("next_node(tree) -> entry when"
+ "~n size(Tree): ~p", [size(Tree)]),
+ false;
+
+next_node(D, {node, subagent}, Oid, RevOidSoFar, MibView) ->
+ ?vtrace("next_node(node,subagent) -> entry when"
+ "~n Oid: ~p"
+ "~n RevOidSoFar: ~p"
+ "~n MibView: ~p",
+ [Oid, RevOidSoFar, MibView]),
+ OidSoFar = lists:reverse(RevOidSoFar),
+ case snmpa_acm:is_definitely_not_in_mib_view(OidSoFar, MibView) of
+ true ->
+ false;
+ _ ->
+ #mib_data{subagents = SAs} = D,
+ case lists:keysearch(OidSoFar, 2, SAs) of
+ {value, {SubAgentPid, OidSoFar}} ->
+ {subagent, SubAgentPid, OidSoFar};
+ _ ->
+ ?vinfo("next_node -> could not find subagent with"
+ "~n OidSoFar: ~p"
+ "~n SAs: ~p", [OidSoFar, SAs]),
+ false
+ end
+ end;
+
+next_node(D, {node, {variable, _MibName}}, [], RevOidSoFar, MibView) ->
+ ?vtrace("next_node(node,variable,[]) -> entry when"
+ "~n RevOidSoFar: ~p"
+ "~n MibView: ~p",
+ [RevOidSoFar, MibView]),
+ OidSoFar = lists:reverse([0 | RevOidSoFar]),
+ case snmpa_acm:validate_mib_view(OidSoFar, MibView) of
+ true ->
+ #mib_data{node_db = Db} = D,
+ case snmpa_general_db:read(Db, lists:reverse(RevOidSoFar)) of
+ false ->
+ ?vinfo("next_node -> could not find variable with"
+ "~n RevOidSoFar: ~p", [RevOidSoFar]),
+ false;
+ {value, #node_info{me = ME}} ->
+ {variable, ME, OidSoFar}
+ end;
+ _ ->
+ false
+ end;
+
+next_node(_D, {node, {variable, _MibName}}, _Oid, _RevOidSoFar, _MibView) ->
+ ?vtrace("next_node(node,variable) -> entry", []),
+ false.
+
+%%-----------------------------------------------------------------
+%% This function is used to find the first leaf from where we
+%% are.
+%% Returns: {subagent, SubAgentPid, SAOid} |
+%% false |
+%% {variable, MibEntry, VarOid} |
+%% {table, TableOid, TableRestOid, MibEntry}
+%% PRE: This function must always be called with a {internal, Tree}
+%% node.
+%%-----------------------------------------------------------------
+find_next(D, {tree, Tree, internal}, Idx, RevOidSoFar, MibView)
+ when Idx < size(Tree) ->
+ case find_next(D, element(Idx+1, Tree), 0, [Idx| RevOidSoFar], MibView) of
+ false ->
+ find_next(D, {tree, Tree, internal}, Idx+1, RevOidSoFar, MibView);
+ Other ->
+ Other
+ end;
+find_next(_D, {tree, _Tree, internal}, _Idx, _RevOidSoFar, _MibView) ->
+ false;
+find_next(_D, undefined_node, _Idx, _RevOidSoFar, _MibView) ->
+ false;
+find_next(D, {tree, Tree, {table, _MibName}}, Idx, RevOidSoFar, MibView) ->
+ find_next(D, {tree, Tree, internal}, Idx, RevOidSoFar, MibView);
+find_next(D, {tree, _Tree, {table_entry, _MibName}}, _Index,
+ RevOidSoFar, MibView) ->
+ OidSoFar = lists:reverse(RevOidSoFar),
+ case snmpa_acm:is_definitely_not_in_mib_view(OidSoFar, MibView) of
+ true ->
+ false;
+ _ ->
+ #mib_data{node_db = Db} = D,
+ case snmpa_general_db:read(Db, OidSoFar) of
+ false ->
+ ?vinfo("find_next -> could not find table_entry ME with"
+ "~n OidSoFar: ~p", [OidSoFar]),
+ false;
+ {value, #node_info{me = ME}} ->
+ {table, OidSoFar, [], ME}
+ end
+ end;
+find_next(D, {node, {variable, _MibName}}, _Idx, RevOidSoFar, MibView) ->
+ OidSoFar = lists:reverse([0 | RevOidSoFar]),
+ case snmpa_acm:validate_mib_view(OidSoFar, MibView) of
+ true ->
+ #mib_data{node_db = Db} = D,
+ case snmpa_general_db:read(Db, lists:reverse(RevOidSoFar)) of
+ false ->
+ ?vinfo("find_next -> could not find variable with"
+ "~n RevOidSoFar: ~p", [RevOidSoFar]),
+ false;
+ {value, #node_info{me = ME}} ->
+ {variable, ME, OidSoFar}
+ end;
+ _ ->
+ false
+ end;
+find_next(D, {node, subagent}, _Idx, RevOidSoFar, MibView) ->
+ OidSoFar = lists:reverse(RevOidSoFar),
+ case snmpa_acm:is_definitely_not_in_mib_view(OidSoFar, MibView) of
+ true ->
+ false;
+ _ ->
+ #mib_data{subagents = SAs} = D,
+ case lists:keysearch(OidSoFar, 2, SAs) of
+ {value, {SubAgentPid, OidSoFar}} ->
+ {subagent, SubAgentPid, OidSoFar};
+ false ->
+ ?vinfo("find_node -> could not find subagent with"
+ "~n OidSoFar: ~p"
+ "~n SAs: ~p", [OidSoFar, SAs]),
+ false
+ end
+ end.
+
+%%%======================================================================
+%%% 3. Tree building functions
+%%% Used when loading mibs.
+%%%======================================================================
+
+build_tree(Mes, MibName) ->
+ ?d("build_tree -> "
+ "~n Mes: ~p", [Mes]),
+ {ListTree, []} = build_subtree([], Mes, MibName),
+ {tree, convert_tree(ListTree), internal}.
+
+%%----------------------------------------------------------------------
+%% Purpose: Builds the tree where all oids have prefix equal to LevelPrefix.
+%% Returns: {Tree, RestMes}
+%% RestMes are Mes that should not be in this subtree.
+%% The Tree is a temporary and simplified data structure that is easy to
+%% convert to the final tuple tree used by the MIB process.
+%% A Node is represented as in the final tree.
+%% The tree is not represented as a N-tuple, but as an Index-list.
+%% Example: Temporary: [{1, Node1}, {3, Node3}]
+%% Final: {Node1, undefined_node, Node3}
+%% Pre: Mes are sorted on oid.
+%%----------------------------------------------------------------------
+build_subtree(LevelPrefix, [Me | Mes], MibName) ->
+ ?vtrace("build subtree -> ~n"
+ " oid: ~p~n"
+ " LevelPrefix: ~p~n"
+ " MibName: ~p", [Me#me.oid, LevelPrefix, MibName]),
+ EType = Me#me.entrytype,
+ ?vtrace("build subtree -> EType = ~p",[EType]),
+ case in_subtree(LevelPrefix, Me) of
+ above ->
+ ?vtrace("build subtree -> above",[]),
+ {[], [Me|Mes]};
+ {node, Index} ->
+ ?vtrace("build subtree -> node at ~p",[Index]),
+ {Tree, RestMes} = build_subtree(LevelPrefix, Mes, MibName),
+ {[{Index, {node, {EType, MibName}}} | Tree], RestMes};
+ {subtree, Index, NewLevelPrefix} ->
+ ?vtrace("build subtree -> subtree at"
+ "~n ~w with ~w",
+ [Index, NewLevelPrefix]),
+ {BelowTree, RestMes} =
+ build_subtree(NewLevelPrefix, Mes, MibName),
+ {CurTree, RestMes2} =
+ build_subtree(LevelPrefix, RestMes, MibName),
+ {[{Index, {tree, BelowTree, {EType,MibName}}}| CurTree], RestMes2};
+ {internal_subtree, Index, NewLevelPrefix} ->
+ ?vtrace("build subtree -> internal_subtree at"
+ "~n ~w with ~w",
+ [Index,NewLevelPrefix]),
+ {BelowTree, RestMes} =
+ build_subtree(NewLevelPrefix, [Me | Mes], MibName),
+ {CurTree, RestMes2} =
+ build_subtree(LevelPrefix, RestMes, MibName),
+ {[{Index, {tree, BelowTree, internal}} | CurTree], RestMes2}
+ end;
+
+build_subtree(_LevelPrefix, [], _MibName) ->
+ ?vtrace("build subtree -> done", []),
+ {[], []}.
+
+%%--------------------------------------------------
+%% Purpose: Determine how/if/where Me should be inserted in subtree
+%% with LevelPrefix. This function does not build any tree, only
+%% determinses what should be done (by build subtree).
+%% Returns:
+%% above - Indicating that this ME should _not_ be in this subtree.
+%% {node, Index} - yes, construct a node with index Index on this level
+%% {internal_subtree, Index, NewLevelPrefix} - yes, there should be an
+%% internal subtree at this index.
+%% {subtree, Index, NewLevelPrefix} - yes, construct a subtree with
+%% NewLevelPrefix and insert this on current level in position Index.
+%%--------------------------------------------------
+in_subtree(LevelPrefix, Me) ->
+ case lists:prefix(LevelPrefix, Me#me.oid) of
+ true when length(Me#me.oid) > length(LevelPrefix) ->
+ classify_how_in_subtree(LevelPrefix, Me);
+ _ ->
+ above
+ end.
+
+%%--------------------------------------------------
+%% See comment about in_subtree/2. This function takes care of all cases
+%% where the ME really should be in _this_ subtree (not above).
+%%--------------------------------------------------
+classify_how_in_subtree(LevelPrefix, Me)
+ when (length(Me#me.oid) =:= (length(LevelPrefix) + 1)) ->
+ Oid = Me#me.oid,
+ case node_or_subtree(Me#me.entrytype) of
+ subtree ->
+ {subtree, lists:last(Oid), Oid};
+ node ->
+ {node, lists:last(Oid)}
+ end;
+
+classify_how_in_subtree(LevelPrefix, Me)
+ when (length(Me#me.oid) > (length(LevelPrefix) + 1)) ->
+ L1 = length(LevelPrefix) + 1,
+ Oid = Me#me.oid,
+ {internal_subtree, lists:nth(L1, Oid), lists:sublist(Oid, 1, L1)}.
+
+%%--------------------------------------------------
+%% Determines how to treat different kinds om MEs in the tree building process.
+%% Pre: all internal nodes have been removed.
+%%--------------------------------------------------
+node_or_subtree(table) -> subtree;
+node_or_subtree(table_entry) -> subtree;
+node_or_subtree(variable) -> node;
+node_or_subtree(table_column) -> node.
+
+%%--------------------------------------------------
+%% Purpose: (Recursively) Converts a temporary tree (see above) to a final tree.
+%% If input is a ListTree, output is a TupleTree.
+%% If input is a Node, output is the same Node.
+%% Pre: All Indexes are >= 0.
+%%--------------------------------------------------
+convert_tree({Index, {tree, Tree, Info}}) when Index >= 0 ->
+ L = lists:map(fun convert_tree/1, Tree),
+ {Index, {tree, dict_list_to_tuple(L), Info}};
+convert_tree({Index, {node, Info}}) when Index >= 0 ->
+ {Index, {node, Info}};
+convert_tree(Tree) when is_list(Tree) ->
+ L = lists:map(fun convert_tree/1, Tree),
+ dict_list_to_tuple(L).
+
+%%----------------------------------------------------------------------
+%% Purpose: Converts a single level (that is non-recursively) from
+%% the temporary indexlist to the N-tuple.
+%% Input: A list of {Index, Data}.
+%% Output: A tuple where element Index is Data.
+%%----------------------------------------------------------------------
+dict_list_to_tuple(L) ->
+ L2 = lists:keysort(1, L),
+ list_to_tuple(integrate_indexes(0, L2)).
+
+%%----------------------------------------------------------------------
+%% Purpose: Helper function for dict_list_to_tuple/1.
+%% Converts an indexlist to a N-list.
+%% Input: A list of {Index, Data}.
+%% Output: A (usually longer, never shorter) list where element Index is Data.
+%% Example: [{1,hej}, {3, sven}] will give output
+%% [undefined_node, hej, undefined_node, sven].
+%% Initially CurIndex should be 0.
+%%----------------------------------------------------------------------
+integrate_indexes(CurIndex, [{CurIndex, Data} | T]) ->
+ [Data | integrate_indexes(CurIndex + 1, T)];
+integrate_indexes(_Index, []) ->
+ [];
+integrate_indexes(CurIndex, L) ->
+ [undefined_node | integrate_indexes(CurIndex + 1, L)].
+
+%%%======================================================================
+%%% 4. Tree merging
+%%% Used by: load mib, insert subagent.
+%%%======================================================================
+
+%%----------------------------------------------------------------------
+%% Arg: Two root nodes (that is to be merged).
+%% Returns: A new root node where the nodes have been merger to one.
+%%----------------------------------------------------------------------
+merge_nodes(Same, Same) ->
+ Same;
+merge_nodes(Node, undefined_node) ->
+ Node;
+merge_nodes(undefined_node, Node) ->
+ Node;
+merge_nodes({tree, Tree1, internal}, {tree, Tree2, internal}) ->
+ {tree, merge_levels(tuple_to_list(Tree1),tuple_to_list(Tree2)), internal};
+merge_nodes(Node1, Node2) ->
+ throw({error_merge_nodes, Node1, Node2}).
+
+%%----------------------------------------------------------------------
+%% Arg: Two levels to be merged.
+%% Here, a level is represented as a list of nodes. A list is easier
+%% to extend than a tuple.
+%% Returns: The resulting, merged level tuple.
+%%----------------------------------------------------------------------
+merge_levels(Level1, Level2) when length(Level1) =:= length(Level2) ->
+ MergeNodes = fun(N1, N2) -> merge_nodes(N1, N2) end,
+ list_to_tuple(snmp_misc:multi_map(MergeNodes, [Level1, Level2]));
+merge_levels(Level1, Level2) when length(Level1) > length(Level2) ->
+ merge_levels(Level1, Level2 ++
+ undefined_nodes_list(length(Level1) - length(Level2)));
+merge_levels(Level1, Level2) when length(Level1) < length(Level2) ->
+ merge_levels(Level2, Level1).
+
+undefined_nodes_list(N) -> lists:duplicate(N, undefined_node).
+
+
+%%%======================================================================
+%%% 5. Tree deletion routines
+%%% (for unload mib)
+%%%======================================================================
+
+%%----------------------------------------------------------------------
+%% Purpose: Actually kicks of the tree reconstruction.
+%% Returns: {list of removed MEs, NewTree}
+%%----------------------------------------------------------------------
+delete_mib_from_tree(MibName, {tree, Tree, internal}) ->
+ case delete_tree(Tree, MibName) of
+ [] ->
+ {tree, {undefined_node}, internal}; % reduce
+ LevelList ->
+ {tree, list_to_tuple(LevelList), internal}
+ end.
+
+%%----------------------------------------------------------------------
+%% Purpose: Deletes all nodes associated to MibName from this level and
+%% all levels below.
+%% If the new level does not contain information (that is, no
+%% other mibs use it) anymore the empty list is returned.
+%% Returns: {MEs, The new level represented as a list}
+%%----------------------------------------------------------------------
+delete_tree(Tree, MibName) when is_tuple(Tree) ->
+ NewLevel = delete_nodes(tuple_to_list(Tree), MibName, []),
+ case lists:filter(fun drop_undefined_nodes/1,NewLevel) of
+ [] -> [];
+ _A_perhaps_shorted_list ->
+ NewLevel % some other mib needs this level
+ end.
+
+%%----------------------------------------------------------------------
+%% Purpose: Nodes belonging to MibName are removed from the tree.
+%% Recursively deletes sub trees to this node.
+%% Returns: {MEs, NewNodesList}
+%%----------------------------------------------------------------------
+delete_nodes([], _MibName, AccNodes) ->
+ lists:reverse(AccNodes);
+
+delete_nodes([{node, {variable, MibName}}|T], MibName, AccNodes) ->
+ delete_nodes(T, MibName, [undefined_node | AccNodes]);
+
+delete_nodes([{node, {table_column, MibName}}|T], MibName, AccNodes) ->
+ delete_nodes(T, MibName, [undefined_node | AccNodes]);
+
+delete_nodes([{tree, _Tree, {table, MibName}}|T], MibName, AccNodes) ->
+ delete_nodes(T, MibName, [undefined_node | AccNodes]);
+
+delete_nodes([{tree, _Tree, {table_entry, MibName}}|T], MibName, AccNodes) ->
+ delete_nodes(T, MibName, [undefined_node | AccNodes]);
+
+delete_nodes([{tree, Tree, Info}|T], MibName, AccNodes) ->
+ case delete_tree(Tree, MibName) of
+ [] -> % tree completely deleted
+ delete_nodes(T, MibName, [undefined_node | AccNodes]);
+ LevelList ->
+ delete_nodes(T, MibName,
+ [{tree, list_to_tuple(LevelList), Info} | AccNodes])
+ end;
+
+delete_nodes([NodeToKeep|T], MibName, AccNodes) ->
+ delete_nodes(T, MibName, [NodeToKeep | AccNodes]).
+
+drop_undefined_nodes(undefined_node) -> false;
+drop_undefined_nodes(_) -> true.
+
+
+%%%======================================================================
+%%% 6. Functions for subagent handling
+%%%======================================================================
+
+%%----------------------------------------------------------------------
+%% Returns: A new Root|{error, reason}
+%%----------------------------------------------------------------------
+insert_subagent(Oid, OldRoot) ->
+ ListTree = build_tree_for_subagent(Oid),
+ case catch convert_tree(ListTree) of
+ {'EXIT', _Reason} ->
+ {error, 'cannot construct tree from oid'};
+ Level when is_tuple(Level) ->
+ T = {tree, Level, internal},
+ case catch merge_nodes(T, OldRoot) of
+ {error_merge_nodes, _Node1, _Node2} ->
+ {error, oid_conflict};
+ NewRoot when is_tuple(NewRoot) andalso
+ (element(1, NewRoot) =:= tree) ->
+ NewRoot
+ end
+ end.
+
+build_tree_for_subagent([Index]) ->
+ [{Index, {node, subagent}}];
+
+build_tree_for_subagent([Index | T]) ->
+ [{Index, {tree, build_tree_for_subagent(T), internal}}].
+
+%%----------------------------------------------------------------------
+%% Returns: A new tree where the subagent at Oid (2nd arg) has been deleted.
+%%----------------------------------------------------------------------
+delete_subagent({tree, Tree, Info}, [Index]) ->
+ {node, subagent} = element(Index+1, Tree),
+ {tree, setelement(Index+1, Tree, undefined_node), Info};
+delete_subagent({tree, Tree, Info}, [Index | TI]) ->
+ {tree, setelement(Index+1, Tree,
+ delete_subagent(element(Index+1, Tree), TI)), Info}.
+
+%%%======================================================================
+%%% 7. Misc functions
+%%%======================================================================
+
+%%----------------------------------------------------------------------
+%% Installs the mibs found in the database when starting the agent.
+%% Basically calls the instrumentation functions for all non-internal
+%% mib-entries
+%%----------------------------------------------------------------------
+install_mibs(MibDb, NodeDb) ->
+ MibNames = loaded(MibDb),
+ ?vtrace("install_mibs -> found following mibs in database: ~n"
+ "~p", [MibNames]),
+ install_mibs2(NodeDb, MibNames).
+
+install_mibs2(_, []) ->
+ ok;
+install_mibs2(NodeDb, [MibName|MibNames]) ->
+ Pattern = #node_info{oid = '_', mib_name = MibName, me = '_'},
+ Nodes = snmpa_general_db:match_object(NodeDb, Pattern),
+ MEs = [ME || #node_info{me = ME} <- Nodes],
+ ?vtrace("install_mibs2 -> installing ~p MEs for mib ~p",
+ [length(MEs),MibName]),
+ NewF = fun(ME) -> call_instrumentation(ME, new) end,
+ lists:foreach(NewF, MEs),
+ install_mibs2(NodeDb, MibNames).
+
+
+%%----------------------------------------------------------------------
+%% Does all side effect stuff during load_mib.
+%%----------------------------------------------------------------------
+install_mib(Db, Symbolic, Mib, MibName, FileName, NonInternalMes) ->
+ ?vdebug("install_mib -> entry with"
+ "~n Symbolic: ~p"
+ "~n MibName: ~p"
+ "~n FileName: ~p", [Symbolic, MibName, FileName]),
+ Rec = #mib_info{name = MibName, symbolic = Symbolic, file_name = FileName},
+ snmpa_general_db:write(Db, Rec),
+ install_mib2(Symbolic, MibName, Mib),
+ NewF = fun(ME) -> call_instrumentation(ME, new) end,
+ lists:foreach(NewF, NonInternalMes).
+
+install_mib2(true, MibName, Mib) ->
+ #mib{table_infos = TabInfos,
+ variable_infos = VarInfos,
+ mes = MEs,
+ asn1_types = ASN1Types,
+ traps = Traps} = Mib,
+ snmpa_symbolic_store:add_table_infos(MibName, TabInfos),
+ snmpa_symbolic_store:add_variable_infos(MibName, VarInfos),
+ snmpa_symbolic_store:add_aliasnames(MibName, MEs),
+ snmpa_symbolic_store:add_types(MibName, ASN1Types),
+ SetF = fun(Trap) ->
+ snmpa_symbolic_store:set_notification(Trap, MibName)
+ end,
+ lists:foreach(SetF, Traps);
+install_mib2(_, _, _) ->
+ ok.
+
+install_mes(_Db, _MibName, []) ->
+ ok;
+install_mes(Db, MibName, [ME|MEs]) ->
+ Node = #node_info{oid = ME#me.oid, mib_name = MibName, me = ME},
+ snmpa_general_db:write(Db, Node),
+ install_mes(Db, MibName, MEs).
+
+
+%%----------------------------------------------------------------------
+%% Does all side effect stuff during unload_mib.
+%%----------------------------------------------------------------------
+uninstall_mib(Db, Symbolic, MibName, MEs) ->
+ ?vtrace("uninstall_mib -> entry with"
+ "~n Db: ~p"
+ "~n Symbolic: ~p"
+ "~n MibName: ~p", [Db, Symbolic, MibName]),
+ Res = snmpa_general_db:delete(Db, MibName),
+ ?vtrace("uninstall_mib -> (mib) db delete result: ~p", [Res]),
+ uninstall_mib2(Symbolic, MibName),
+ DelF = fun(ME) -> call_instrumentation(ME, delete) end,
+ lists:foreach(DelF, MEs).
+
+uninstall_mib2(true, MibName) ->
+ snmpa_symbolic_store:delete_table_infos(MibName),
+ snmpa_symbolic_store:delete_variable_infos(MibName),
+ snmpa_symbolic_store:delete_aliasnames(MibName),
+ snmpa_symbolic_store:delete_types(MibName),
+ snmpa_symbolic_store:delete_notifications(MibName);
+uninstall_mib2(_, _) ->
+ ok.
+
+uninstall_mes(Db, MibName) ->
+ Pattern = #node_info{oid = '_', mib_name = MibName, me = '_'},
+ snmpa_general_db:match_delete(Db, Pattern).
+
+
+%%----------------------------------------------------------------------
+%% Create a list of the names of all the loaded mibs
+%%----------------------------------------------------------------------
+loaded(Db) ->
+ [N || #mib_info{name = N} <- snmpa_general_db:tab2list(Db)].
+
+
+%%----------------------------------------------------------------------
+%% Calls MFA-instrumentation with 'new' or 'delete' operation.
+%%----------------------------------------------------------------------
+call_instrumentation(#me{entrytype = variable, mfa={M,F,A}}, Operation) ->
+ ?vtrace("call instrumentation with"
+ "~n entrytype: variable"
+ "~n MFA: {~p,~p,~p}"
+ "~n Operation: ~p",
+ [M,F,A,Operation]),
+ catch apply(M, F, [Operation | A]);
+call_instrumentation(#me{entrytype = table_entry, mfa={M,F,A}}, Operation) ->
+ ?vtrace("call instrumentation with"
+ "~n entrytype: table_entry"
+ "~n MFA: {~p,~p,~p}"
+ "~n Operation: ~p",
+ [M,F,A,Operation]),
+ catch apply(M, F, [Operation | A]);
+call_instrumentation(_ShitME, _Operation) ->
+ done.
+
+
+maybe_drop_me(#me{entrytype = internal}) -> false;
+maybe_drop_me(#me{entrytype = group}) -> false;
+maybe_drop_me(#me{imported = true}) -> false;
+maybe_drop_me(_) -> true.
+
+
+%%----------------------------------------------------------------------
+%% Code change functions
+%%----------------------------------------------------------------------
+
+code_change(down, State) ->
+ ?d("code_change(down) -> entry",[]),
+ State;
+
+code_change(up, State) ->
+ ?d("code_change(up)",[]),
+ State;
+
+code_change(_Vsn, State) ->
+ State.
+
diff --git a/lib/snmp/src/agent/snmpa_mib_data_tttn.erl b/lib/snmp/src/agent/snmpa_mib_data_tttn.erl
new file mode 100644
index 0000000000..9b4493a03f
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_mib_data_tttn.erl
@@ -0,0 +1,1444 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1996-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%
+%%
+
+-module(snmpa_mib_data_tttn).
+
+
+%%%-----------------------------------------------------------------
+%%%
+%%% TTTN - TupleTreeTupleNodes
+%%%
+%%% This module implements the MIB (internal) data structures.
+%%% The TTTN MIB Data structure consists of three items:
+%%%
+%%% 1) A mib-storage (as specified when new is called) for
+%%% the data associated with each variable, table,
+%%% table-entry and table-column in the MIB.
+%%% 2) A tree contains information of the Oids in the MIB.
+%%% 3) A list of registered subagents.
+%%%
+%%% The subagent information is consequently duplicated. It resides
+%%% both in the tree and in the list.
+%%%
+%%% When a mib is loaded, the tree is built from the plain list
+%%% in the binary file.
+%%%
+%%%-----------------------------------------------------------------
+
+-include_lib("snmp/include/snmp_types.hrl").
+-include_lib("snmp/src/misc/snmp_debug.hrl").
+
+-define(VMODULE,"MDATA_TTTN").
+-include_lib("snmp/src/misc/snmp_verbosity.hrl").
+
+-behaviour(snmpa_mib_data).
+
+-define(MIB_DATA, snmpa_mib_data).
+-define(MIB_NODE, snmpa_mib_node).
+-define(MIB_TREE, snmpa_mib_tree).
+-define(DUMMY_TREE_GENERATION, 1).
+-define(DEFAULT_TREE, {tree,{undefined_node},internal}).
+
+
+%%%-----------------------------------------------------------------
+%%% Table of contents
+%%% =================
+%%% 1. Interface
+%%% 2. Implementation of tree access
+%%% 3. Tree building functions
+%%% 4. Tree merging
+%%% 5. Tree deletion routines
+%%% 6. Functions for subagent handling
+%%% 7. Misc functions
+%%%-----------------------------------------------------------------
+
+-record(mib_data,
+ {
+ %% Mib storage module
+ module :: snmpa:mib_storage_module(),
+
+ %% A database of loaded mibs
+ %% #mib_info{}
+ mib_db,
+
+ %% A database with information about each node in the tree
+ %% #node_info{}
+ node_db,
+
+ %% A database containing _one_ record with the tree
+ %% without the subagent(s).
+ %% (the reason for this is part to get replication
+ %% and part out of convenience)
+ %% #tree{}
+ tree_db,
+
+ %% The root node (same as the tree part of the tree_db
+ %% but with the subagents added).
+ tree,
+
+ %% A list of {SAPid, Oid}
+ subagents = []
+ }).
+
+-record(mib_info, {name, symbolic, file_name}).
+-record(node_info, {oid, mib_name, me}).
+
+
+%% (behaviour) API
+-export([new/1,
+ close/1,
+ sync/1,
+ load_mib/4,
+ unload_mib/4,
+ lookup/2,
+ next/3,
+ register_subagent/3,
+ unregister_subagent/2,
+ dump/2,
+ which_mib/2, which_mibs/1,
+ whereis_mib/2,
+ info/1, info/2,
+ backup/2,
+ code_change/4]).
+
+
+%%-----------------------------------------------------------------
+%% A tree is represented as a N-tuple, where each element is a
+%% node. A node is:
+%% 1) {tree, Tree, Info} where Info can be {table, Id}, {table_entry, Id}
+%% or perhaps 'internal'
+%% 2) undefined_node (memory optimization (instead of {node, undefined}))
+%% 3) {node, Info} where Info can be {subagent, Pid}, {variable, Id},
+%% {table_column, Id}
+%% Id is {MibName, MibEntry}
+%% The over all root is represented as {tree, Tree, internal}.
+%%
+%% tree() = {tree, nodes(), tree_info()}
+%% nodes() = {tree() | node() | undefined_node, ...}
+%% node() = {node, node_info()}
+%% tree_info() = {table, Id} | {table_entry, Id} | internal
+%% node_info() = {subagent, Pid} | {variable, Id} | {table_colum, Id}
+%%-----------------------------------------------------------------
+
+%% This record is what is stored in the database. The 'tree' part
+%% is described above...
+-record(tree, {generation = ?DUMMY_TREE_GENERATION, root = ?DEFAULT_TREE}).
+
+
+%%%======================================================================
+%%% 1. Interface
+%%%======================================================================
+
+%%-----------------------------------------------------------------
+%% Func: new/1
+%% Returns: A representation of mib data.
+%%-----------------------------------------------------------------
+
+%% Where -> A list of nodes where the tables will be created
+new(MibStorage) ->
+ Mod = snmp_misc:get_option(module, MibStorage),
+ Opts = snmp_misc:get_option(options, MibStorage, []),
+
+ %% First we must check if there is already something to read
+ %% If a database already exists, then the tree structure has to be read
+ ?vdebug("open (mib) database",[]),
+ MibDb =
+ case Mod:open(?MIB_DATA, mib_info, record_info(fields, mib_info),
+ set, Opts) of
+ {ok, T1} ->
+ T1;
+ {error, Reason1} ->
+ throw({error, {open, mib_data, Reason1}})
+ end,
+
+ ?vdebug("open (mib) node database",[]),
+ NodeDb =
+ case Mod:open(?MIB_NODE, node_info, record_info(fields, node_info),
+ set, Opts) of
+ {ok, T2} ->
+ T2;
+ {error, Reason2} ->
+ throw({error, {open, mib_node, Reason2}})
+ end,
+
+ ?vdebug("open (mib) tree database",[]),
+ TreeDb =
+ case Mod:open(?MIB_TREE, tree, record_info(fields, tree),
+ set, Opts) of
+ {ok, T3} ->
+ T3;
+ {error, Reason3} ->
+ throw({error, {open, mib_tree, Reason3}})
+ end,
+
+ ?vdebug("write the default (mib) tree",[]),
+ Tree =
+ case Mod:read(TreeDb, ?DUMMY_TREE_GENERATION) of
+ false ->
+ T = #tree{},
+ Mod:write(TreeDb, T),
+ T;
+ {value, T} ->
+ T
+ end,
+ ?vdebug("install (existing) mibs",[]),
+ install_mibs(Mod, MibDb, NodeDb),
+ ?vdebug("done",[]),
+ #mib_data{module = Mod,
+ mib_db = MibDb,
+ node_db = NodeDb,
+ tree_db = TreeDb,
+ tree = Tree}.
+
+
+%%----------------------------------------------------------------------
+%% Returns: new mib data | {error, Reason}
+%%----------------------------------------------------------------------
+load_mib(MibData, FileName, MeOverride, TeOverride)
+ when is_record(MibData,mib_data) andalso is_list(FileName) ->
+ ?vlog("load mib file: ~p",[FileName]),
+ ActualFileName = filename:rootname(FileName, ".bin") ++ ".bin",
+ MibName = list_to_atom(filename:basename(FileName, ".bin")),
+ (catch do_load_mib(MibData, ActualFileName, MibName,
+ MeOverride, TeOverride)).
+
+do_load_mib(MibData, ActualFileName, MibName, MeOverride, TeOverride) ->
+ ?vtrace("do_load_mib -> entry with"
+ "~n ActualFileName: ~s"
+ "~n MibName: ~p",[ActualFileName, MibName]),
+ #mib_data{module = Mod,
+ mib_db = MibDb,
+ node_db = NodeDb,
+ %% tree_db = TreeDb,
+ tree = Tree} = MibData,
+ verify_not_loaded(Mod, MibDb, MibName),
+ ?vtrace("do_load_mib -> already loaded mibs:"
+ "~n ~p", [loaded(Mod, MibDb)]),
+ Mib = do_read_mib(ActualFileName),
+ ?vtrace("do_load_mib -> read mib ~s",[Mib#mib.name]),
+ NonInternalMes =
+ lists:filter(fun(ME) -> maybe_drop_me(ME) end, Mib#mib.mes),
+ OldRoot = Tree#tree.root,
+ T = build_tree(NonInternalMes, MibName),
+ ?d("load_mib -> "
+ "~n OldRoot: ~p"
+ "~n T: ~p", [OldRoot, T]),
+ case (catch merge_nodes(T, OldRoot)) of
+ {error_merge_nodes, Node1, Node2} ->
+ ?vlog("error merging nodes:"
+ "~n~p~nand~n~p", [Node1,Node2]),
+ {error, oid_conflict};
+ NewRoot when is_tuple(NewRoot) andalso (element(1,NewRoot) =:= tree) ->
+ ?d("load_mib -> "
+ "~n NewRoot: ~p", [NewRoot]),
+ Symbolic = not lists:member(no_symbolic_info, Mib#mib.misc),
+ case (catch check_notif_and_mes(TeOverride, MeOverride, Symbolic,
+ Mib#mib.traps, NonInternalMes)) of
+ true ->
+ install_mes(Mod, NodeDb, MibName, NonInternalMes),
+ install_mib(Mod,
+ MibDb, Symbolic, Mib,
+ MibName, ActualFileName, NonInternalMes),
+ ?vtrace("installed mib ~s", [Mib#mib.name]),
+ Tree2 = Tree#tree{root = NewRoot},
+ {ok, MibData#mib_data{tree = Tree2}};
+ Else ->
+ Else
+ end
+ end.
+
+
+verify_not_loaded(Mod, Tab, Name) ->
+ case Mod:read(Tab, Name) of
+ {value, #mib_info{name = Name}} ->
+ throw({error, already_loaded});
+ false ->
+ ok
+ end.
+
+do_read_mib(ActualFileName) ->
+ case snmp_misc:read_mib(ActualFileName) of
+ {error, Reason} ->
+ ?vlog("Failed reading mib file ~p with reason: ~p",
+ [ActualFileName, Reason]),
+ throw({error, Reason});
+ {ok, Mib} ->
+ Mib
+ end.
+
+%% The Tree DB is handled in a special way since it can be very large.
+sync(#mib_data{module = Mod,
+ mib_db = M,
+ node_db = N,
+ tree_db = T, tree = Tree, subagents = []}) ->
+ Mod:sync(M),
+ Mod:sync(N),
+ Mod:write(T, Tree),
+ Mod:sync(T);
+sync(#mib_data{module = Mod,
+ mib_db = M,
+ node_db = N,
+ tree_db = T, tree = Tree, subagents = SAs}) ->
+
+ Mod:sync(M),
+ Mod:sync(N),
+
+ %% Ouch. Since the subagent info is dynamic we do not
+ %% want to store the tree containing subagent info. So, we
+ %% have to create a tmp tree without those and store it.
+
+ case delete_subagents(Tree, SAs) of
+ {ok, TreeWithoutSAs} ->
+ Mod:write(T, TreeWithoutSAs),
+ Mod:sync(T);
+ Error ->
+ Error
+ end.
+
+delete_subagents(Tree, []) ->
+ {ok, Tree};
+delete_subagents(Tree0, [{_, Oid}|SAs]) ->
+ case (catch delete_subagent(Tree0, Oid)) of
+ {tree, _Tree, _Info} = Tree1 ->
+ delete_subagents(Tree1, SAs);
+ _Error ->
+ {error, {'invalid oid', Oid}}
+ end.
+
+%%----------------------------------------------------------------------
+%% (OTP-3601)
+%%----------------------------------------------------------------------
+check_notif_and_mes(TeOverride,MeOverride,Symbolic,Traps,MEs) ->
+ ?vtrace("check notifications and mib entries",[]),
+ check_notifications(TeOverride,Symbolic,Traps),
+ check_mes(MeOverride,MEs).
+
+check_notifications(true, _Symbolic, _Traps) ->
+ ?vtrace("trapentry override = true => skip check",[]),
+ true;
+check_notifications(_, Symbolic, Traps) ->
+ check_notifications(Symbolic, Traps).
+
+check_notifications(true, Traps) ->
+ check_notifications(Traps);
+check_notifications(_, _) -> true.
+
+check_notifications([]) -> true;
+check_notifications([#trap{trapname = Key} = Trap | Traps]) ->
+ ?vtrace("check notification [trap] with Key: ~p",[Key]),
+ case snmpa_symbolic_store:get_notification(Key) of
+ {value, Trap} -> check_notifications(Traps);
+ {value, _} -> throw({error, {'trap already defined', Key}});
+ undefined -> check_notifications(Traps)
+ end;
+check_notifications([#notification{trapname = Key} = Notif | Traps]) ->
+ ?vtrace("check notification [notification] with Key: ~p",[Key]),
+ case snmpa_symbolic_store:get_notification(Key) of
+ {value, Notif} ->
+ check_notifications(Traps);
+ {value, _} ->
+ throw({error, {'notification already defined', Key}});
+ undefined ->
+ check_notifications(Traps)
+ end;
+check_notifications([Crap | Traps]) ->
+ ?vlog("skipped check of: ~n~p",[Crap]),
+ check_notifications(Traps).
+
+check_mes(true,_) ->
+ ?vtrace("mibentry override = true => skip check",[]),
+ true;
+check_mes(_,MEs) ->
+ check_mes(MEs).
+
+check_mes([]) -> true;
+check_mes([#me{aliasname = Name, oid = Oid1} | MEs]) ->
+ ?vtrace("check mib entries with aliasname: ~p",[Name]),
+ case snmpa_symbolic_store:aliasname_to_oid(Name) of
+ {value, Oid1} ->
+ check_mes(MEs);
+ {value, Oid2} ->
+ ?vinfo("~n expecting '~p'~n but found '~p'",[Oid1, Oid2]),
+ throw({error, {'mibentry already defined', Name}});
+ false ->
+ check_mes(MEs)
+ end;
+check_mes([Crap | MEs]) ->
+ ?vlog("skipped check of: ~n~p",[Crap]),
+ check_mes(MEs).
+
+
+
+%%----------------------------------------------------------------------
+%% Returns: new mib data | {error, Reason}
+%%----------------------------------------------------------------------
+unload_mib(MibData, FileName, _, _) when is_list(FileName) ->
+ MibName = list_to_atom(filename:basename(FileName, ".bin")),
+ (catch do_unload_mib(MibData, MibName)).
+
+do_unload_mib(MibData, MibName) ->
+ ?vtrace("do_unload_mib -> entry with"
+ "~n MibName: ~p", [MibName]),
+ #mib_data{module = Mod,
+ mib_db = MibDb,
+ node_db = NodeDb,
+ %% tree_db = TreeDb,
+ tree = Tree} = MibData,
+ #mib_info{symbolic = Symbolic} = verify_loaded(Mod, MibDb, MibName),
+ NewRoot = delete_mib_from_tree(MibName, Tree#tree.root),
+ MEs = uninstall_mes(Mod, NodeDb, MibName),
+ uninstall_mib(Mod, MibDb, Symbolic, MibName, MEs),
+ NewMibData = MibData#mib_data{tree = Tree#tree{root = NewRoot}},
+ {ok, NewMibData}.
+
+verify_loaded(Mod, Tab, Name) ->
+ case Mod:read(Tab, Name) of
+ {value, MibInfo} ->
+ MibInfo;
+ false ->
+ throw({error, not_loaded})
+ end.
+
+
+close(#mib_data{module = Mod,
+ mib_db = MibDb,
+ node_db = NodeDb,
+ tree_db = TreeDb}) ->
+ Mod:close(MibDb),
+ Mod:close(NodeDb),
+ Mod:close(TreeDb),
+ ok.
+
+register_subagent(#mib_data{tree = T} = MibData, Oid, Pid) ->
+ case insert_subagent(Oid, T#tree.root) of
+ {error, Reason} ->
+ {error, Reason};
+ NewRootTree ->
+ SAs = [{Pid, Oid} | MibData#mib_data.subagents],
+ T2 = T#tree{root = NewRootTree},
+ {ok, MibData#mib_data{tree = T2, subagents = SAs}}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Purpose: Get a list of all loaded mibs
+%% Returns: [{Name, File}]
+%%----------------------------------------------------------------------
+
+which_mibs(#mib_data{module = Mod, mib_db = Db}) ->
+ Mibs = Mod:tab2list(Db),
+ [{Name, File} || #mib_info{name = Name, file_name = File} <- Mibs].
+
+
+%%----------------------------------------------------------------------
+%% Purpose: Get a list of all loaded mibs
+%% Returns: [{Name, File}]
+%%----------------------------------------------------------------------
+
+whereis_mib(#mib_data{module = Mod, mib_db = Db}, Name) ->
+ case Mod:read(Db, Name) of
+ {value, #mib_info{file_name = File}} ->
+ {ok, File};
+ false ->
+ {error, not_found}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Purpose: Deletes SA with Pid from all subtrees it handles.
+%% Returns: NewMibData.
+%%----------------------------------------------------------------------
+unregister_subagent(#mib_data{subagents = SAs} = MibData, Pid)
+ when is_pid(Pid) ->
+ SAs = MibData#mib_data.subagents,
+ case lists:keysearch(Pid, 1, SAs) of
+ false ->
+ {ok, MibData};
+ {value, {Pid, Oid}} ->
+ % we should never get an error since Oid is found in MibData.
+ {ok, NewMibData, _DeletedSA} = unregister_subagent(MibData, Oid),
+ % continue if the same Pid handles other mib subtrees.
+ unregister_subagent(NewMibData, Pid)
+ end;
+
+%%----------------------------------------------------------------------
+%% Purpose: Deletes one unique subagent.
+%% Returns: {error, Reason} | {ok, NewMibData, DeletedSubagentPid}
+%%----------------------------------------------------------------------
+unregister_subagent(#mib_data{tree = T} = MibData, Oid) when is_list(Oid) ->
+ case (catch delete_subagent(T#tree.root, Oid)) of
+ {tree, Tree, Info} ->
+ OldSAs = MibData#mib_data.subagents,
+ {value, {Pid, _Oid}} = lists:keysearch(Oid, 2, OldSAs),
+ SAs = lists:keydelete(Oid, 2, OldSAs),
+ T2 = T#tree{root = {tree, Tree, Info}},
+ {ok,
+ MibData#mib_data{tree = T2, subagents = SAs},
+ Pid};
+ _ ->
+ {error, {invalid_oid, Oid}}
+ end.
+
+%%----------------------------------------------------------------------
+%% Purpose: To inpect memory usage, loaded mibs, registered subagents
+%%----------------------------------------------------------------------
+info(MibData) ->
+ ?vtrace("retrieve info",[]),
+ #mib_data{module = Mod,
+ mib_db = MibDb,
+ node_db = NodeDb,
+ tree_db = TreeDb,
+ tree = Tree,
+ subagents = SAs} = MibData,
+ LoadedMibs = old_format(Mod:tab2list(MibDb)),
+ TreeSize = snmp_misc:mem_size(Tree),
+ {memory, ProcSize} = erlang:process_info(self(), memory),
+ MibDbSize = Mod:info(MibDb, memory),
+ NodeDbSize = Mod:info(NodeDb, memory),
+ TreeDbSize = Mod:info(TreeDb, memory),
+ [{loaded_mibs, LoadedMibs}, {subagents, SAs}, {tree_size_bytes, TreeSize},
+ {process_memory, ProcSize},
+ {db_memory, [{mib,MibDbSize},{node,NodeDbSize},{tree,TreeDbSize}]}].
+
+info(#mib_data{module = Mod, mib_db = MibDb}, loaded_mibs) ->
+ Mibs = Mod:tab2list(MibDb),
+ [filename:rootname(FN, ".bin") || #mib_info{file_name = FN} <- Mibs];
+info(#mib_data{tree = Tree}, tree_size_bytes) ->
+ snmp_misc:mem_size(Tree);
+info(_, process_memory) ->
+ {memory, ProcSize} = erlang:process_info(self(),memory),
+ ProcSize;
+info(#mib_data{module = Mod,
+ mib_db = MibDb,
+ node_db = NodeDb,
+ tree_db = TreeDb},
+ db_memory) ->
+ MibDbSize = Mod:info(MibDb, memory),
+ NodeDbSize = Mod:info(NodeDb, memory),
+ TreeDbSize = Mod:info(TreeDb, memory),
+ [{mib, MibDbSize}, {node, NodeDbSize}, {tree, TreeDbSize}];
+info(#mib_data{subagents = SAs}, subagents) ->
+ SAs.
+
+old_format(LoadedMibs) ->
+ ?vtrace("convert mib info to old format",[]),
+ [{N,S,F} || #mib_info{name=N,symbolic=S,file_name=F} <- LoadedMibs].
+
+
+%%----------------------------------------------------------------------
+%% A total dump for debugging.
+%%----------------------------------------------------------------------
+
+dump(#mib_data{module = Mod,
+ mib_db = MibDb,
+ node_db = NodeDb,
+ tree = Tree}, io) ->
+ (catch io:format("MIB-tables:~n~p~n~n",
+ [Mod:tab2list(MibDb)])),
+ (catch io:format("MIB-entries:~n~p~n~n",
+ [Mod:tab2list(NodeDb)])),
+ (catch io:format("Tree:~n~p~n", [Tree])), % good luck reading it!
+ ok;
+
+dump(#mib_data{module = Mod,
+ mib_db = MibDb,
+ node_db = NodeDb,
+ tree = Tree}, File) ->
+ case file:open(File, [write]) of
+ {ok, Fd} ->
+ io:format(Fd,"~s~n",
+ [snmp:date_and_time_to_string(snmp:date_and_time())]),
+ (catch io:format(Fd,"MIB-tables:~n~p~n~n",
+ [Mod:tab2list(MibDb)])),
+ (catch io:format(Fd, "MIB-entries:~n~p~n~n",
+ [Mod:tab2list(NodeDb)])),
+ io:format(Fd,"Tree:~n~p~n", [Tree]), % good luck reading it!
+ file:close(Fd),
+ ok;
+ {error, Reason} ->
+ ?vinfo("~n Failed opening file '~s' for reason ~p",
+ [File, Reason]),
+ {error, Reason}
+ end.
+
+
+backup(#mib_data{module = Mod,
+ mib_db = M,
+ node_db = N,
+ tree_db = T}, BackupDir) ->
+ MRes = Mod:backup(M, BackupDir),
+ NRes = Mod:backup(N, BackupDir),
+ TRes = Mod:backup(T, BackupDir),
+ handle_backup_res([{mib_db, MRes}, {node_db, NRes}, {tree_db, TRes}]).
+
+handle_backup_res(Res) ->
+ handle_backup_res(Res, []).
+
+handle_backup_res([], []) ->
+ ok;
+handle_backup_res([], Err) ->
+ {error, lists:reverse(Err)};
+handle_backup_res([{_, ok}|Res], Err) ->
+ handle_backup_res(Res, Err);
+handle_backup_res([{Tag, {error, Reason}}|Res], Err) ->
+ handle_backup_res(Res, [{Tag, Reason}|Err]);
+handle_backup_res([{Tag, Error}|Res], Err) ->
+ handle_backup_res(Res, [{Tag, Error}|Err]).
+
+
+%%%======================================================================
+%%% 2. Implementation of tree access
+%%% lookup and next.
+%%%======================================================================
+
+
+which_mib(#mib_data{tree = T} = D, Oid) ->
+ ?vtrace("which_mib -> entry with"
+ "~n Oid: ~p",[Oid]),
+ case (catch find_node(D, T#tree.root, Oid, [])) of
+ {variable, _ME, Mib} ->
+ ?vtrace("which_mib -> variable:"
+ "~n Mib: ~p", [Mib]),
+ {ok, Mib};
+ {table, _EntryME, _, Mib} ->
+ ?vtrace("which_mib -> table:"
+ "~n Mib: ~p", [Mib]),
+ {ok, Mib};
+ {subagent, SubAgentPid, _SANextOid} ->
+ ?vtrace("which_mib -> subagent:"
+ "~n SubAgentPid: ~p", [SubAgentPid]),
+ {error, {subagent, SubAgentPid}};
+ {false, ErrorCode} ->
+ ?vtrace("which_mib -> false:"
+ "~n ErrorCode: ~p",[ErrorCode]),
+ {error, ErrorCode};
+ false ->
+ ?vtrace("which_mib -> false",[]),
+ {error, noSuchObject};
+ {'EXIT', R} ->
+ ?vtrace("which_mib -> exit:"
+ "~n R: ~p",[R]),
+ {error, noSuchObject}
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Func: lookup/2
+%% Purpose: Finds the mib entry corresponding to the Oid. If it is a
+%% variable, the Oid must be <Oid for var>.0 and if it is
+%% a table, Oid must be <table>.<entry>.<col>.<any>
+%% Returns: {variable, MibEntry} |
+%% {table_column, MibEntry, TableEntryOid} |
+%% {subagent, SubAgentPid, SAOid} |
+%% {false, Reason}
+%%-----------------------------------------------------------------
+lookup(#mib_data{tree = T} = D, Oid) ->
+ ?vtrace("lookup -> entry with"
+ "~n Oid: ~p",[Oid]),
+ case (catch find_node(D, T#tree.root, Oid, [])) of
+ {variable, ME, _Mib} when is_record(ME, me) ->
+ ?vtrace("lookup -> variable:"
+ "~n ME: ~p",[ME]),
+ {variable, ME};
+ {table, EntryME, {ColME, TableEntryOid}, _Mib} ->
+ ?vtrace("lookup -> table:"
+ "~n EntryME: ~p"
+ "~n ColME: ~p"
+ "~n RevTableEntryOid: ~p",
+ [EntryME, ColME, TableEntryOid]),
+ MFA = EntryME#me.mfa,
+ RetME = ColME#me{mfa = MFA},
+ {table_column, RetME, TableEntryOid};
+ {subagent, SubAgentPid, SANextOid} ->
+ ?vtrace("lookup -> subagent:"
+ "~n SubAgentPid: ~p"
+ "~n SANextOid: ~p", [SubAgentPid, SANextOid]),
+ {subagent, SubAgentPid, SANextOid};
+ {false, ErrorCode} ->
+ ?vtrace("lookup -> false:"
+ "~n ErrorCode: ~p",[ErrorCode]),
+ {false, ErrorCode};
+ false ->
+ ?vtrace("lookup -> false",[]),
+ {false, noSuchObject};
+ {'EXIT', R} ->
+ ?vtrace("lookup -> exit:"
+ "~n R: ~p",[R]),
+ {false, noSuchObject}
+ end.
+
+
+find_node(D, {tree, Tree, {table, _}}, RestOfOid, RevOid) ->
+ ?vtrace("find_node(tree,table) -> entry with"
+ "~n RestOfOid: ~p"
+ "~n RevOid: ~p",[RestOfOid, RevOid]),
+ find_node(D, {tree, Tree, internal}, RestOfOid, RevOid);
+find_node(D, {tree, Tree, {table_entry, _}}, RestOfOid, RevOid) ->
+ ?vtrace("find_node(tree,table_entry) -> entry with"
+ "~n RestOfOid: ~p"
+ "~n RevOid: ~p",[RestOfOid, RevOid]),
+ #mib_data{module = Mod, node_db = Db} = D,
+ Oid = lists:reverse(RevOid),
+ case Mod:read(Db, Oid) of
+ {value, #node_info{me = ME, mib_name = Mib}} ->
+ case find_node(D, {tree, Tree, internal}, RestOfOid, RevOid) of
+ {false, ErrorCode} -> {false, ErrorCode};
+ Val -> {table, ME, Val, Mib}
+ end;
+ false ->
+ ?vinfo("find_node -> could not find table_entry ME with"
+ "~n RevOid: ~p"
+ "~n when"
+ "~n RestOfOid: ~p",
+ [RevOid, RestOfOid]),
+ false
+ end;
+find_node(D, {tree, Tree, _Internal}, [Int | RestOfOid], RevOid) ->
+ ?vtrace("find_node(tree) -> entry with"
+ "~n Int: ~p"
+ "~n RestOfOid: ~p"
+ "~n RevOid: ~p",[Int, RestOfOid, RevOid]),
+ find_node(D, element(Int+1, Tree), RestOfOid, [Int | RevOid]);
+find_node(D, {node, {table_column, _}}, RestOfOid, [ColInt | RevOid]) ->
+ ?vtrace("find_node(tree,table_column) -> entry with"
+ "~n RestOfOid: ~p"
+ "~n ColInt: ~p"
+ "~n RevOid: ~p",[RestOfOid, ColInt, RevOid]),
+ #mib_data{module = Mod, node_db = Db} = D,
+ Oid = lists:reverse([ColInt | RevOid]),
+ case Mod:read(Db, Oid) of
+ {value, #node_info{me = ME}} ->
+ {ME, lists:reverse(RevOid)};
+ false ->
+ X = Mod:read(Db, lists:reverse([ColInt | RevOid])),
+ ?vinfo("find_node -> could not find table_column ME with"
+ "~n RevOid: ~p"
+ "~n trying [~p|~p]"
+ "~n X: ~p",
+ [RevOid, [ColInt | RevOid], X]),
+ false
+ end;
+find_node(D, {node, {variable, _MibName}}, [0], RevOid) ->
+ ?vtrace("find_node(tree,variable,[0]) -> entry with"
+ "~n RevOid: ~p",[RevOid]),
+ #mib_data{module = Mod, node_db = Db} = D,
+ Oid = lists:reverse(RevOid),
+ case Mod:read(Db, Oid) of
+ {value, #node_info{me = ME, mib_name = Mib}} ->
+ {variable, ME, Mib};
+ false ->
+ ?vinfo("find_node -> could not find variable ME with"
+ "~n RevOid: ~p", [RevOid]),
+ false
+ end;
+find_node(_D, {node, {variable, _MibName}}, [], _RevOid) ->
+ ?vtrace("find_node(tree,variable,[]) -> entry",[]),
+ {false, noSuchObject};
+find_node(_D, {node, {variable, _MibName}}, _, _RevOid) ->
+ ?vtrace("find_node(tree,variable) -> entry",[]),
+ {false, noSuchInstance};
+find_node(D, {node, subagent}, _RestOfOid, SARevOid) ->
+ ?vtrace("find_node(tree,subagent) -> entry with"
+ "~n SARevOid: ~p",[SARevOid]),
+ #mib_data{subagents = SAs} = D,
+ SAOid = lists:reverse(SARevOid),
+ case lists:keysearch(SAOid, 2, SAs) of
+ {value, {SubAgentPid, SAOid}} ->
+ {subagent, SubAgentPid, SAOid};
+ false ->
+ ?vinfo("find_node -> could not find subagent with"
+ "~n SAOid: ~p"
+ "~n SAs: ~p", [SAOid, SAs]),
+ false
+ end;
+find_node(_D, Node, _RestOfOid, _RevOid) ->
+ ?vtrace("find_node -> failed:~n~p",[Node]),
+ {false, noSuchObject}.
+
+
+%%-----------------------------------------------------------------
+%% Func: next/3
+%% Purpose: Finds the lexicographically next oid.
+%% Returns: endOfMibView |
+%% {subagent, SubAgentPid, SAOid} |
+%% {variable, MibEntry, VarOid} |
+%% {table, TableOid, TableRestOid, MibEntry}
+%% If a variable is returnes, it is in the MibView.
+%% If a table or subagent is returned, it *may* be in the MibView.
+%%-----------------------------------------------------------------
+next(#mib_data{tree = T} = D, Oid, MibView) ->
+ case catch next_node(D, T#tree.root, Oid, [], MibView) of
+ false -> endOfMibView;
+ Else -> Else
+ end.
+
+%%-----------------------------------------------------------------
+%% This function is used as long as we have any Oid left. Take
+%% one integer at a time from the Oid, and traverse the tree
+%% accordingly. When the Oid is empty, call find_next.
+%% Returns: {subagent, SubAgentPid, SAOid} |
+%% false |
+%% {variable, MibEntry, VarOid} |
+%% {table, TableOid, TableRestOid, MibEntry}
+%%-----------------------------------------------------------------
+next_node(_D, undefined_node, _Oid, _RevOidSoFar, _MibView) ->
+ ?vtrace("next_node(undefined_node) -> entry", []),
+ false;
+
+next_node(_D, {tree, Tree, {table_entry, _Id}}, [Int | _Oid],
+ _RevOidSoFar, _MibView)
+ when Int+1 > size(Tree) ->
+ ?vtrace("next_node(tree,table_entry) -> entry when not found whith"
+ "~n Int: ~p"
+ "~n size(Tree): ~p", [Int, size(Tree)]),
+ false;
+next_node(D, {tree, Tree, {table_entry, _MibName}},
+ Oid, RevOidSoFar, MibView) ->
+ ?vtrace("next_node(tree,table_entry) -> entry when"
+ "~n size(Tree): ~p"
+ "~n Oid: ~p"
+ "~n RevOidSoFar: ~p"
+ "~n MibView: ~p", [size(Tree), Oid, RevOidSoFar, MibView]),
+ OidSoFar = lists:reverse(RevOidSoFar),
+ case snmpa_acm:is_definitely_not_in_mib_view(OidSoFar, MibView) of
+ true ->
+ ?vdebug("next_node(tree,table_entry) -> not in mib view",[]),
+ false;
+ _ ->
+ #mib_data{module = Mod, node_db = Db} = D,
+ case Mod:read(Db, OidSoFar) of
+ false ->
+ ?vinfo("next_node -> could not find table_entry with"
+ "~n OidSoFar: ~p", [OidSoFar]),
+ false;
+ {value, #node_info{me = ME}} ->
+ ?vtrace("next_node(tree,table_entry) -> found: ~n ~p",
+ [ME]),
+ {table, OidSoFar, Oid, ME}
+ end
+ end;
+
+next_node(D, {tree, Tree, _Info}, [Int | RestOfOid], RevOidSoFar, MibView)
+ when (Int < size(Tree)) andalso (Int >= 0) ->
+ ?vtrace("next_node(tree) -> entry when"
+ "~n size(Tree): ~p"
+ "~n Int: ~p"
+ "~n RestOfOid: ~p"
+ "~n RevOidSoFar: ~p"
+ "~n MibView: ~p",
+ [size(Tree), Int, RestOfOid, RevOidSoFar, MibView]),
+ case next_node(D, element(Int+1,Tree),
+ RestOfOid, [Int|RevOidSoFar], MibView) of
+ false ->
+ find_next(D, {tree, Tree, _Info}, Int+1, RevOidSoFar, MibView);
+ Else ->
+ Else
+ end;
+%% no solution
+next_node(D, {tree, Tree, _Info}, [], RevOidSoFar, MibView) ->
+ ?vtrace("next_node(tree,[]) -> entry when"
+ "~n size(Tree): ~p"
+ "~n RevOidSoFar: ~p"
+ "~n MibView: ~p",
+ [size(Tree), RevOidSoFar, MibView]),
+ find_next(D, {tree, Tree, _Info}, 0, RevOidSoFar, MibView);
+next_node(_D, {tree, Tree, _Info}, _RestOfOid, _RevOidSoFar, _MibView) ->
+ ?vtrace("next_node(tree) -> entry when"
+ "~n size(Tree): ~p", [size(Tree)]),
+ false;
+
+next_node(D, {node, subagent}, Oid, RevOidSoFar, MibView) ->
+ ?vtrace("next_node(node,subagent) -> entry when"
+ "~n Oid: ~p"
+ "~n RevOidSoFar: ~p"
+ "~n MibView: ~p",
+ [Oid, RevOidSoFar, MibView]),
+ OidSoFar = lists:reverse(RevOidSoFar),
+ case snmpa_acm:is_definitely_not_in_mib_view(OidSoFar, MibView) of
+ true ->
+ false;
+ _ ->
+ #mib_data{subagents = SAs} = D,
+ case lists:keysearch(OidSoFar, 2, SAs) of
+ {value, {SubAgentPid, OidSoFar}} ->
+ {subagent, SubAgentPid, OidSoFar};
+ _ ->
+ ?vinfo("next_node -> could not find subagent with"
+ "~n OidSoFar: ~p"
+ "~n SAs: ~p", [OidSoFar, SAs]),
+ false
+ end
+ end;
+
+next_node(D, {node, {variable, _MibName}}, [], RevOidSoFar, MibView) ->
+ ?vtrace("next_node(node,variable,[]) -> entry when"
+ "~n RevOidSoFar: ~p"
+ "~n MibView: ~p",
+ [RevOidSoFar, MibView]),
+ OidSoFar = lists:reverse([0 | RevOidSoFar]),
+ case snmpa_acm:validate_mib_view(OidSoFar, MibView) of
+ true ->
+ #mib_data{module = Mod, node_db = Db} = D,
+ case Mod:read(Db, lists:reverse(RevOidSoFar)) of
+ false ->
+ ?vinfo("next_node -> could not find variable with"
+ "~n RevOidSoFar: ~p", [RevOidSoFar]),
+ false;
+ {value, #node_info{me = ME}} ->
+ {variable, ME, OidSoFar}
+ end;
+ _ ->
+ false
+ end;
+
+next_node(_D, {node, {variable, _MibName}}, _Oid, _RevOidSoFar, _MibView) ->
+ ?vtrace("next_node(node,variable) -> entry", []),
+ false.
+
+
+%%-----------------------------------------------------------------
+%% This function is used to find the first leaf from where we
+%% are.
+%% Returns: {subagent, SubAgentPid, SAOid} |
+%% false |
+%% {variable, MibEntry, VarOid} |
+%% {table, TableOid, TableRestOid, MibEntry}
+%% PRE: This function must always be called with a {internal, Tree}
+%% node.
+%%-----------------------------------------------------------------
+find_next(D, {tree, Tree, internal}, Idx, RevOidSoFar, MibView)
+ when Idx < size(Tree) ->
+ case find_next(D, element(Idx+1, Tree), 0, [Idx| RevOidSoFar], MibView) of
+ false ->
+ find_next(D, {tree, Tree, internal}, Idx+1, RevOidSoFar, MibView);
+ Other ->
+ Other
+ end;
+find_next(_D, {tree, _Tree, internal}, _Idx, _RevOidSoFar, _MibView) ->
+ false;
+find_next(_D, undefined_node, _Idx, _RevOidSoFar, _MibView) ->
+ false;
+find_next(D, {tree, Tree, {table, _MibName}}, Idx, RevOidSoFar, MibView) ->
+ find_next(D, {tree, Tree, internal}, Idx, RevOidSoFar, MibView);
+find_next(D, {tree, _Tree, {table_entry, _MibName}}, _Index,
+ RevOidSoFar, MibView) ->
+ OidSoFar = lists:reverse(RevOidSoFar),
+ case snmpa_acm:is_definitely_not_in_mib_view(OidSoFar, MibView) of
+ true ->
+ false;
+ _ ->
+ #mib_data{module = Mod, node_db = Db} = D,
+ case Mod:read(Db, OidSoFar) of
+ false ->
+ ?vinfo("find_next -> could not find table_entry ME with"
+ "~n OidSoFar: ~p", [OidSoFar]),
+ false;
+ {value, #node_info{me = ME}} ->
+ {table, OidSoFar, [], ME}
+ end
+ end;
+find_next(D, {node, {variable, _MibName}}, _Idx, RevOidSoFar, MibView) ->
+ OidSoFar = lists:reverse([0 | RevOidSoFar]),
+ case snmpa_acm:validate_mib_view(OidSoFar, MibView) of
+ true ->
+ #mib_data{module = Mod, node_db = Db} = D,
+ case Mod:read(Db, lists:reverse(RevOidSoFar)) of
+ false ->
+ ?vinfo("find_next -> could not find variable with"
+ "~n RevOidSoFar: ~p", [RevOidSoFar]),
+ false;
+ {value, #node_info{me = ME}} ->
+ {variable, ME, OidSoFar}
+ end;
+ _ ->
+ false
+ end;
+find_next(D, {node, subagent}, _Idx, RevOidSoFar, MibView) ->
+ OidSoFar = lists:reverse(RevOidSoFar),
+ case snmpa_acm:is_definitely_not_in_mib_view(OidSoFar, MibView) of
+ true ->
+ false;
+ _ ->
+ #mib_data{subagents = SAs} = D,
+ case lists:keysearch(OidSoFar, 2, SAs) of
+ {value, {SubAgentPid, OidSoFar}} ->
+ {subagent, SubAgentPid, OidSoFar};
+ false ->
+ ?vinfo("find_node -> could not find subagent with"
+ "~n OidSoFar: ~p"
+ "~n SAs: ~p", [OidSoFar, SAs]),
+ false
+ end
+ end.
+
+%%%======================================================================
+%%% 3. Tree building functions
+%%% Used when loading mibs.
+%%%======================================================================
+
+build_tree(Mes, MibName) ->
+ ?d("build_tree -> "
+ "~n Mes: ~p", [Mes]),
+ {ListTree, []} = build_subtree([], Mes, MibName),
+ {tree, convert_tree(ListTree), internal}.
+
+%%----------------------------------------------------------------------
+%% Purpose: Builds the tree where all oids have prefix equal to LevelPrefix.
+%% Returns: {Tree, RestMes}
+%% RestMes are Mes that should not be in this subtree.
+%% The Tree is a temporary and simplified data structure that is easy to
+%% convert to the final tuple tree used by the MIB process.
+%% A Node is represented as in the final tree.
+%% The tree is not represented as a N-tuple, but as an Index-list.
+%% Example: Temporary: [{1, Node1}, {3, Node3}]
+%% Final: {Node1, undefined_node, Node3}
+%% Pre: Mes are sorted on oid.
+%%----------------------------------------------------------------------
+build_subtree(LevelPrefix, [Me | Mes], MibName) ->
+ ?vtrace("build subtree -> ~n"
+ " oid: ~p~n"
+ " LevelPrefix: ~p~n"
+ " MibName: ~p", [Me#me.oid, LevelPrefix, MibName]),
+ EType = Me#me.entrytype,
+ ?vtrace("build subtree -> EType = ~p",[EType]),
+ case in_subtree(LevelPrefix, Me) of
+ above ->
+ ?vtrace("build subtree -> above",[]),
+ {[], [Me|Mes]};
+ {node, Index} ->
+ ?vtrace("build subtree -> node at ~p",[Index]),
+ {Tree, RestMes} = build_subtree(LevelPrefix, Mes, MibName),
+ {[{Index, {node, {EType, MibName}}} | Tree], RestMes};
+ {subtree, Index, NewLevelPrefix} ->
+ ?vtrace("build subtree -> subtree at"
+ "~n ~w with ~w",
+ [Index, NewLevelPrefix]),
+ {BelowTree, RestMes} =
+ build_subtree(NewLevelPrefix, Mes, MibName),
+ {CurTree, RestMes2} =
+ build_subtree(LevelPrefix, RestMes, MibName),
+ {[{Index, {tree, BelowTree, {EType,MibName}}}| CurTree], RestMes2};
+ {internal_subtree, Index, NewLevelPrefix} ->
+ ?vtrace("build subtree -> internal_subtree at"
+ "~n ~w with ~w",
+ [Index,NewLevelPrefix]),
+ {BelowTree, RestMes} =
+ build_subtree(NewLevelPrefix, [Me | Mes], MibName),
+ {CurTree, RestMes2} =
+ build_subtree(LevelPrefix, RestMes, MibName),
+ {[{Index, {tree, BelowTree, internal}} | CurTree], RestMes2}
+ end;
+
+build_subtree(_LevelPrefix, [], _MibName) ->
+ ?vtrace("build subtree -> done", []),
+ {[], []}.
+
+%%--------------------------------------------------
+%% Purpose: Determine how/if/where Me should be inserted in subtree
+%% with LevelPrefix. This function does not build any tree, only
+%% determinses what should be done (by build subtree).
+%% Returns:
+%% above - Indicating that this ME should _not_ be in this subtree.
+%% {node, Index} - yes, construct a node with index Index on this level
+%% {internal_subtree, Index, NewLevelPrefix} - yes, there should be an
+%% internal subtree at this index.
+%% {subtree, Index, NewLevelPrefix} - yes, construct a subtree with
+%% NewLevelPrefix and insert this on current level in position Index.
+%%--------------------------------------------------
+in_subtree(LevelPrefix, Me) ->
+ case lists:prefix(LevelPrefix, Me#me.oid) of
+ true when length(Me#me.oid) > length(LevelPrefix) ->
+ classify_how_in_subtree(LevelPrefix, Me);
+ _ ->
+ above
+ end.
+
+%%--------------------------------------------------
+%% See comment about in_subtree/2. This function takes care of all cases
+%% where the ME really should be in _this_ subtree (not above).
+%%--------------------------------------------------
+classify_how_in_subtree(LevelPrefix, Me)
+ when (length(Me#me.oid) =:= (length(LevelPrefix) + 1)) ->
+ Oid = Me#me.oid,
+ case node_or_subtree(Me#me.entrytype) of
+ subtree ->
+ {subtree, lists:last(Oid), Oid};
+ node ->
+ {node, lists:last(Oid)}
+ end;
+
+classify_how_in_subtree(LevelPrefix, Me)
+ when (length(Me#me.oid) > (length(LevelPrefix) + 1)) ->
+ L1 = length(LevelPrefix) + 1,
+ Oid = Me#me.oid,
+ {internal_subtree, lists:nth(L1, Oid), lists:sublist(Oid, 1, L1)}.
+
+%%--------------------------------------------------
+%% Determines how to treat different kinds om MEs in the tree building process.
+%% Pre: all internal nodes have been removed.
+%%--------------------------------------------------
+node_or_subtree(table) -> subtree;
+node_or_subtree(table_entry) -> subtree;
+node_or_subtree(variable) -> node;
+node_or_subtree(table_column) -> node.
+
+%%--------------------------------------------------
+%% Purpose: (Recursively) Converts a temporary tree (see above) to a final tree.
+%% If input is a ListTree, output is a TupleTree.
+%% If input is a Node, output is the same Node.
+%% Pre: All Indexes are >= 0.
+%%--------------------------------------------------
+convert_tree({Index, {tree, Tree, Info}}) when Index >= 0 ->
+ L = lists:map(fun convert_tree/1, Tree),
+ {Index, {tree, dict_list_to_tuple(L), Info}};
+convert_tree({Index, {node, Info}}) when Index >= 0 ->
+ {Index, {node, Info}};
+convert_tree(Tree) when is_list(Tree) ->
+ L = lists:map(fun convert_tree/1, Tree),
+ dict_list_to_tuple(L).
+
+%%----------------------------------------------------------------------
+%% Purpose: Converts a single level (that is non-recursively) from
+%% the temporary indexlist to the N-tuple.
+%% Input: A list of {Index, Data}.
+%% Output: A tuple where element Index is Data.
+%%----------------------------------------------------------------------
+dict_list_to_tuple(L) ->
+ L2 = lists:keysort(1, L),
+ list_to_tuple(integrate_indexes(0, L2)).
+
+%%----------------------------------------------------------------------
+%% Purpose: Helper function for dict_list_to_tuple/1.
+%% Converts an indexlist to a N-list.
+%% Input: A list of {Index, Data}.
+%% Output: A (usually longer, never shorter) list where element Index is Data.
+%% Example: [{1,hej}, {3, sven}] will give output
+%% [undefined_node, hej, undefined_node, sven].
+%% Initially CurIndex should be 0.
+%%----------------------------------------------------------------------
+integrate_indexes(CurIndex, [{CurIndex, Data} | T]) ->
+ [Data | integrate_indexes(CurIndex + 1, T)];
+integrate_indexes(_Index, []) ->
+ [];
+integrate_indexes(CurIndex, L) ->
+ [undefined_node | integrate_indexes(CurIndex + 1, L)].
+
+%%%======================================================================
+%%% 4. Tree merging
+%%% Used by: load mib, insert subagent.
+%%%======================================================================
+
+%%----------------------------------------------------------------------
+%% Arg: Two root nodes (that is to be merged).
+%% Returns: A new root node where the nodes have been merger to one.
+%%----------------------------------------------------------------------
+merge_nodes(Same, Same) ->
+ Same;
+merge_nodes(Node, undefined_node) ->
+ Node;
+merge_nodes(undefined_node, Node) ->
+ Node;
+merge_nodes({tree, Tree1, internal}, {tree, Tree2, internal}) ->
+ {tree, merge_levels(tuple_to_list(Tree1),tuple_to_list(Tree2)), internal};
+merge_nodes(Node1, Node2) ->
+ throw({error_merge_nodes, Node1, Node2}).
+
+%%----------------------------------------------------------------------
+%% Arg: Two levels to be merged.
+%% Here, a level is represented as a list of nodes. A list is easier
+%% to extend than a tuple.
+%% Returns: The resulting, merged level tuple.
+%%----------------------------------------------------------------------
+merge_levels(Level1, Level2) when length(Level1) =:= length(Level2) ->
+ MergeNodes = fun(N1, N2) -> merge_nodes(N1, N2) end,
+ list_to_tuple(snmp_misc:multi_map(MergeNodes, [Level1, Level2]));
+merge_levels(Level1, Level2) when length(Level1) > length(Level2) ->
+ merge_levels(Level1, Level2 ++
+ undefined_nodes_list(length(Level1) - length(Level2)));
+merge_levels(Level1, Level2) when length(Level1) < length(Level2) ->
+ merge_levels(Level2, Level1).
+
+undefined_nodes_list(N) -> lists:duplicate(N, undefined_node).
+
+
+%%%======================================================================
+%%% 5. Tree deletion routines
+%%% (for unload mib)
+%%%======================================================================
+
+%%----------------------------------------------------------------------
+%% Purpose: Actually kicks of the tree reconstruction.
+%% Returns: {list of removed MEs, NewTree}
+%%----------------------------------------------------------------------
+delete_mib_from_tree(MibName, {tree, Tree, internal}) ->
+ case delete_tree(Tree, MibName) of
+ [] ->
+ {tree, {undefined_node}, internal}; % reduce
+ LevelList ->
+ {tree, list_to_tuple(LevelList), internal}
+ end.
+
+%%----------------------------------------------------------------------
+%% Purpose: Deletes all nodes associated to MibName from this level and
+%% all levels below.
+%% If the new level does not contain information (that is, no
+%% other mibs use it) anymore the empty list is returned.
+%% Returns: {MEs, The new level represented as a list}
+%%----------------------------------------------------------------------
+delete_tree(Tree, MibName) when is_tuple(Tree) ->
+ NewLevel = delete_nodes(tuple_to_list(Tree), MibName, []),
+ case lists:filter(fun drop_undefined_nodes/1,NewLevel) of
+ [] -> [];
+ _A_perhaps_shorted_list ->
+ NewLevel % some other mib needs this level
+ end.
+
+%%----------------------------------------------------------------------
+%% Purpose: Nodes belonging to MibName are removed from the tree.
+%% Recursively deletes sub trees to this node.
+%% Returns: {MEs, NewNodesList}
+%%----------------------------------------------------------------------
+delete_nodes([], _MibName, AccNodes) ->
+ lists:reverse(AccNodes);
+
+delete_nodes([{node, {variable, MibName}}|T], MibName, AccNodes) ->
+ delete_nodes(T, MibName, [undefined_node | AccNodes]);
+
+delete_nodes([{node, {table_column, MibName}}|T], MibName, AccNodes) ->
+ delete_nodes(T, MibName, [undefined_node | AccNodes]);
+
+delete_nodes([{tree, _Tree, {table, MibName}}|T], MibName, AccNodes) ->
+ delete_nodes(T, MibName, [undefined_node | AccNodes]);
+
+delete_nodes([{tree, _Tree, {table_entry, MibName}}|T], MibName, AccNodes) ->
+ delete_nodes(T, MibName, [undefined_node | AccNodes]);
+
+delete_nodes([{tree, Tree, Info}|T], MibName, AccNodes) ->
+ case delete_tree(Tree, MibName) of
+ [] -> % tree completely deleted
+ delete_nodes(T, MibName, [undefined_node | AccNodes]);
+ LevelList ->
+ delete_nodes(T, MibName,
+ [{tree, list_to_tuple(LevelList), Info} | AccNodes])
+ end;
+
+delete_nodes([NodeToKeep|T], MibName, AccNodes) ->
+ delete_nodes(T, MibName, [NodeToKeep | AccNodes]).
+
+drop_undefined_nodes(undefined_node) -> false;
+drop_undefined_nodes(_) -> true.
+
+
+%%%======================================================================
+%%% 6. Functions for subagent handling
+%%%======================================================================
+
+%%----------------------------------------------------------------------
+%% Returns: A new Root|{error, reason}
+%%----------------------------------------------------------------------
+insert_subagent(Oid, OldRoot) ->
+ ListTree = build_tree_for_subagent(Oid),
+ case catch convert_tree(ListTree) of
+ {'EXIT', _Reason} ->
+ {error, 'cannot construct tree from oid'};
+ Level when is_tuple(Level) ->
+ T = {tree, Level, internal},
+ case catch merge_nodes(T, OldRoot) of
+ {error_merge_nodes, _Node1, _Node2} ->
+ {error, oid_conflict};
+ NewRoot when is_tuple(NewRoot) andalso
+ (element(1, NewRoot) =:= tree) ->
+ NewRoot
+ end
+ end.
+
+build_tree_for_subagent([Index]) ->
+ [{Index, {node, subagent}}];
+
+build_tree_for_subagent([Index | T]) ->
+ [{Index, {tree, build_tree_for_subagent(T), internal}}].
+
+
+%%----------------------------------------------------------------------
+%% Returns: A new tree where the subagent at Oid (2nd arg) has been deleted.
+%%----------------------------------------------------------------------
+
+delete_subagent({tree, Tree, Info}, [Index]) ->
+ {node, subagent} = element(Index+1, Tree),
+ {tree, setelement(Index+1, Tree, undefined_node), Info};
+delete_subagent({tree, Tree, Info}, [Index | TI]) ->
+ {tree, setelement(Index+1, Tree,
+ delete_subagent(element(Index+1, Tree), TI)), Info}.
+
+
+%%%======================================================================
+%%% 7. Misc functions
+%%%======================================================================
+
+%%----------------------------------------------------------------------
+%% Installs the mibs found in the database when starting the agent.
+%% Basically calls the instrumentation functions for all non-internal
+%% mib-entries
+%%----------------------------------------------------------------------
+install_mibs(Mod, MibDb, NodeDb) ->
+ MibNames = loaded(Mod, MibDb),
+ ?vtrace("install_mibs -> found following mibs in database: ~n"
+ "~p", [MibNames]),
+ install_mibs2(Mod, NodeDb, MibNames).
+
+install_mibs2(_, _, []) ->
+ ok;
+install_mibs2(Mod, NodeDb, [MibName|MibNames]) ->
+ Pattern = #node_info{oid = '_', mib_name = MibName, me = '_'},
+ Nodes = Mod:match_object(NodeDb, Pattern),
+ MEs = [ME || #node_info{me = ME} <- Nodes],
+ ?vtrace("install_mibs2 -> installing ~p MEs for mib ~p",
+ [length(MEs), MibName]),
+ NewF = fun(ME) -> call_instrumentation(ME, new) end,
+ lists:foreach(NewF, MEs),
+ install_mibs2(Mod, NodeDb, MibNames).
+
+
+%%----------------------------------------------------------------------
+%% Does all side effect stuff during load_mib.
+%%----------------------------------------------------------------------
+install_mib(Mod, Db, Symbolic, Mib, MibName, FileName, NonInternalMes) ->
+ ?vdebug("install_mib -> entry with"
+ "~n Symbolic: ~p"
+ "~n MibName: ~p"
+ "~n FileName: ~p", [Symbolic, MibName, FileName]),
+ Rec = #mib_info{name = MibName, symbolic = Symbolic, file_name = FileName},
+ Mod:write(Db, Rec),
+ install_mib2(Symbolic, MibName, Mib),
+ NewF = fun(ME) -> call_instrumentation(ME, new) end,
+ lists:foreach(NewF, NonInternalMes).
+
+install_mib2(true, MibName, Mib) ->
+ #mib{table_infos = TabInfos,
+ variable_infos = VarInfos,
+ mes = MEs,
+ asn1_types = ASN1Types,
+ traps = Traps} = Mib,
+ snmpa_symbolic_store:add_table_infos(MibName, TabInfos),
+ snmpa_symbolic_store:add_variable_infos(MibName, VarInfos),
+ snmpa_symbolic_store:add_aliasnames(MibName, MEs),
+ snmpa_symbolic_store:add_types(MibName, ASN1Types),
+ SetF = fun(Trap) ->
+ snmpa_symbolic_store:set_notification(Trap, MibName)
+ end,
+ lists:foreach(SetF, Traps);
+install_mib2(_, _, _) ->
+ ok.
+
+install_mes(Mod, Db, MibName, MEs) ->
+ Write = fun(#me{oid = Oid} = ME) ->
+ Node = #node_info{oid = Oid,
+ mib_name = MibName,
+ me = ME},
+ Mod:write(Db, Node)
+ end,
+ install_mes(Write, MEs).
+
+install_mes(_Write, []) ->
+ ok;
+install_mes(Write, [ME|MEs]) ->
+ Write(ME),
+ install_mes(Write, MEs).
+
+
+%%----------------------------------------------------------------------
+%% Does all side effect stuff during unload_mib.
+%%----------------------------------------------------------------------
+uninstall_mib(Mod, Db, Symbolic, MibName, MEs) ->
+ ?vtrace("uninstall_mib -> entry with"
+ "~n Db: ~p"
+ "~n Symbolic: ~p"
+ "~n MibName: ~p", [Db, Symbolic, MibName]),
+ Res = Mod:delete(Db, MibName),
+ ?vtrace("uninstall_mib -> (mib) db delete result: ~p", [Res]),
+ uninstall_mib2(Symbolic, MibName),
+ DelF = fun(ME) -> call_instrumentation(ME, delete) end,
+ lists:foreach(DelF, MEs).
+
+uninstall_mib2(true, MibName) ->
+ snmpa_symbolic_store:delete_table_infos(MibName),
+ snmpa_symbolic_store:delete_variable_infos(MibName),
+ snmpa_symbolic_store:delete_aliasnames(MibName),
+ snmpa_symbolic_store:delete_types(MibName),
+ snmpa_symbolic_store:delete_notifications(MibName);
+uninstall_mib2(_, _) ->
+ ok.
+
+uninstall_mes(Mod, Db, MibName) ->
+ Pattern = #node_info{oid = '_', mib_name = MibName, me = '_'},
+ Mod:match_delete(Db, Pattern).
+
+
+%%----------------------------------------------------------------------
+%% Create a list of the names of all the loaded mibs
+%%----------------------------------------------------------------------
+loaded(Mod, Db) ->
+ [N || #mib_info{name = N} <- Mod:tab2list(Db)].
+
+
+%%----------------------------------------------------------------------
+%% Calls MFA-instrumentation with 'new' or 'delete' operation.
+%%----------------------------------------------------------------------
+call_instrumentation(#me{entrytype = variable, mfa={M,F,A}}, Operation) ->
+ ?vtrace("call instrumentation with"
+ "~n entrytype: variable"
+ "~n MFA: {~p,~p,~p}"
+ "~n Operation: ~p",
+ [M,F,A,Operation]),
+ catch apply(M, F, [Operation | A]);
+call_instrumentation(#me{entrytype = table_entry, mfa={M,F,A}}, Operation) ->
+ ?vtrace("call instrumentation with"
+ "~n entrytype: table_entry"
+ "~n MFA: {~p,~p,~p}"
+ "~n Operation: ~p",
+ [M,F,A,Operation]),
+ catch apply(M, F, [Operation | A]);
+call_instrumentation(_ShitME, _Operation) ->
+ done.
+
+
+maybe_drop_me(#me{entrytype = internal}) -> false;
+maybe_drop_me(#me{entrytype = group}) -> false;
+maybe_drop_me(#me{imported = true}) -> false;
+maybe_drop_me(_) -> true.
+
+
+%%----------------------------------------------------------------------
+%% Code change functions
+%%----------------------------------------------------------------------
+
+code_change(down, _Vsn, _Extra, State) ->
+ ?d("code_change(down) -> entry when"
+ "~n Vsn: ~p"
+ "~n Extra: ~p", [_Vsn, _Extra]),
+ State;
+
+code_change(up, _Vsn, _Extra, State) ->
+ ?d("code_change(up) -> entry when"
+ "~n Vsn: ~p"
+ "~n Extra: ~p", [_Vsn, _Extra]),
+ State.
+
+
diff --git a/lib/snmp/src/agent/snmpa_mib_lib.erl b/lib/snmp/src/agent/snmpa_mib_lib.erl
index 3c94cc8095..ecdf968458 100644
--- a/lib/snmp/src/agent/snmpa_mib_lib.erl
+++ b/lib/snmp/src/agent/snmpa_mib_lib.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
diff --git a/lib/snmp/src/agent/snmpa_mib_storage.erl b/lib/snmp/src/agent/snmpa_mib_storage.erl
new file mode 100644
index 0000000000..ed0607fb84
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_mib_storage.erl
@@ -0,0 +1,182 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013-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%
+%%
+
+-module(snmpa_mib_storage).
+
+-export_type([
+ mib_storage_fields/0,
+ mib_storage_table_type/0,
+ mib_storage_table_id/0
+ ]).
+
+
+%%% ----------------------------------------------------------------
+%%% This behaviour module defines the API for the mib-storage.
+%%% This is how the agent stores its internal mib-data
+%%% (symbolic-store and mib-server).
+%%%-----------------------------------------------------------------
+
+-type mib_storage_fields() :: [atom()].
+-type mib_storage_table_type() :: set | bag.
+-type mib_storage_table_id() :: term().
+
+
+%% ---------------------------------------------------------------
+%% open
+%%
+%% Open or create a mib-storage table.
+%% If any extra info needs to be communicated to the implementor
+%% (of the behaviour), this is done using the *Options* argument.
+%% ---------------------------------------------------------------
+
+%% Options is callback module dependant
+
+-callback open(Name :: atom(),
+ RecName :: atom(),
+ Fields :: mib_storage_fields(),
+ Type :: mib_storage_table_type(),
+ Options :: list()) ->
+ {ok, TabId :: mib_storage_table_id()} | {error, Reason :: term()}.
+
+
+%% ---------------------------------------------------------------
+%% close
+%%
+%% Close the mib-storage table. What this does is up to the
+%% implementor (when using mnesia it may be a no-op but for ets
+%% it may actually delete the table).
+%% ---------------------------------------------------------------
+
+-callback close(TabId :: mib_storage_table_id()) ->
+ term().
+
+
+%% ---------------------------------------------------------------
+%% read/2
+%%
+%% Retrieve a record from the mib-storage table.
+%% ---------------------------------------------------------------
+
+-callback read(TabId :: mib_storage_table_id(),
+ Key :: term()) ->
+ false | {value, Record :: tuple()}.
+
+
+%% ---------------------------------------------------------------
+%% write/2
+%%
+%% Write a record to the mib-storage table.
+%% ---------------------------------------------------------------
+
+-callback write(TabId :: mib_storage_table_id(),
+ Record :: tuple()) ->
+ ok | {error, Reason :: term()}.
+
+
+%% ---------------------------------------------------------------
+%% delete/1
+%%
+%% Delete the mib-storage table.
+%% ---------------------------------------------------------------
+
+-callback delete(TabId :: mib_storage_table_id()) ->
+ snmp:void().
+
+
+%% ---------------------------------------------------------------
+%% delete/2
+%%
+%% Delete a record from the mib-storage table.
+%% ---------------------------------------------------------------
+
+-callback delete(TabId :: mib_storage_table_id(),
+ Key :: term()) ->
+ ok | {error, Reason :: term()}.
+
+
+%% ---------------------------------------------------------------
+%% match_object
+%%
+%% Search the mib-storage table for records which matches
+%% the pattern.
+%% ---------------------------------------------------------------
+
+-callback match_object(TabId :: mib_storage_table_id(),
+ Pattern :: ets:match_pattern()) ->
+ {ok, Recs :: [tuple()]} | {error, Reason :: term()}.
+
+
+%% ---------------------------------------------------------------
+%% match_delete
+%%
+%% Search the mib-storage table for records which matches the
+%% pattern and deletes them from the database and return the
+%5 deleted records.
+%% ---------------------------------------------------------------
+
+-callback match_delete(TabId :: mib_storage_table_id(),
+ Pattern :: ets:match_pattern()) ->
+ {ok, Recs :: [tuple()]} | {error, Reason :: term()}.
+
+
+%% ---------------------------------------------------------------
+%% tab2list
+%%
+%% Return all records in the table in the form of a list.
+%% ---------------------------------------------------------------
+
+-callback tab2list(TabId :: mib_storage_table_id()) ->
+ [tuple()].
+
+
+%% ---------------------------------------------------------------
+%% info/1,2
+%%
+%% Retrieve implementation dependent mib-storage table
+%% information.
+%% ---------------------------------------------------------------
+
+-callback info(TabId :: mib_storage_table_id()) ->
+ Info :: term().
+
+-callback info(TabId :: mib_storage_table_id(), Item :: atom()) ->
+ Info :: term().
+
+
+%% ---------------------------------------------------------------
+%% sync
+%%
+%% Dump mib-storage table to disc (if it has a disk component).
+%% ---------------------------------------------------------------
+
+-callback sync(TabId :: mib_storage_table_id()) ->
+ snmp:void().
+
+
+%% ---------------------------------------------------------------
+%% backup
+%%
+%% Make a backup copy of the mib-storage table.
+%% ---------------------------------------------------------------
+
+-callback backup(TabId :: mib_storage_table_id(),
+ Dir :: file:filename()) ->
+ ok | {error, Reason :: term()}.
+
diff --git a/lib/snmp/src/agent/snmpa_mib_storage_dets.erl b/lib/snmp/src/agent/snmpa_mib_storage_dets.erl
new file mode 100644
index 0000000000..2459b6bc3e
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_mib_storage_dets.erl
@@ -0,0 +1,310 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013-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%
+%%
+-module(snmpa_mib_storage_dets).
+
+-behaviour(snmpa_mib_storage).
+
+
+%%%-----------------------------------------------------------------
+%%% This module implements the snmpa_mib_storage behaviour.
+%%% It uses dets for storage.
+%%%-----------------------------------------------------------------
+
+-export([
+ open/5,
+ close/1,
+ read/2,
+ write/2,
+ delete/1,
+ delete/2,
+ match_object/2,
+ match_delete/2,
+ tab2list/1,
+ info/1, info/2,
+ sync/1,
+ backup/2
+ ]).
+
+
+-define(VMODULE, "MS-DETS").
+-include("snmp_verbosity.hrl").
+
+-record(tab, {id, rec_name}).
+
+
+%% ---------------------------------------------------------------
+%% open
+%%
+%% Open or create a mib-storage (dets) table.
+%%
+%% Opts - A list of implementation dependent options
+%% dets_open_options() = [dets_open_option()]
+%% dets_open_option() = {dir, filename()} |
+%% {action, keep | clear} |
+%% {auto_save, default | pos_integer()} |
+%% {repair, force | boolean()}
+%%
+%% ---------------------------------------------------------------
+
+open(Name, RecName, _Fields, Type, Opts) ->
+ Dir = snmp_misc:get_option(dir, Opts),
+ Action = snmp_misc:get_option(action, Opts, keep),
+ AutoSave = snmp_misc:get_option(auto_save, Opts, default),
+ Repair = snmp_misc:get_option(repair, Opts, false),
+ File = dets_filename(Name, Dir),
+ OpenOpts = [{file, File},
+ {type, Type},
+ {keypos, 2},
+ {repair, Repair}] ++
+ case AutoSave of
+ default ->
+ [];
+ _ ->
+ [{auto_save, AutoSave}]
+ end,
+ case dets:open_file(Name, OpenOpts) of
+ {ok, ID} when (Action =:= keep) ->
+ {ok, #tab{id = ID, rec_name = RecName}};
+ {ok, ID} when (Action =:= clear) ->
+ dets:match_delete(ID, '_'),
+ {ok, #tab{id = ID, rec_name = RecName}};
+ {error, Reason} ->
+ {error, {dets_open, Reason}}
+ end.
+
+dets_filename(Name, Dir) ->
+ Dir1 = dets_filename1(Dir),
+ Dir2 = string:strip(Dir1, right, $/),
+ io_lib:format("~s/~p.dat", [Dir2, Name]).
+
+dets_filename1([]) -> ".";
+dets_filename1(Dir) -> Dir.
+
+
+%% ---------------------------------------------------------------
+%% close
+%%
+%% Close the table.
+%% ---------------------------------------------------------------
+
+close(#tab{id = ID}) ->
+ ?vtrace("close database ~p", [ID]),
+ dets:close(ID).
+
+
+%% ---------------------------------------------------------------
+%% read
+%%
+%% Retrieve a record from the database table.
+%% ---------------------------------------------------------------
+
+read(#tab{id = ID}, Key) ->
+ ?vtrace("read from table ~p: ~p", [ID, Key]),
+ case dets:lookup(ID, Key) of
+ [Rec|_] -> {value, Rec};
+ _ -> false
+ end.
+
+
+%% ---------------------------------------------------------------
+%% write
+%%
+%% Write a record to the database table.
+%% ---------------------------------------------------------------
+
+write(#tab{id = ID, rec_name = RecName}, Rec)
+ when (is_tuple(Rec) andalso (element(1, Rec) =:= RecName)) ->
+ ?vtrace("write to table ~p", [ID]),
+ dets:insert(ID, Rec).
+
+
+%% ---------------------------------------------------------------
+%% delete
+%%
+%% Delete the database table.
+%% ---------------------------------------------------------------
+
+delete(#tab{id = ID}) ->
+ ?vtrace("delete database ~p", [ID]),
+ File = dets:info(ID, filename),
+ case dets:close(ID) of
+ ok ->
+ file:delete(File);
+ Error ->
+ Error
+ end.
+
+
+%% ---------------------------------------------------------------
+%% delete
+%%
+%% Delete a record from the database table.
+%% ---------------------------------------------------------------
+
+delete(#tab{id = ID}, Key) ->
+ ?vtrace("delete from table ~p: ~p", [ID, Key]),
+ dets:delete(ID, Key).
+
+
+%% ---------------------------------------------------------------
+%% match_object
+%%
+%% Search the database table for records witch matches the pattern.
+%% ---------------------------------------------------------------
+
+match_object(#tab{id = ID}, Pattern) ->
+ ?vtrace("match_object in ~p of ~p", [ID, Pattern]),
+ dets:match_object(ID, Pattern).
+
+
+%% ---------------------------------------------------------------
+%% match_delete
+%%
+%% Search the database table for records witch matches the
+%% pattern and deletes them from the database table.
+%% ---------------------------------------------------------------
+
+match_delete(#tab{id = ID}, Pattern) ->
+ ?vtrace("match_delete in ~p with pattern ~p", [ID, Pattern]),
+ Recs = dets:match_object(ID, Pattern),
+ dets:match_delete(ID, Pattern),
+ Recs.
+
+
+%% ---------------------------------------------------------------
+%% tab2list
+%%
+%% Return all records in the table in the form of a list.
+%% ---------------------------------------------------------------
+
+tab2list(#tab{id = ID} = Tab) ->
+ ?vtrace("tab2list -> list of ~p", [ID]),
+ match_object(Tab, '_').
+
+
+%% ---------------------------------------------------------------
+%% info
+%%
+%% Retrieve implementation dependent mib-storage table
+%% information.
+%% ---------------------------------------------------------------
+
+info(#tab{id = ID}) ->
+ ?vtrace("info -> info of ~p", [ID]),
+ dets:info(ID).
+
+
+info(TabId, all = _Item) ->
+ info(TabId);
+info(#tab{id = ID}, memory = _Item) ->
+ ?vtrace("info on ~p (~w)", [ID, _Item]),
+ dets:info(ID, file_size);
+info(#tab{id = ID}, Item) ->
+ ?vtrace("info on ~p (~w)", [ID, Item]),
+ dets:info(ID, Item).
+
+
+%% ---------------------------------------------------------------
+%% sync
+%%
+%% Dump mib-storage table to disc (if it has a disk component)
+%% ---------------------------------------------------------------
+
+sync(#tab{id = ID}) ->
+ ?vtrace("sync -> sync ~p", [ID]),
+ dets:sync(ID).
+
+
+%% ---------------------------------------------------------------
+%% backup
+%%
+%% Make a backup copy of the mib-storage table.
+%% ---------------------------------------------------------------
+
+backup(#tab{id = ID}, BackupDir) ->
+ ?vtrace("backup -> backup of ~p to ~p", [ID, BackupDir]),
+ case dets:info(ID, filename) of
+ undefined ->
+ {error, no_file};
+ Filename ->
+ case filename:dirname(Filename) of
+ BackupDir ->
+ {error, db_dir};
+ _ ->
+ Type = dets:info(ID, type),
+ KP = dets:info(ID, keypos),
+ dets_backup(ID,
+ filename:basename(Filename),
+ BackupDir, Type, KP)
+ end
+ end.
+
+
+dets_backup(ID, Filename, BackupDir, Type, KP) ->
+ ?vtrace("dets_backup -> entry with"
+ "~n ID: ~p"
+ "~n Filename: ~p"
+ "~n BackupDir: ~p"
+ "~n Type: ~p"
+ "~n KP: ~p", [ID, Filename, BackupDir, Type, KP]),
+ BackupFile = filename:join(BackupDir, Filename),
+ ?vtrace("dets_backup -> "
+ "~n BackupFile: ~p", [BackupFile]),
+ Backup = list_to_atom(atom_to_list(ID) ++ "_backup"),
+ Opts = [{file, BackupFile}, {type, Type}, {keypos, KP}],
+ case dets:open_file(Backup, Opts) of
+ {ok, B} ->
+ ?vtrace("dets_backup -> create fun", []),
+ F = fun(Arg) ->
+ dets_backup(Arg, start, ID, B)
+ end,
+ dets:safe_fixtable(ID, true),
+ Res = dets:init_table(Backup, F, [{format, bchunk}]),
+ dets:safe_fixtable(ID, false),
+ ?vtrace("dets_backup -> Res: ~p", [Res]),
+ Res;
+ Error ->
+ ?vinfo("dets_backup -> open_file failed: "
+ "~n ~p", [Error]),
+ Error
+ end.
+
+dets_backup(close, _Cont, _ID, B) ->
+ dets:close(B),
+ ok;
+dets_backup(read, Cont1, ID, B) ->
+ case dets:bchunk(ID, Cont1) of
+ {Cont2, Data} ->
+ F = fun(Arg) ->
+ dets_backup(Arg, Cont2, ID, B)
+ end,
+ {Data, F};
+ '$end_of_table' ->
+ dets:close(B),
+ end_of_input;
+ Error ->
+ Error
+ end.
+
+
+%%----------------------------------------------------------------------
+
+%% user_err(F, A) ->
+%% snmpa_error:user_err(F, A).
diff --git a/lib/snmp/src/agent/snmpa_mib_storage_ets.erl b/lib/snmp/src/agent/snmpa_mib_storage_ets.erl
new file mode 100644
index 0000000000..68dfa83247
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_mib_storage_ets.erl
@@ -0,0 +1,342 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013-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%
+%%
+
+-module(snmpa_mib_storage_ets).
+
+-behaviour(snmpa_mib_storage).
+
+%%%-----------------------------------------------------------------
+%%% This module implements the snmpa_mib_storage behaviour.
+%%% It uses ets for storage.
+%%%-----------------------------------------------------------------
+
+-export([
+ open/5,
+ close/1,
+ read/2,
+ write/2,
+ delete/1,
+ delete/2,
+ match_object/2,
+ match_delete/2,
+ tab2list/1,
+ info/1, info/2,
+ sync/1,
+ backup/2
+ ]).
+
+
+-define(VMODULE,"MS-ETS").
+-include("snmp_verbosity.hrl").
+
+-record(tab, {id, rec_name, file, checksum = false}).
+
+
+%% ---------------------------------------------------------------
+%% open
+%%
+%% Open or create an ets table.
+%% Possibly also read data from a (specified) file (mirror) and
+%% populate the table from that (the dir option).
+%%
+%% Opts - A list of implementation dependent options
+%% ets_open_options() = [ets_open_option()]
+%% ets_open_option() = {dir, filename()} |
+%% {action, keep | clear} |
+%% {checksum, boolean()}
+%%
+%% The RecName and Fields arguments are not used in this
+%% implementation.
+%%
+%% ---------------------------------------------------------------
+
+%% This function creates the ets table
+open(Name, RecName, _Fields, Type, Opts) ->
+ ?vtrace("open table ~p", [Name]),
+ case lists:keysearch(dir, 1, Opts) of
+ {value, {dir, Dir}} ->
+ Action = snmp_misc:get_option(action, Opts, keep),
+ Checksum = snmp_misc:get_option(checksum, Opts, false),
+ ?vtrace("open ~p database ~p - check if file exist", [Type, Name]),
+ File = filename:join(Dir, atom_to_list(Name) ++ ".db"),
+ case file:read_file_info(File) of
+ {ok, _} ->
+ ?vdebug("open ~p database ~p - file exist - try reading",
+ [Type, Name]),
+ case ets:file2tab(File, [{verify, Checksum}]) of
+ {ok, ID} ->
+ ?vtrace("open ~p database ~p - "
+ "data read from file", [Type, Name]),
+ {ok, #tab{id = ID,
+ rec_name = RecName,
+ file = File,
+ checksum = Checksum}};
+ {error, Reason} when (Action =:= keep) ->
+ ?vinfo("open ~p database ~p - "
+ "failed reading from file (keep): "
+ "~n ~p",
+ [Type, Name, Reason]),
+ {error, {file2tab, Reason}};
+ {error, Reason} ->
+ ?vlog("open ~p database ~p - "
+ "failed reading from file (clear): "
+ "~n ~p", [Type, Name, Reason]),
+ user_err("Warning: could not read file - "
+ "create new (empty): "
+ "~n File: ~p"
+ "~n Reason: ~p", [File, Reason]),
+ ID = ets:new(Name, [Type, protected, {keypos, 2}]),
+ write_ets_file(ID, File, Checksum),
+ {ok, #tab{id = ID,
+ rec_name = RecName,
+ file = File,
+ checksum = Checksum}}
+ end;
+ {error, enoent} ->
+ %% No such file - create it
+ ?vdebug("open ~p database ~p - "
+ "file does *not* exist - create",
+ [Type, Name]),
+ ID = ets:new(Name, [Type, protected, {keypos, 2}]),
+ write_ets_file(ID, File, Checksum),
+ {ok, #tab{id = ID,
+ rec_name = RecName,
+ file = File,
+ checksum = Checksum}};
+ {error, Reason} when (Action =:= keep) ->
+ ?vinfo("open ~p database ~p - "
+ "failed reading file info (keep): "
+ "~n ~p",
+ [Type, Name, Reason]),
+ {error, {read_file_info, Reason}};
+ {error, Reason} ->
+ ?vlog("open ~p database ~p - "
+ "failed reading file info (clear): "
+ "~n ~p",
+ [Type, Name, Reason]),
+ user_err("Warning: could not read file info - "
+ "create new file: "
+ "~n File: ~p"
+ "~n Reason: ~p", [File, Reason]),
+ ID = ets:new(Name, [Type, protected, {keypos, 2}]),
+ write_ets_file(ID, File, Checksum),
+ {ok, #tab{id = ID,
+ rec_name = RecName,
+ file = File,
+ checksum = Checksum}}
+ end;
+ false ->
+ ?vdebug("open ~p database ~p - ok", [Type, Name]),
+ ID = ets:new(Name, [Type, protected, {keypos, 2}]),
+ {ok, #tab{id = ID, rec_name = RecName}}
+ end.
+
+
+%% ---------------------------------------------------------------
+%% close
+%%
+%% Close the mib-storage table.
+%% We will delete the table and if there is a file component,
+%% will also be written to file.
+%% ---------------------------------------------------------------
+close(#tab{id = ID, file = undefined}) ->
+ ?vtrace("close (delete) table ~p", [ID]),
+ ets:delete(ID);
+close(#tab{id = ID, file = File, checksum = Checksum}) ->
+ ?vtrace("close (delete) table ~p", [ID]),
+ write_ets_file(ID, File, Checksum),
+ ets:delete(ID).
+
+
+%% ---------------------------------------------------------------
+%% read
+%%
+%% Retrieve a record from the mib-storage table.
+%% ---------------------------------------------------------------
+
+read(#tab{id = ID}, Key) ->
+ ?vtrace("read from table ~p: ~p", [ID, Key]),
+ case ets:lookup(ID, Key) of
+ [Rec|_] -> {value, Rec};
+ _ -> false
+ end.
+
+
+%% ---------------------------------------------------------------
+%% write
+%%
+%% Write a record to the mib-storage table.
+%% ---------------------------------------------------------------
+
+%% This is a very crude guard test is used instead of: is_record(Rec, RecName)
+write(#tab{id = ID, rec_name = RecName}, Rec)
+ when (is_tuple(Rec) andalso (element(1, Rec) =:= RecName)) ->
+ ?vtrace("write to table ~p", [ID]),
+ ets:insert(ID, Rec).
+
+
+%% ---------------------------------------------------------------
+%% delete
+%%
+%% Delete the mib-storage table.
+%% ---------------------------------------------------------------
+delete(#tab{id = ID, file = undefined}) ->
+ ?vtrace("delete table ~p", [ID]),
+ ets:delete(ID);
+delete(#tab{id = ID, file = File}) ->
+ ?vtrace("delete table ~p", [ID]),
+ file:delete(File),
+ ets:delete(ID).
+
+
+%% ---------------------------------------------------------------
+%% delete
+%%
+%% Delete a record from the mib-storage table.
+%% ---------------------------------------------------------------
+delete(#tab{id = ID}, Key) ->
+ ?vtrace("delete from table ~p: ~p", [ID, Key]),
+ ets:delete(ID, Key).
+
+
+%% ---------------------------------------------------------------
+%% match_object
+%%
+%% Search the mib-storage table for records witch matches
+%% the pattern.
+%% ---------------------------------------------------------------
+
+match_object(#tab{id = ID}, Pattern) ->
+ ?vtrace("match_object in ~p of ~p", [ID, Pattern]),
+ ets:match_object(ID, Pattern).
+
+
+%% ---------------------------------------------------------------
+%% match_delete
+%%
+%% Search the mib-storage table for records witch matches
+%% the pattern and deletes them from the table.
+%% ---------------------------------------------------------------
+
+match_delete(#tab{id = ID}, Pattern) ->
+ ?vtrace("match_delete in ~p with pattern ~p", [ID, Pattern]),
+ Recs = ets:match_object(ID, Pattern),
+ ets:match_delete(ID, Pattern),
+ Recs.
+
+
+%% ---------------------------------------------------------------
+%% tab2list
+%%
+%% Return all records in the mib-storage table in the form
+%% of a list.
+%% ---------------------------------------------------------------
+
+tab2list(#tab{id = ID}) ->
+ ?vtrace("tab2list -> list of ~p", [ID]),
+ ets:tab2list(ID).
+
+
+
+%% ---------------------------------------------------------------
+%% info/1,2
+%%
+%% Retrieve implementation dependent mib-storage table
+%% information.
+%% ---------------------------------------------------------------
+info(#tab{id = ID}) ->
+ ?vtrace("info on ~p", [ID]),
+ case ets:info(ID) of
+ undefined ->
+ [];
+ L ->
+ L
+ end.
+
+
+info(TabId, all = _Item) ->
+ info(TabId);
+info(#tab{id = ID}, Item) ->
+ ?vtrace("info on ~p", [ID]),
+ ets:info(ID, Item).
+
+
+%% ---------------------------------------------------------------
+%% sync
+%%
+%% Dump mib-storage table to disc (if there is a file compionent)
+%% ---------------------------------------------------------------
+
+sync(#tab{file = undefined}) ->
+ ok;
+sync(#tab{id = ID, file = File, checksum = Checksum}) ->
+ ?vtrace("sync ~p", [ID]),
+ write_ets_file(ID, File, Checksum).
+
+
+%% ---------------------------------------------------------------
+%% backup
+%%
+%% Make a backup copy of the mib-storage table. Only valid id
+%% there is a file component.
+%% ---------------------------------------------------------------
+
+backup(#tab{file = undefined}, _BackupDir) ->
+ ok;
+backup(#tab{id = ID, file = File, checksum = Checksum}, BackupDir) ->
+ ?vtrace("backup ~p to ~p", [ID, BackupDir]),
+ Filename = filename:basename(File),
+ case filename:join(BackupDir, Filename) of
+ File ->
+ %% Oups: backup-dir and db-dir the same
+ {error, db_dir};
+ BackupFile ->
+ write_ets_file(ID, BackupFile, Checksum)
+ end.
+
+
+%%----------------------------------------------------------------------
+
+write_ets_file(ID, File, Checksum) when (Checksum =:= true) ->
+ do_write_ets_file(ID, File, [{extended_info, [md5sum]}]);
+write_ets_file(ID, File, Checksum) when (Checksum =:= false) ->
+ do_write_ets_file(ID, File, []).
+
+do_write_ets_file(ID, File, Options) ->
+ TmpFile = File ++ ".tmp",
+ case ets:tab2file(ID, TmpFile, Options) of
+ ok ->
+ case file:rename(TmpFile, File) of
+ ok ->
+ ok;
+ Else ->
+ user_err("Warning: could not move file ~p"
+ " (~p)", [File, Else])
+ end;
+ {error, Reason} ->
+ user_err("Warning: could not save file ~p (~p)",
+ [File, Reason])
+ end.
+
+
+%%----------------------------------------------------------------------
+
+user_err(F, A) ->
+ snmpa_error:user_err(F, A).
diff --git a/lib/snmp/src/agent/snmpa_mib_storage_mnesia.erl b/lib/snmp/src/agent/snmpa_mib_storage_mnesia.erl
new file mode 100644
index 0000000000..5f66b2ed9f
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_mib_storage_mnesia.erl
@@ -0,0 +1,303 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013-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%
+%%
+-module(snmpa_mib_storage_mnesia).
+
+
+-behaviour(snmpa_mib_storage).
+
+%%%-----------------------------------------------------------------
+%%% This module implements the snmpa_mib_storage behaviour.
+%%% It uses mnesia for storage.
+%%%-----------------------------------------------------------------
+
+-export([
+ open/5,
+ close/1,
+ read/2,
+ write/2,
+ delete/1,
+ delete/2,
+ match_object/2,
+ match_delete/2,
+ tab2list/1,
+ info/1, info/2,
+ sync/1,
+ backup/2
+ ]).
+
+
+-define(VMODULE,"MS-MNESIA").
+-include("snmp_verbosity.hrl").
+
+-record(tab, {id}).
+
+
+%% ---------------------------------------------------------------
+%% open
+%%
+%% Open or create a mnesia table.
+%%
+%% Opts - A list of implementation dependent options
+%% mnesia_open_options() = [mnesia_open_option()]
+%% mnesia_open_option() = {action, keep | clear} |
+%% {nodes, [node()]}
+%%
+%% ---------------------------------------------------------------
+
+open(Name, RecName, Fields, Type, Opts) ->
+ ?vtrace("open ~p table ~p for record ~p",
+ [Type, Name, RecName]),
+ Action = get_action(Opts),
+ Nodes = get_nodes(Opts),
+ case table_exists(Name) of
+ true when (Action =:= keep) ->
+ ?vtrace("open table ~p - exist (keep)", [Name]),
+ {ok, #tab{id = Name}};
+ true when (Action =:= clear) ->
+ ?vtrace("open table ~p - exist (clear)", [Name]),
+ F = fun() -> mnesia:clear_table(Name) end,
+ case mnesia:transaction(F) of
+ {aborted, Reason} ->
+ {error, {clear, Reason}};
+ {atomic, _} ->
+ {ok, #tab{id = Name}}
+ end;
+ false ->
+ ?vtrace("open table ~p - does not exist", [Name]),
+ Args = [{record_name, RecName},
+ {attributes, Fields},
+ {type, Type},
+ {disc_copies, Nodes}],
+ case mnesia:create_table(Name, Args) of
+ {atomic, ok} ->
+ ?vtrace("open table ~p - ok", [Name]),
+ {ok, #tab{id = Name}};
+ {aborted, Reason} ->
+ ?vinfo("open table ~p - aborted"
+ "~n Reason: ~p", [Name, Reason]),
+ {error, {create, Reason}}
+ end
+ end.
+
+table_exists(Name) ->
+ case (catch mnesia:table_info(Name, type)) of
+ {'EXIT', _Reason} ->
+ false;
+ _ ->
+ true
+ end.
+
+
+%% ---------------------------------------------------------------
+%% close
+%%
+%% Close the mib-storage table.
+%% This does nothing in the mnesia case.
+%% ---------------------------------------------------------------
+
+close(_) ->
+ ?vtrace("close mib-storage - ignore",[]),
+ ok.
+
+
+%% ---------------------------------------------------------------
+%% read
+%%
+%% Retrieve a record from the mib-storage table.
+%% ---------------------------------------------------------------
+
+read(#tab{id = ID}, Key) ->
+ ?vtrace("read (dirty) from database ~p: ~p", [ID, Key]),
+ case (catch mnesia:dirty_read(ID, Key)) of
+ [Rec|_] -> {value,Rec};
+ _ -> false
+ end.
+
+
+%% ---------------------------------------------------------------
+%% write
+%%
+%% Write a record to the mib-storage table.
+%% ---------------------------------------------------------------
+
+write(#tab{id = ID}, Rec) ->
+ ?vtrace("write to database ~p", [ID]),
+ F = fun() -> mnesia:write(ID, Rec, write) end,
+ case mnesia:transaction(F) of
+ {aborted, _Reason} = ABORTED ->
+ {error, ABORTED};
+ {atomic,_} ->
+ ok
+ end.
+
+
+%% ---------------------------------------------------------------
+%% delete
+%%
+%% Delete the mib-storage table.
+%% ---------------------------------------------------------------
+
+delete(#tab{id = ID}) ->
+ ?vtrace("delete database: ~p", [ID]),
+ mnesia:delete_table(ID).
+
+
+%% ---------------------------------------------------------------
+%% delete
+%%
+%% Delete a record from the mib-storage table.
+%% ---------------------------------------------------------------
+
+delete(#tab{id = ID}, Key) ->
+ ?vtrace("delete from database ~p: ~p", [ID, Key]),
+ F = fun() -> mnesia:delete(ID, Key, write) end,
+ case mnesia:transaction(F) of
+ {aborted, _Reason} = ABORTED ->
+ {error, ABORTED};
+ {atomic, _} ->
+ ok
+ end.
+
+
+%% ---------------------------------------------------------------
+%% match_object
+%%
+%% Search the mib-storage table for records witch matches
+%% the pattern.
+%% ---------------------------------------------------------------
+
+match_object(#tab{id = ID}, Pattern) ->
+ ?vtrace("match_object in ~p of ~p", [ID, Pattern]),
+ F = fun() -> mnesia:match_object(ID, Pattern, read) end,
+ case mnesia:transaction(F) of
+ {aborted, _Reason} = ABORTED ->
+ {error, ABORTED};
+ {atomic, Rs} ->
+ Rs
+ end.
+
+
+%% ---------------------------------------------------------------
+%% match_delete
+%%
+%% Search the mib-storage table for records witch matches
+%% the pattern and deletes them from the table.
+%% ---------------------------------------------------------------
+
+match_delete(#tab{id = ID}, Pattern) ->
+ ?vtrace("match_delete in ~p with pattern ~p", [ID, Pattern]),
+ F = fun() ->
+ Recs = mnesia:match_object(ID, Pattern, read),
+ lists:foreach(fun(Rec) ->
+ mnesia:delete_object(ID, Rec, write)
+ end, Recs),
+ Recs
+ end,
+ case mnesia:transaction(F) of
+ {aborted, _Reason} = ABORTED ->
+ {error, ABORTED};
+ {atomic, Rs} ->
+ Rs
+ end.
+
+
+%% ---------------------------------------------------------------
+%% tab2list
+%%
+%% Return all records in the mib-storage table in the form of
+%% a list.
+%% ---------------------------------------------------------------
+
+tab2list(#tab{id = ID} = Tab) ->
+ ?vtrace("tab2list -> list of ~p", [ID]),
+ match_object(Tab, mnesia:table_info(ID, wild_pattern)).
+
+
+%% ---------------------------------------------------------------
+%% info
+%%
+%% Retrieve implementation dependent mib-storage table
+%% information.
+%% ---------------------------------------------------------------
+
+info(#tab{id = ID}) ->
+ case (catch mnesia:table_info(ID, all)) of
+ Info when is_list(Info) ->
+ Info;
+ {'EXIT', {aborted, Reason}} ->
+ {error, Reason}
+ end.
+
+
+info(#tab{id = ID}, Item) ->
+ mnesia:table_info(ID, Item).
+
+
+%% ---------------------------------------------------------------
+%% sync
+%%
+%% Ignore
+%% ---------------------------------------------------------------
+
+sync(_) ->
+ ok.
+
+
+%% ---------------------------------------------------------------
+%% backup
+%%
+%% Ignore. Mnesia handles its own backups.
+%% ---------------------------------------------------------------
+
+backup(_, _) ->
+ ok.
+
+
+%%----------------------------------------------------------------------
+
+get_action(Opts) ->
+ snmp_misc:get_option(action, Opts, keep).
+
+get_nodes(Opts) ->
+ case snmp_misc:get_option(nodes, Opts, erlang:nodes()) of
+ [] ->
+ [node()];
+ Nodes when is_list(Nodes) ->
+ Nodes;
+ all ->
+ erlang:nodes();
+ visible ->
+ erlang:nodes(visible);
+ connected ->
+ erlang:nodes(connected);
+ db_nodes ->
+ try mnesia:system_info(db_nodes) of
+ DbNodes when is_list(DbNodes) ->
+ DbNodes;
+ _ ->
+ erlang:nodes()
+ catch
+ _:_ ->
+ erlang:nodes()
+ end
+ end.
+
+%% user_err(F, A) ->
+%% snmpa_error:user_err(F, A).
diff --git a/lib/snmp/src/agent/snmpa_misc_sup.erl b/lib/snmp/src/agent/snmpa_misc_sup.erl
index 488d3f7921..746405ec1d 100644
--- a/lib/snmp/src/agent/snmpa_misc_sup.erl
+++ b/lib/snmp/src/agent/snmpa_misc_sup.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
diff --git a/lib/snmp/src/agent/snmpa_mpd.erl b/lib/snmp/src/agent/snmpa_mpd.erl
index 2d37ea56f0..b440d57d03 100644
--- a/lib/snmp/src/agent/snmpa_mpd.erl
+++ b/lib/snmp/src/agent/snmpa_mpd.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2015. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
+%% 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
%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -20,7 +21,7 @@
-export([init/1, reset/0, inc/1, counters/0,
discarded_pdu/1,
- process_packet/6, process_packet/7,
+ process_packet/5, process_packet/6, process_packet/7,
generate_response_msg/5, generate_response_msg/6,
generate_msg/5, generate_msg/6,
generate_discovery_msg/4,
@@ -75,8 +76,9 @@
init(Vsns) ->
?vlog("init -> entry with"
"~n Vsns: ~p", [Vsns]),
- {A,B,C} = erlang:now(),
- random:seed(A,B,C),
+ 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)}),
init_counters(),
@@ -113,22 +115,30 @@ reset() ->
% length(snmp_pdus:enc_message(M)) + 4.
%%-----------------------------------------------------------------
-%% Func: process_packet(Packet, TDomain, TAddress, State, Log) ->
+%% Func: process_packet(Packet, Domain, Address, State, Log) ->
%% {ok, SnmpVsn, Pdu, PduMS, ACMData} | {discarded, Reason}
%% Types: Packet = binary()
-%% TDomain = snmpUDPDomain | transportDomain()
-%% TAddress = {Ip, Udp} (*but* depends on TDomain)
+%% Domain = snmpUDPDomain | transportDomain()
+%% Address = {Ip, Udp} (*but* depends on Domain)
%% State = #state
%% Purpose: This is the main Message Dispatching function. (see
%% section 4.2.1 in rfc2272)
%%-----------------------------------------------------------------
-process_packet(Packet, TDomain, TAddress, State, NoteStore, Log) ->
+process_packet(Packet, From, State, NoteStore, Log) ->
LocalEngineID = ?DEFAULT_LOCAL_ENGINE_ID,
- process_packet(Packet, TDomain, TAddress, LocalEngineID,
- State, NoteStore, Log).
-
-process_packet(Packet, TDomain, TAddress, LocalEngineID,
- State, NoteStore, Log) ->
+ process_packet(Packet, From, LocalEngineID, State, NoteStore, Log).
+
+process_packet(
+ Packet, Domain, Address, LocalEngineID, State, NoteStore, Log) ->
+ From = {Domain, Address},
+ process_packet(Packet, From, LocalEngineID, State, NoteStore, Log).
+
+process_packet(Packet, Domain, Address, State, NoteStore, Log)
+ when is_atom(Domain) ->
+ LocalEngineID = ?DEFAULT_LOCAL_ENGINE_ID,
+ From = {Domain, Address},
+ process_packet(Packet, From, LocalEngineID, State, NoteStore, Log);
+process_packet(Packet, From, LocalEngineID, State, NoteStore, Log) ->
inc(snmpInPkts),
case catch snmp_pdus:dec_message_only(binary_to_list(Packet)) of
@@ -136,17 +146,17 @@ process_packet(Packet, TDomain, TAddress, LocalEngineID,
when State#state.v1 =:= true ->
?vlog("v1, community: ~s", [Community]),
HS = ?empty_msg_size + length(Community),
- v1_v2c_proc('version-1', NoteStore, Community,
- TDomain, TAddress,
- LocalEngineID, Data, HS, Log, Packet);
+ v1_v2c_proc(
+ 'version-1', NoteStore, Community, From,
+ LocalEngineID, Data, HS, Log, Packet);
#message{version = 'version-2', vsn_hdr = Community, data = Data}
when State#state.v2c =:= true ->
?vlog("v2c, community: ~s", [Community]),
HS = ?empty_msg_size + length(Community),
- v1_v2c_proc('version-2', NoteStore, Community,
- TDomain, TAddress,
- LocalEngineID, Data, HS, Log, Packet);
+ v1_v2c_proc(
+ 'version-2', NoteStore, Community, From,
+ LocalEngineID, Data, HS, Log, Packet);
#message{version = 'version-3', vsn_hdr = V3Hdr, data = Data}
when State#state.v3 =:= true ->
@@ -154,9 +164,9 @@ process_packet(Packet, TDomain, TAddress, LocalEngineID,
[V3Hdr#v3_hdr.msgID,
V3Hdr#v3_hdr.msgFlags,
V3Hdr#v3_hdr.msgSecurityModel]),
- v3_proc(NoteStore, Packet,
- TDomain, TAddress,
- LocalEngineID, V3Hdr, Data, Log);
+ v3_proc(
+ NoteStore, Packet, From,
+ LocalEngineID, V3Hdr, Data, Log);
{'EXIT', {bad_version, Vsn}} ->
?vtrace("exit: bad version: ~p",[Vsn]),
@@ -183,11 +193,32 @@ discarded_pdu(Variable) -> inc(Variable).
%%-----------------------------------------------------------------
%% Handles a Community based message (v1 or v2c).
%%-----------------------------------------------------------------
-v1_v2c_proc(Vsn, NoteStore, Community, Domain,
- {Ip, Udp}, LocalEngineID,
- Data, HS, Log, Packet) ->
- TDomain = snmp_conf:mk_tdomain(Domain),
- TAddress = snmp_conf:mk_taddress(Domain, Ip, Udp),
+v1_v2c_proc(
+ Vsn, NoteStore, Community, From,
+ LocalEngineID, Data, HS, Log, Packet) ->
+ try
+ case From of
+ {D, A} when is_atom(D) ->
+ {snmp_conf:mk_tdomain(D),
+ snmp_conf:mk_taddress(D, A)};
+ {_, P} = A when is_integer(P) ->
+ {snmp_conf:mk_tdomain(),
+ snmp_conf:mk_taddress(A)}
+ end
+ of
+ {TDomain, TAddress} ->
+ v1_v2c_proc_dec(
+ Vsn, NoteStore, Community, TDomain, TAddress,
+ LocalEngineID, Data, HS, Log, Packet)
+ catch
+ _ ->
+ {discarded, {badarg, From}}
+ end.
+
+
+v1_v2c_proc_dec(
+ Vsn, NoteStore, Community, TDomain, TAddress,
+ LocalEngineID, Data, HS, Log, Packet) ->
AgentMS = get_engine_max_message_size(LocalEngineID),
MgrMS = snmp_community_mib:get_target_addr_ext_mms(TDomain, TAddress),
PduMS = case MgrMS of
@@ -214,7 +245,7 @@ v1_v2c_proc(Vsn, NoteStore, Community, Domain,
case Pdu#pdu.type of
'set-request' ->
%% Check if this message has already been processed
- Key = {agent, Ip, ReqId},
+ Key = {agent, {TDomain, TAddress}, ReqId},
case snmp_note_store:get_note(NoteStore, Key) of
undefined ->
%% Set the processed note _after_ pdu processing.
@@ -236,13 +267,7 @@ v1_v2c_proc(Vsn, NoteStore, Community, Domain,
{discarded, Reason};
_TrapPdu ->
{discarded, trap_pdu}
- end;
-v1_v2c_proc(_Vsn, _NoteStore, _Community, snmpUDPDomain, TAddress,
- _LocalEngineID, _Data, _HS, _Log, _Packet) ->
- {discarded, {badarg, TAddress}};
-v1_v2c_proc(_Vsn, _NoteStore, _Community, TDomain, _TAddress,
- _LocalEngineID, _Data, _HS, _Log, _Packet) ->
- {discarded, {badarg, TDomain}}.
+ end.
sec_model('version-1') -> ?SEC_V1;
sec_model('version-2') -> ?SEC_V2C.
@@ -252,8 +277,7 @@ sec_model('version-2') -> ?SEC_V2C.
%% Handles a SNMPv3 Message, following the procedures in rfc2272,
%% section 4.2 and 7.2
%%-----------------------------------------------------------------
-v3_proc(NoteStore, Packet, _TDomain, _TAddress, LocalEngineID,
- V3Hdr, Data, Log) ->
+v3_proc(NoteStore, Packet, _From, LocalEngineID, V3Hdr, Data, Log) ->
case (catch v3_proc(NoteStore, Packet, LocalEngineID, V3Hdr, Data, Log)) of
{'EXIT', Reason} ->
exit(Reason);
@@ -657,7 +681,7 @@ generate_response_msg(Vsn, RePdu, Type,
?SEC_USM ->
snmpa_usm
end,
- SecEngineID = LocalEngineID,
+ SecEngineID = LocalEngineID, % 3.1.1a
?vtrace("generate_response_msg -> SecEngineID: ~w", [SecEngineID]),
case (catch SecModule:generate_outgoing_msg(Message,
SecEngineID,
@@ -749,21 +773,7 @@ generate_v3_report_msg(MsgID, MsgSecurityModel, Data, LocalEngineID,
ContextEngineID, ContextName, SecData},
LocalEngineID, Log).
-%% req_id(#scopedPdu{data = #pdu{request_id = ReqId}}) ->
-%% ?vtrace("Report ReqId: ~p",[ReqId]),
-%% ReqId;
-%% req_id(_) ->
-%% 0. % RFC2572, 7.1.3.c.4
-
-%% maybe_generate_discovery1_report_msg() ->
-%% case (catch DiscoveryHandler:handle_discovery1(Ip, Udp, EngineId)) of
-%% {ok, Entry} when is_record(Entry, snmp_discovery_data1) ->
-%% ok;
-%% ignore ->
-%% ok;
-%% {error, Reason} ->
-
%% Response to stage 1 discovery message (terminating, i.e. from the manager)
generate_discovery1_report_msg(MsgID, MsgSecurityModel,
SecName, SecLevel,
@@ -999,7 +1009,7 @@ generate_discovery_msg(NoteStore, {TDomain, TAddress},
InitialUserName,
ContextName, Timeout) ->
- {ok, {_Domain, Address}} = transform_taddr(TDomain, TAddress),
+ {ok, {Domain, Address}} = transform_taddr(TDomain, TAddress),
%% 7.1.7
?vdebug("generate_discovery_msg -> 7.1.7 (~w)", [ManagerEngineID]),
@@ -1041,7 +1051,7 @@ generate_discovery_msg(NoteStore, {TDomain, TAddress},
%% Log(Packet),
inc_snmp_out_vars(Pdu),
?vdebug("generate_discovery_msg -> done", []),
- {Packet, Address};
+ {Domain, Address, Packet};
Error ->
throw(Error)
@@ -1081,8 +1091,22 @@ transform_taddr(?transportDomainUdpIpv4, [A, B, C, D, P1, P2]) ->
{ok, {Domain, Address}};
transform_taddr(?transportDomainUdpIpv4, BadAddr) ->
{error, {bad_transportDomainUdpIpv4_address, BadAddr}};
-transform_taddr(?transportDomainUdpIpv6,
- [A1, A2, A3, A4, A5, A6, A7, A8, P1, P2]) ->
+transform_taddr(
+ ?transportDomainUdpIpv6,
+ [A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16,
+ P1, P2]) ->
+ Domain = transportDomainUdpIpv6,
+ Addr =
+ {(A1 bsl 8) bor A2, (A3 bsl 8) bor A4,
+ (A5 bsl 8) bor A6, (A7 bsl 8) bor A8,
+ (A9 bsl 8) bor A10, (A11 bsl 8) bor A12,
+ (A13 bsl 8) bor A14, (A15 bsl 8) bor A16},
+ Port = P1 bsl 8 + P2,
+ Address = {Addr, Port},
+ {ok, {Domain, Address}};
+transform_taddr(
+ ?transportDomainUdpIpv6,
+ [A1, A2, A3, A4, A5, A6, A7, A8, P1, P2]) ->
Domain = transportDomainUdpIpv6,
Addr = {A1, A2, A3, A4, A5, A6, A7, A8},
Port = P1 bsl 8 + P2,
@@ -1171,6 +1195,9 @@ mk_v1_v2_packet_list([{Domain, Addr} | T],
%% Sending from default UDP port
inc_snmp_out_vars(Pdu),
Entry = {Domain, Addr, Packet},
+ %% It would be cleaner to return {To, Packet} to not
+ %% break the abstraction for an address on the
+ %% {Domain, Address} format.
mk_v1_v2_packet_list(T, Packet, Len, Pdu, [Entry | Acc]).
@@ -1277,6 +1304,9 @@ mk_v3_packet_entry(NoteStore, Domain, Addr,
req_id = Pdu#pdu.request_id},
snmp_note_store:set_note(NoteStore, 1500, CacheKey, CacheVal),
inc_snmp_out_vars(Pdu),
+ %% It would be cleaner to return {To, Packet} to not
+ %% break the abstraction for an address on the
+ %% {Domain, Address} format.
{ok, {Domain, Addr, Data}}
end.
diff --git a/lib/snmp/src/agent/snmpa_net_if.erl b/lib/snmp/src/agent/snmpa_net_if.erl
index 79c85a6e4e..ecf9498ca9 100644
--- a/lib/snmp/src/agent/snmpa_net_if.erl
+++ b/lib/snmp/src/agent/snmpa_net_if.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2015. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -35,18 +36,27 @@
-include("snmp_debug.hrl").
-include("snmp_verbosity.hrl").
--record(state, {parent,
- note_store,
- master_agent,
- usock,
- usock_opts,
- mpd_state,
- log,
- reqs = [],
- debug = false,
- limit = infinity,
- rcnt = [],
- filter}).
+-record(state,
+ {parent,
+ note_store,
+ master_agent,
+ transports = [],
+%% usock,
+%% usock_opts,
+ mpd_state,
+ log,
+ reqs = [],
+ debug = false,
+ limit = infinity,
+%% rcnt = [],
+ filter}).
+%% domain = snmpUDPDomain}).
+
+-record(transport,
+ {socket,
+ domain = snmpUDPDomain,
+ opts = [],
+ req_refs = []}).
-ifndef(default_verbosity).
-define(default_verbosity,silence).
@@ -104,13 +114,9 @@ get_request_limit(Pid) ->
set_request_limit(Pid, NewLimit) ->
call(Pid, {set_request_limit, NewLimit}).
-get_port() ->
- {value, UDPPort} = snmp_framework_mib:intAgentUDPPort(get),
- UDPPort.
-
-get_address() ->
- {value, IPAddress} = snmp_framework_mib:intAgentIpAddress(get),
- IPAddress.
+get_transports() ->
+ {value, Transports} = snmp_framework_mib:intAgentTransports(get),
+ Transports.
filter_reset(Pid) ->
Pid ! filter_reset.
@@ -129,7 +135,22 @@ init(Prio, NoteStore, MasterAgent, Parent, Opts) ->
case (catch do_init(Prio, NoteStore, MasterAgent, Parent, Opts)) of
{ok, State} ->
proc_lib:init_ack({ok, self()}),
- loop(State);
+ try loop(State)
+ catch
+ C:E when C =/= exit, E =/= shutdown ->
+ Fmt =
+ "loop/1 EXCEPTION ~w:~w~n"
+ " ~p",
+ S = erlang:get_stacktrace(),
+ case C of
+ exit ->
+ %% Externally killed, root cause is elsewhere
+ info_msg(Fmt, [C, E, S]);
+ _ ->
+ error_msg(Fmt, [C, E, S])
+ end,
+ erlang:raise(C, E, S)
+ end;
{error, Reason} ->
config_err("failed starting net-if: ~n~p", [Reason]),
proc_lib:init_ack({error, Reason});
@@ -147,12 +168,6 @@ do_init(Prio, NoteStore, MasterAgent, Parent, Opts) ->
put(verbosity,get_verbosity(Opts)),
?vlog("starting",[]),
- %% -- Port and address --
- UDPPort = get_port(),
- ?vdebug("port: ~w",[UDPPort]),
- IPAddress = get_address(),
- ?vdebug("addr: ~w",[IPAddress]),
-
%% -- Versions --
Vsns = get_vsns(Opts),
?vdebug("vsns: ~w",[Vsns]),
@@ -162,39 +177,45 @@ do_init(Prio, NoteStore, MasterAgent, Parent, Opts) ->
?vdebug("Limit: ~w", [Limit]),
FilterOpts = get_filter_opts(Opts),
FilterMod = create_filter(FilterOpts),
- ?vdebug("FilterMod: ~w", [FilterMod]),
+ ?vdebug("FilterMod: ~w FilterOpts: ~p", [FilterMod,FilterOpts]),
%% -- Audit trail log
Log = create_log(),
?vdebug("Log: ~w",[Log]),
-
- %% -- Socket --
- IPOpts1 = ip_opt_bind_to_ip_address(Opts, IPAddress),
- IPOpts2 = ip_opt_no_reuse_address(Opts),
- IPOpts3 = ip_opt_recbuf(Opts),
- IPOpts4 = ip_opt_sndbuf(Opts),
- IPOpts = [binary | IPOpts1 ++ IPOpts2 ++ IPOpts3 ++ IPOpts4],
- ?vdebug("open socket with options: ~w",[IPOpts]),
- case gen_udp_open(UDPPort, IPOpts) of
- {ok, Sock} ->
+ DomainAddresses = get_transports(),
+ ?vdebug("DomainAddresses: ~w",[DomainAddresses]),
+ try
+ [begin
+ SocketOpts = socket_opts(Domain, Address, Opts),
+ Socket = socket_open(Domain, SocketOpts),
+ active_once(Socket),
+ #transport{
+ socket = Socket,
+ domain = Domain,
+ opts = SocketOpts}
+ end || {Domain, Address} <- DomainAddresses]
+ of
+ [] ->
+ ?vinfo("No transports configured: ~p", [DomainAddresses]),
+ {error, {no_transports,DomainAddresses}};
+ Transports ->
MpdState = snmpa_mpd:init(Vsns),
- init_counters(),
- active_once(Sock),
+ init_counters(),
S = #state{parent = Parent,
note_store = NoteStore,
master_agent = MasterAgent,
mpd_state = MpdState,
- usock = Sock,
- usock_opts = IPOpts,
+ transports = Transports,
log = Log,
limit = Limit,
filter = FilterMod},
?vdebug("started with MpdState: ~p", [MpdState]),
- {ok, S};
- {error, Reason} ->
- ?vinfo("Failed to open UDP socket: ~p", [Reason]),
- {error, {udp_open, UDPPort, Reason}}
+ {ok, S}
+ catch
+ Error ->
+ ?vinfo("Failed to initialize socket(s): ~p", [Error]),
+ {error, Error}
end.
@@ -250,48 +271,84 @@ create_filter(BadOpts) ->
throw({error, {bad_filter_opts, BadOpts}}).
-log({_, []}, _, _, _, _) ->
+log({_, []}, _, _, _) ->
ok;
-log({Log, Types}, 'set-request', Packet, Addr, Port) ->
+log({Log, Types}, 'set-request', Packet, Address) ->
case lists:member(write, Types) of
true ->
- snmp_log:log(Log, Packet, Addr, Port);
+ snmp_log:log(Log, Packet, format_address(Address));
false ->
ok
end;
-log({Log, Types}, _, Packet, Addr, Port) ->
+log({Log, Types}, _, Packet, Address) ->
case lists:member(read, Types) of
true ->
- snmp_log:log(Log, Packet, Addr, Port);
+ snmp_log:log(Log, Packet, format_address(Address));
false ->
ok
- end;
-log(_, _, _, _, _) ->
- ok.
-
-
-gen_udp_open(Port, Opts) ->
+ end.
+
+format_address(Address) ->
+ iolist_to_binary(snmp_conf:mk_addr_string(Address)).
+
+
+socket_open(snmpUDPDomain = Domain, [IpPort | Opts]) ->
case init:get_argument(snmp_fd) of
{ok, [[FdStr]]} ->
Fd = list_to_integer(FdStr),
- gen_udp:open(0, [{fd, Fd}|Opts]);
+ ?vdebug("socket_open(~p, [~p | ~p]) Fd: ~p",
+ [Domain, IpPort, Opts, Fd]),
+ gen_udp_open(0, [{fd, Fd} | Opts]);
error ->
case init:get_argument(snmpa_fd) of
{ok, [[FdStr]]} ->
Fd = list_to_integer(FdStr),
- gen_udp:open(0, [{fd, Fd}|Opts]);
+ ?vdebug("socket_open(~p, [~p | ~p]) Fd: ~p",
+ [Domain, IpPort, Opts, Fd]),
+ gen_udp_open(0, [{fd, Fd} | Opts]);
error ->
- gen_udp:open(Port, Opts)
+ ?vdebug("socket_open(~p, [~p | ~p])",
+ [Domain, IpPort, Opts]),
+ gen_udp_open(IpPort, Opts)
end
+ end;
+socket_open(Domain, [IpPort | Opts])
+ when Domain =:= transportDomainUdpIpv4;
+ Domain =:= transportDomainUdpIpv6 ->
+ ?vdebug("socket_open(~p, [~p | ~p])", [Domain, IpPort, Opts]),
+ gen_udp_open(IpPort, Opts);
+socket_open(Domain, Opts) ->
+ throw({socket_open, Domain, Opts}).
+
+gen_udp_open(IpPort, Opts) ->
+ case gen_udp:open(IpPort, Opts) of
+ {ok, Socket} ->
+ Socket;
+ {error, Reason} ->
+ throw({udp_open, IpPort, Reason})
end.
-loop(S) ->
+
+loop(#state{transports = Transports, limit = Limit, parent = Parent} = S) ->
+ ?vdebug("loop(~p)", [S]),
receive
- {udp, _UdpId, Ip, Port, Packet} ->
- ?vlog("got paket from ~w:~w",[Ip,Port]),
- NewS = maybe_handle_recv(S, Ip, Port, Packet),
- loop(NewS);
+ {udp, Socket, IpAddr, IpPort, Packet} = Msg when is_port(Socket) ->
+ ?vlog("got paket from ~w:~w on ~w", [IpAddr, IpPort, Socket]),
+ case lists:keyfind(Socket, #transport.socket, Transports) of
+ #transport{socket = Socket, domain = Domain} = Transport ->
+ From =
+ case Domain of
+ snmpUDPDomain ->
+ {IpAddr, IpPort};
+ _ ->
+ {Domain, {IpAddr, IpPort}}
+ end,
+ loop(maybe_handle_recv(S, Transport, From, Packet));
+ false ->
+ error_msg("Packet on unknown port: ~p", [Msg]),
+ loop(S)
+ end;
{info, ReplyRef, Pid} ->
Info = get_info(S),
@@ -299,47 +356,78 @@ loop(S) ->
loop(S);
%% response (to get/get_next/get_bulk/set requests)
- {snmp_response, Vsn, RePdu, Type, ACMData, Dest, []} ->
+ {snmp_response, Vsn, RePdu, Type, ACMData, To, Extra} ->
?vlog("reply pdu: "
"~n ~s",
[?vapply(snmp_misc, format, [256, "~w", [RePdu]])]),
- NewS = maybe_handle_reply_pdu(S, Vsn, RePdu, Type, ACMData, Dest),
- loop(NewS);
+ {_, ReqRef} = lists:keyfind(request_ref, 1, Extra),
+ case
+ case
+ (Limit =/= infinity) andalso
+ select_transport_from_req_ref(ReqRef, Transports)
+ of
+ false ->
+ select_transport_from_domain(
+ address_to_domain(To),
+ Transports);
+ T ->
+ T
+ end
+ of
+ false ->
+ error_msg(
+ "Can not find transport for response PDU to: ~s",
+ [format_address(To)]),
+ loop(S);
+ Transport ->
+ NewS = update_req_counter_outgoing(S, Transport, ReqRef),
+ maybe_handle_reply_pdu(
+ NewS, Transport, Vsn, RePdu, Type, ACMData, To),
+ loop(NewS)
+ end;
%% Traps/notification
- {send_pdu, Vsn, Pdu, MsgData, To} ->
- ?vdebug("send pdu: "
- "~n Pdu: ~p"
- "~n To: ~p", [Pdu, To]),
- NewS = maybe_handle_send_pdu(S, Vsn, Pdu, MsgData, To, undefined),
+ {send_pdu, Vsn, Pdu, MsgData, TDomAddrs} ->
+ ?vdebug("send pdu:~n"
+ " Pdu: ~p~n"
+ " TDomAddrs: ~p", [Pdu, TDomAddrs]),
+ NewS =
+ maybe_handle_send_pdu(
+ S, Vsn, Pdu, MsgData, TDomAddrs, undefined),
loop(NewS);
%% We dont use the extra-info at this time, ...
- {send_pdu, Vsn, Pdu, MsgData, To, _ExtraInfo} ->
- ?vdebug("send pdu: "
- "~n Pdu: ~p"
- "~n To: ~p", [Pdu, To]),
- NewS = maybe_handle_send_pdu(S, Vsn, Pdu, MsgData, To, undefined),
+ {send_pdu, Vsn, Pdu, MsgData, TDomAddrs, _ExtraInfo} ->
+ ?vdebug("send pdu:~n"
+ " Pdu: ~p~n"
+ " TDomAddrs: ~p", [Pdu, TDomAddrs]),
+ NewS =
+ maybe_handle_send_pdu(
+ S, Vsn, Pdu, MsgData, TDomAddrs, undefined),
loop(NewS);
%% Informs
- {send_pdu_req, Vsn, Pdu, MsgData, To, From} ->
- ?vdebug("send pdu request: "
- "~n Pdu: ~p"
- "~n To: ~p"
- "~n From: ~p",
- [Pdu, To, toname(From)]),
- NewS = maybe_handle_send_pdu(S, Vsn, Pdu, MsgData, To, From),
+ {send_pdu_req, Vsn, Pdu, MsgData, TDomAddrs, From} ->
+ ?vdebug("send pdu request:~n"
+ " Pdu: ~p~n"
+ " TDomAddrs: ~p~n"
+ " From: ~p",
+ [Pdu, TDomAddrs, toname(From)]),
+ NewS =
+ maybe_handle_send_pdu(
+ S, Vsn, Pdu, MsgData, TDomAddrs, From),
loop(NewS);
%% We dont use the extra-info at this time, ...
- {send_pdu_req, Vsn, Pdu, MsgData, To, From, _ExtraInfo} ->
- ?vdebug("send pdu request: "
- "~n Pdu: ~p"
- "~n To: ~p"
- "~n From: ~p",
- [Pdu, To, toname(From)]),
- NewS = maybe_handle_send_pdu(S, Vsn, Pdu, MsgData, To, From),
+ {send_pdu_req, Vsn, Pdu, MsgData, TDomAddrs, From, _ExtraInfo} ->
+ ?vdebug("send pdu request:~n"
+ " Pdu: ~p~n"
+ " TDomAddrs: ~p~n"
+ " From: ~p",
+ [Pdu, TDomAddrs, toname(From)]),
+ NewS =
+ maybe_handle_send_pdu(
+ S, Vsn, Pdu, MsgData, TDomAddrs, From),
loop(NewS);
%% Discovery Inform
@@ -365,15 +453,34 @@ loop(S) ->
NewS = handle_send_discovery(S, Pdu, MsgData, To, From),
loop(NewS);
- {discarded_pdu, _Vsn, ReqId, _ACMData, Variable, _Extra} ->
- ?vdebug("discard PDU: ~p", [Variable]),
+ {discarded_pdu, _Vsn, ReqId, _ACMData, Variable, Extra} ->
+ ?vdebug("discard PDU: ~p - ~p - ~p",
+ [Variable, Extra, Transports]),
snmpa_mpd:discarded_pdu(Variable),
- NewS = update_req_counter_outgoing(S, ReqId),
- loop(NewS);
+ {_, ReqRef} = lists:keyfind(request_ref, 1, Extra),
+ if
+ Limit =:= infinity ->
+ %% The incoming PDU was not registered
+ loop(update_req_counter_outgoing(S, false, ReqRef));
+ true ->
+ case
+ select_transport_from_req_ref(ReqRef, Transports)
+ of
+ false ->
+ error_msg(
+ "Can not find transport for discarded PDU: ~p",
+ [ReqId]),
+ loop(S);
+ Transport ->
+ loop(
+ update_req_counter_outgoing(
+ S, Transport, ReqRef))
+ end
+ end;
{get_log_type, ReplyRef, Pid} ->
?vdebug("get log type: ~p", []),
- #state{log = {_, LogType}} = S,
+ {_, LogType} = S#state.log,
Pid ! {ReplyRef, {ok, LogType}, self()},
loop(S);
@@ -385,7 +492,6 @@ loop(S) ->
{get_request_limit, ReplyRef, Pid} ->
?vdebug("get request limit: ~p", []),
- #state{limit = Limit} = S,
Pid ! {ReplyRef, {ok, Limit}, self()},
loop(S);
@@ -409,36 +515,50 @@ loop(S) ->
reset_counters(),
loop(S);
- {'EXIT', Parent, Reason} when Parent == S#state.parent ->
+ {'EXIT', Parent, Reason} ->
?vlog("parent (~p) exited: "
"~n ~p", [Parent, Reason]),
exit(Reason);
- {'EXIT', Port, Reason} when Port == S#state.usock ->
- UDPPort = get_port(),
- NewS =
- case gen_udp_open(UDPPort, S#state.usock_opts) of
- {ok, Id} ->
- error_msg("Port ~p exited for reason"
- "~n ~p"
- "~n Re-opened (~p)", [Port, Reason, Id]),
- S#state{usock = Id};
- {error, ReopenReason} ->
- error_msg("Port ~p exited for reason"
- "~n ~p"
- "~n Re-open failed with reason"
- "~n ~p",
- [Port, Reason, ReopenReason]),
- ok
- end,
- loop(NewS);
-
- {'EXIT', Port, Reason} when is_port(Port) ->
- error_msg("Exit message from port ~p for reason ~p~n",
- [Port, Reason]),
- loop(S);
-
- {'EXIT', Pid, Reason} ->
+ {'EXIT', Socket, Reason} when is_port(Socket) ->
+ case lists:keyfind(Socket, #transport.socket, Transports) of
+ #transport{
+ socket = Socket,
+ domain = Domain,
+ opts = SocketOpts,
+ req_refs = ReqRefs} = Transport ->
+ try socket_open(Domain, SocketOpts) of
+ NewSocket ->
+ error_msg(
+ "Socket ~p exited for reason"
+ "~n ~p"
+ "~n Re-opened (~p)",
+ [Socket, Reason, NewSocket]),
+ (length(ReqRefs) < Limit) andalso
+ active_once(NewSocket),
+ S#state{
+ transports =
+ lists:keyreplace(
+ Socket, #transport.socket, Transports,
+ Transport#transport{socket = NewSocket})}
+ catch
+ ReopenReason ->
+ error_msg(
+ "Socket ~p exited for reason"
+ "~n ~p"
+ "~n Re-open failed with reason"
+ "~n ~p",
+ [Socket, Reason, ReopenReason]),
+ exit(ReopenReason)
+ end;
+ false ->
+ error_msg(
+ "Exit message from port ~p for reason ~p~n",
+ [Socket, Reason]),
+ loop(S)
+ end;
+
+ {'EXIT', Pid, Reason} when is_pid(Pid) ->
?vlog("~p exited: "
"~n ~p", [Pid, Reason]),
NewS = clear_reqs(Pid, S),
@@ -446,205 +566,321 @@ loop(S) ->
{system, From, Msg} ->
?vdebug("system event ~p from ~p", [Msg, From]),
- sys:handle_system_msg(Msg, From, S#state.parent, ?MODULE, [], S);
+ sys:handle_system_msg(Msg, From, Parent, ?MODULE, [], S);
_ ->
loop(S)
end.
-update_req_counter_incomming(#state{limit = infinity, usock = Sock} = S, _) ->
- active_once(Sock), %% No limit so activate directly
+update_req_counter_incoming(
+ #state{limit = infinity} = S,
+ #transport{socket = Socket},
+ _ReqRef) ->
+ active_once(Socket), %% No limit so activate directly
S;
-update_req_counter_incomming(#state{limit = Limit,
- rcnt = RCnt,
- usock = Sock} = S, Rid)
- when length(RCnt) + 1 == Limit ->
+update_req_counter_incoming(
+ #state{limit = Limit} = S,
+ #transport{socket = Socket, req_refs = ReqRefs} = T,
+ ReqRef) when length(ReqRefs) + 1 >= Limit ->
%% Ok, one more and we are at the limit.
%% Just make sure we are not already processing this one...
- case lists:member(Rid, RCnt) of
+ case lists:member(ReqRef, ReqRefs) of
false ->
%% We are at the limit, do _not_ activate socket
- S#state{rcnt = [Rid|RCnt]};
+ update_transport_req_refs(S, T, [ReqRef | ReqRefs]);
true ->
- active_once(Sock),
+ active_once(Socket),
S
end;
-update_req_counter_incomming(#state{rcnt = RCnt,
- usock = Sock} = S, Rid) ->
- active_once(Sock),
- case lists:member(Rid, RCnt) of
+update_req_counter_incoming(
+ #state{} = S,
+ #transport{socket = Socket, req_refs = ReqRefs} = T,
+ ReqRef) ->
+ active_once(Socket),
+ case lists:member(ReqRef, ReqRefs) of
false ->
- S#state{rcnt = [Rid|RCnt]};
+ update_transport_req_refs(S, T, [ReqRef | ReqRefs]);
true ->
S
end.
-
-update_req_counter_outgoing(#state{limit = infinity} = S, _Rid) ->
+update_req_counter_outgoing(
+ #state{limit = infinity} = S,
+ _Transport, _ReqRef) ->
%% Already activated (in the incoming function)
S;
-update_req_counter_outgoing(#state{limit = Limit,
- rcnt = RCnt,
- usock = Sock} = S, Rid)
- when length(RCnt) == Limit ->
- ?vtrace("handle_req_counter_outgoing(~w) -> entry with"
- "~n Rid: ~w"
- "~n length(RCnt): ~w", [Limit, Rid, length(RCnt)]),
- case lists:delete(Rid, RCnt) of
- NewRCnt when length(NewRCnt) < Limit ->
+update_req_counter_outgoing(
+ #state{limit = Limit} = S,
+ #transport{socket = Socket, req_refs = ReqRefs} = Transport,
+ ReqRef) ->
+ LengthReqRefs = length(ReqRefs),
+ ?vtrace("update_req_counter_outgoing() -> entry with~n"
+ " Limit: ~w~n"
+ " ReqRef: ~w~n"
+ " length(ReqRefs): ~w", [Limit, ReqRef, LengthReqRefs]),
+ NewReqRefs = lists:delete(ReqRef, ReqRefs),
+ (LengthReqRefs >= Limit) andalso (length(NewReqRefs) < Limit) andalso
+ begin
?vtrace("update_req_counter_outgoing -> "
- "passed below limit: activate", []),
- active_once(Sock),
- S#state{rcnt = NewRCnt};
- _ ->
- S
- end;
-update_req_counter_outgoing(#state{limit = Limit, rcnt = RCnt} = S,
- Rid) ->
- ?vtrace("handle_req_counter_outgoing(~w) -> entry with"
- "~n Rid: ~w"
- "~n length(RCnt): ~w", [Limit, Rid, length(RCnt)]),
- NewRCnt = lists:delete(Rid, RCnt),
- S#state{rcnt = NewRCnt}.
-
-
-maybe_handle_recv(#state{usock = Sock, filter = FilterMod} = S,
- Ip, Port, Packet) ->
- case (catch FilterMod:accept_recv(Ip, Port)) of
+ "passed below limit: activate", []),
+ active_once(Socket)
+ end,
+ update_transport_req_refs(S, Transport, NewReqRefs).
+
+update_transport_req_refs(
+ #state{transports = Transports} = S,
+ #transport{socket = Socket} = T,
+ ReqRefs) ->
+ S#state{
+ transports =
+ lists:keyreplace(
+ Socket, #transport.socket, Transports,
+ T#transport{req_refs = ReqRefs})}.
+
+
+maybe_handle_recv(
+ #state{filter = FilterMod} = S,
+ #transport{socket = Socket} = Transport,
+ From, Packet) ->
+ {From_1, From_2} = From,
+ case
+ try FilterMod:accept_recv(From_1, From_2)
+ catch
+ Class:Exception ->
+ error_msg(
+ "FilterMod:accept_recv(~p, ~p) crashed: ~w:~w~n ~p",
+ [From_1,From_2,Class,Exception,erlang:get_stacktrace()]),
+ true
+ end
+ of
false ->
%% Drop the received packet
inc(netIfMsgInDrops),
- active_once(Sock),
+ active_once(Socket),
S;
- _ ->
- handle_recv(S, Ip, Port, Packet)
+ Other ->
+ case Other of
+ true ->
+ ok;
+ _ ->
+ error_msg(
+ "FilterMod:accept_recv(~p, ~p) returned: ~p",
+ [From_1,From_2,Other])
+ end,
+ handle_recv(S, Transport, From, Packet)
end.
-handle_discovery_response(_Ip, _Port, #pdu{request_id = ReqId} = Pdu,
- ManagerEngineId,
- #state{usock = Sock, reqs = Reqs} = S) ->
- case lists:keysearch(ReqId, 1, S#state.reqs) of
- {value, {_, Pid}} ->
- active_once(Sock),
- Pid ! {snmp_discovery_response_received, Pdu, ManagerEngineId},
- NReqs = lists:keydelete(ReqId, 1, Reqs),
- S#state{reqs = NReqs};
- _ ->
- %% Ouch, timeout? resend?
- S
- end.
-
-handle_recv(#state{usock = Sock,
- mpd_state = MpdState,
- note_store = NS,
- log = Log} = S, Ip, Port, Packet) ->
- put(n1, erlang:now()),
- LogF = fun(Type, Data) ->
- log(Log, Type, Data, Ip, Port)
- end,
- Domain = snmp_conf:which_domain(Ip), % What the ****...
- case (catch snmpa_mpd:process_packet(Packet,
- Domain, {Ip, Port},
- MpdState, NS, LogF)) of
+handle_recv(
+ #state{mpd_state = MpdState, note_store = NS, log = Log} = S,
+ #transport{socket = Socket} = Transport,
+ From, Packet) ->
+ put(n1, erlang:monotonic_time(micro_seconds)),
+ LogF =
+ fun(Type, Data) ->
+ log(Log, Type, Data, From)
+ end,
+ case (catch snmpa_mpd:process_packet(
+ Packet, From, MpdState, NS, LogF)) of
{ok, _Vsn, Pdu, _PduMS, {discovery, ManagerEngineId}} ->
- handle_discovery_response(Ip, Port, Pdu, ManagerEngineId, S);
+ handle_discovery_response(
+ S, Transport, From, Pdu, ManagerEngineId);
{ok, _Vsn, Pdu, _PduMS, discovery} ->
- handle_discovery_response(Ip, Port, Pdu, undefined, S);
+ handle_discovery_response(
+ S, Transport, From, Pdu, undefined);
{ok, Vsn, Pdu, PduMS, ACMData} ->
?vlog("got pdu ~s",
[?vapply(snmp_misc, format, [256, "~w", [Pdu]])]),
- %% handle_recv_pdu(Ip, Port, Vsn, Pdu, PduMS, ACMData, S);
- maybe_handle_recv_pdu(Ip, Port, Vsn, Pdu, PduMS, ACMData, S);
+ %% handle_recv_pdu(S, Transport, From, Vsn, Pdu, PduMS, ACMData);
+ maybe_handle_recv_pdu(
+ S, Transport, From, Vsn, Pdu, PduMS, ACMData);
{discarded, Reason} ->
?vlog("packet discarded for reason: ~s",
[?vapply(snmp_misc, format, [256, "~w", [Reason]])]),
- active_once(Sock),
+ active_once(Socket),
S;
{discarded, Reason, ReportPacket} ->
?vlog("sending report for reason: "
"~n ~s",
[?vapply(snmp_misc, format, [256, "~w", [Reason]])]),
- (catch udp_send(S#state.usock, Ip, Port, ReportPacket)),
- active_once(Sock),
+ (catch udp_send(Socket, From, ReportPacket)),
+ active_once(Socket),
S;
{discovery, ReportPacket} ->
?vlog("sending discovery report", []),
- (catch udp_send(S#state.usock, Ip, Port, ReportPacket)),
- active_once(Sock),
+ (catch udp_send(Socket, From, ReportPacket)),
+ active_once(Socket),
S;
Error ->
error_msg("processing of received message failed: "
"~n ~p", [Error]),
- active_once(Sock),
+ active_once(Socket),
S
end.
-
-maybe_handle_recv_pdu(Ip, Port, Vsn, #pdu{type = Type} = Pdu, PduMS, ACMData,
- #state{usock = Sock, filter = FilterMod} = S) ->
- case (catch FilterMod:accept_recv_pdu(Ip, Port, Type)) of
+
+handle_discovery_response(
+ #state{reqs = Reqs} = S,
+ #transport{socket = Socket},
+ _From,
+ #pdu{request_id = ReqId} = Pdu,
+ ManagerEngineId) ->
+ case lists:keyfind(ReqId, 1, S#state.reqs) of
+ {ReqId, Pid} ->
+ active_once(Socket),
+ Pid ! {snmp_discovery_response_received, Pdu, ManagerEngineId},
+ %% XXX Strange... Reqs from this Pid should be reaped
+ %% at process exit by clear_reqs/2 so the following
+ %% should be redundant.
+ NReqs = lists:keydelete(ReqId, 1, Reqs),
+ S#state{reqs = NReqs};
+ false ->
+ %% Ouch, timeout? resend?
+ S
+ end.
+
+maybe_handle_recv_pdu(
+ #state{filter = FilterMod} = S,
+ #transport{socket = Socket} = Transport,
+ From, Vsn,
+ #pdu{type = Type} = Pdu, PduMS, ACMData) ->
+ {From_1, From_2} = From,
+ case
+ try FilterMod:accept_recv_pdu(From_1, From_2, Type)
+ catch
+ Class:Exception ->
+ error_msg(
+ "FilterMod:accept_recv_pdu(~p, ~p, ~p) crashed: ~w:~w~n"
+ " ~p",
+ [From_1,From_2,Type,Class,Exception,
+ erlang:get_stacktrace()]),
+ true
+ end
+ of
false ->
inc(netIfPduInDrops),
- active_once(Sock),
- ok;
- _ ->
- handle_recv_pdu(Ip, Port, Vsn, Pdu, PduMS, ACMData, S)
- end;
-maybe_handle_recv_pdu(Ip, Port, Vsn, Pdu, PduMS, ACMData, S) ->
- handle_recv_pdu(Ip, Port, Vsn, Pdu, PduMS, ACMData, S).
+ active_once(Socket),
+ S;
+ Other ->
+ case Other of
+ true ->
+ ok;
+ _ ->
+ error_msg(
+ "FilterMod:accept_recv_pdu(~p, ~p, ~p) returned: ~p",
+ [From_1,From_2,Type,Other])
+ end,
+ handle_recv_pdu(S, Transport, From, Vsn, Pdu, PduMS, ACMData)
+ end.
-handle_recv_pdu(Ip, Port, Vsn, #pdu{type = 'get-response'} = Pdu,
- _PduMS, _ACMData, #state{usock = Sock} = S) ->
- active_once(Sock),
- handle_response(Vsn, Pdu, {Ip, Port}, S),
+handle_recv_pdu(
+ #state{reqs = Reqs} = S,
+ #transport{socket = Socket},
+ From, Vsn,
+ #pdu{type = 'get-response', request_id = ReqId} = Pdu,
+ _PduMS, _ACMData) ->
+ active_once(Socket),
+ case lists:keyfind(ReqId, 1, Reqs) of
+ {ReqId, Pid} ->
+ ?vdebug("handle_recv_pdu -> "
+ "~n send response to receiver ~p", [Pid]),
+ Pid ! {snmp_response_received, Vsn, Pdu, From};
+ false ->
+ ?vdebug("handle_recv_pdu -> "
+ "~n No receiver available for response pdu", [])
+ end,
S;
-handle_recv_pdu(Ip, Port, Vsn, #pdu{request_id = Rid, type = Type} = Pdu,
- PduMS, ACMData, #state{master_agent = Pid} = S)
- when ((Type =:= 'get-request') orelse
- (Type =:= 'get-next-request') orelse
- (Type =:= 'get-bulk-request')) ->
- ?vtrace("handle_recv_pdu -> received get (~w)", [Type]),
- Pid ! {snmp_pdu, Vsn, Pdu, PduMS, ACMData, {Ip, Port}, []},
- update_req_counter_incomming(S, Rid);
-handle_recv_pdu(Ip, Port, Vsn, Pdu, PduMS, ACMData,
- #state{usock = Sock, master_agent = Pid} = S) ->
+handle_recv_pdu(
+ #state{master_agent = Pid} = S,
+ #transport{} = Transport,
+ From, Vsn,
+ #pdu{type = Type} = Pdu,
+ PduMS, ACMData)
+ when Type =:= 'set-request';
+ Type =:= 'get-request';
+ Type =:= 'get-next-request';
+ Type =:= 'get-bulk-request' ->
+ ?vtrace("handle_recv_pdu -> received request (~w)", [Type]),
+ ReqRef = make_ref(),
+ Extra = [{request_ref, ReqRef}],
+ Pid ! {snmp_pdu, Vsn, Pdu, PduMS, ACMData, From, Extra},
+ NewS = update_req_counter_incoming(S, Transport, ReqRef),
+ ?vdebug("handle_recv_pdu -> ~p", [NewS]),
+ NewS;
+handle_recv_pdu(
+ #state{master_agent = Pid} = S,
+ #transport{socket = Socket},
+ From, Vsn, Pdu, PduMS, ACMData) ->
?vtrace("handle_recv_pdu -> received other request", []),
- active_once(Sock),
- Pid ! {snmp_pdu, Vsn, Pdu, PduMS, ACMData, {Ip, Port}, []},
+ active_once(Socket),
+ Pid ! {snmp_pdu, Vsn, Pdu, PduMS, ACMData, From, []},
S.
-maybe_handle_reply_pdu(#state{filter = FilterMod} = S, Vsn,
- #pdu{request_id = Rid} = Pdu,
- Type, ACMData, {Ip, Port} = Dest) ->
- S1 = update_req_counter_outgoing(S, Rid),
- case (catch FilterMod:accept_send_pdu([{Ip, Port}], Type)) of
+maybe_handle_reply_pdu(
+ #state{filter = FilterMod, transports = Transports} = S,
+ #transport{} = Transport,
+ Vsn,
+ #pdu{} = Pdu,
+ Type, ACMData, To) ->
+ %%
+ Addresses = [fix_filter_address(Transports, To)],
+ case
+ try
+ FilterMod:accept_send_pdu(Addresses, Type)
+ catch
+ Class:Exception ->
+ error_msg(
+ "FilterMod:accept_send_pdu(~p, ~p) crashed: ~w:~w~n ~p",
+ [Addresses, Type, Class, Exception,
+ erlang:get_stacktrace()]),
+ true
+ end
+ of
false ->
inc(netIfPduOutDrops),
ok;
- _ ->
- handle_reply_pdu(S1, Vsn, Pdu, Type, ACMData, Dest)
- end,
- S1.
-
-handle_reply_pdu(#state{log = Log,
- usock = Sock,
- filter = FilterMod},
- Vsn, Pdu, Type, ACMData, {Ip, Port}) ->
- LogF = fun(Type2, Data) ->
- log(Log, Type2, Data, Ip, Port)
- end,
+ Other ->
+ case Other of
+ true ->
+ ok;
+ _ ->
+ error_msg(
+ "FilterMod:accept_send_pdu(~p, ~p) returned: ~p",
+ [Addresses,Type,Other])
+ end,
+ handle_reply_pdu(S, Transport, Vsn, Pdu, Type, ACMData, To)
+ end.
+
+handle_reply_pdu(
+ #state{log = Log} = S,
+ #transport{} = Transport,
+ Vsn,
+ #pdu{} = Pdu,
+ Type, ACMData, To) ->
+ %%
+ LogF =
+ fun(Type2, Data) ->
+ log(Log, Type2, Data, To)
+ end,
case (catch snmpa_mpd:generate_response_msg(Vsn, Pdu, Type,
ACMData, LogF)) of
{ok, Packet} ->
?vinfo("time in agent: ~w mysec", [time_in_agent()]),
- maybe_udp_send(FilterMod, Sock, Ip, Port, Packet);
+ try maybe_udp_send(S, Transport, To, Packet)
+ catch
+ {Reason, Sz} ->
+ error_msg("Cannot send message "
+ "~n size: ~p"
+ "~n reason: ~p"
+ "~n pdu: ~p",
+ [Sz, Reason, Pdu])
+ end;
{discarded, Reason} ->
?vlog("handle_reply_pdu -> "
"~n reply discarded for reason: ~s",
@@ -652,105 +888,116 @@ handle_reply_pdu(#state{log = Log,
ok;
{'EXIT', Reason} ->
user_err("failed generating response message: "
- "~nPDU: ~w~n~w", [Pdu, Reason])
+ "~nPDU: ~p~n~p", [Pdu, Reason])
end.
-
-
-process_taddrs(To) ->
- process_taddrs(To, []).
-
-process_taddrs([], Acc) ->
- lists:reverse(Acc);
-%% v3
-process_taddrs([{{_Domain, AddrAndPort}, _SecData}|T], Acc) ->
- process_taddrs(T, [AddrAndPort|Acc]);
-%% v1 & v2
-process_taddrs([{_Domain, AddrAndPort}|T], Acc) ->
- process_taddrs(T, [AddrAndPort|Acc]).
-merge_taddrs(To1, To2) ->
- merge_taddrs(To1, To2, []).
-
-merge_taddrs([], _To2, Acc) ->
- lists:reverse(Acc);
-%% v3
-merge_taddrs([{{_, AddrAndPort}, _} = H|To1], To2, Acc) ->
- case lists:member(AddrAndPort, To2) of
- true ->
- merge_taddrs(To1, To2, [H|Acc]);
- false ->
- merge_taddrs(To1, To2, Acc)
- end;
-%% v1 & v2
-merge_taddrs([{_, AddrAndPort} = H|To1], To2, Acc) ->
- case lists:member(AddrAndPort, To2) of
- true ->
- merge_taddrs(To1, To2, [H|Acc]);
- false ->
- merge_taddrs(To1, To2, Acc)
- end;
-merge_taddrs([_Crap|To1], To2, Acc) ->
- merge_taddrs(To1, To2, Acc).
-maybe_handle_send_pdu(#state{filter = FilterMod} = S,
- Vsn, Pdu, MsgData, To0, From) ->
+maybe_handle_send_pdu(
+ #state{filter = FilterMod, transports = Transports} = S,
+ Vsn, Pdu, MsgData, TDomAddrSecs, From) ->
- ?vtrace("maybe_handle_send_pdu -> entry with"
- "~n FilterMod: ~p"
- "~n To0: ~p", [FilterMod, To0]),
+ ?vtrace("maybe_handle_send_pdu -> entry with~n"
+ " FilterMod: ~p~n"
+ " TDomAddrSecs: ~p", [FilterMod, TDomAddrSecs]),
- To1 = snmpa_mpd:process_taddrs(To0),
- To2 = process_taddrs(To1),
+ DomAddrSecs = snmpa_mpd:process_taddrs(TDomAddrSecs),
+ AddressesToFilter =
+ case is_legacy_transports(Transports) of
+ true ->
+ [fix_filter_legacy_mpd_address(DAS)
+ || DAS <- DomAddrSecs];
+ false ->
+ [fix_filter_mpd_address(DAS)
+ || DAS <- DomAddrSecs]
+ end,
- case (catch FilterMod:accept_send_pdu(To2, pdu_type_of(Pdu))) of
+ Type = pdu_type_of(Pdu),
+
+ case
+ try FilterMod:accept_send_pdu(AddressesToFilter, Type)
+ catch
+ Class:Exception ->
+ error_msg(
+ "FilterMod:accept_send_pdu(~p, ~p) crashed: ~w:~w~n ~p",
+ [AddressesToFilter,Type,
+ Class,Exception,erlang:get_stacktrace()]),
+ true
+ end
+ of
false ->
inc(netIfPduOutDrops),
ok;
true ->
- handle_send_pdu(S, Vsn, Pdu, MsgData, To1, From);
- To3 when is_list(To3) ->
- To4 = merge_taddrs(To1, To3),
- ?vtrace("maybe_handle_send_pdu -> To4: "
- "~n ~p", [To4]),
- handle_send_pdu(S, Vsn, Pdu, MsgData, To4, From);
- _ ->
- handle_send_pdu(S, Vsn, Pdu, MsgData, To1, From)
+ handle_send_pdu(S, Vsn, Pdu, MsgData, DomAddrSecs, From);
+ FilteredAddresses when is_list(FilteredAddresses) ->
+ FilteredDomAddrSecs =
+ case is_legacy_transports(Transports) of
+ true ->
+ [DAS ||
+ DAS <- DomAddrSecs,
+ lists:member(
+ fix_filter_legacy_mpd_address(DAS),
+ FilteredAddresses)];
+ false ->
+ [DAS ||
+ DAS <- DomAddrSecs,
+ lists:member(
+ fix_filter_mpd_address(DAS),
+ FilteredAddresses)]
+ end,
+ ?vtrace("maybe_handle_send_pdu -> FilteredDomAddrSecs:~n"
+ " ~p", [FilteredDomAddrSecs]),
+ handle_send_pdu(S, Vsn, Pdu, MsgData, FilteredDomAddrSecs, From);
+ Other ->
+ error_msg(
+ "FilterMod:accept_send_pdu(~p, ~p) returned: ~p",
+ [AddressesToFilter,Type,Other]),
+ handle_send_pdu(S, Vsn, Pdu, MsgData, DomAddrSecs, From)
end.
-handle_send_pdu(#state{note_store = NS} = S, Vsn, Pdu, MsgData, To, From) ->
-
- ?vtrace("handle_send_pdu -> entry with"
- "~n Pdu: ~p"
- "~n To: ~p", [Pdu, To]),
+handle_send_pdu(
+ #state{note_store = NS} = S,
+ Vsn, Pdu, MsgData, DomAddrSecs, From) ->
+ %%
+ ?vtrace("handle_send_pdu -> entry with~n"
+ " Pdu: ~p~n"
+ " DomAddrSecs: ~p", [Pdu, DomAddrSecs]),
- case (catch snmpa_mpd:generate_msg(Vsn, NS, Pdu, MsgData, To)) of
+ case (catch snmpa_mpd:generate_msg(
+ Vsn, NS, Pdu, MsgData, DomAddrSecs)) of
{ok, Addresses} ->
- handle_send_pdu(S, Pdu, Addresses);
+ do_handle_send_pdu(S, Pdu, Addresses);
{discarded, Reason} ->
?vlog("handle_send_pdu -> "
"~n PDU ~p not sent due to ~p", [Pdu, Reason]),
ok;
{'EXIT', Reason} ->
user_err("failed generating message: "
- "~nPDU: ~w~n~w", [Pdu, Reason]),
+ "~nPDU: ~p~n~p", [Pdu, Reason]),
ok
end,
case From of
undefined ->
S;
- Pid ->
+ Pid when is_pid(Pid) ->
?vtrace("link to ~p and add to request list", [Pid]),
link(Pid),
- NReqs = snmp_misc:keyreplaceadd(Pid, 2, S#state.reqs,
- {Pdu#pdu.request_id, From}),
+ NReqs =
+ snmp_misc:keyreplaceadd(
+ Pid, 2, S#state.reqs, {Pdu#pdu.request_id, From}),
S#state{reqs = NReqs}
end.
-handle_send_discovery(#state{note_store = NS} = S,
- Pdu, MsgData,
- To, From) ->
+handle_send_discovery(
+ #state{
+ note_store = NS,
+ log = Log,
+ reqs = Reqs,
+ transports = Transports} = S,
+ #pdu{type = Type, request_id = ReqId} = Pdu,
+ MsgData, To, From) when is_pid(From) ->
?vtrace("handle_send_discovery -> entry with"
"~n Pdu: ~p"
@@ -759,155 +1006,173 @@ handle_send_discovery(#state{note_store = NS} = S,
"~n From: ~p", [Pdu, MsgData, To, From]),
case (catch snmpa_mpd:generate_discovery_msg(NS, Pdu, MsgData, To)) of
- {ok, {Packet, {Ip, Port}}} ->
- handle_send_discovery(S, Pdu, Packet, Ip, Port, From);
+ {ok, {Domain, Address, Packet}} ->
+ case select_transport_from_domain(Domain, Transports) of
+ false ->
+ error_msg(
+ "Can not find transport to: ~s",
+ [format_address(To)]),
+ S;
+ #transport{socket = Socket} ->
+ log(Log, Type, Packet, {Domain, Address}),
+ udp_send(Socket, {Domain, Address}, Packet),
+ ?vtrace("handle_send_discovery -> sent (~w)", [ReqId]),
+ NReqs = snmp_misc:keyreplaceadd(From, 2, Reqs, {ReqId, From}),
+ S#state{reqs = NReqs}
+ end;
{discarded, Reason} ->
?vlog("handle_send_discovery -> "
"~n Discovery PDU ~p not sent due to ~p", [Pdu, Reason]),
- ok;
+ S;
{'EXIT', Reason} ->
user_err("failed generating discovery message: "
- "~n PDU: ~w"
- "~n Reason: ~w", [Pdu, Reason]),
- ok
+ "~n PDU: ~p"
+ "~n Reason: ~p", [Pdu, Reason]),
+ S
end.
-handle_send_discovery(#state{log = Log,
- usock = Sock,
- reqs = Reqs} = S,
- #pdu{type = Type,
- request_id = ReqId},
- Packet, Ip, Port, From)
- when is_binary(Packet) ->
- log(Log, Type, Packet, Ip, Port),
- udp_send(Sock, Ip, Port, Packet),
- ?vtrace("handle_send_discovery -> sent (~w)", [ReqId]),
- NReqs = snmp_misc:keyreplaceadd(From, 2, Reqs, {ReqId, From}),
- S#state{reqs = NReqs}.
-
-handle_send_pdu(S, #pdu{type = Type} = Pdu, Addresses) ->
- handle_send_pdu(S, Type, Pdu, Addresses);
-handle_send_pdu(S, Trap, Addresses) ->
- handle_send_pdu(S, trappdu, Trap, Addresses).
+do_handle_send_pdu(S, #pdu{type = Type} = Pdu, Addresses) ->
+ do_handle_send_pdu(S, Type, Pdu, Addresses);
+do_handle_send_pdu(S, Trap, Addresses) ->
+ do_handle_send_pdu(S, trappdu, Trap, Addresses).
-handle_send_pdu(S, Type, Pdu, Addresses) ->
- case (catch handle_send_pdu1(S, Type, Addresses)) of
+do_handle_send_pdu(S, Type, Pdu, Addresses) ->
+ try do_handle_send_pdu1(S, Type, Addresses)
+ catch
{Reason, Sz} ->
- error_msg("Cannot send message "
- "~n size: ~p"
- "~n reason: ~p"
- "~n pdu: ~p",
- [Sz, Reason, Pdu]);
- _ ->
- ok
- end.
-
-handle_send_pdu1(#state{log = Log,
- usock = Sock,
- filter = FilterMod}, Type, Addresses) ->
- SendFun =
- fun({snmpUDPDomain, {Ip, Port}, Packet})
- when is_binary(Packet) ->
- ?vdebug("[snmpUDPDomain] sending packet:"
- "~n size: ~p"
- "~n to: ~p:~p",
- [sz(Packet), Ip, Port]),
- maybe_udp_send(FilterMod, Log, Type, Sock, Ip, Port, Packet);
-
- ({snmpUDPDomain, {Ip, Port}, {Packet, _LogData}})
- when is_binary(Packet) ->
- ?vdebug("[snmpUDPDomain] sending encrypted packet:"
- "~n size: ~p"
- "~n to: ~p:~p",
- [sz(Packet), Ip, Port]),
- maybe_udp_send(FilterMod, Log, Type, Sock, Ip, Port, Packet);
-
- ({transportDomainUdpIpv4, {Ip, Port}, Packet})
- when is_binary(Packet) ->
- ?vdebug("[transportDomainUdpIpv4] sending packet:"
- "~n size: ~p"
- "~n to: ~p:~p",
- [sz(Packet), Ip, Port]),
- maybe_udp_send(FilterMod, Log, Type, Sock, Ip, Port, Packet);
-
- ({transportDomainUdpIpv4, {Ip, Port}, {Packet, _LogData}})
- when is_binary(Packet) ->
- ?vdebug("[transportDomainUdpIpv4] sending encrypted packet:"
- "~n size: ~p"
- "~n to: ~p:~p",
- [sz(Packet), Ip, Port]),
- maybe_udp_send(FilterMod, Log, Type, Sock, Ip, Port, Packet);
-
- ({transportDomainUdpIpv6, {Ip, Port}, Packet})
- when is_binary(Packet) ->
- ?vdebug("[transportDomainUdpIpv6] sending packet:"
- "~n size: ~p"
- "~n to: ~p:~p",
- [sz(Packet), Ip, Port]),
- maybe_udp_send(FilterMod, Log, Type, Sock, Ip, Port, Packet);
-
- ({transportDomainUdpIpv6, {Ip, Port}, {Packet, _LogData}})
- when is_binary(Packet) ->
- ?vdebug("[transportDomainUdpIpv6] sending encrypted packet:"
- "~n size: ~p"
- "~n to: ~p:~p",
- [sz(Packet), Ip, Port]),
- maybe_udp_send(FilterMod, Log, Type, Sock, Ip, Port, Packet);
-
- (_X) ->
- ?vlog("** bad res: ~p", [_X]),
- ok
- end,
- lists:foreach(SendFun, Addresses).
-
-
-handle_response(Vsn, Pdu, From, S) ->
- case lists:keysearch(Pdu#pdu.request_id, 1, S#state.reqs) of
- {value, {_, Pid}} ->
- ?vdebug("handle_response -> "
- "~n send response to receiver ~p", [Pid]),
- Pid ! {snmp_response_received, Vsn, Pdu, From};
- _ ->
- ?vdebug("handle_response -> "
- "~n No receiver available for response pdu", [])
+ error_msg(
+ "Can not send message~n"
+ " size: ~p~n"
+ " reason: ~p~n"
+ " pdu: ~p",
+ [Sz, Reason, Pdu])
end.
-maybe_udp_send(FilterMod, Sock, Ip, Port, Packet) ->
- case (catch FilterMod:accept_send(Ip, Port)) of
+do_handle_send_pdu1(
+ #state{transports = Transports} = S,
+ Type, Addresses) ->
+ lists:foreach(
+ fun ({Domain, Address, Packet}) when is_binary(Packet) ->
+ ?vdebug(
+ "[~w] sending packet:~n"
+ " size: ~p~n"
+ " to: ~p", [Domain, sz(Packet), Address]),
+ To = {Domain, Address},
+ case select_transport_from_domain(Domain, Transports) of
+ false ->
+ error_msg(
+ "Can not find transport~n"
+ " size: ~p~n"
+ " to: ~s",
+ [sz(Packet), format_address(To)]);
+ Transport ->
+ maybe_udp_send(S, Transport, To, Packet)
+ end;
+ ({Domain, Address, {Packet, LogData}}) when is_binary(Packet) ->
+ ?vdebug(
+ "[~w] sending encrypted packet:~n"
+ " size: ~p~n"
+ " to: ~p", [Domain, sz(Packet), Address]),
+ To = {Domain, Address},
+ case select_transport_from_domain(Domain, Transports) of
+ false ->
+ error_msg(
+ "Can not find transport~n"
+ " size: ~p~n"
+ " to: ~s",
+ [sz(Packet), format_address(To)]);
+ Transport ->
+ maybe_udp_send(S, Transport, To, Packet, Type, LogData)
+ end
+ end,
+ Addresses).
+
+maybe_udp_send(
+ #state{filter = FilterMod, transports = Transports},
+ #transport{socket = Socket},
+ To, Packet) ->
+ {To_1, To_2} = fix_filter_address(Transports, To),
+ case
+ try FilterMod:accept_send(To_1, To_2)
+ catch
+ Class:Exception ->
+ error_msg(
+ "FilterMod:accept_send(~p, ~p) crashed: ~w:~w~n ~p",
+ [To_1,To_2,Class,Exception,erlang:get_stacktrace()]),
+ true
+ end
+ of
false ->
inc(netIfMsgOutDrops),
ok;
- _ ->
- (catch udp_send(Sock, Ip, Port, Packet))
+ Other ->
+ case Other of
+ true ->
+ ok;
+ _ ->
+ error_msg(
+ "FilterMod:accept_send(~p, ~p) returned: ~p",
+ [To_1,To_2,Other])
+ end,
+ udp_send(Socket, To, Packet)
end.
-maybe_udp_send(FilterMod, AtLog, Type, Sock, Ip, Port, Packet) ->
- case (catch FilterMod:accept_send(Ip, Port)) of
+maybe_udp_send(
+ #state{log = Log, filter = FilterMod, transports = Transports},
+ #transport{socket = Socket},
+ To, Packet, Type, _LogData) ->
+ {To_1, To_2} = fix_filter_address(Transports, To),
+ case
+ try FilterMod:accept_send(To_1, To_2)
+ catch
+ Class:Exception ->
+ error_msg(
+ "FilterMod:accept_send(~p, ~p) crashed for: ~w:~w~n ~p",
+ [To_1, To_2, Class, Exception, erlang:get_stacktrace()]),
+ true
+ end
+ of
false ->
inc(netIfMsgOutDrops),
ok;
- _ ->
- log(AtLog, Type, Packet, Ip, Port),
- (catch udp_send(Sock, Ip, Port, Packet))
+ Other ->
+ case Other of
+ true ->
+ ok;
+ _ ->
+ error_msg(
+ "FilterMod:accept_send(~p, ~p) returned: ~p",
+ [To_1,To_2,Other])
+ end,
+ log(Log, Type, Packet, To),
+ udp_send(Socket, To, Packet)
end.
-
-udp_send(UdpId, AgentIp, UdpPort, B) ->
- case (catch gen_udp:send(UdpId, AgentIp, UdpPort, B)) of
+udp_send(Socket, To, B) ->
+ {IpAddr, IpPort} =
+ case To of
+ {Domain, Addr} when is_atom(Domain) ->
+ Addr;
+ {_, P} = Addr when is_integer(P) ->
+ Addr
+ end,
+ try gen_udp:send(Socket, IpAddr, IpPort, B) of
{error, emsgsize} ->
%% From this message we cannot recover, so exit sending loop
throw({emsgsize, sz(B)});
{error, ErrorReason} ->
error_msg("[error] cannot send message "
"(destination: ~p:~p, size: ~p, reason: ~p)",
- [AgentIp, UdpPort, sz(B), ErrorReason]);
- {'EXIT', ExitReason} ->
- error_msg("[exit] cannot send message "
- "(destination: ~p:~p, size: ~p, reason: ~p)",
- [AgentIp, UdpPort, sz(B), ExitReason]);
- _ ->
+ [IpAddr, IpPort, sz(B), ErrorReason]);
+ ok ->
ok
+ catch
+ error:ExitReason ->
+ error_msg("[exit] cannot send message "
+ "(destination: ~p:~p, size: ~p, reason: ~p, at: ~p)",
+ [IpAddr, IpPort, sz(B), ExitReason,
+ erlang:get_stacktrace()])
end.
sz(L) when is_list(L) -> length(L);
@@ -957,6 +1222,75 @@ active_once(Sock) ->
inet:setopts(Sock, [{active, once}]).
+select_transport_from_req_ref(_, []) ->
+ false;
+select_transport_from_req_ref(
+ ReqRef,
+ [#transport{req_refs = ReqRefs} = Transport | Transports]) ->
+ case lists:member(ReqRef, ReqRefs) of
+ true ->
+ Transport;
+ false ->
+ select_transport_from_req_ref(ReqRef, Transports)
+ end.
+
+select_transport_from_domain(Domain, Transports) when is_atom(Domain) ->
+ Pos = #transport.domain,
+ case lists:keyfind(Domain, Pos, Transports) of
+ #transport{domain = Domain} = Transport ->
+ Transport;
+ false when Domain == snmpUDPDomain ->
+ lists:keyfind(transportDomainUdpIpv4, Pos, Transports);
+ false when Domain == transportDomainUdpIpv4 ->
+ lists:keyfind(snmpUDPDomain, Pos, Transports);
+ false ->
+ false
+ end.
+
+address_to_domain({Domain, _Addr}) when is_atom(Domain) ->
+ Domain;
+address_to_domain({_Ip, Port}) when is_integer(Port) ->
+ snmpUDPDomain.
+
+%% If the agent uses legacy snmpUDPDomain e.g has not set
+%% intAgentTransportDomain, then make sure
+%% snmpa_network_interface_filter gets legacy arguments
+%% to not break backwards compatibility.
+%%
+fix_filter_address(Transports, Address) ->
+ case is_legacy_transports(Transports) of
+ true ->
+ case Address of
+ {Domain, Addr} when is_atom(Domain) ->
+ Addr;
+ {_, IpPort} = Addr when is_integer(IpPort) ->
+ Addr
+ end;
+ false ->
+ Address
+ end.
+
+is_legacy_transports([#transport{domain = snmpUDPDomain}]) ->
+ true;
+is_legacy_transports([#transport{} | _]) ->
+ false.
+
+fix_filter_legacy_mpd_address(Domain_Address_SecData) ->
+ case Domain_Address_SecData of
+ {{Domain, Addr}, _SecData} when is_atom(Domain) -> % v3
+ Addr;
+ {Domain, Addr} when is_atom(Domain) -> % v1 & v2
+ Addr
+ end.
+
+fix_filter_mpd_address(Domain_Address_SecData) ->
+ case Domain_Address_SecData of
+ {{Domain, _Addr} = Address, _SecData} when is_atom(Domain) -> % v3
+ Address;
+ {Domain, _Addr} = Address when is_atom(Domain) -> % v1 & v2
+ Address
+ end.
+
%%%-----------------------------------------------------------------
handle_set_log_type(#state{log = {Log, OldValue}} = State, NewType)
@@ -1046,15 +1380,7 @@ do_close_log(_) ->
%%% DEBUG FUNCTIONS
%%%-----------------------------------------------------------------
time_in_agent() ->
- subtr(erlang:now(), get(n1)).
-
-subtr({X1,Y1,Z1}, {X1,Y1,Z2}) ->
- Z1 - Z2;
-subtr({X1,Y1,Z1}, {X1,Y2,Z2}) ->
- ((Y1-Y2) * 1000000) + (Z1 - Z2);
-subtr({X1,Y1,Z1}, {X2,Y2,Z2}) ->
- ((X1 - X2) * 1000000000000) + ((Y1 - Y2) * 1000000) + (Z1 - Z2).
-
+ erlang:monotonic_time(micro_seconds) - get(n1).
%% ----------------------------------------------------------------
@@ -1113,37 +1439,39 @@ get_counters([Counter|Counters], Acc) ->
%% ----------------------------------------------------------------
-ip_opt_bind_to_ip_address(Opts, Ip) ->
- case get_bind_to_ip_address(Opts) of
- true ->
- [{ip, list_to_tuple(Ip)}];
- _ ->
- []
- end.
-
-ip_opt_no_reuse_address(Opts) ->
- case get_no_reuse_address(Opts) of
- false ->
- [{reuseaddr, true}];
- _ ->
- []
- end.
-
-ip_opt_recbuf(Opts) ->
- case get_recbuf(Opts) of
- use_default ->
- [];
- Sz ->
- [{recbuf, Sz}]
- end.
-
-ip_opt_sndbuf(Opts) ->
- case get_sndbuf(Opts) of
- use_default ->
- [];
- Sz ->
- [{sndbuf, Sz}]
- end.
+socket_opts(Domain, {IpAddr, IpPort}, Opts) ->
+ [IpPort, % Picked off at socket open, separate argument
+ binary
+ | case snmp_conf:tdomain_to_family(Domain) of
+ inet6 = Family ->
+ [Family, {ipv6_v6only, true}];
+ Family ->
+ [Family]
+ end ++
+ case get_bind_to_ip_address(Opts) of
+ true ->
+ [{ip, IpAddr}];
+ _ ->
+ []
+ end ++
+ case get_no_reuse_address(Opts) of
+ false ->
+ [{reuseaddr, true}];
+ _ ->
+ []
+ end ++
+ case get_recbuf(Opts) of
+ use_default ->
+ [];
+ Sz ->
+ [{recbuf, Sz}]
+ end ++
+ case get_sndbuf(Opts) of
+ use_default ->
+ [];
+ Sz ->
+ [{sndbuf, Sz}]
+ end].
%% ----------------------------------------------------------------
@@ -1203,6 +1531,9 @@ get_bind_to_ip_address(Opts) ->
error_msg(F,A) ->
?snmpa_error("NET-IF server: " ++ F, A).
+info_msg(F,A) ->
+ ?snmpa_info("NET-IF server: " ++ F, A).
+
%% ---
user_err(F, A) ->
@@ -1227,14 +1558,14 @@ call(Pid, Req) ->
%% ----------------------------------------------------------------
-get_info(#state{usock = Id, reqs = Reqs}) ->
+get_info(#state{transports = Transports, reqs = Reqs}) ->
ProcSize = proc_mem(self()),
- PortInfo = get_port_info(Id),
Counters = get_counters(),
- [{reqs, Reqs},
- {counters, Counters},
- {process_memory, ProcSize},
- {port_info, PortInfo}].
+ [{reqs, Reqs},
+ {counters, Counters},
+ {process_memory, ProcSize}
+ | [{port_info, get_port_info(Socket)}
+ || #transport{socket = Socket} <- Transports]].
proc_mem(P) when is_pid(P) ->
case (catch erlang:process_info(P, memory)) of
@@ -1299,10 +1630,3 @@ get_port_info(Id) ->
%% ----------------------------------------------------------------
-
-% i(F) ->
-% i(F, []).
-
-% i(F, A) ->
-% io:format("~p: " ++ F ++ "~n", [?MODULE|A]).
-
diff --git a/lib/snmp/src/agent/snmpa_net_if_filter.erl b/lib/snmp/src/agent/snmpa_net_if_filter.erl
index 989f7c95b3..1db8609eaf 100644
--- a/lib/snmp/src/agent/snmpa_net_if_filter.erl
+++ b/lib/snmp/src/agent/snmpa_net_if_filter.erl
@@ -1,52 +1,67 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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_net_if_filter).
--export([accept_recv/2,
- accept_send/2,
- accept_recv_pdu/3,
- accept_send_pdu/2]).
+%% Behaviour
+-export([accept_recv/2, accept_send/2, accept_recv_pdu/3, accept_send_pdu/2]).
-include("snmp_debug.hrl").
-accept_recv(_Addr, _Port) ->
- ?d("accept_recv -> entry with"
- "~n Addr: ~p"
- "~n Port: ~p", [_Addr, _Port]),
+accept_recv(Domain, _Address) when is_atom(Domain) ->
+ ?d("accept_recv -> entry with~n"
+ " Domain: ~p~n"
+ " Address: ~p", [Domain, _Address]),
+ true;
+accept_recv(_Addr, Port) when is_integer(Port) ->
+ ?d("accept_recv -> entry with~n"
+ " Addr: ~p~n"
+ " Port: ~p", [_Addr, Port]),
true.
-accept_send(_Addr, _Port) ->
- ?d("accept_send -> entry with"
- "~n Addr: ~p"
- "~n Port: ~p", [_Addr, _Port]),
+accept_send(Domain, _Address) when is_atom(Domain) ->
+ ?d("accept_send -> entry with~n"
+ " Domain: ~p~n"
+ " Address: ~p", [Domain, _Address]),
+ true;
+accept_send(_Addr, Port) when is_integer(Port) ->
+ ?d("accept_send -> entry with~n"
+ " Addr: ~p~n"
+ " Port: ~p", [_Addr, Port]),
true.
-accept_recv_pdu(_Addr, _Port, _PduType) ->
- ?d("accept_recv_pdu -> entry with"
- "~n Addr: ~p"
- "~n Port: ~p"
- "~n PduType: ~p", [_Addr, _Port, _PduType]),
+accept_recv_pdu(Domain, _Address, _PduType) when is_atom(Domain) ->
+ ?d("accept_recv -> entry with~n"
+ " Domain: ~p~n"
+ " Address: ~p~n"
+ " PduType: ~p", [Domain, _Address, _PduType]),
+ true;
+accept_recv_pdu(_Addr, Port, _PduType) when is_integer(Port) ->
+ ?d("accept_recv_pdu -> entry with~n"
+ " Addr: ~p~n"
+ " Port: ~p~n"
+ " PduType: ~p", [_Addr, Port, _PduType]),
true.
accept_send_pdu(_Targets, _PduType) ->
- ?d("accept_send_pdu -> entry with"
- "~n Targets: ~p"
- "~n PduType: ~p", [_Targets, _PduType]),
+ ?d("accept_send_pdu -> entry with~n"
+ " Targets: ~p~n"
+ " PduType: ~p", [_Targets, _PduType]),
true.
diff --git a/lib/snmp/src/agent/snmpa_network_interface.erl b/lib/snmp/src/agent/snmpa_network_interface.erl
index 887ea22549..699fbde671 100644
--- a/lib/snmp/src/agent/snmpa_network_interface.erl
+++ b/lib/snmp/src/agent/snmpa_network_interface.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
diff --git a/lib/snmp/src/agent/snmpa_network_interface_filter.erl b/lib/snmp/src/agent/snmpa_network_interface_filter.erl
index 6fa131beee..1524a6447b 100644
--- a/lib/snmp/src/agent/snmpa_network_interface_filter.erl
+++ b/lib/snmp/src/agent/snmpa_network_interface_filter.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -23,7 +24,7 @@
behaviour_info(callbacks) ->
- [{accept_recv, 2},
+ [{accept_recv, 2},
{accept_send, 2},
{accept_recv_pdu, 3},
{accept_send_pdu, 2}];
@@ -31,20 +32,21 @@ behaviour_info(_) ->
undefined.
-%% accept_recv(address(), port()) -> boolean()
+%% accept_recv({domain(), address()}) -> boolean()
%% Called at the receiption of a message
%% (before *any* processing has been done).
%%
-%% accept_send(address(), port()) -> boolean()
+%% accept_send({domain(), address()}) -> boolean()
%% Called before the sending of a message
%% (after *all* processing has been done).
%%
-%% accept_recv_pdu(Addr, Port, pdu_type()) -> boolean()
+%% accept_recv_pdu({domain(), address()}, pdu_type()) -> boolean()
%% Called after the basic message processing (MPD) has been done,
%% but before the pdu is handed over to the master-agent for
%% primary processing.
%%
-%% accept_send_pdu(Targets, pdu_type()) -> boolean() | NewTargets
+%% accept_send_pdu([{domain(), address()}, ...] = Targets, pdu_type()) ->
+%% boolean() | NewTargets
%% Called before the basic message processing (MPD) is done,
%% when a pdu has been received from the master-agent.
%%
diff --git a/lib/snmp/src/agent/snmpa_notification_delivery_info_receiver.erl b/lib/snmp/src/agent/snmpa_notification_delivery_info_receiver.erl
index b9ec5ff05e..aca90baf0e 100644
--- a/lib/snmp/src/agent/snmpa_notification_delivery_info_receiver.erl
+++ b/lib/snmp/src/agent/snmpa_notification_delivery_info_receiver.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
diff --git a/lib/snmp/src/agent/snmpa_notification_filter.erl b/lib/snmp/src/agent/snmpa_notification_filter.erl
index 199cf725fd..6300d450c7 100644
--- a/lib/snmp/src/agent/snmpa_notification_filter.erl
+++ b/lib/snmp/src/agent/snmpa_notification_filter.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
diff --git a/lib/snmp/src/agent/snmpa_set.erl b/lib/snmp/src/agent/snmpa_set.erl
index 0f85d0aaa0..9833d6fdcc 100644
--- a/lib/snmp/src/agent/snmpa_set.erl
+++ b/lib/snmp/src/agent/snmpa_set.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
diff --git a/lib/snmp/src/agent/snmpa_set_lib.erl b/lib/snmp/src/agent/snmpa_set_lib.erl
index 9f355855b4..57507a36e8 100644
--- a/lib/snmp/src/agent/snmpa_set_lib.erl
+++ b/lib/snmp/src/agent/snmpa_set_lib.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -368,47 +369,44 @@ make_value_a_correct_value(Value, ASN1Type, Mfa) ->
dbg_apply(M,F,A) ->
case maybe_verbose_apply(M, F, A) of
- %% <Future proofing>
- %% As of R15 we get extra info containing,
- %% among other things, line numbers.
- {'EXIT', {undef, [{M, F, A, _} | _]}} ->
- {'EXIT', {hook_undef, {M, F, A}}};
- {'EXIT', {function_clause, [{M, F, A, _} | _]}} ->
- {'EXIT', {hook_function_clause, {M, F, A}}};
-
- %% This is really overkill, but just to be on the safe side...
- {'EXIT', {undef, {M, F, A, _}}} ->
- {'EXIT', {hook_undef, {M, F, A}}};
- {'EXIT', {function_clause, {M, F, A, _}}} ->
- {'EXIT', {hook_function_clause, {M, F, A}}};
- %% </Future proofing>
-
-
- %% Old format format for compatibility
- {'EXIT', {undef, [{M, F, A} | _]}} ->
- {'EXIT', {hook_undef, {M, F, A}}};
- {'EXIT', {function_clause, [{M, F, A} | _]}} ->
- {'EXIT', {hook_function_clause, {M, F, A}}};
-
- % XYZ: Older format for compatibility
- {'EXIT', {undef, {M, F, A}}} ->
- {'EXIT', {hook_undef, {M, F, A}}};
- {'EXIT', {function_clause, {M, F, A}}} ->
- {'EXIT', {hook_function_clause, {M, F, A}}};
-
- Result ->
- Result
+ %% <Future proofing>
+ %% As of R15 we get extra info containing,
+ %% among other things, line numbers.
+ {'EXIT', {undef, [{M, F, A, _} | _]}} ->
+ {'EXIT', {hook_undef, {M, F, A}}};
+ {'EXIT', {function_clause, [{M, F, A, _} | _]}} ->
+ {'EXIT', {hook_function_clause, {M, F, A}}};
+
+ %% This is really overkill, but just to be on the safe side...
+ {'EXIT', {undef, {M, F, A, _}}} ->
+ {'EXIT', {hook_undef, {M, F, A}}};
+ {'EXIT', {function_clause, {M, F, A, _}}} ->
+ {'EXIT', {hook_function_clause, {M, F, A}}};
+ %% </Future proofing>
+
+ %% Old format format for compatibility
+ {'EXIT', {undef, [{M, F, A} | _]}} ->
+ {'EXIT', {hook_undef, {M, F, A}}};
+ {'EXIT', {function_clause, [{M, F, A} | _]}} ->
+ {'EXIT', {hook_function_clause, {M, F, A}}};
+
+ % XYZ: Older format for compatibility
+ {'EXIT', {undef, {M, F, A}}} ->
+ {'EXIT', {hook_undef, {M, F, A}}};
+ {'EXIT', {function_clause, {M, F, A}}} ->
+ {'EXIT', {hook_function_clause, {M, F, A}}};
+
+ Result ->
+ Result
end.
-
maybe_verbose_apply(M, F, A) ->
case get(verbosity) of
- false ->
- (catch apply(M,F,A));
- _ ->
- ?vlog("~n apply: ~w,~w,~p~n", [M,F,A]),
- Res = (catch apply(M,F,A)),
- ?vlog("~n returned: ~p", [Res]),
- Res
+ false ->
+ (catch apply(M,F,A));
+ _ ->
+ ?vlog("~n apply: ~w,~w,~p~n", [M,F,A]),
+ Res = (catch apply(M,F,A)),
+ ?vlog("~n returned: ~p", [Res]),
+ Res
end.
-
diff --git a/lib/snmp/src/agent/snmpa_set_mechanism.erl b/lib/snmp/src/agent/snmpa_set_mechanism.erl
index 4561fb035b..2f24f38092 100644
--- a/lib/snmp/src/agent/snmpa_set_mechanism.erl
+++ b/lib/snmp/src/agent/snmpa_set_mechanism.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
diff --git a/lib/snmp/src/agent/snmpa_supervisor.erl b/lib/snmp/src/agent/snmpa_supervisor.erl
index 7a9c214e0d..cdb5ca840d 100644
--- a/lib/snmp/src/agent/snmpa_supervisor.erl
+++ b/lib/snmp/src/agent/snmpa_supervisor.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -224,26 +225,101 @@ init([AgentType, Opts]) ->
ets:insert(snmp_agent_table, {error_report_mod, ErrorReportMod}),
%% -- mib storage --
+ %% MibStorage has only one mandatory part: module
+ %% Everything else is module dependent and therefor
+ %% put in a special option: options
MibStorage =
- case get_opt(mib_storage, Opts, ets) of
+ case get_opt(mib_storage, Opts, [{module, snmpa_mib_storage_ets}]) of
+
+ %% --- ETS wrappers ---
+
+ ets ->
+ [{module, snmpa_mib_storage_ets}];
+ {ets, default} ->
+ [{module, snmpa_mib_storage_ets},
+ {options, [{dir, filename:join([DbDir])},
+ {action, keep}]}];
+ {ets, Dir} when is_list(Dir) ->
+ [{module, snmpa_mib_storage_ets},
+ {options, [{dir, filename:join([Dir])},
+ {action, keep}]}];
+ {ets, default, Action} when ((Action =:= keep) orelse
+ (Action =:= clear)) ->
+ [{module, snmpa_mib_storage_ets},
+ {options, [{dir, filename:join([DbDir])},
+ {action, Action}]}];
+ {ets, Dir, Action} when is_list(Dir) andalso
+ ((Action =:= keep) orelse
+ (Action =:= clear)) ->
+ [{module, snmpa_mib_storage_ets},
+ {options, [{dir, filename:join([Dir])},
+ {action, Action}]}];
+
+ %% --- DETS wrappers ---
+
dets ->
- {dets, DbDir};
+ [{module, snmpa_mib_storage_dets},
+ {options, [{dir, filename:join([DbDir])},
+ {action, keep}]}];
{dets, default} ->
- {dets, DbDir};
- {dets, default, Act} ->
- {dets, DbDir, Act};
- {ets, default} ->
- {ets, DbDir};
+ [{module, snmpa_mib_storage_dets},
+ {options, [{dir, filename:join([DbDir])},
+ {action, keep}]}];
+ {dets, default, Action} when ((Action =:= keep) orelse
+ (Action =:= clear)) ->
+ [{module, snmpa_mib_storage_dets},
+ {options, [{dir, filename:join([DbDir])},
+ {action, Action}]}];
+ {dets, Dir, Action} when is_list(Dir) andalso
+ ((Action =:= keep) orelse
+ (Action =:= clear)) ->
+ [{module, snmpa_mib_storage_dets},
+ {options, [{dir, filename:join([Dir])},
+ {action, Action}]}];
+
+ %% --- Mnesia wrappers ---
+
mnesia ->
- {mnesia, erlang:nodes()};
- {mnesia, visible} ->
- {mnesia, erlang:nodes(visible)};
- {mnesia, connected} ->
- {mnesia, erlang:nodes(connected)};
- Other ->
+ [{module, snmpa_mib_storage_mnesia},
+ {options, [{nodes, erlang:nodes()},
+ {action, keep}]}];
+ {mnesia, Nodes0} ->
+ Nodes =
+ if
+ Nodes0 =:= visible ->
+ erlang:nodes(visible);
+ Nodes0 =:= connected ->
+ erlang:nodes(connected);
+ Nodes0 =:= [] ->
+ [node()];
+ true ->
+ Nodes0
+ end,
+ [{module, snmpa_mib_storage_mnesia},
+ {options, [{nodes, Nodes},
+ {action, keep}]}];
+ {mnesia, Nodes0, Action} when ((Action =:= keep) orelse
+ (Action =:= clear)) ->
+ Nodes =
+ if
+ Nodes0 =:= visible ->
+ erlang:nodes(visible);
+ Nodes0 =:= connected ->
+ erlang:nodes(connected);
+ Nodes0 =:= [] ->
+ [node()];
+ true ->
+ Nodes0
+ end,
+ [{module, snmpa_mib_storage_mnesia},
+ {options, [{nodes, Nodes},
+ {action, Action}]}];
+
+ Other when is_list(Other) ->
Other
end,
- ?vdebug("[agent table] store mib storage: ~w",[MibStorage]),
+
+ ?vdebug("[agent table] store mib storage: ~w", [MibStorage]),
ets:insert(snmp_agent_table, {mib_storage, MibStorage}),
%% -- Agent mib storage --
@@ -281,7 +357,7 @@ init([AgentType, Opts]) ->
SymStoreSpec =
worker_spec(snmpa_symbolic_store, SymStoreArgs, Restart, 2000),
- LdbArgs = [Prio, DbDir, LdbOpts],
+ LdbArgs = [Prio, DbDir, DbInitError, LdbOpts],
LocalDbSpec =
worker_spec(snmpa_local_db, LdbArgs, Restart, 5000),
@@ -388,7 +464,7 @@ init([AgentType, Opts]) ->
AgentSpec =
worker_spec(snmpa_agent,
- [Prio,snmp_master_agent,none,Ref,AgentOpts],
+ [Prio, snmp_master_agent, none, Ref, AgentOpts],
Restart, 15000),
AgentSupSpec =
sup_spec(snmpa_agent_sup, [AgentSpec],
diff --git a/lib/snmp/src/agent/snmpa_svbl.erl b/lib/snmp/src/agent/snmpa_svbl.erl
index 9c2910580e..8955bed0f2 100644
--- a/lib/snmp/src/agent/snmpa_svbl.erl
+++ b/lib/snmp/src/agent/snmpa_svbl.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
diff --git a/lib/snmp/src/agent/snmpa_symbolic_store.erl b/lib/snmp/src/agent/snmpa_symbolic_store.erl
index 6c58ffde41..945a4e9a9c 100644
--- a/lib/snmp/src/agent/snmpa_symbolic_store.erl
+++ b/lib/snmp/src/agent/snmpa_symbolic_store.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -78,7 +79,7 @@
gen_server:start_link({local, ?SERVER}, ?MODULE, [Prio, Opts], [])).
-endif.
--record(state, {db, backup}).
+-record(state, {module, db, backup}).
-record(symbol, {key, mib_name, info}).
@@ -112,6 +113,9 @@ backup(BackupDir) ->
get_db() ->
call(get_db).
+which_module() ->
+ call(which_module).
+
%%----------------------------------------------------------------------
%% Returns: {value, Oid} | false
@@ -202,49 +206,63 @@ verbosity(Verbosity) ->
%%----------------------------------------------------------------------
%% DB access (read) functions: Returns: {value, Oid} | false
%%----------------------------------------------------------------------
+
aliasname_to_oid(Db, Aliasname) ->
- case snmpa_general_db:read(Db, {alias, Aliasname}) of
+ Mod = which_module(),
+ aliasname_to_oid(Mod, Db, Aliasname).
+
+aliasname_to_oid(Mod, Db, Aliasname) ->
+ case Mod:read(Db, {alias, Aliasname}) of
{value,#symbol{info = {Oid, _Enums}}} -> {value, Oid};
false -> false
end.
-oid_to_aliasname(Db,Oid) ->
- case snmpa_general_db:read(Db, {oid, Oid}) of
+oid_to_aliasname(Db, Oid) ->
+ Mod = which_module(),
+ oid_to_aliasname(Mod, Db, Oid).
+
+oid_to_aliasname(Mod, Db, Oid) ->
+ case Mod:read(Db, {oid, Oid}) of
{value,#symbol{info = Aliasname}} -> {value, Aliasname};
_ -> false
end.
-which_notifications(Db) ->
+which_notifications(Mod, Db) ->
Pattern = #symbol{key = {trap, '_'}, _ = '_'},
- Symbols = snmpa_general_db:match_object(Db, Pattern),
+ Symbols = Mod:match_object(Db, Pattern),
[{Name, Mib, Rec} || #symbol{key = {trap, Name},
mib_name = Mib,
info = Rec} <- Symbols].
-which_aliasnames(Db) ->
+which_aliasnames(Mod, Db) ->
Pattern = #symbol{key = {alias, '_'}, _ = '_'},
- Symbols = snmpa_general_db:match_object(Db, Pattern),
+ Symbols = Mod:match_object(Db, Pattern),
[Alias || #symbol{key = {alias, Alias}} <- Symbols].
-which_tables(Db) ->
+which_tables(Mod, Db) ->
Pattern = #symbol{key = {table_info, '_'}, _ = '_'},
- Symbols = snmpa_general_db:match_object(Db, Pattern),
+ Symbols = Mod:match_object(Db, Pattern),
[Name || #symbol{key = {table_info, Name}} <- Symbols].
-which_variables(Db) ->
+which_variables(Mod, Db) ->
Pattern = #symbol{key = {variable_info, '_'}, _ = '_'},
- Symbols = snmpa_general_db:match_object(Db, Pattern),
+ Symbols = Mod:match_object(Db, Pattern),
[Name || #symbol{key = {variable_info, Name}} <- Symbols].
-int_to_enum(Db,TypeOrObjName,Int) ->
- case snmpa_general_db:read(Db, {alias, TypeOrObjName}) of
+
+int_to_enum(Db, TypeOrObjName, Int) ->
+ Mod = which_module(),
+ int_to_enum(Mod, Db, TypeOrObjName, Int).
+
+int_to_enum(Mod, Db, TypeOrObjName, Int) ->
+ case Mod:read(Db, {alias, TypeOrObjName}) of
{value,#symbol{info = {_Oid, Enums}}} ->
case lists:keysearch(Int, 2, Enums) of
{value, {Enum, _Int}} -> {value, Enum};
false -> false
end;
false -> % Not an Aliasname ->
- case snmpa_general_db:read(Db, {type, TypeOrObjName}) of
+ case Mod:read(Db, {type, TypeOrObjName}) of
{value,#symbol{info = Enums}} ->
case lists:keysearch(Int, 2, Enums) of
{value, {Enum, _Int}} -> {value, Enum};
@@ -256,14 +274,18 @@ int_to_enum(Db,TypeOrObjName,Int) ->
end.
enum_to_int(Db, TypeOrObjName, Enum) ->
- case snmpa_general_db:read(Db, {alias, TypeOrObjName}) of
+ Mod = which_module(),
+ enum_to_int(Mod, Db, TypeOrObjName, Enum).
+
+enum_to_int(Mod, Db, TypeOrObjName, Enum) ->
+ case Mod:read(Db, {alias, TypeOrObjName}) of
{value,#symbol{info = {_Oid, Enums}}} ->
case lists:keysearch(Enum, 1, Enums) of
{value, {_Enum, Int}} -> {value, Int};
false -> false
end;
false -> % Not an Aliasname
- case snmpa_general_db:read(Db, {type, TypeOrObjName}) of
+ case Mod:read(Db, {type, TypeOrObjName}) of
{value,#symbol{info = Enums}} ->
case lists:keysearch(Enum, 1, Enums) of
{value, {_Enum, Int}} -> {value, Int};
@@ -278,8 +300,9 @@ enum_to_int(Db, TypeOrObjName, Enum) ->
%%----------------------------------------------------------------------
%% DB access (read) functions: Returns: false|{value, Info}
%%----------------------------------------------------------------------
-table_info(Db,TableName) ->
- case snmpa_general_db:read(Db, {table_info, TableName}) of
+
+table_info(Mod, Db, TableName) ->
+ case Mod:read(Db, {table_info, TableName}) of
{value,#symbol{info = Info}} -> {value, Info};
false -> false
end.
@@ -288,8 +311,8 @@ table_info(Db,TableName) ->
%%----------------------------------------------------------------------
%% DB access (read) functions: Returns: false|{value, Info}
%%----------------------------------------------------------------------
-variable_info(Db,VariableName) ->
- case snmpa_general_db:read(Db, {variable_info, VariableName}) of
+variable_info(Mod, Db, VariableName) ->
+ case Mod:read(Db, {variable_info, VariableName}) of
{value,#symbol{info = Info}} -> {value, Info};
false -> false
end.
@@ -299,7 +322,7 @@ variable_info(Db,VariableName) ->
%% Implementation
%%----------------------------------------------------------------------
-init([Prio,Opts]) ->
+init([Prio, Opts]) ->
?d("init -> entry with"
"~n Prio: ~p"
"~n Opts: ~p", [Prio,Opts]),
@@ -317,102 +340,125 @@ do_init(Prio, Opts) ->
put(sname,ss),
put(verbosity,get_verbosity(Opts)),
?vlog("starting",[]),
- Storage = get_mib_storage(Opts),
+ MibStorage = get_mib_storage(Opts),
+ Mod = snmp_misc:get_option(module, MibStorage),
+ MsOpts = snmp_misc:get_option(options, MibStorage, []),
+
%% type = bag solves the problem with import and multiple
%% object/type definitions.
- Db = snmpa_general_db:open(Storage, snmpa_symbolic_store,
- symbol, record_info(fields,symbol), bag),
- S = #state{db = Db},
- ?vdebug("started",[]),
- {ok, S}.
+ case Mod:open(?MODULE, symbol, record_info(fields, symbol), bag, MsOpts) of
+ {ok, Db} ->
+ S = #state{module = Mod, db = Db},
+ ?vdebug("started",[]),
+ {ok, S};
+ {error, _} = ERROR ->
+ ERROR
+ end.
handle_call(get_db, _From, #state{db = DB} = S) ->
?vlog("get db",[]),
{reply, DB, S};
-handle_call({table_info, TableName}, _From, #state{db = DB} = S) ->
+handle_call(which_module, _From, #state{module = Mod} = S) ->
+ ?vlog("which module",[]),
+ {reply, Mod, S};
+
+handle_call({table_info, TableName}, _From,
+ #state{module = Mod, db = DB} = S) ->
?vlog("table info: ~p",[TableName]),
- Res = table_info(DB, TableName),
+ Res = table_info(Mod, DB, TableName),
?vdebug("table info result: ~p",[Res]),
{reply, Res, S};
-handle_call({variable_info, VariableName}, _From, #state{db = DB} = S) ->
+handle_call({variable_info, VariableName}, _From,
+ #state{module = Mod, db = DB} = S) ->
?vlog("variable info: ~p",[VariableName]),
- Res = variable_info(DB, VariableName),
+ Res = variable_info(Mod, DB, VariableName),
?vdebug("variable info result: ~p",[Res]),
{reply, Res, S};
-handle_call({aliasname_to_oid, Aliasname}, _From, #state{db = DB} = S) ->
+handle_call({aliasname_to_oid, Aliasname}, _From,
+ #state{module = Mod, db = DB} = S) ->
?vlog("aliasname to oid: ~p",[Aliasname]),
- Res = aliasname_to_oid(DB,Aliasname),
+ Res = aliasname_to_oid(Mod, DB, Aliasname),
?vdebug("aliasname to oid result: ~p",[Res]),
{reply, Res, S};
-handle_call({oid_to_aliasname, Oid}, _From, #state{db = DB} = S) ->
+handle_call({oid_to_aliasname, Oid}, _From,
+ #state{module = Mod, db = DB} = S) ->
?vlog("oid to aliasname: ~p",[Oid]),
- Res = oid_to_aliasname(DB, Oid),
+ Res = oid_to_aliasname(Mod, DB, Oid),
?vdebug("oid to aliasname result: ~p",[Res]),
{reply, Res, S};
-handle_call(which_aliasnames, _From, #state{db = DB} = S) ->
+handle_call(which_aliasnames, _From,
+ #state{module = Mod, db = DB} = S) ->
?vlog("which aliasnames",[]),
- Res = which_aliasnames(DB),
+ Res = which_aliasnames(Mod, DB),
?vdebug("which aliasnames: ~p",[Res]),
{reply, Res, S};
-handle_call(which_tables, _From, #state{db = DB} = S) ->
+handle_call(which_tables, _From,
+ #state{module = Mod, db = DB} = S) ->
?vlog("which tables",[]),
- Res = which_tables(DB),
+ Res = which_tables(Mod, DB),
?vdebug("which tables: ~p",[Res]),
{reply, Res, S};
-handle_call(which_variables, _From, #state{db = DB} = S) ->
+handle_call(which_variables, _From,
+ #state{module = Mod, db = DB} = S) ->
?vlog("which variables",[]),
- Res = which_variables(DB),
+ Res = which_variables(Mod, DB),
?vdebug("which variables: ~p",[Res]),
{reply, Res, S};
-handle_call({enum_to_int, TypeOrObjName, Enum}, _From, #state{db = DB} = S) ->
+handle_call({enum_to_int, TypeOrObjName, Enum}, _From,
+ #state{module = Mod, db = DB} = S) ->
?vlog("enum to int: ~p, ~p",[TypeOrObjName,Enum]),
- Res = enum_to_int(DB, TypeOrObjName, Enum),
+ Res = enum_to_int(Mod, DB, TypeOrObjName, Enum),
?vdebug("enum to int result: ~p",[Res]),
{reply, Res, S};
-handle_call({int_to_enum, TypeOrObjName, Int}, _From, #state{db = DB} = S) ->
+handle_call({int_to_enum, TypeOrObjName, Int}, _From,
+ #state{module = Mod, db = DB} = S) ->
?vlog("int to enum: ~p, ~p",[TypeOrObjName,Int]),
- Res = int_to_enum(DB, TypeOrObjName, Int),
+ Res = int_to_enum(Mod, DB, TypeOrObjName, Int),
?vdebug("int to enum result: ~p",[Res]),
{reply, Res, S};
-handle_call({set_notification, MibName, Trap}, _From, #state{db = DB} = S) ->
+handle_call({set_notification, MibName, Trap}, _From,
+ #state{module = Mod, db = DB} = S) ->
?vlog("set notification:"
"~n ~p~n ~p", [MibName,Trap]),
- set_notif(DB, MibName, Trap),
+ set_notif(Mod, DB, MibName, Trap),
{reply, true, S};
-handle_call({delete_notifications, MibName}, _From, #state{db = DB} = S) ->
+handle_call({delete_notifications, MibName}, _From,
+ #state{module = Mod, db = DB} = S) ->
?vlog("delete notification: ~p",[MibName]),
- delete_notif(DB, MibName),
+ delete_notif(Mod, DB, MibName),
{reply, true, S};
-handle_call(which_notifications, _From, #state{db = DB} = S) ->
+handle_call(which_notifications, _From,
+ #state{module = Mod, db = DB} = S) ->
?vlog("which notifications", []),
- Reply = which_notifications(DB),
+ Reply = which_notifications(Mod, DB),
{reply, Reply, S};
-handle_call({get_notification, Key}, _From, #state{db = DB} = S) ->
+handle_call({get_notification, Key}, _From,
+ #state{module = Mod, db = DB} = S) ->
?vlog("get notification: ~p",[Key]),
- Res = get_notif(DB, Key),
+ Res = get_notif(Mod, DB, Key),
?vdebug("get notification result: ~p",[Res]),
{reply, Res, S};
-handle_call(info, _From, #state{db = DB} = S) ->
+handle_call(info, _From, #state{module = Mod, db = DB} = S) ->
?vlog("info",[]),
- Info = get_info(DB),
+ Info = get_info(Mod, DB),
{reply, Info, S};
-handle_call({backup, BackupDir}, From, #state{db = DB} = S) ->
+handle_call({backup, BackupDir}, From, #state{module = Mod, db = DB} = S) ->
?vlog("info to ~p",[BackupDir]),
Pid = self(),
V = get(verbosity),
@@ -424,7 +470,7 @@ handle_call({backup, BackupDir}, From, #state{db = DB} = S) ->
put(sname, albs),
put(verbosity, V),
Dir = filename:join([BackupDir]),
- Reply = snmpa_general_db:backup(DB, Dir),
+ Reply = Mod:backup(DB, Dir),
Pid ! {backup_done, Reply},
unlink(Pid)
end),
@@ -446,7 +492,7 @@ handle_call(Req, _From, S) ->
{reply, Reply, S}.
-handle_cast({add_types, MibName, Types}, #state{db = DB} = S) ->
+handle_cast({add_types, MibName, Types}, #state{module = Mod, db = DB} = S) ->
?vlog("add types for ~p:",[MibName]),
F = fun(#asn1_type{assocList = Alist, aliasname = Name}) ->
case snmp_misc:assq(enums, Alist) of
@@ -455,20 +501,21 @@ handle_cast({add_types, MibName, Types}, #state{db = DB} = S) ->
Rec = #symbol{key = {type, Name},
mib_name = MibName,
info = Es},
- snmpa_general_db:write(DB, Rec);
+ Mod:write(DB, Rec);
false -> done
end
end,
lists:foreach(F, Types),
{noreply, S};
-handle_cast({delete_types, MibName}, #state{db = DB} = S) ->
+handle_cast({delete_types, MibName}, #state{module = Mod, db = DB} = S) ->
?vlog("delete types: ~p",[MibName]),
Pattern = #symbol{key = {type, '_'}, mib_name = MibName, info = '_'},
- snmpa_general_db:match_delete(DB, Pattern),
+ Mod:match_delete(DB, Pattern),
{noreply, S};
-handle_cast({add_aliasnames, MibName, MEs}, #state{db = DB} = S) ->
+handle_cast({add_aliasnames, MibName, MEs},
+ #state{module = Mod, db = DB} = S) ->
?vlog("add aliasnames for ~p:",[MibName]),
F = fun(#me{aliasname = AN, oid = Oid, asn1_type = AT}) ->
Enums =
@@ -480,20 +527,21 @@ handle_cast({add_aliasnames, MibName, MEs}, #state{db = DB} = S) ->
end;
_ -> []
end,
- write_alias(AN, DB, Enums, MibName, Oid)
+ write_alias(Mod, AN, DB, Enums, MibName, Oid)
end,
lists:foreach(F, MEs),
{noreply, S};
-handle_cast({delete_aliasname, MibName}, #state{db = DB} = S) ->
+handle_cast({delete_aliasname, MibName}, #state{module = Mod, db = DB} = S) ->
?vlog("delete aliasname: ~p",[MibName]),
Pattern1 = #symbol{key = {alias, '_'}, mib_name = MibName, info = '_'},
- snmpa_general_db:match_delete(DB, Pattern1),
+ Mod:match_delete(DB, Pattern1),
Pattern2 = #symbol{key = {oid, '_'}, mib_name = MibName, info = '_'},
- snmpa_general_db:match_delete(DB, Pattern2),
+ Mod:match_delete(DB, Pattern2),
{noreply, S};
-handle_cast({add_table_infos, MibName, TableInfos}, #state{db = DB} = S) ->
+handle_cast({add_table_infos, MibName, TableInfos},
+ #state{module = Mod, db = DB} = S) ->
?vlog("add table infos for ~p:",[MibName]),
F = fun({Name, TableInfo}) ->
?vlog("add table info~n ~p -> ~p",
@@ -501,19 +549,20 @@ handle_cast({add_table_infos, MibName, TableInfos}, #state{db = DB} = S) ->
Rec = #symbol{key = {table_info, Name},
mib_name = MibName,
info = TableInfo},
- snmpa_general_db:write(DB, Rec)
+ Mod:write(DB, Rec)
end,
lists:foreach(F, TableInfos),
{noreply, S};
-handle_cast({delete_table_infos, MibName}, #state{db = DB} = S) ->
+handle_cast({delete_table_infos, MibName},
+ #state{module = Mod, db = DB} = S) ->
?vlog("delete table infos: ~p",[MibName]),
Pattern = #symbol{key = {table_info, '_'}, mib_name = MibName, info = '_'},
- snmpa_general_db:match_delete(DB, Pattern),
+ Mod:match_delete(DB, Pattern),
{noreply, S};
handle_cast({add_variable_infos, MibName, VariableInfos},
- #state{db = DB} = S) ->
+ #state{module = Mod, db = DB} = S) ->
?vlog("add variable infos for ~p:",[MibName]),
F = fun({Name, VariableInfo}) ->
?vlog("add variable info~n ~p -> ~p",
@@ -521,17 +570,18 @@ handle_cast({add_variable_infos, MibName, VariableInfos},
Rec = #symbol{key = {variable_info, Name},
mib_name = MibName,
info = VariableInfo},
- snmpa_general_db:write(DB, Rec)
+ Mod:write(DB, Rec)
end,
lists:foreach(F, VariableInfos),
{noreply, S};
-handle_cast({delete_variable_infos, MibName}, #state{db = DB} = S) ->
+handle_cast({delete_variable_infos, MibName},
+ #state{module = Mod, db = DB} = S) ->
?vlog("delete variable infos: ~p",[MibName]),
Pattern = #symbol{key = {variable_info,'_'},
mib_name = MibName,
info = '_'},
- snmpa_general_db:match_delete(DB, Pattern),
+ Mod:match_delete(DB, Pattern),
{noreply, S};
handle_cast({verbosity,Verbosity}, State) ->
@@ -565,9 +615,9 @@ handle_info(Info, S) ->
{noreply, S}.
-terminate(Reason, S) ->
- ?vlog("terminate: ~p",[Reason]),
- snmpa_general_db:close(S#state.db).
+terminate(Reason, #state{module = Mod, db = DB}) ->
+ ?vlog("terminate: ~p", [Reason]),
+ Mod:close(DB).
%%----------------------------------------------------------
@@ -575,28 +625,28 @@ terminate(Reason, S) ->
%%----------------------------------------------------------
% downgrade
-code_change({down, _Vsn}, #state{db = DB, backup = B}, downgrade_to_pre_4_7) ->
- ?d("code_change(down) -> entry", []),
- stop_backup_server(B),
- S = {state, DB},
- {ok, S};
-
-% upgrade
-code_change(_Vsn, S, upgrade_from_pre_4_7) ->
- ?d("code_change(up) -> entry", []),
- {state, DB} = S,
- S1 = #state{db = DB},
- {ok, S1};
+%% code_change({down, _Vsn}, #state{db = DB, backup = B}, downgrade_to_pre_4_7) ->
+%% ?d("code_change(down) -> entry", []),
+%% stop_backup_server(B),
+%% S = {state, DB},
+%% {ok, S};
+
+%% % upgrade
+%% code_change(_Vsn, S, upgrade_from_pre_4_7) ->
+%% ?d("code_change(up) -> entry", []),
+%% {state, DB} = S,
+%% S1 = #state{db = DB},
+%% {ok, S1};
code_change(_Vsn, S, _Extra) ->
?d("code_change -> entry [do nothing]", []),
{ok, S}.
-stop_backup_server(undefined) ->
- ok;
-stop_backup_server({Pid, _}) when is_pid(Pid) ->
- exit(Pid, kill).
+%% stop_backup_server(undefined) ->
+%% ok;
+%% stop_backup_server({Pid, _}) when is_pid(Pid) ->
+%% exit(Pid, kill).
@@ -609,13 +659,13 @@ stop_backup_server({Pid, _}) when is_pid(Pid) ->
%%-----------------------------------------------------------------
%% Returns: {value, Value} | undefined
%%-----------------------------------------------------------------
-get_notif(Db, Key) ->
- case snmpa_general_db:read(Db, {trap, Key}) of
+get_notif(Mod, Db, Key) ->
+ case Mod:read(Db, {trap, Key}) of
{value,#symbol{info = Value}} -> {value, Value};
false -> undefined
end.
-set_notif(Db, MibName, Trap) when is_record(Trap, trap) ->
+set_notif(Mod, Db, MibName, Trap) when is_record(Trap, trap) ->
#trap{trapname = Name} = Trap,
Rec = #symbol{key = {trap, Name}, mib_name = MibName, info = Trap},
%% convert old v1 trap to oid
@@ -625,40 +675,41 @@ set_notif(Db, MibName, Trap) when is_record(Trap, trap) ->
Oid0 ->
Oid0 ++ [0, Trap#trap.specificcode]
end,
- write_alias(Name, Db, MibName, Oid),
- snmpa_general_db:write(Db, Rec);
-set_notif(Db, MibName, Trap) ->
+ write_alias(Mod, Name, Db, MibName, Oid),
+ Mod:write(Db, Rec);
+set_notif(Mod, Db, MibName, Trap) ->
#notification{trapname = Name, oid = Oid} = Trap,
Rec = #symbol{key = {trap, Name}, mib_name = MibName, info = Trap},
- write_alias(Name, Db, MibName, Oid),
- snmpa_general_db:write(Db, Rec).
+ write_alias(Mod, Name, Db, MibName, Oid),
+ Mod:write(Db, Rec).
-delete_notif(Db, MibName) ->
+delete_notif(Mod, Db, MibName) ->
Pattern = #symbol{key = {trap, '_'}, mib_name = MibName, info = '_'},
- snmpa_general_db:match_delete(Db, Pattern).
+ Mod:match_delete(Db, Pattern).
-write_alias(AN, DB, MibName, Oid) ->
- write_alias(AN, DB, [], MibName, Oid).
+write_alias(Mod, AN, DB, MibName, Oid) ->
+ write_alias(Mod, AN, DB, [], MibName, Oid).
-write_alias(AN, DB, Enums, MibName, Oid) ->
+write_alias(Mod, AN, DB, Enums, MibName, Oid) ->
?vlog("add alias~n ~p -> {~p,~p}",[AN, Oid, Enums]),
Rec1 = #symbol{key = {alias, AN},
mib_name = MibName,
info = {Oid,Enums}},
- snmpa_general_db:write(DB, Rec1),
+ Mod:write(DB, Rec1),
?vlog("add oid~n ~p -> ~p",[Oid, AN]),
Rec2 = #symbol{key = {oid, Oid},
mib_name = MibName,
info = AN},
- snmpa_general_db:write(DB, Rec2).
+ Mod:write(DB, Rec2).
+
%% -------------------------------------
-get_info(DB) ->
+get_info(Mod, DB) ->
ProcSize = proc_mem(self()),
- DbSz = tab_size(DB),
- [{process_memory, ProcSize}, {db_memory, DbSz}].
+ DbMemory = Mod:info(DB, memory),
+ [{process_memory, ProcSize}, {db_memory, DbMemory}].
proc_mem(P) when is_pid(P) ->
case (catch erlang:process_info(P, memory)) of
@@ -667,26 +718,15 @@ proc_mem(P) when is_pid(P) ->
_ ->
undefined
end.
-%% proc_mem(_) ->
-%% undefined.
-
-tab_size(DB) ->
- case (catch snmpa_general_db:info(DB, memory)) of
- Sz when is_integer(Sz) ->
- Sz;
- _ ->
- undefined
- end.
-
%% -------------------------------------
get_verbosity(L) ->
- snmp_misc:get_option(verbosity,L,?default_verbosity).
+ snmp_misc:get_option(verbosity, L, ?default_verbosity).
get_mib_storage(L) ->
- snmp_misc:get_option(mib_storage,L,ets).
+ snmp_misc:get_option(mib_storage, L).
%% -------------------------------------
diff --git a/lib/snmp/src/agent/snmpa_target_cache.erl b/lib/snmp/src/agent/snmpa_target_cache.erl
index 2aa35aa46a..72caf72b33 100644
--- a/lib/snmp/src/agent/snmpa_target_cache.erl
+++ b/lib/snmp/src/agent/snmpa_target_cache.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -21,8 +22,6 @@
-behaviour(gen_server).
%% External exports
-%% Avoid warning for local function demonitor/1 clashing with autoimported BIF.
--compile({no_auto_import,[demonitor/1]}).
-export([start_link/2, stop/0, verbosity/1]).
-export([
@@ -213,21 +212,6 @@ do_init(Prio, Opts) ->
%% requests will have to wait.
%%
-monitor(Pid) -> erlang:monitor(process, Pid).
--ifdef(SNMP_R10).
-demonitor(Ref) ->
- erlang:demonitor(Ref),
- receive
- {_, Ref, _, _, _} ->
- true
- after 0 ->
- true
- end.
--else.
-demonitor(Ref) ->
- erlang:demonitor(Ref, [flush]).
--endif.
-
%% (1) No write_lock active or waiting
handle_call({lock, read = Type, infinity}, {Pid, _} = From,
@@ -236,7 +220,7 @@ handle_call({lock, read = Type, infinity}, {Pid, _} = From,
"entry when no waiting or active writer with"
"~n Pid: ~p"
"~n Cnt: ~p", [Pid, Cnt]),
- MonRef = monitor(Pid),
+ MonRef = erlang:monitor(process, Pid),
Locker = #locker{pid = Pid,
from = From,
mon_ref = MonRef,
@@ -252,7 +236,7 @@ handle_call({lock, read = Type, infinity}, {Pid, _} = From, State) ->
?vlog("lock(read, infinity) -> "
"entry when active or waiting write locks with"
"~n Pid: ~p", [Pid]),
- MonRef = monitor(Pid),
+ MonRef = erlang:monitor(process, Pid),
Locker = #locker{pid = Pid,
from = From,
mon_ref = MonRef,
@@ -273,7 +257,7 @@ handle_call({lock, write = Type, infinity}, {Pid, _} = From,
?vlog("lock(write, infinity) -> "
"entry when no active lockers with"
"~n Pid: ~p", [Pid]),
- MonRef = monitor(Pid),
+ MonRef = erlang:monitor(process, Pid),
Locker = #locker{pid = Pid,
from = From,
mon_ref = MonRef,
@@ -290,7 +274,7 @@ handle_call({lock, write = Type, infinity}, {Pid, _} = From,
?vlog("lock(write, infinity) -> "
"entry when active lockers with"
"~n Pid: ~p", [Pid]),
- MonRef = monitor(Pid),
+ MonRef = erlang:monitor(process, Pid),
Locker = #locker{pid = Pid,
from = From,
mon_ref = MonRef,
@@ -307,7 +291,7 @@ handle_call({lock, write = Type, infinity}, {Pid, _} = From,
#state{writer = true} = State) ->
?vlog("lock(write, infinity) -> entry with"
"~n Pid: ~p", [Pid]),
- MonRef = monitor(Pid),
+ MonRef = erlang:monitor(process, Pid),
Locker = #locker{pid = Pid,
from = From,
mon_ref = MonRef,
@@ -429,7 +413,7 @@ handle_cast({unlock, Pid},
[#locker{mon_ref = MonRef, type = read}] ->
?vdebug("unlock -> found read locker"
"~n MonRef: ~p", [MonRef]),
- demonitor(MonRef),
+ erlang:demonitor(MonRef, [flush]),
ets:delete(?LOCKER_TAB, Pid),
%% ?vtrace("unlock -> done when"
%% "~n Lockers: ~p", [ets:tab2list(?LOCKER_TAB)]),
@@ -437,7 +421,7 @@ handle_cast({unlock, Pid},
[#locker{mon_ref = MonRef, type = write}] ->
?vdebug("unlock -> found write locker"
"~n MonRef: ~p", [MonRef]),
- demonitor(MonRef),
+ erlang:demonitor(MonRef, [flush]),
ets:delete(?LOCKER_TAB, Pid),
%% ?vtrace("unlock -> done when"
%% "~n Lockers: ~p", [ets:tab2list(?LOCKER_TAB)]),
@@ -459,7 +443,7 @@ handle_cast({unlock, Pid},
[#locker{mon_ref = MonRef, type = read}] when (Cnt == 1) ->
?vdebug("unlock -> found read locker"
"~n MonRef: ~p", [MonRef]),
- demonitor(MonRef),
+ erlang:demonitor(MonRef, [flush]),
ets:delete(?LOCKER_TAB, Pid),
case active_waiting_writer(Waiting) of
{true, StillWaiting} ->
@@ -482,7 +466,7 @@ handle_cast({unlock, Pid},
[#locker{mon_ref = MonRef, type = read}] ->
?vdebug("unlock -> found read locker"
"~n MonRef: ~p", [MonRef]),
- demonitor(MonRef),
+ erlang:demonitor(MonRef, [flush]),
ets:delete(?LOCKER_TAB, Pid),
%% ?vtrace("unlock -> done when"
%% "~n Lockers: ~p", [ets:tab2list(?LOCKER_TAB)]),
@@ -492,7 +476,7 @@ handle_cast({unlock, Pid},
%% Release the hord (maybe)
?vdebug("unlock -> found write locker"
"~n MonRef: ~p", [MonRef]),
- demonitor(MonRef),
+ erlang:demonitor(MonRef, [flush]),
ets:delete(?LOCKER_TAB, Pid),
{Active, StillWaiting, Writer} =
activate_waiting_readers_or_maybe_writer(Waiting),
diff --git a/lib/snmp/src/agent/snmpa_trap.erl b/lib/snmp/src/agent/snmpa_trap.erl
index 994d926224..e75016f7ec 100644
--- a/lib/snmp/src/agent/snmpa_trap.erl
+++ b/lib/snmp/src/agent/snmpa_trap.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
+%% 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
%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -270,12 +271,13 @@ localise_type({VariableOid, Value}, Mib) when is_list(VariableOid) ->
localise_type(X, _) -> X.
%%-----------------------------------------------------------------
-%% Func: make_v1_trap_pdu/4
+%% Func: make_v1_trap_pdu/5
%% Args: Enterprise = oid()
%% Specific = integer()
%% Varbinds is as returned from initiate_vars
%% (but only {Oid, Type[, Value} permitted)
%% SysUpTime = integer()
+%% AgentIp = {A, B, C, D}
%% Purpose: Make a #trappdu
%% Checks the Varbinds to see that no symbolic names are
%% present, and that each var has a type. Performs a get
@@ -284,7 +286,7 @@ localise_type(X, _) -> X.
%% Fails: yes
%% NOTE: Executed at the MA
%%-----------------------------------------------------------------
-make_v1_trap_pdu(Enterprise, Specific, VarbindList, SysUpTime) ->
+make_v1_trap_pdu(Enterprise, Specific, VarbindList, SysUpTime, AgentIp) ->
{Enterp,Generic,Spec} =
case Enterprise of
?snmp ->
@@ -292,7 +294,6 @@ make_v1_trap_pdu(Enterprise, Specific, VarbindList, SysUpTime) ->
_ ->
{Enterprise,?enterpriseSpecific,Specific}
end,
- {value, AgentIp} = snmp_framework_mib:intAgentIpAddress(get),
#trappdu{enterprise = Enterp,
agent_addr = AgentIp,
generic_trap = Generic,
@@ -369,6 +370,7 @@ send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID,
{tag, T},
{err, E},
{stacktrace, erlang:get_stacktrace()}],
+ ?vlog("snmpa_trap:send_trap exception: ~p", [Info]),
{error, {failed_sending_trap, Info}}
end.
@@ -789,23 +791,19 @@ send_trap_pdus([], ContextName, {TrapRec, Vbs},
send_v1_trap(_TrapRec, [], _Vbs, _ExtraInfo, _NetIf, _SysUpTime) ->
ok;
-send_v1_trap(#trap{enterpriseoid = Enter, specificcode = Spec},
- V1Res, Vbs, ExtraInfo, NetIf, SysUpTime) ->
+send_v1_trap(
+ #trap{enterpriseoid = Enter, specificcode = Spec},
+ V1Res, Vbs, ExtraInfo, NetIf, SysUpTime) ->
?vdebug("prepare to send v1 trap "
"~n '~p'"
"~n with"
"~n ~p"
"~n to"
"~n ~p", [Enter, Spec, V1Res]),
- TrapPdu = make_v1_trap_pdu(Enter, Spec, Vbs, SysUpTime),
- AddrCommunities = mk_addr_communities(V1Res),
- lists:foreach(fun({Community, Addrs}) ->
- ?vtrace("send v1 trap pdu to ~p",[Addrs]),
- NetIf ! {send_pdu, 'version-1', TrapPdu,
- {community, Community}, Addrs, ExtraInfo}
- end, AddrCommunities);
-send_v1_trap(#notification{oid = Oid}, V1Res, Vbs, ExtraInfo, NetIf,
- SysUpTime) ->
+ do_send_v1_trap(Enter, Spec, V1Res, Vbs, ExtraInfo, NetIf, SysUpTime);
+send_v1_trap(
+ #notification{oid = Oid},
+ V1Res, Vbs, ExtraInfo, NetIf, SysUpTime) ->
%% Use alg. in rfc2089 to map a v2 trap to a v1 trap
% delete Counter64 objects from vbs
?vdebug("prepare to send v1 trap '~p'",[Oid]),
@@ -822,14 +820,38 @@ send_v1_trap(#notification{oid = Oid}, V1Res, Vbs, ExtraInfo, NetIf,
{lists:reverse(First),Last}
end
end,
- TrapPdu = make_v1_trap_pdu(Enter, Spec, NVbs, SysUpTime),
+ do_send_v1_trap(Enter, Spec, V1Res, NVbs, ExtraInfo, NetIf, SysUpTime).
+
+do_send_v1_trap(Enter, Spec, V1Res, NVbs, ExtraInfo, NetIf, SysUpTime) ->
+ {value, Transports} = snmp_framework_mib:intAgentTransports(get),
+ {_Domain, {AgentIp, _AgentPort}} =
+ case lists:keyfind(snmpUDPDomain, 1, Transports) of
+ false ->
+ case lists:keyfind(transportDomainUdpIpv4, 1, Transports) of
+ false ->
+ ?vtrace(
+ "snmpa_trap: can not send v1 trap "
+ "without IPv4 domain: ~p",
+ [Transports]),
+ user_err(
+ "snmpa_trap: can not send v1 trap "
+ "without IPv4 domain: ~p",
+ [Transports]);
+ DomainAddr ->
+ DomainAddr
+ end;
+ DomainAddr ->
+ DomainAddr
+ end,
+ TrapPdu = make_v1_trap_pdu(Enter, Spec, NVbs, SysUpTime, AgentIp),
AddrCommunities = mk_addr_communities(V1Res),
- lists:foreach(fun({Community, Addrs}) ->
- ?vtrace("send v1 trap to ~p",[Addrs]),
- NetIf ! {send_pdu, 'version-1', TrapPdu,
- {community, Community}, Addrs, ExtraInfo}
- end, AddrCommunities).
-
+ lists:foreach(
+ fun ({Community, Addrs}) ->
+ ?vtrace("send v1 trap to ~p",[Addrs]),
+ NetIf ! {send_pdu, 'version-1', TrapPdu,
+ {community, Community}, Addrs, ExtraInfo}
+ end, AddrCommunities).
+
send_v2_trap(_TrapRec, [], _Vbs, _Recv, _ExtraInfo, _NetIf, _SysUpTime) ->
ok;
send_v2_trap(TrapRec, V2Res, Vbs, Recv, ExtraInfo, NetIf, SysUpTime) ->
@@ -1045,7 +1067,7 @@ deliver_recv(#snmpa_notification_delivery_info{tag = Tag,
"~n DeliveryResult: ~p"
"~n TAddr: ~p"
"", [Tag, Mod, Extra, DeliveryResult, TAddr]),
- Addr = transform_taddr(TAddr),
+ [Addr] = transform_taddrs([TAddr]),
(catch Mod:delivery_info(Tag, Addr, DeliveryResult, Extra));
deliver_recv({Tag, Receiver}, MsgId, Result) ->
?vtrace("deliver_recv -> entry with"
@@ -1072,35 +1094,90 @@ deliver_recv(Else, _MsgId, _Result) ->
[Else]),
user_err("snmpa: bad receiver, ~w\n", [Else]).
-transform_taddrs(Addrs) ->
- [transform_taddr(Addr) || Addr <- Addrs].
+transform_taddrs(TAddrs) ->
+ UseTDomain =
+ case snmp_framework_mib:intAgentTransportDomain(get) of
+ {value,snmpUDPDomain} ->
+ false;
+ {value,_} ->
+ true;
+ genErr ->
+ false
+ end,
+ DomAddrs = [transform_taddr(TAddr) || TAddr <- TAddrs],
+ case UseTDomain of
+ true ->
+ DomAddrs;
+ false ->
+ [Addr || {_Domain, Addr} <- DomAddrs]
+ end.
-transform_taddr({?snmpUDPDomain, [A1, A2, A3, A4, P1, P2]}) -> % v2
- Addr = {A1, A2, A3, A4},
+%% v2
+transform_taddr({?snmpUDPDomain, Addr}) ->
+ transform_taddr(transportDomainIdpIpv4, Addr);
+transform_taddr({?transportDomainUdpIpv4, Addr}) ->
+ transform_taddr(transportDomainUdpIpv4, Addr);
+transform_taddr({?transportDomainUdpIpv6, Addr}) ->
+ transform_taddr(transportDomainUdpIpv6, Addr);
+%% v3
+transform_taddr({{?snmpUDPDomain, Addr}, _MsgData}) ->
+ transform_taddr(transportDomainUdpIpv4, Addr);
+transform_taddr({{?transportDomainUdpIpv4, Addr}, _MsgData}) ->
+ transform_taddr(transportDomainUdpIpv4, Addr);
+transform_taddr({{?transportDomainUdpIpv6, Addr}, _MsgData}) ->
+ transform_taddr(transportDomainUdpIpv6, Addr).
+
+transform_taddr(
+ transportDomainUdpIpv4 = Domain,
+ [A1,A2,A3,A4,P1,P2]) ->
+ Ip = {A1, A2, A3, A4},
Port = P1 bsl 8 + P2,
- {Addr, Port};
-transform_taddr({?transportDomainUdpIpv4, [A1, A2, A3, A4, P1, P2]}) -> % v2
- Addr = {A1, A2, A3, A4},
+ {Domain, {Ip, Port}};
+transform_taddr(
+ transportDomainUdpIpv6 = Domain,
+ [A1, A2, A3, A4, A5, A6, A7, A8, P1, P2]) ->
+ Ip = {A1, A2, A3, A4, A5, A6, A7, A8},
Port = P1 bsl 8 + P2,
- {Addr, Port};
-transform_taddr({?transportDomainUdpIpv6,
- [A1, A2, A3, A4, A5, A6, A7, A8, P1, P2]}) -> % v2
- Addr = {A1, A2, A3, A4, A5, A6, A7, A8},
+ {Domain, {Ip, Port}};
+transform_taddr(
+ transportDomainUdpIpv6 = Domain,
+ [A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16,
+ P1, P2]) ->
+ Ip =
+ {(A1 bsl 8) bor A2, (A3 bsl 8) bor A4,
+ (A5 bsl 8) bor A6, (A7 bsl 8) bor A8,
+ (A9 bsl 8) bor A10, (A11 bsl 8) bor A12,
+ (A13 bsl 8) bor A14, (A15 bsl 8) bor A16},
Port = P1 bsl 8 + P2,
- {Addr, Port};
-transform_taddr({{?snmpUDPDomain, [A1, A2, A3, A4, P1, P2]}, _MsgData}) -> % v3
- Addr = {A1, A2, A3, A4},
- Port = P1 bsl 8 + P2,
- {Addr, Port};
-transform_taddr({{?transportDomainUdpIpv4, [A1, A2, A3, A4, P1, P2]}, _MsgData}) -> % v3
- Addr = {A1, A2, A3, A4},
- Port = P1 bsl 8 + P2,
- {Addr, Port};
-transform_taddr({{?transportDomainUdpIpv6,
- [A1, A2, A3, A4, A5, A6, A7, A8, P1, P2]}, _MsgData}) -> % v3
- Addr = {A1, A2, A3, A4, A5, A6, A7, A8},
- Port = P1 bsl 8 + P2,
- {Addr, Port}.
+ {Domain, {Ip, Port}}.
+
+%% transform_taddr({?snmpUDPDomain, [A1, A2, A3, A4, P1, P2]}) -> % v2
+%% Addr = {A1, A2, A3, A4},
+%% Port = P1 bsl 8 + P2,
+%% {Addr, Port};
+%% transform_taddr({?transportDomainUdpIpv4, [A1, A2, A3, A4, P1, P2]}) -> % v2
+%% Addr = {A1, A2, A3, A4},
+%% Port = P1 bsl 8 + P2,
+%% {Addr, Port};
+%% transform_taddr({?transportDomainUdpIpv6,
+%% [A1, A2, A3, A4, A5, A6, A7, A8, P1, P2]}) -> % v2
+%% Addr = {A1, A2, A3, A4, A5, A6, A7, A8},
+%% Port = P1 bsl 8 + P2,
+%% {Addr, Port};
+%% transform_taddr({{?snmpUDPDomain, [A1, A2, A3, A4, P1, P2]}, _MsgData}) -> % v3
+%% Addr = {A1, A2, A3, A4},
+%% Port = P1 bsl 8 + P2,
+%% {Addr, Port};
+%% transform_taddr({{?transportDomainUdpIpv4, [A1, A2, A3, A4, P1, P2]}, _MsgData}) -> % v3
+%% Addr = {A1, A2, A3, A4},
+%% Port = P1 bsl 8 + P2,
+%% {Addr, Port};
+%% transform_taddr({{?transportDomainUdpIpv6,
+%% [A1, A2, A3, A4, A5, A6, A7, A8, P1, P2]}, _MsgData}) -> % v3
+%% Addr = {A1, A2, A3, A4, A5, A6, A7, A8},
+%% Port = P1 bsl 8 + P2,
+%% {Addr, Port}.
+
check_all_varbinds(#notification{oid = Oid}, Vbs, MibView) ->
diff --git a/lib/snmp/src/agent/snmpa_usm.erl b/lib/snmp/src/agent/snmpa_usm.erl
index 6f54307f9f..fb616cd9ef 100644
--- a/lib/snmp/src/agent/snmpa_usm.erl
+++ b/lib/snmp/src/agent/snmpa_usm.erl
@@ -1,21 +1,25 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2015. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
+%% 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
%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
+%% AES: RFC 3826
+%%
+
-module(snmpa_usm).
%% Avoid warning for local function error/1 clashing with autoimported BIF.
@@ -642,8 +646,9 @@ get_des_salt() ->
ets:insert(snmp_agent_table, {usm_des_salt, 0}),
0;
_ -> % it doesn't exist, initialize
- {A1,A2,A3} = erlang:now(),
- random:seed(A1,A2,A3),
+ random:seed(erlang:phash2([node()]),
+ erlang:monotonic_time(),
+ erlang:unique_integer()),
R = random:uniform(4294967295),
ets:insert(snmp_agent_table, {usm_des_salt, R}),
R
@@ -652,7 +657,10 @@ get_des_salt() ->
[?i32(EngineBoots), ?i32(SaltInt)].
aes_encrypt(PrivKey, Data) ->
- snmp_usm:aes_encrypt(PrivKey, Data, fun get_aes_salt/0).
+ EngineBoots = snmp_framework_mib:get_engine_boots(),
+ EngineTime = snmp_framework_mib:get_engine_time(),
+ snmp_usm:aes_encrypt(PrivKey, Data, fun get_aes_salt/0,
+ EngineBoots, EngineTime).
aes_decrypt(PrivKey, UsmSecParams, EncData) ->
#usmSecurityParameters{msgPrivacyParameters = PrivParams,
@@ -671,8 +679,9 @@ get_aes_salt() ->
ets:insert(snmp_agent_table, {usm_aes_salt, 0}),
0;
_ -> % it doesn't exist, initialize
- {A1,A2,A3} = erlang:now(),
- random:seed(A1,A2,A3),
+ random:seed(erlang:phash2([node()]),
+ erlang:monotonic_time(),
+ erlang:unique_integer()),
R = random:uniform(36893488147419103231),
ets:insert(snmp_agent_table, {usm_aes_salt, R}),
R
diff --git a/lib/snmp/src/agent/snmpa_vacm.erl b/lib/snmp/src/agent/snmpa_vacm.erl
index dadcf32543..f9df52010b 100644
--- a/lib/snmp/src/agent/snmpa_vacm.erl
+++ b/lib/snmp/src/agent/snmpa_vacm.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2015. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -305,8 +306,8 @@ dump_table() ->
%% time dumping the table.
unique_table_name(Pre) ->
%% We want something that is guaranteed to be unique,
- %% therefor we use erlang:now() instead of os:timestamp()
- unique_table_name(Pre, erlang:now()).
+ %% therefor we use erlang:timestamp() instead of os:timestamp()
+ unique_table_name(Pre, erlang:timestamp()).
unique_table_name(Pre, {_A, _B, C} = Now) ->
{Date, Time} = calendar:now_to_datetime(Now),
@@ -445,6 +446,3 @@ gc_tab(Oid) ->
user_err(F, A) ->
snmpa_error:user_err(F, A).
-
-% config_err(F, A) ->
-% snmpa_error:config_err(F, A).
diff --git a/lib/snmp/src/agent/snmpa_vacm.hrl b/lib/snmp/src/agent/snmpa_vacm.hrl
index 681591d212..527298e499 100644
--- a/lib/snmp/src/agent/snmpa_vacm.hrl
+++ b/lib/snmp/src/agent/snmpa_vacm.hrl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
diff --git a/lib/snmp/src/app/Makefile b/lib/snmp/src/app/Makefile
index d89eb4e723..6f2b8a4077 100644
--- a/lib/snmp/src/app/Makefile
+++ b/lib/snmp/src/app/Makefile
@@ -2,18 +2,19 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2003-2009. All Rights Reserved.
+# Copyright Ericsson AB 2003-2016. All Rights Reserved.
#
-# The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved online at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
+# 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%
@@ -79,6 +80,8 @@ endif
# FLAGS
# ----------------------------------------------------
+ERL_COMPILE_FLAGS += -pa $(ERL_TOP)/lib/snmp/ebin
+
ifeq ($(WARN_UNUSED_VARS),true)
ERL_COMPILE_FLAGS += +warn_unused_vars
endif
@@ -116,10 +119,10 @@ info:
# ----------------------------------------------------
$(APP_TARGET): $(APP_SRC) ../../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
# ----------------------------------------------------
# Release Target
@@ -127,14 +130,14 @@ $(APPUP_TARGET): $(APPUP_SRC) ../../vsn.mk
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/src/app
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)/src/app
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src/app"
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)/src/app"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
$(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) \
- $(RELSYSDIR)/ebin
- $(INSTALL_DIR) $(RELSYSDIR)/include
- $(INSTALL_DATA) $(EXT_HRL_FILES) $(RELSYSDIR)/include
+ "$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/include"
+ $(INSTALL_DATA) $(EXT_HRL_FILES) "$(RELSYSDIR)/include"
release_docs_spec:
diff --git a/lib/snmp/src/app/depend.mk b/lib/snmp/src/app/depend.mk
index 1080cb5693..bf213c2aec 100644
--- a/lib/snmp/src/app/depend.mk
+++ b/lib/snmp/src/app/depend.mk
@@ -2,18 +2,19 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2009. All Rights Reserved.
+# Copyright Ericsson AB 2004-2016. All Rights Reserved.
#
-# The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved online at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
+# 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%
diff --git a/lib/snmp/src/app/modules.mk b/lib/snmp/src/app/modules.mk
index 678f15de5c..2bfd2d5c56 100644
--- a/lib/snmp/src/app/modules.mk
+++ b/lib/snmp/src/app/modules.mk
@@ -2,18 +2,19 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2009. All Rights Reserved.
+# Copyright Ericsson AB 2004-2016. All Rights Reserved.
#
-# The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved online at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
+# 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%
diff --git a/lib/snmp/src/app/snmp.app.src b/lib/snmp/src/app/snmp.app.src
index a880a14696..d4bf0de61a 100644
--- a/lib/snmp/src/app/snmp.app.src
+++ b/lib/snmp/src/app/snmp.app.src
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -22,12 +23,12 @@
{vsn, "%VSN%"},
{modules, [
%% Compiler modules (not in the runtime part of the app)
-% snmpc,
-% snmpc_lib,
-% snmpc_mib_gram,
-% snmpc_mib_to_hrl,
-% snmpc_misc,
-% snmpc_tok,
+ snmpc,
+ snmpc_lib,
+ snmpc_mib_gram,
+ snmpc_mib_to_hrl,
+ snmpc_misc,
+ snmpc_tok,
%% Application modules
snmp,
@@ -48,11 +49,15 @@
snmpa_error_io,
snmpa_error_logger,
snmpa_error_report,
- snmpa_general_db,
snmpa_local_db,
snmpa_mib,
snmpa_mib_data,
+ snmpa_mib_data_tttn,
snmpa_mib_lib,
+ snmpa_mib_storage,
+ snmpa_mib_storage_ets,
+ snmpa_mib_storage_dets,
+ snmpa_mib_storage_mnesia,
snmpa_misc_sup,
snmpa_mpd,
snmpa_net_if,
@@ -91,6 +96,7 @@
snmpm_mpd,
snmpm_net_if,
snmpm_net_if_filter,
+ snmpm_net_if_mt,
snmpm_network_interface,
snmpm_network_interface_filter,
snmpm_server,
@@ -131,4 +137,6 @@
%% configuration and use), and in that case mnesia must also be started,
%% before snmp.
{applications, [kernel, stdlib]},
- {mod, {snmp_app, []}}]}.
+ {mod, {snmp_app, []}},
+ {runtime_dependencies, ["stdlib-2.5","runtime_tools-1.8.14","mnesia-4.12",
+ "kernel-3.0","erts-6.0","crypto-3.3"]}]}.
diff --git a/lib/snmp/src/app/snmp.appup.src b/lib/snmp/src/app/snmp.appup.src
index c8e5eec6db..db09ec3dc5 100644
--- a/lib/snmp/src/app/snmp.appup.src
+++ b/lib/snmp/src/app/snmp.appup.src
@@ -1,377 +1,32 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2012. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
-
+%% -*- erlang -*-
{"%VSN%",
%% ----- U p g r a d e -------------------------------------------------------
-
+%% Instruction examples:
+%% {restart_application, snmp}
+%% {load_module, snmp_pdus, soft_purge, soft_purge, []}
+%% {update, snmpa_local_db, soft, soft_purge, soft_purge, []}
+%% {add_module, snmpm_net_if_mt}
[
- {"4.21.6",
- [
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_mib, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []}
- ]
- },
- {"4.21.5",
- [
- {load_module, snmpa, soft_purge, soft_purge, []},
- {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]},
- {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
- {load_module, snmpa_trap, soft_purge, soft_purge, []},
- {load_module, snmpa_vacm, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_mib, soft, soft_purge, soft_purge, []},
- {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []}
- ]
- },
- {"4.21.4",
- [
- {load_module, snmpa, soft_purge, soft_purge, []},
- {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]},
- {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
- {load_module, snmpa_trap, soft_purge, soft_purge, []},
- {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
-
- {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
- {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
- {load_module, snmpa_vacm, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_mib, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []}
- ]
- },
- {"4.21.3",
- [
- {load_module, snmpa, soft_purge, soft_purge, []},
- {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]},
- {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
- {load_module, snmpa_trap, soft_purge, soft_purge, []},
- {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
-
- {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
- {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
- {load_module, snmpa_vacm, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_mib, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []}
- ]
- },
- {"4.21.2",
- [
- {load_module, snmpa, soft_purge, soft_purge, []},
- {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]},
- {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
- {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
-
- {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
- {load_module, snmpa_vacm, soft_purge, soft_purge, []},
- {load_module, snmpa_mpd, soft_purge, soft_purge, []},
- {load_module, snmpa_set_lib, soft_purge, soft_purge, []},
- {load_module, snmpa_trap, soft_purge, soft_purge, []},
- {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_mib, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []}
- ]
- },
- {"4.21.1",
- [
- {load_module, snmpa, soft_purge, soft_purge, []},
- {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]},
- {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
- {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
-
- {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
- {load_module, snmpa_vacm, soft_purge, soft_purge, []},
- {load_module, snmpa_mpd, soft_purge, soft_purge, []},
- {load_module, snmpa_set_lib, soft_purge, soft_purge, []},
- {load_module, snmpa_trap, soft_purge, soft_purge, []},
- {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_mib, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []},
- {update, snmp_note_store, soft, soft_purge, soft_purge, []}
- ]
- },
- {"4.21",
- [
- {load_module, snmpa, soft_purge, soft_purge, []},
- {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
- {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
-
- {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
- {load_module, snmpa_vacm, soft_purge, soft_purge, []},
- {load_module, snmpa_mpd, soft_purge, soft_purge, []},
- {load_module, snmpa_set_lib, soft_purge, soft_purge, []},
- {load_module, snmpa_trap, soft_purge, soft_purge, []},
- {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]},
- {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_mib, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []},
- {update, snmp_note_store, soft, soft_purge, soft_purge, []}
- ]
- },
- {"4.20.1",
- [
- {load_module, snmpa, soft_purge, soft_purge, []},
- {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
- {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
-
- {load_module, snmpa_vacm, soft_purge, soft_purge, []},
- {load_module, snmpa_set_lib, soft_purge, soft_purge, []},
- {load_module, snmpa_trap, soft_purge, soft_purge, []},
- {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]},
- {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
- {load_module, snmpm, soft_purge, soft_purge,
- [snmpm_server, snmpm_config, snmp_config]},
- {load_module, snmp_conf, soft_purge, soft_purge, []},
- {load_module, snmp_config, soft_purge, soft_purge, []},
- {load_module, snmpm_mpd, soft_purge, soft_purge,
- [snmp_conf, snmp_config, snmpm_config]},
- {load_module, snmpa_mpd, soft_purge, soft_purge,
- [snmp_conf, snmp_config]},
- {load_module, snmpa_conf, soft_purge, soft_purge, [snmp_config]},
- {update, snmp_note_store, soft, soft_purge, soft_purge, []},
- {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_mib, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]},
- {update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]},
- {update, snmpm_server, soft, soft_purge, soft_purge,
- [snmpm_net_if, snmpm_mpd, snmpm_config]},
- {update, snmpm_net_if, soft, soft_purge, soft_purge,
- [snmp_conf, snmpm_mpd, snmpm_config]}
- ]
- },
- {"4.20",
- [
- {load_module, snmpa, soft_purge, soft_purge, []},
- {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
- {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
-
- {load_module, snmpa_vacm, soft_purge, soft_purge, []},
- {load_module, snmpa_set_lib, soft_purge, soft_purge, []},
- {load_module, snmpa_trap, soft_purge, soft_purge, []},
- {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
- {load_module, snmp_target_mib, soft_purge, soft_purge,
- [snmpa_mib_lib, snmp_conf]},
- {load_module, snmpm, soft_purge, soft_purge,
- [snmpm_server, snmpm_config, snmp_config]},
- {load_module, snmp_conf, soft_purge, soft_purge, []},
- {load_module, snmp_config, soft_purge, soft_purge, []},
- {load_module, snmpm_mpd, soft_purge, soft_purge,
- [snmp_conf, snmp_config, snmpm_config]},
- {load_module, snmpa_mpd, soft_purge, soft_purge,
- [snmp_conf, snmp_config]},
- {load_module, snmpa_conf, soft_purge, soft_purge, [snmp_config]},
- {update, snmp_note_store, soft, soft_purge, soft_purge, []},
- {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_mib, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]},
- {update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]},
- {update, snmpm_server, soft, soft_purge, soft_purge,
- [snmpm_net_if, snmpm_mpd, snmpm_config]},
- {update, snmpm_net_if, soft, soft_purge, soft_purge,
- [snmp_conf, snmpm_mpd, snmpm_config]}
- ]
- }
- ],
-
+ {<<"5\\.2\\.4">>,
+ [{load_module, snmp, soft_purge, soft_purge, []},
+ {load_module, snmpc_lib, soft_purge, soft_purge, []},
+ {load_module, snmpc_mib_gram, soft_purge, soft_purge, []}]},
+ {<<"5\\..*">>, [{restart_application, snmp}]},
+ {<<"4\\..*">>, [{restart_application, snmp}]}
+ ],
+
%% ------D o w n g r a d e ---------------------------------------------------
-
+%% Instruction examples:
+%% {remove, {snmpm_net_if_mt, soft_purge, soft_purge}}
+
[
- {"4.21.6",
- [
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_mib, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []}
- ]
- },
- {"4.21.5",
- [
- {load_module, snmpa, soft_purge, soft_purge, []},
- {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]},
- {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
- {load_module, snmpa_trap, soft_purge, soft_purge, []},
- {load_module, snmpa_vacm, soft_purge, soft_purge, []},
- {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_mib, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []}
- ]
- },
- {"4.21.4",
- [
- {load_module, snmpa, soft_purge, soft_purge, []},
- {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]},
- {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
- {load_module, snmpa_trap, soft_purge, soft_purge, []},
- {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
-
- {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
- {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
- {load_module, snmpa_vacm, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_mib, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []}
- ]
- },
- {"4.21.3",
- [
- {load_module, snmpa, soft_purge, soft_purge, []},
- {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]},
- {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
- {load_module, snmpa_trap, soft_purge, soft_purge, []},
- {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
-
- {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
- {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
- {load_module, snmpa_vacm, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_mib, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []}
- ]
- },
- {"4.21.2",
- [
- {load_module, snmpa, soft_purge, soft_purge, []},
- {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]},
- {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
- {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
-
- {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
- {load_module, snmpa_vacm, soft_purge, soft_purge, []},
- {load_module, snmpa_mpd, soft_purge, soft_purge, []},
- {load_module, snmpa_set_lib, soft_purge, soft_purge, []},
- {load_module, snmpa_trap, soft_purge, soft_purge, []},
- {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_mib, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []}
- ]
- },
- {"4.21.1",
- [
- {load_module, snmpa, soft_purge, soft_purge, []},
- {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]},
- {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
- {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
-
- {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
- {load_module, snmpa_vacm, soft_purge, soft_purge, []},
- {load_module, snmpa_mpd, soft_purge, soft_purge, []},
- {load_module, snmpa_set_lib, soft_purge, soft_purge, []},
- {load_module, snmpa_trap, soft_purge, soft_purge, []},
- {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_mib, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []},
- {update, snmp_note_store, soft, soft_purge, soft_purge, []}
- ]
- },
- {"4.21",
- [
- {load_module, snmpa, soft_purge, soft_purge, []},
- {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
- {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
-
- {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
- {load_module, snmpa_vacm, soft_purge, soft_purge, []},
- {load_module, snmpa_mpd, soft_purge, soft_purge, []},
- {load_module, snmpa_set_lib, soft_purge, soft_purge, []},
- {load_module, snmpa_trap, soft_purge, soft_purge, []},
- {load_module, snmp_target_mib, soft_purge, soft_purge, []},
- {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_mib, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []},
- {update, snmp_note_store, soft, soft_purge, soft_purge, []}
- ]
- },
- {"4.20.1",
- [
- {load_module, snmpa, soft_purge, soft_purge, []},
- {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
- {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
-
- {load_module, snmpa_vacm, soft_purge, soft_purge, []},
- {load_module, snmpa_set_lib, soft_purge, soft_purge, []},
- {load_module, snmpa_trap, soft_purge, soft_purge, []},
- {load_module, snmp_target_mib, soft_purge, soft_purge, []},
- {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
- {load_module, snmpm, soft_purge, soft_purge,
- [snmpm_server, snmpm_config, snmp_config]},
- {load_module, snmp_conf, soft_purge, soft_purge, []},
- {load_module, snmp_config, soft_purge, soft_purge, []},
- {load_module, snmpm_mpd, soft_purge, soft_purge,
- [snmp_conf, snmp_config, snmpm_config]},
- {load_module, snmpa_mpd, soft_purge, soft_purge,
- [snmp_conf, snmp_config]},
- {load_module, snmpa_conf, soft_purge, soft_purge, [snmp_config]},
- {update, snmp_note_store, soft, soft_purge, soft_purge, []},
- {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_mib, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]},
- {update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]},
- {update, snmpm_server, soft, soft_purge, soft_purge,
- [snmpm_net_if, snmpm_mpd, snmpm_config]},
- {update, snmpm_net_if, soft, soft_purge, soft_purge,
- [snmp_conf, snmpm_mpd, snmpm_config]}
- ]
- },
- {"4.20",
- [
- {load_module, snmpa, soft_purge, soft_purge, []},
- {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
- {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
-
- {load_module, snmpa_vacm, soft_purge, soft_purge, []},
- {load_module, snmpa_set_lib, soft_purge, soft_purge, []},
- {load_module, snmpa_trap, soft_purge, soft_purge, []},
- {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
- {load_module, snmp_target_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmpm, soft_purge, soft_purge,
- [snmpm_server, snmpm_config, snmp_config]},
- {load_module, snmp_conf, soft_purge, soft_purge, []},
- {load_module, snmp_config, soft_purge, soft_purge, []},
- {load_module, snmpm_mpd, soft_purge, soft_purge,
- [snmp_conf, snmp_config, snmpm_config]},
- {load_module, snmpa_mpd, soft_purge, soft_purge,
- [snmp_conf, snmp_config]},
- {load_module, snmpa_conf, soft_purge, soft_purge, [snmp_config]},
- {update, snmp_note_store, soft, soft_purge, soft_purge, []},
- {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_mib, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]},
- {update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]},
- {update, snmpm_server, soft, soft_purge, soft_purge,
- [snmpm_net_if, snmpm_mpd, snmpm_config]},
- {update, snmpm_net_if, soft, soft_purge, soft_purge,
- [snmp_conf, snmpm_mpd, snmpm_config]}
- ]
- }
- ]
-}.
+ {<<"5\\.2\\.4">>,
+ [{load_module, snmp, soft_purge, soft_purge, []},
+ {load_module, snmpc_lib, soft_purge, soft_purge, []},
+ {load_module, snmpc_mib_gram, soft_purge, soft_purge, []}]},
+ {<<"5\\..*">>, [{restart_application, snmp}]},
+ {<<"4\\..*">>, [{restart_application, snmp}]}
+ ]
+}.
diff --git a/lib/snmp/src/app/snmp.erl b/lib/snmp/src/app/snmp.erl
index 3e0f05e604..8a736f688b 100644
--- a/lib/snmp/src/app/snmp.erl
+++ b/lib/snmp/src/app/snmp.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -49,7 +50,8 @@
read_mib/1,
- log_to_txt/5, log_to_txt/6, log_to_txt/7,
+ log_to_txt/5, log_to_txt/6, log_to_txt/7, log_to_txt/8,
+ log_to_io/4, log_to_io/5, log_to_io/6, log_to_io/7,
change_log_size/2,
octet_string_to_bits/1, bits_to_octet_string/1,
@@ -89,6 +91,37 @@
]).
+-export_type([
+ dir/0,
+ snmp_timer/0,
+
+ engine_id/0,
+ tdomain/0,
+ community/0,
+ mms/0,
+ version/0,
+ sec_model/0,
+ sec_name/0,
+ sec_level/0,
+
+ oid/0,
+ varbind/0,
+ ivarbind/0,
+ asn1_type/0,
+ table_info/0,
+ variable_info/0,
+ me/0,
+ trap/0,
+ notification/0,
+ pdu/0,
+ trappdu/0,
+ mib/0,
+ mib_name/0,
+
+ void/0
+ ]).
+
+
%% This is for XREF
-deprecated([{c, 1, eventually},
{c, 2, eventually},
@@ -140,6 +173,42 @@
-define(APPLICATION, snmp).
+-define(ATL_BLOCK_DEFAULT, true).
+
+-include_lib("snmp/include/snmp_types.hrl").
+
+
+%%-----------------------------------------------------------------
+%% Types
+%%-----------------------------------------------------------------
+
+-type dir() :: string().
+-type snmp_timer() :: #snmp_incr_timer{}.
+
+-type engine_id() :: string().
+-type tdomain() :: transportDomainUdpIpv4 | transportDomainUdpIpv6.
+-type community() :: string().
+-type mms() :: non_neg_integer().
+-type version() :: v1 | v2 | v3.
+-type sec_model() :: any | v1 | v2c | usm.
+-type sec_name() :: string().
+-type sec_level() :: noAuthNoPriv | authNoPriv | authPriv.
+
+-type oid() :: [non_neg_integer()].
+-type varbind() :: #varbind{}.
+-type ivarbind() :: #ivarbind{}.
+-type asn1_type() :: #asn1_type{}.
+-type table_info() :: #table_info{}.
+-type variable_info() :: #variable_info{}.
+-type me() :: #me{}.
+-type trap() :: #trap{}.
+-type notification() :: #notification{}.
+-type mib() :: #mib{}.
+-type mib_name() :: string().
+-type pdu() :: #pdu{}.
+-type trappdu() :: #trappdu{}.
+
+-type void() :: term().
%%-----------------------------------------------------------------
@@ -504,9 +573,16 @@ print_mod_info(Prefix, {Module, Info}) ->
CompDate =
case key1search(compile_time, Info) of
{value, {Year, Month, Day, Hour, Min, Sec}} ->
- lists:flatten(
- io_lib:format("~w-~2..0w-~2..0w ~2..0w:~2..0w:~2..0w",
- [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) ->
+ [io_lib:format("~2.16.0b", [Byte]) || <<Byte>> <= MD5];
_ ->
"Not found"
end,
@@ -514,12 +590,14 @@ 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 Compile time: ~s~n"
+ "~s MD5 digest: ~s~n",
[Prefix, Module,
Prefix, Vsn,
Prefix, AppVsn,
- Prefix, CompVer,
- Prefix, CompDate]),
+ Prefix, CompVer,
+ Prefix, CompDate,
+ Prefix, Digest]),
ok.
key1search(Key, Vals) ->
@@ -548,7 +626,7 @@ versions1() ->
Error ->
Error
end.
-
+
versions2() ->
case ms2() of
{ok, Mods} ->
@@ -556,25 +634,56 @@ versions2() ->
Error ->
Error
end.
-
+
version_info(Mods) ->
SysInfo = sys_info(),
OsInfo = os_info(),
ModInfo = [mod_version_info(Mod) || Mod <- Mods],
[{sys_info, SysInfo}, {os_info, OsInfo}, {mod_info, ModInfo}].
-
+
mod_version_info(Mod) ->
Info = Mod:module_info(),
- {value, {attributes, Attr}} = lists:keysearch(attributes, 1, Info),
- {value, {vsn, [Vsn]}} = lists:keysearch(vsn, 1, Attr),
- {value, {app_vsn, AppVsn}} = lists:keysearch(app_vsn, 1, Attr),
- {value, {compile, Comp}} = lists:keysearch(compile, 1, Info),
- {value, {version, Ver}} = lists:keysearch(version, 1, Comp),
- {value, {time, Time}} = lists:keysearch(time, 1, Comp),
- {Mod, [{vsn, Vsn},
- {app_vsn, AppVsn},
- {compiler_version, Ver},
- {compile_time, Time}]}.
+ {Mod,
+ case key1search(attributes, Info) of
+ {value, Attr} ->
+ case key1search(vsn, Attr) of
+ {value, [Vsn]} ->
+ [{vsn, Vsn}];
+ not_found ->
+ []
+ end ++
+ case key1search(app_vsn, Attr) of
+ {value, AppVsn} ->
+ [{app_vsn, AppVsn}];
+ not_found ->
+ []
+ end;
+ not_found ->
+ []
+ end ++
+ case key1search(compile, Info) of
+ {value, Comp} ->
+ case key1search(version, Comp) of
+ {value, Ver} ->
+ [{compiler_version, Ver}];
+ not_found ->
+ []
+ end ++
+ case key1search(time, Comp) of
+ {value, Ver} ->
+ [{compile_time, Ver}];
+ not_found ->
+ []
+ end;
+ not_found ->
+ []
+ end ++
+ case key1search(md5, Info) of
+ {value, Bin} ->
+ [{md5, Bin}];
+ not_found ->
+ []
+ end}.
sys_info() ->
SysArch = string:strip(erlang:system_info(system_architecture),right,$\n),
@@ -837,12 +946,60 @@ read_mib(FileName) ->
%%%-----------------------------------------------------------------
log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile) ->
- snmp_log:log_to_txt(LogName, LogFile, LogDir, Mibs, OutFile).
+ Block = ?ATL_BLOCK_DEFAULT,
+ Start = null,
+ Stop = null,
+ log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop).
+
+log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block)
+ when ((Block =:= true) orelse (Block =:= false)) ->
+ Start = null,
+ Stop = null,
+ log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop);
log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start) ->
- snmp_log:log_to_txt(LogName, LogFile, LogDir, Mibs, OutFile, Start).
+ Block = ?ATL_BLOCK_DEFAULT,
+ Stop = null,
+ log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop).
+
+log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start)
+ when ((Block =:= true) orelse (Block =:= false)) ->
+ Stop = null,
+ log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop);
log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) ->
- snmp_log:log_to_txt(LogName, LogFile, LogDir, Mibs, OutFile, Start, Stop).
-
+ Block = ?ATL_BLOCK_DEFAULT,
+ log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop).
+
+log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop) ->
+ snmp_log:log_to_txt(LogName, Block, LogFile, LogDir, Mibs, OutFile,
+ Start, Stop).
+
+
+log_to_io(LogDir, Mibs, LogName, LogFile) ->
+ Block = ?ATL_BLOCK_DEFAULT,
+ Start = null,
+ Stop = null,
+ log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop).
+
+log_to_io(LogDir, Mibs, LogName, LogFile, Block)
+ when ((Block =:= true) orelse (Block =:= false)) ->
+ Start = null,
+ Stop = null,
+ log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop);
+log_to_io(LogDir, Mibs, LogName, LogFile, Start) ->
+ Block = ?ATL_BLOCK_DEFAULT,
+ Stop = null,
+ log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop).
+
+log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start)
+ when ((Block =:= true) orelse (Block =:= false)) ->
+ Stop = null,
+ log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop);
+log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop) ->
+ Block = ?ATL_BLOCK_DEFAULT,
+ log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop).
+
+log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop) ->
+ snmp_log:log_to_io(LogName, Block, LogFile, LogDir, Mibs, Start, Stop).
change_log_size(LogName, NewSize) ->
snmp_log:change_size(LogName, NewSize).
@@ -855,12 +1012,12 @@ change_log_size(LogName, NewSize) ->
%% Usage: erl -s snmp str_apply '{Mod,Func,ArgList}'
str_apply([Atom]) ->
Str = atom_to_list(Atom),
- {Mod,Func,Args} = to_erlang_term(Str),
- apply(Mod,Func,Args).
+ {Mod, Func, Args} = to_erlang_term(Str),
+ apply(Mod, Func, Args).
to_erlang_term(String) ->
{ok, Tokens, _} = erl_scan:string(lists:append([String, ". "])),
- {ok,Term} = erl_parse:parse_term(Tokens),
+ {ok, Term} = erl_parse:parse_term(Tokens),
Term.
diff --git a/lib/snmp/src/app/snmp_app.erl b/lib/snmp/src/app/snmp_app.erl
index deb42cc373..dbc1ec0b6d 100644
--- a/lib/snmp/src/app/snmp_app.erl
+++ b/lib/snmp/src/app/snmp_app.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -62,17 +63,17 @@ entities([], []) ->
?d("entities -> converted config: ~n~p", [Conf]),
[{agent, Conf}]
end;
-entities([], E) ->
+entities([], Acc) ->
?d("entities -> done", []),
- lists:reverse(E);
-entities([ET|ETs], E) ->
+ lists:reverse(Acc);
+entities([Ent|Ents], Acc) ->
?d("entities -> entry with"
- "~n ET: ~p", [ET]),
- case application:get_env(snmp, ET) of
+ "~n Ent: ~p", [Ent]),
+ case application:get_env(snmp, Ent) of
{ok, Conf} ->
- entities(ETs, [{ET, Conf}|E]);
+ entities(Ents, [{Ent, Conf}|Acc]);
_ ->
- entities(ETs, E)
+ entities(Ents, Acc)
end.
start_entities(_Type, []) ->
diff --git a/lib/snmp/src/app/snmp_app_sup.erl b/lib/snmp/src/app/snmp_app_sup.erl
index d0c190b51f..eb89cc5b6d 100644
--- a/lib/snmp/src/app/snmp_app_sup.erl
+++ b/lib/snmp/src/app/snmp_app_sup.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
diff --git a/lib/snmp/src/app/snmp_internal.hrl b/lib/snmp/src/app/snmp_internal.hrl
index 5ff715e0b7..374767df15 100644
--- a/lib/snmp/src/app/snmp_internal.hrl
+++ b/lib/snmp/src/app/snmp_internal.hrl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -24,6 +25,8 @@
-define(APPLICATION, snmp).
-endif.
+-define(STACK(), erlang:get_stacktrace()).
+
-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)).
-define(snmp_error(C, F, A), ?snmp_msg(error_msg, C, F, A)).
diff --git a/lib/snmp/src/compile/Makefile b/lib/snmp/src/compile/Makefile
index 627af6f185..4093ffa9ca 100644
--- a/lib/snmp/src/compile/Makefile
+++ b/lib/snmp/src/compile/Makefile
@@ -2,18 +2,19 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2011. All Rights Reserved.
+# Copyright Ericsson AB 1997-2016. All Rights Reserved.
#
-# The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved online at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
+# 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%
@@ -120,13 +121,13 @@ $(GENERATED_PARSER): $(PARSER_SRC)
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/src/compiler
- $(INSTALL_DATA) $(ESCRIPT_SRC) $(PARSER_SRC) $(ERL_FILES) $(INTERNAL_HRL_FILES) $(RELSYSDIR)/src/compiler
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(EBIN_FILES) $(RELSYSDIR)/ebin
- $(INSTALL_DIR) $(RELSYSDIR)/bin
- $(INSTALL_SCRIPT) $(ESCRIPT_BIN) $(RELSYSDIR)/bin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src/compiler"
+ $(INSTALL_DATA) $(ESCRIPT_SRC) $(PARSER_SRC) $(ERL_FILES) $(INTERNAL_HRL_FILES) "$(RELSYSDIR)/src/compiler"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(EBIN_FILES) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/bin"
+ $(INSTALL_SCRIPT) $(ESCRIPT_BIN) "$(RELSYSDIR)/bin"
release_docs_spec:
diff --git a/lib/snmp/src/compile/depend.mk b/lib/snmp/src/compile/depend.mk
index 3ee8dc4bec..57b7c19daf 100644
--- a/lib/snmp/src/compile/depend.mk
+++ b/lib/snmp/src/compile/depend.mk
@@ -2,18 +2,19 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2011. All Rights Reserved.
+# Copyright Ericsson AB 2004-2016. All Rights Reserved.
#
-# The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved online at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
+# 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%
@@ -45,5 +46,5 @@ $(EBIN)/snmpc_mib_gram.$(EMULATOR): \
snmpc_mib_gram.erl
$(BIN)/snmpc: snmpc.src ../../vsn.mk
- $(PERL) -p -e 's?%VSN%?$(VSN)? ' < $< > $@
- chmod 755 $@
+ $(vsn_verbose)$(PERL) -p -e 's?%VSN%?$(VSN)? ' < $< > $@
+ $(V_at)chmod 755 $@
diff --git a/lib/snmp/src/compile/modules.mk b/lib/snmp/src/compile/modules.mk
index 399e4f865e..9ca5ebb95a 100644
--- a/lib/snmp/src/compile/modules.mk
+++ b/lib/snmp/src/compile/modules.mk
@@ -2,18 +2,19 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2011. All Rights Reserved.
+# Copyright Ericsson AB 2004-2016. All Rights Reserved.
#
-# The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved online at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
+# 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%
diff --git a/lib/snmp/src/compile/snmpc.erl b/lib/snmp/src/compile/snmpc.erl
index 5e6b81f1ec..416353508e 100644
--- a/lib/snmp/src/compile/snmpc.erl
+++ b/lib/snmp/src/compile/snmpc.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
+%% 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
%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -63,7 +64,7 @@ compile(Input, _Output, Options) ->
{ok, _} ->
ok;
{error, Reason} ->
- io:format("~p", [Reason]),
+ io:format("~tp", [Reason]),
error
end.
@@ -125,7 +126,14 @@ compile(FileName) ->
%%----------------------------------------------------------------------
compile(FileName, Options) when is_list(FileName) ->
- true = snmpc_misc:is_string(FileName),
+ case snmpc_misc:check_file(FileName) of
+ true ->
+ compile_1(FileName, Options);
+ false ->
+ {error, {invalid_file, FileName}}
+ end.
+
+compile_1(FileName, Options) ->
DefOpts = [{deprecated, true},
{group_check, true},
{i, ["./"]},
@@ -409,8 +417,9 @@ get_verbosity(Options) ->
%%----------------------------------------------------------------------
init(From, MibFileName, Options) ->
- {A,B,C} = now(),
- random:seed(A,B,C),
+ random:seed(erlang:phash2([node()]),
+ erlang:monotonic_time(),
+ erlang:unique_integer()),
put(options, Options),
put(verbosity, get_verbosity(Options)),
put(description, get_description(Options)),
@@ -516,7 +525,7 @@ definitions_loop([{#mc_object_type{name = NameOfTable,
fields = FieldList},
Sline}|ColsEtc],
Data) ->
- ?vlog("defloop -> "
+ ?vlog("defloop(~w) -> "
"[object_type(sequence_of),object_type(type,[1]),sequence]:"
"~n NameOfTable: ~p"
"~n SeqName: ~p"
@@ -535,7 +544,8 @@ definitions_loop([{#mc_object_type{name = NameOfTable,
"~n Eline: ~p"
"~n FieldList: ~p"
"~n Sline: ~p",
- [NameOfTable,SeqName,Taccess,Kind,Tstatus,
+ [?LINE,
+ NameOfTable,SeqName,Taccess,Kind,Tstatus,
Tindex,Tunits,Tline,
NameOfEntry,TEline,IndexingInfo,Estatus,Eunits,Ref,Eline,
FieldList,Sline]),
@@ -562,8 +572,9 @@ definitions_loop([{#mc_object_type{name = NameOfTable,
units = Eunits},
{ColMEs, RestObjs} =
define_cols(ColsEtc, 1, FieldList, NameOfEntry, NameOfTable, []),
+ AfterIdxTypes = after_indexes_type(IndexingInfo, RestObjs),
TableInfo = snmpc_lib:make_table_info(Eline, NameOfTable,
- IndexingInfo, ColMEs),
+ IndexingInfo, AfterIdxTypes, ColMEs),
snmpc_lib:add_cdata(#cdata.mes,
[TableEntryME,
TableME#me{assocList=[{table_info,
@@ -595,7 +606,7 @@ definitions_loop([{#mc_object_type{name = NameOfTable,
Sline}|ColsEtc],
#dldata{relaxed_row_name_assign_check = true} = Data)
when is_integer(Idx) andalso (Idx > 1) ->
- ?vlog("defloop -> "
+ ?vlog("defloop(~w) -> "
"[object_type(sequence_of),object_type(type,[~w]),sequence]:"
"~n NameOfTable: ~p"
"~n SeqName: ~p"
@@ -614,7 +625,8 @@ definitions_loop([{#mc_object_type{name = NameOfTable,
"~n Eline: ~p"
"~n FieldList: ~p"
"~n Sline: ~p",
- [Idx,
+ [?LINE,
+ Idx,
NameOfTable,SeqName,Taccess,Kind,Tstatus,
Tindex,Tunits,Tline,
NameOfEntry,TEline,IndexingInfo,Estatus,Eunits,Ref,Eline,
@@ -644,8 +656,9 @@ definitions_loop([{#mc_object_type{name = NameOfTable,
units = Eunits},
{ColMEs, RestObjs} =
define_cols(ColsEtc, 1, FieldList, NameOfEntry, NameOfTable, []),
+ AfterIdxTypes = after_indexes_type(IndexingInfo, RestObjs),
TableInfo = snmpc_lib:make_table_info(Eline, NameOfTable,
- IndexingInfo, ColMEs),
+ IndexingInfo, AfterIdxTypes, ColMEs),
snmpc_lib:add_cdata(#cdata.mes,
[TableEntryME,
TableME#me{assocList=[{table_info,
@@ -673,7 +686,7 @@ definitions_loop([{#mc_object_type{name = NameOfTable,
{#mc_sequence{name = SeqName,
fields = FieldList}, Sline}|ColsEtc],
Data) ->
- ?vlog("defloop -> "
+ ?vlog("defloop(~w) -> "
"[object_type(sequence_of),object_type(type),sequence(fieldList)]:"
"~n NameOfTable: ~p"
"~n SeqName: ~p"
@@ -692,7 +705,8 @@ definitions_loop([{#mc_object_type{name = NameOfTable,
"~n Eline: ~p"
"~n FieldList: ~p"
"~n Sline: ~p",
- [NameOfTable,SeqName,Taccess,Kind,Tstatus,
+ [?LINE,
+ NameOfTable,SeqName,Taccess,Kind,Tstatus,
Tindex,Tunits,Tline,
NameOfEntry,IndexingInfo,Estatus,BadOID,Eunits,Ref,Eline,
FieldList,Sline]),
@@ -720,8 +734,9 @@ definitions_loop([{#mc_object_type{name = NameOfTable,
units = Eunits},
{ColMEs, RestObjs} =
define_cols(ColsEtc, 1, FieldList, NameOfEntry, NameOfTable, []),
+ AfterIdxTypes = after_indexes_type(IndexingInfo, RestObjs),
TableInfo = snmpc_lib:make_table_info(Eline, NameOfTable,
- IndexingInfo, ColMEs),
+ IndexingInfo, AfterIdxTypes, ColMEs),
snmpc_lib:add_cdata(#cdata.mes,
[TableEntryME,
TableME#me{assocList=[{table_info,
@@ -813,7 +828,7 @@ definitions_loop([{#mc_module_identity{name = NewVarName,
"~n Desc: ~p"
"~n Revs0: ~p"
"~n Parent: ~p"
- "~n SubIndex: ~p",
+ "~n SubIndex: ~w",
[NewVarName, LU, Org, CI, Desc, Revs0, Parent, SubIndex], Line),
ensure_macro_imported('MODULE-IDENTITY', Line),
snmpc_lib:register_oid(Line, NewVarName, Parent, SubIndex),
@@ -839,7 +854,7 @@ definitions_loop([{#mc_internal{name = NewVarName,
"~n NewVarName: ~p"
"~n Macro: ~p"
"~n Parent: ~p"
- "~n SubIndex: ~p",
+ "~n SubIndex: ~w",
[NewVarName, Macro, Parent, SubIndex], Line),
ensure_macro_imported(Macro, Line),
snmpc_lib:register_oid(Line, NewVarName, Parent, SubIndex),
@@ -1205,6 +1220,12 @@ safe_elem(N,T) ->
X -> X
end.
+
+%% An table index is either:
+%% a) part of the table
+%% b) not part of the table and defined *before* the table
+%% c) not part of the table and defined *after* the table
+
%% A correct column
define_cols([{#mc_object_type{name = NameOfCol,
syntax = Type1,
@@ -1379,14 +1400,45 @@ define_cols(Rest, _SubIndex,_,_,_,ColMEs) ->
snmpc_lib:print_error("Corrupt table definition.",[]),
{ColMEs,Rest}.
+
+%% Table indexes can either be:
+%% a) part of the table (a column)
+%% b) not part of the table and defined *before* the table
+%% c) not part of the table and defined *after* the table
+
+after_indexes_type({indexes, Indexes}, Objs) ->
+ after_indexes_type2(Indexes, Objs);
+after_indexes_type(_, _) ->
+ [].
+
+after_indexes_type2(Indexes, Objs) ->
+ after_indexes_type2(Indexes, Objs, []).
+
+after_indexes_type2([], _Objs, IndexesASN1types) ->
+ IndexesASN1types;
+after_indexes_type2([Index|Indexes], Objs, Acc) ->
+ Acc2 = after_indexes_type3(Index, Objs, Acc),
+ after_indexes_type2(Indexes, Objs, Acc2).
+
+after_indexes_type3(_Index, [], Acc) ->
+ Acc;
+after_indexes_type3(Index,
+ [{#mc_object_type{name = Index,
+ syntax = Syntax},_}|_], Acc) ->
+ ASN1 = snmpc_lib:make_ASN1type(Syntax),
+ [{Index, ASN1}|Acc];
+after_indexes_type3(Index, [_|Objs], Acc) ->
+ after_indexes_type3(Index, Objs, Acc).
+
+
+
ensure_macro_imported(dummy, _Line) -> ok;
ensure_macro_imported(Macro, Line) ->
Macros = (get(cdata))#cdata.imported_macros,
case lists:member(Macro, Macros) of
true -> ok;
false ->
- snmpc_lib:print_error("Macro ~p not imported.", [Macro],
- Line)
+ snmpc_lib:print_error("Macro ~p not imported.", [Macro], Line)
end.
test_table(NameOfTable, Taccess, Kind, _Tindex, Tline) ->
diff --git a/lib/snmp/src/compile/snmpc.hrl b/lib/snmp/src/compile/snmpc.hrl
index 1c0808d065..b3c66f4f3d 100644
--- a/lib/snmp/src/compile/snmpc.hrl
+++ b/lib/snmp/src/compile/snmpc.hrl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
diff --git a/lib/snmp/src/compile/snmpc.src b/lib/snmp/src/compile/snmpc.src
index 9d1af42764..e64b6607c4 100644
--- a/lib/snmp/src/compile/snmpc.src
+++ b/lib/snmp/src/compile/snmpc.src
@@ -3,18 +3,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -404,13 +405,12 @@ e(Reason) ->
otp_release() ->
system_info(otp_release, string).
-
system_info(Tag, Type) ->
case (catch erlang:system_info(Tag)) of
- {'EXIT', _} ->
- "-";
- Info when is_list(Info) andalso (Type =:= string) ->
- Info;
- Info ->
- lists:flatten(io_lib:format("~w", [Info]))
+ {'EXIT', _} ->
+ "-";
+ Info when is_list(Info) andalso (Type =:= string) ->
+ Info;
+ Info ->
+ lists:flatten(io_lib:format("~w", [Info]))
end.
diff --git a/lib/snmp/src/compile/snmpc_lib.erl b/lib/snmp/src/compile/snmpc_lib.erl
index 38bb8f3ac6..33ddd78308 100644
--- a/lib/snmp/src/compile/snmpc_lib.erl
+++ b/lib/snmp/src/compile/snmpc_lib.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
+%% 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
%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -24,7 +25,7 @@
-compile({no_auto_import,[error/2]}).
-export([test_father/4, make_ASN1type/1, import/1, makeInternalNode2/2,
is_consistent/1, resolve_defval/1, make_variable_info/1,
- check_trap_name/3, make_table_info/4, get_final_mib/2, set_dir/2,
+ check_trap_name/3, make_table_info/5, get_final_mib/2, set_dir/2,
look_at/1, add_cdata/2,
check_object_group/4, check_notification_group/4,
check_notification/3,
@@ -98,7 +99,7 @@ make_ASN1type({{type_with_size,Type,{range,Lo,Hi}},Line}) ->
print_error("Undefined type '~w'",[Type],Line),
guess_string_type()
end;
-make_ASN1type({{integer_with_enum,Type,Enums},Line}) ->
+make_ASN1type({{type_with_enum,Type,Enums},Line}) ->
case lookup_vartype(Type) of
{value,ASN1type} -> ASN1type#asn1_type{assocList = [{enums, Enums}]};
false ->
@@ -139,6 +140,7 @@ allow_size_rfc1902('Integer32') -> true;
allow_size_rfc1902('Unsigned32') -> true;
allow_size_rfc1902('OCTET STRING') -> true;
allow_size_rfc1902('Gauge32') -> true;
+allow_size_rfc1902('Opaque') -> true;
allow_size_rfc1902(_) -> false.
guess_integer_type() ->
@@ -240,7 +242,10 @@ import_mib({{'SNMPv2-SMI', ImportsFromMib},Line}) ->
aliasname = 'Opaque'},
#asn1_type{bertype = 'Counter64',
aliasname = 'Counter64',
- lo = 0, hi = 18446744073709551615}],
+ lo = 0, hi = 18446744073709551615},
+ #asn1_type{bertype = 'BITS',
+ aliasname = 'BITS'}
+ ],
Macros = ['MODULE-IDENTITY','OBJECT-IDENTITY','OBJECT-TYPE',
'NOTIFICATION-TYPE'],
import_built_in_loop(ImportsFromMib,Nodes,Types,Macros,'SNMPv2-SMI',Line);
@@ -704,29 +709,38 @@ check_trap_name(EnterpriseName, Line, MEs) ->
%% This information is needed to be able to create default instrumentation
%% functions for tables.
%%----------------------------------------------------------------------
-make_table_info(Line, _TableName, {augments,SrcTableEntry}, ColumnMEs) ->
+
+make_table_info(Line, TableName, {augments, SrcTableEntry}, _, ColumnMEs) ->
ColMEs = lists:keysort(#me.oid, ColumnMEs),
- %% Nbr_of_Cols = length(ColMEs),
+ Nbr_of_Cols = length(ColMEs),
MEs = ColMEs ++ (get(cdata))#cdata.mes,
- Aug = case lookup(SrcTableEntry,MEs) of
+ Aug = case lookup(SrcTableEntry, MEs) of
false ->
print_error("Cannot AUGMENT the non-existing table entry ~p",
- [SrcTableEntry],Line),
+ [SrcTableEntry], Line),
{augments, error};
- {value,ME} ->
- {augments, {SrcTableEntry,translate_type(ME#me.asn1_type)}}
+ {value, ME} ->
+ {augments, {SrcTableEntry, translate_type(ME#me.asn1_type)}}
end,
- #table_info{index_types = Aug};
-make_table_info(Line, TableName, {indexes,[]}, _ColumnMEs) ->
+ FirstNonIdxCol = augments_first_non_index_column(ColMEs),
+ NoAccs = list_not_accessible(FirstNonIdxCol, ColMEs),
+ FirstAcc = first_accessible(TableName, ColMEs),
+ #table_info{nbr_of_cols = Nbr_of_Cols,
+ first_accessible = FirstAcc,
+ not_accessible = NoAccs,
+ index_types = Aug};
+make_table_info(Line, TableName, {indexes, []}, _, _ColumnMEs) ->
print_error("Table ~w lacks indexes.", [TableName],Line),
#table_info{};
-make_table_info(Line, TableName, {indexes,Indexes}, ColumnMEs) ->
+make_table_info(Line, TableName, {indexes, Indexes}, AfterIdxTypes,
+ ColumnMEs) ->
ColMEs = lists:keysort(#me.oid, ColumnMEs),
NonImpliedIndexes = lists:map(fun non_implied_name/1, Indexes),
test_read_create_access(ColMEs, Line, dummy),
NonIndexCol = test_index_positions(Line, NonImpliedIndexes, ColMEs),
Nbr_of_Cols = length(ColMEs),
- ASN1Indexes = find_asn1_types_for_indexes(Indexes, ColMEs, Line),
+ ASN1Indexes = find_asn1_types_for_indexes(Indexes,
+ AfterIdxTypes, ColMEs, Line),
FA = first_accessible(TableName, ColMEs),
StatCol = find_status_col(Line, TableName, ColMEs),
NoAccs = list_not_accessible(NonIndexCol,ColMEs),
@@ -810,11 +824,17 @@ get_defvals(ColMEs) ->
lists:filter(fun drop_undefined/1,
lists:map(fun column_and_defval/1, ColMEs))).
-find_asn1_types_for_indexes(Indexes, ColMEs,Line) ->
- MEs = ColMEs ++ (get(cdata))#cdata.mes,
+find_asn1_types_for_indexes(Indexes, AfterIdxTypes, ColMEs, Line) ->
+ ?vtrace("find_asn1_types_for_indexes -> "
+ "~n Indexes: ~p"
+ "~n ColMEs: ~p"
+ "~n Line: ~p", [Indexes, ColMEs, Line]),
+ MEs = ColMEs ++ (get(cdata))#cdata.mes ++
+ [#me{aliasname = Idx, asn1_type = Type} || {Idx, Type} <-
+ AfterIdxTypes],
test_implied(Indexes, Line),
lists:map(fun (ColumnName) ->
- translate_type(get_asn1_type(ColumnName, MEs,Line))
+ translate_type(get_asn1_type(ColumnName, MEs, Line))
end,
Indexes).
@@ -840,7 +860,11 @@ column_and_defval(#me{oid = Oid, assocList = AssocList}) ->
end.
%% returns: an asn1_type if ColME is an indexfield, otherwise undefined.
-get_asn1_type({implied,ColumnName}, MEs, Line) ->
+get_asn1_type({implied, ColumnName}, MEs, Line) ->
+ ?vtrace("get_asn1_type(implied) -> "
+ "~n ColumnName: ~p"
+ "~n MEs: ~p"
+ "~n Line: ~p", [ColumnName, MEs, Line]),
case lookup(ColumnName, MEs) of
{value,#me{asn1_type=A}} when A#asn1_type.bertype =:=
'OCTET STRING' ->
@@ -853,6 +877,10 @@ get_asn1_type({implied,ColumnName}, MEs, Line) ->
[Shit], Line)
end;
get_asn1_type(ColumnName, MEs, Line) ->
+ ?vtrace("get_asn1_type -> "
+ "~n ColumnName: ~p"
+ "~n MEs: ~p"
+ "~n Line: ~p", [ColumnName, MEs, Line]),
case lookup(ColumnName, MEs) of
{value,ME} -> ME#me.asn1_type;
false -> error("Can't find object ~p. Used as INDEX in table.",
@@ -860,11 +888,17 @@ get_asn1_type(ColumnName, MEs, Line) ->
end.
test_index_positions(Line, Indexes, ColMEs) ->
- TLI = lists:filter(fun (IndexName) ->
- is_table_local_index(IndexName,ColMEs) end,
- Indexes),
+ IsTLI = fun(IndexName) -> is_table_local_index(IndexName, ColMEs) end,
+ TLI = lists:filter(IsTLI, Indexes),
test_index_positions_impl(Line, TLI, ColMEs).
+%% An table that augments another cannot conatin any index,
+%% so the first non-index column is always the first column.
+augments_first_non_index_column([]) ->
+ none;
+augments_first_non_index_column([#me{oid=Col}|_ColMEs]) ->
+ Col.
+
%% Returns the first non-index column | none
test_index_positions_impl(_Line, [], []) -> none;
test_index_positions_impl(_Line, [], [#me{oid=Col}|_ColMEs]) ->
diff --git a/lib/snmp/src/compile/snmpc_lib.hrl b/lib/snmp/src/compile/snmpc_lib.hrl
index 35ec9abd03..8d76817cec 100644
--- a/lib/snmp/src/compile/snmpc_lib.hrl
+++ b/lib/snmp/src/compile/snmpc_lib.hrl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
diff --git a/lib/snmp/src/compile/snmpc_mib_gram.yrl b/lib/snmp/src/compile/snmpc_mib_gram.yrl
index 74b9ddaa25..14a668127e 100644
--- a/lib/snmp/src/compile/snmpc_mib_gram.yrl
+++ b/lib/snmp/src/compile/snmpc_mib_gram.yrl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -244,16 +245,36 @@ listofdefinitions -> definition : ['$1'] .
listofdefinitions -> listofdefinitions definition : ['$2' | '$1'].
import -> '$empty' : [].
-import -> 'IMPORTS' imports ';' : '$2'.
-
-imports -> imports_from_one_mib : ['$1'].
-imports -> imports_from_one_mib imports : ['$1' | '$2'].
+import -> 'IMPORTS' imports ';' :
+%% i("import ->"
+%% "~n imports: ~p", ['$2']),
+ '$2'.
+
+imports -> imports_from_one_mib :
+%% i("imports ->"
+%% "~n imports_from_one_mib: ~p", ['$1']),
+ ['$1'].
+imports -> imports_from_one_mib imports :
+%% i("imports ->"
+%% "~n imports_from_one_mib: ~p"
+%% "~n imports: ~p", ['$1', '$2']),
+ ['$1' | '$2'].
imports_from_one_mib -> listofimports 'FROM' variable :
+%% i("imports_from_one_mib ->"
+%% "~n listofimports: ~p"
+%% "~n variable: ~p", ['$1', '$3']),
{{val('$3'), lreverse(imports_from_one_mib, '$1')}, line_of('$2')}.
-listofimports -> import_stuff : ['$1'].
-listofimports -> listofimports ',' import_stuff : ['$3' | '$1'].
+listofimports -> import_stuff :
+%% i("listofimports ->"
+%% "~n import_stuff: ~p", ['$1']),
+ ['$1'].
+listofimports -> listofimports ',' import_stuff :
+%% i("listofimports ->"
+%% "~n listofimports: ~p"
+%% "~n import_stuff: ~p", ['$1', '$3']),
+ ['$3' | '$1'].
import_stuff -> 'OBJECT-TYPE' : {builtin, 'OBJECT-TYPE'}.
import_stuff -> 'TRAP-TYPE' : {builtin, 'TRAP-TYPE'}.
@@ -314,6 +335,8 @@ import_stuff -> 'TDomain'
: ensure_ver(2,'$1'), {builtin, 'TDomain'}.
import_stuff -> 'TAddress'
: ensure_ver(2,'$1'), {builtin, 'TAddress'}.
+import_stuff -> 'BITS'
+ : ensure_ver(2,'$1'), {builtin, 'BITS'}.
traptype -> objectname 'TRAP-TYPE' 'ENTERPRISE' objectname varpart
description referpart implies integer :
@@ -364,10 +387,12 @@ syntax -> type : {{type, cat('$1')},line_of('$1')}.
syntax -> type size : {{type_with_size, cat('$1'), '$2'},line_of('$1')}.
syntax -> usertype size : {{type_with_size,val('$1'), '$2'},line_of('$1')}.
syntax -> 'INTEGER' '{' namedbits '}' :
- {{integer_with_enum, 'INTEGER', '$3'}, line_of('$1')}.
+ {{type_with_enum, 'INTEGER', '$3'}, line_of('$1')}.
syntax -> 'BITS' '{' namedbits '}' :
ensure_ver(2,'$1'),
{{bits, '$3'}, line_of('$1')}.
+syntax -> usertype '{' namedbits '}' :
+ {{type_with_enum, 'INTEGER', '$3'}, line_of('$1')}.
syntax -> 'SEQUENCE' 'OF' usertype :
{{sequence_of,val('$3')},line_of('$1')}.
@@ -748,7 +773,7 @@ statusv1(Tok) ->
obsolete -> obsolete;
deprecated -> deprecated;
Else -> return_error(line_of(Tok),
- "syntax error before: " ++ atom_to_list(Else))
+ "(statusv1) syntax error before: " ++ atom_to_list(Else))
end.
statusv2(Tok) ->
@@ -757,7 +782,7 @@ statusv2(Tok) ->
deprecated -> deprecated;
obsolete -> obsolete;
Else -> return_error(line_of(Tok),
- "syntax error before: " ++ atom_to_list(Else))
+ "(statusv2) syntax error before: " ++ atom_to_list(Else))
end.
ac_status(Tok) ->
@@ -765,7 +790,7 @@ ac_status(Tok) ->
current -> current;
obsolete -> obsolete;
Else -> return_error(line_of(Tok),
- "syntax error before: " ++ atom_to_list(Else))
+ "(ac_status) syntax error before: " ++ atom_to_list(Else))
end.
accessv1(Tok) ->
@@ -775,7 +800,7 @@ accessv1(Tok) ->
'write-only' -> 'write-only';
'not-accessible' -> 'not-accessible';
Else -> return_error(line_of(Tok),
- "syntax error before: " ++ atom_to_list(Else))
+ "(accessv1) syntax error before: " ++ atom_to_list(Else))
end.
accessv2(Tok) ->
@@ -786,7 +811,7 @@ accessv2(Tok) ->
'read-write' -> 'read-write';
'read-create' -> 'read-create';
Else -> return_error(line_of(Tok),
- "syntax error before: " ++ atom_to_list(Else))
+ "(accessv2) syntax error before: " ++ atom_to_list(Else))
end.
ac_access(Tok) ->
@@ -798,7 +823,7 @@ ac_access(Tok) ->
'read-create' -> 'read-create';
'write-only' -> 'write-only'; % for backward-compatibility only
Else -> return_error(line_of(Tok),
- "syntax error before: " ++ atom_to_list(Else))
+ "(ac_access) syntax error before: " ++ atom_to_list(Else))
end.
%% ---------------------------------------------------------------------
diff --git a/lib/snmp/src/compile/snmpc_mib_to_hrl.erl b/lib/snmp/src/compile/snmpc_mib_to_hrl.erl
index e8c46a0521..bc18afbdc9 100644
--- a/lib/snmp/src/compile/snmpc_mib_to_hrl.erl
+++ b/lib/snmp/src/compile/snmpc_mib_to_hrl.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
diff --git a/lib/snmp/src/compile/snmpc_misc.erl b/lib/snmp/src/compile/snmpc_misc.erl
index 557f3e0f6b..312074f2e7 100644
--- a/lib/snmp/src/compile/snmpc_misc.erl
+++ b/lib/snmp/src/compile/snmpc_misc.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -28,7 +29,7 @@
bits_to_int/2,
ensure_trailing_dir_delimiter/1,
foreach/3,
- is_string/1,
+ check_file/1,
read_mib/1,
read_noexit/2,
strip_extension_from_filename/2,
@@ -85,21 +86,21 @@ to_upper([C|Cs]) -> [C|to_upper(Cs)];
to_upper([]) -> [].
-is_string([]) -> true;
-is_string([Tkn | Str])
- when is_integer(Tkn) andalso (Tkn >= 0) andalso (Tkn =< 255) ->
- is_string(Str);
-is_string(_) -> false.
-
-
+check_file(FileName) ->
+ case filename:extension(FileName) of
+ ".mib" ->
+ filelib:is_regular(FileName);
+ _ ->
+ filelib:is_regular(FileName ++ ".mib")
+ end.
+
+
foreach(Function, ExtraArgs, [H | T]) ->
apply(Function, [H | ExtraArgs]),
foreach(Function, ExtraArgs, T);
foreach(_Function, _ExtraArgs, []) ->
true.
-
-
%%----------------------------------------------------------------------
%% Returns: {ok, Mib}|{error, Reason}
%% The reason for having the function if this module is:
diff --git a/lib/snmp/src/compile/snmpc_misc.hrl b/lib/snmp/src/compile/snmpc_misc.hrl
index c29f2eb9e5..2df6d1863d 100644
--- a/lib/snmp/src/compile/snmpc_misc.hrl
+++ b/lib/snmp/src/compile/snmpc_misc.hrl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
diff --git a/lib/snmp/src/compile/snmpc_tok.erl b/lib/snmp/src/compile/snmpc_tok.erl
index e238b256d0..9114cc90de 100644
--- a/lib/snmp/src/compile/snmpc_tok.erl
+++ b/lib/snmp/src/compile/snmpc_tok.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
diff --git a/lib/snmp/src/manager/Makefile b/lib/snmp/src/manager/Makefile
index c1d5703300..0cc87492f1 100644
--- a/lib/snmp/src/manager/Makefile
+++ b/lib/snmp/src/manager/Makefile
@@ -2,18 +2,19 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2009. All Rights Reserved.
+# Copyright Ericsson AB 2004-2016. All Rights Reserved.
#
-# The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved online at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
+# 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%
@@ -111,13 +112,13 @@ info:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/src/manager
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)/src/manager
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
-# $(INSTALL_DIR) $(RELSYSDIR)/include
-# $(INSTALL_DATA) $(EXT_HRL_FILES) $(RELSYSDIR)/include
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src/manager"
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)/src/manager"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
+# $(INSTALL_DIR) "$(RELSYSDIR)/include"
+# $(INSTALL_DATA) $(EXT_HRL_FILES) "$(RELSYSDIR)/include"
release_docs_spec:
diff --git a/lib/snmp/src/manager/depend.mk b/lib/snmp/src/manager/depend.mk
index 0e7e9e3df7..7d8f81f55a 100644
--- a/lib/snmp/src/manager/depend.mk
+++ b/lib/snmp/src/manager/depend.mk
@@ -2,18 +2,19 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2009. All Rights Reserved.
+# Copyright Ericsson AB 2004-2016. All Rights Reserved.
#
-# The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved online at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
+# 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%
@@ -49,6 +50,14 @@ $(EBIN)/snmpm_net_if.$(EMULATOR): \
snmpm_net_if.erl \
snmpm_network_interface.erl
+$(EBIN)/snmpm_net_if_mt.$(EMULATOR): \
+ snmpm_net_if_mt.erl \
+ ../../include/snmp_types.hrl \
+ ../misc/snmp_debug.hrl \
+ ../misc/snmp_verbosity.hrl \
+ snmpm_net_if.erl \
+ snmpm_network_interface.erl
+
$(EBIN)/snmpm_server.$(EMULATOR): \
../../include/snmp_types.hrl \
../../include/STANDARD-MIB.hrl \
diff --git a/lib/snmp/src/manager/modules.mk b/lib/snmp/src/manager/modules.mk
index 79f3dd65d9..ea9b52d653 100644
--- a/lib/snmp/src/manager/modules.mk
+++ b/lib/snmp/src/manager/modules.mk
@@ -2,18 +2,19 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2009. All Rights Reserved.
+# Copyright Ericsson AB 2004-2016. All Rights Reserved.
#
-# The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved online at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
+# 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%
@@ -31,6 +32,7 @@ MODULES = \
snmpm_mpd \
snmpm_misc_sup \
snmpm_net_if \
+ snmpm_net_if_mt \
snmpm_net_if_filter \
snmpm_server \
snmpm_server_sup \
diff --git a/lib/snmp/src/manager/snmpm.erl b/lib/snmp/src/manager/snmpm.erl
index 6d2ac8d747..cf8c95d69f 100644
--- a/lib/snmp/src/manager/snmpm.erl
+++ b/lib/snmp/src/manager/snmpm.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -75,8 +76,10 @@
%%
%% Logging
- log_to_txt/2, log_to_txt/3, log_to_txt/4,
- log_to_txt/5, log_to_txt/6, log_to_txt/7,
+ log_to_txt/1, log_to_txt/2, log_to_txt/3, log_to_txt/4,
+ log_to_txt/5, log_to_txt/6, log_to_txt/7, log_to_txt/8,
+ log_to_io/1, log_to_io/2, log_to_io/3, log_to_io/4,
+ log_to_io/5, log_to_io/6, log_to_io/7,
change_log_size/1,
get_log_type/0,
set_log_type/1,
@@ -104,63 +107,15 @@
async_get_bulk/5, async_get_bulk/6, async_get_bulk/7, async_get_bulk/8
]).
-%% Backward compatibility exports (API version "1")
--deprecated({agent_info, 3}).
--deprecated({update_agent_info, 5}).
--deprecated({g, 3}).
--deprecated({g, 4}).
--deprecated({g, 5}).
--deprecated({g, 6}).
--deprecated({g, 7}).
--deprecated({ag, 3}).
--deprecated({ag, 4}).
--deprecated({ag, 5}).
--deprecated({ag, 6}).
--deprecated({ag, 7}).
--deprecated({gn, 3}).
--deprecated({gn, 4}).
--deprecated({gn, 5}).
--deprecated({gn, 6}).
--deprecated({gn, 7}).
--deprecated({agn, 3}).
--deprecated({agn, 4}).
--deprecated({agn, 5}).
--deprecated({agn, 6}).
--deprecated({agn, 7}).
--deprecated({gb, 5}).
--deprecated({gb, 6}).
--deprecated({gb, 7}).
--deprecated({gb, 8}).
--deprecated({gb, 9}).
--deprecated({agb, 5}).
--deprecated({agb, 6}).
--deprecated({agb, 7}).
--deprecated({agb, 8}).
--deprecated({agb, 9}).
--deprecated({s, 3}).
--deprecated({s, 4}).
--deprecated({s, 5}).
--deprecated({s, 6}).
--deprecated({s, 7}).
--deprecated({as, 3}).
--deprecated({as, 4}).
--deprecated({as, 5}).
--deprecated({as, 6}).
--deprecated({as, 7}).
--export([
- agent_info/3, update_agent_info/5,
- g/3, g/4, g/5, g/6, g/7,
- ag/3, ag/4, ag/5, ag/6, ag/7,
- gn/3, gn/4, gn/5, gn/6, gn/7,
- agn/3, agn/4, agn/5, agn/6, agn/7,
- gb/5, gb/6, gb/7, gb/8, gb/9,
- agb/5, agb/6, agb/7, agb/8, agb/9,
- s/3, s/4, s/5, s/6, s/7,
- as/3, as/4, as/5, as/6, as/7
- ]).
-
%% Application internal export
-export([start_link/3, snmpm_start_verify/2, snmpm_start_verify/3]).
+-export([target_name/1, target_name/2]).
+
+-export_type([
+ register_timeout/0,
+ agent_config/0,
+ target_name/0
+ ]).
-include_lib("snmp/src/misc/snmp_debug.hrl").
@@ -170,6 +125,26 @@
-include("snmp_verbosity.hrl").
-define(DEFAULT_AGENT_PORT, 161).
+-define(ATL_BLOCK_DEFAULT, true).
+
+
+%%-----------------------------------------------------------------
+%% Types
+%%-----------------------------------------------------------------
+
+-type register_timeout() :: pos_integer() | snmp:snmp_timer().
+-type agent_config() :: {engine_id, snmp:engine_id()} | % Mandatory
+ {address, inet:ip_address()} | % Mandatory
+ {port, inet:port_number()} | % Optional
+ {tdomain, snmp:tdomain()} | % Optional
+ {community, snmp:community()} | % Optional
+ {timeout, register_timeout()} | % Optional
+ {max_message_size, snmp:mms()} | % Optional
+ {version, snmp:version()} | % Optional
+ {sec_moduel, snmp:sec_model()} | % Optional
+ {sec_name, snmp:sec_name()} | % Optional
+ {sec_level, snmp:sec_level()}. % Optional
+-type target_name() :: string().
%% This function is called when the snmp application
@@ -405,21 +380,33 @@ register_agent(UserId, Addr) ->
register_agent(UserId, Addr, ?DEFAULT_AGENT_PORT, []).
%% Backward compatibility
-register_agent(UserId, Addr, Port, Config0) ->
+register_agent(UserId, Domain, Addr, Config0) when is_atom(Domain) ->
case lists:keymember(target_name, 1, Config0) of
false ->
- TargetName = mk_target_name(Addr, Port, Config0),
- Config = [{reg_type, addr_port},
- {address, Addr}, {port, Port} | Config0],
+ TargetName = mk_target_name(Domain, Addr, Config0),
+ Config =
+ [{reg_type, addr_port},
+ {tdomain, Domain}, {taddress, Addr} | Config0],
do_register_agent(UserId, TargetName, ensure_engine_id(Config));
true ->
{value, {_, TargetName}} =
lists:keysearch(target_name, 1, Config0),
Config1 = lists:keydelete(target_name, 1, Config0),
- Config2 = [{reg_type, addr_port},
- {address, Addr}, {port, Port} | Config1],
+ Config2 =
+ [{reg_type, addr_port},
+ {tdomain, Domain}, {taddress, Addr} | Config1],
register_agent(UserId, TargetName, ensure_engine_id(Config2))
- end.
+ end;
+register_agent(UserId, Ip, Port, Config) when is_integer(Port) ->
+ Domain = snmpm_config:default_transport_domain(),
+ Addr =
+ case snmp_conf:check_address(Domain, {Ip, Port}) of
+ ok ->
+ {Ip, Port};
+ {ok, FixedAddr} ->
+ FixedAddr
+ end,
+ register_agent(UserId, Domain, Addr, Config).
unregister_agent(UserId, TargetName) when is_list(TargetName) ->
snmpm_config:unregister_agent(UserId, TargetName);
@@ -428,40 +415,24 @@ unregister_agent(UserId, TargetName) when is_list(TargetName) ->
unregister_agent(UserId, Addr) ->
unregister_agent(UserId, Addr, ?DEFAULT_AGENT_PORT).
-unregister_agent(UserId, Addr, Port) ->
- case target_name(Addr, Port) of
+unregister_agent(UserId, DomainIp, AddressPort) ->
+ case target_name(DomainIp, AddressPort) of
{ok, TargetName} ->
unregister_agent(UserId, TargetName);
Error ->
Error
end.
+
agent_info(TargetName, Item) ->
snmpm_config:agent_info(TargetName, Item).
-%% Backward compatibility
-agent_info(Addr, Port, Item) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- agent_info(TargetName, Item);
- Error ->
- Error
- end.
-
update_agent_info(UserId, TargetName, Info) when is_list(Info) ->
snmpm_config:update_agent_info(UserId, TargetName, Info).
update_agent_info(UserId, TargetName, Item, Val) ->
update_agent_info(UserId, TargetName, [{Item, Val}]).
-%% Backward compatibility functions
-update_agent_info(UserId, Addr, Port, Item, Val) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- update_agent_info(UserId, TargetName, Item, Val);
- Error ->
- Error
- end.
which_agents() ->
snmpm_config:which_agents().
@@ -549,57 +520,8 @@ sync_get(UserId, TargetName, Context, Oids, Timeout, ExtraInfo) ->
%% </BACKWARD-COMPAT>
-%% <DEPRECATED>
-g(UserId, Addr, Oids) ->
- g(UserId, Addr, ?DEFAULT_AGENT_PORT, Oids).
-
-g(UserId, Addr, CtxName, Oids) when is_list(CtxName) andalso is_list(Oids) ->
- g(UserId, Addr, ?DEFAULT_AGENT_PORT, CtxName, Oids);
-
-g(UserId, Addr, Port, Oids) when is_integer(Port) andalso is_list(Oids) ->
- g(UserId, Addr, Port, ?DEFAULT_CONTEXT, Oids);
-
-g(UserId, Addr, Oids, Timeout)
- when is_list(Oids) andalso is_integer(Timeout) ->
- g(UserId, Addr, ?DEFAULT_AGENT_PORT, Oids, Timeout).
-
-g(UserId, Addr, Port, CtxName, Oids)
- when is_integer(Port) andalso is_list(CtxName) andalso is_list(Oids) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- sync_get(UserId, TargetName, CtxName, Oids);
- Error ->
- Error
- end;
-
-g(UserId, Addr, Port, Oids, Timeout)
- when is_integer(Port) andalso is_list(Oids) andalso is_integer(Timeout) ->
- g(UserId, Addr, Port, ?DEFAULT_CONTEXT, Oids, Timeout);
-
-g(UserId, Addr, CtxName, Oids, Timeout)
- when is_list(CtxName) andalso is_list(Oids) andalso is_integer(Timeout) ->
- g(UserId, Addr, ?DEFAULT_AGENT_PORT, CtxName, Oids, Timeout).
-
-g(UserId, Addr, Port, CtxName, Oids, Timeout) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- sync_get(UserId, TargetName, CtxName, Oids, Timeout);
- Error ->
- Error
- end.
-
-g(UserId, Addr, Port, CtxName, Oids, Timeout, ExtraInfo) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- sync_get(UserId, TargetName, CtxName, Oids, Timeout, ExtraInfo);
- Error ->
- Error
- end.
-%% </DEPRECATED>
-
-
-%% --- asynchroneous get-request ---
+%% --- asynchronous get-request ---
%%
%% The reply will be delivered to the user
%% through a call to handle_pdu/5
@@ -634,55 +556,6 @@ async_get(UserId, TargetName, Context, Oids, Expire, ExtraInfo) ->
%% </BACKWARD-COMPAT>
-%% <DEPRECATED>
-ag(UserId, Addr, Oids) ->
- ag(UserId, Addr, ?DEFAULT_AGENT_PORT, Oids).
-
-ag(UserId, Addr, Port, Oids) when is_integer(Port) andalso is_list(Oids) ->
- ag(UserId, Addr, Port, ?DEFAULT_CONTEXT, Oids);
-
-ag(UserId, Addr, CtxName, Oids) when is_list(CtxName) andalso is_list(Oids) ->
- ag(UserId, Addr, ?DEFAULT_AGENT_PORT, CtxName, Oids);
-
-ag(UserId, Addr, Oids, Expire) when is_list(Oids) andalso is_integer(Expire) ->
- ag(UserId, Addr, ?DEFAULT_AGENT_PORT, ?DEFAULT_CONTEXT, Oids, Expire).
-
-ag(UserId, Addr, Port, CtxName, Oids)
- when is_integer(Port) andalso is_list(CtxName) andalso is_list(Oids) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- async_get(UserId, TargetName, CtxName, Oids);
- Error ->
- Error
- end;
-
-ag(UserId, Addr, Port, Oids, Expire)
- when is_integer(Port) andalso is_list(Oids) andalso is_integer(Expire) ->
- ag(UserId, Addr, Port, ?DEFAULT_CONTEXT, Oids, Expire);
-
-ag(UserId, Addr, CtxName, Oids, Expire)
- when is_list(CtxName) andalso is_list(Oids) andalso is_integer(Expire) ->
- ag(UserId, Addr, ?DEFAULT_AGENT_PORT, CtxName, Oids, Expire).
-
-ag(UserId, Addr, Port, CtxName, Oids, Expire) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- async_get(UserId, TargetName, CtxName, Oids, Expire);
- Error ->
- Error
- end.
-
-ag(UserId, Addr, Port, CtxName, Oids, Expire, ExtraInfo) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- async_get(UserId, TargetName, CtxName, Oids, Expire, ExtraInfo);
- Error ->
- Error
- end.
-%% </DEPRECATED>
-
-
-
%% --- synchroneous get_next-request ---
%%
@@ -716,56 +589,7 @@ sync_get_next(UserId, TargetName, Context, Oids, Timeout, ExtraInfo) ->
%% </BACKWARD-COMPAT>
-%% <DEPRECATED>
-gn(UserId, Addr, Oids) ->
- gn(UserId, Addr, ?DEFAULT_AGENT_PORT, Oids).
-
-gn(UserId, Addr, CtxName, Oids) when is_list(CtxName) andalso is_list(Oids) ->
- gn(UserId, Addr, ?DEFAULT_AGENT_PORT, CtxName, Oids);
-
-gn(UserId, Addr, Port, Oids) when is_integer(Port) andalso is_list(Oids) ->
- gn(UserId, Addr, Port, ?DEFAULT_CONTEXT, Oids);
-
-gn(UserId, Addr, Oids, Timeout)
- when is_list(Oids) andalso is_integer(Timeout) ->
- gn(UserId, Addr, ?DEFAULT_AGENT_PORT, Oids, Timeout).
-
-gn(UserId, Addr, Port, CtxName, Oids)
- when is_integer(Port) andalso is_list(CtxName) andalso is_list(Oids) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- sync_get_next(UserId, TargetName, CtxName, Oids);
- Error ->
- Error
- end;
-
-gn(UserId, Addr, Port, Oids, Timeout)
- when is_integer(Port) andalso is_list(Oids) andalso is_integer(Timeout) ->
- gn(UserId, Addr, Port, ?DEFAULT_CONTEXT, Oids, Timeout);
-gn(UserId, Addr, CtxName, Oids, Timeout)
- when is_list(CtxName) andalso is_list(Oids) andalso is_integer(Timeout) ->
- gn(UserId, Addr, ?DEFAULT_AGENT_PORT, CtxName, Oids, Timeout).
-
-gn(UserId, Addr, Port, CtxName, Oids, Timeout) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- sync_get_next(UserId, TargetName, CtxName, Oids, Timeout);
- Error ->
- Error
- end.
-
-gn(UserId, Addr, Port, CtxName, Oids, Timeout, ExtraInfo) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- sync_get_next(UserId, TargetName, CtxName, Oids, Timeout, ExtraInfo);
- Error ->
- Error
- end.
-%% </DEPRECATED>
-
-
-
-%% --- asynchroneous get_next-request ---
+%% --- asynchronous get_next-request ---
%%
async_get_next2(UserId, TargetName, Oids) ->
@@ -798,56 +622,6 @@ async_get_next(UserId, TargetName, Context, Oids, Expire, ExtraInfo) ->
%% </BACKWARD-COMPAT>
-%% <DEPRECATED>
-agn(UserId, Addr, Oids) ->
- agn(UserId, Addr, ?DEFAULT_AGENT_PORT, Oids).
-
-agn(UserId, Addr, CtxName, Oids) when is_list(CtxName) andalso is_list(Oids) ->
- agn(UserId, Addr, ?DEFAULT_AGENT_PORT, CtxName, Oids);
-
-agn(UserId, Addr, Port, Oids) when is_integer(Port) andalso is_list(Oids) ->
- agn(UserId, Addr, Port, ?DEFAULT_CONTEXT, Oids);
-
-agn(UserId, Addr, Oids, Expire)
- when is_list(Oids) andalso is_integer(Expire) ->
- agn(UserId, Addr, ?DEFAULT_AGENT_PORT, Oids, Expire).
-
-agn(UserId, Addr, Port, CtxName, Oids)
- when is_integer(Port) andalso is_list(CtxName) andalso is_list(Oids) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- async_get_next(UserId, TargetName, CtxName, Oids);
- Error ->
- Error
- end;
-
-agn(UserId, Addr, Port, Oids, Expire)
- when is_integer(Port) andalso is_list(Oids) andalso is_integer(Expire) ->
- agn(UserId, Addr, Port, ?DEFAULT_CONTEXT, Oids, Expire);
-agn(UserId, Addr, CtxName, Oids, Expire)
- when is_list(CtxName) andalso is_list(CtxName) andalso is_integer(Expire) ->
- agn(UserId, Addr, ?DEFAULT_AGENT_PORT, CtxName, Oids, Expire).
-
-agn(UserId, Addr, Port, CtxName, Oids, Expire) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- async_get_next(UserId, TargetName, CtxName, Oids, Expire);
- Error ->
- Error
- end.
-
-agn(UserId, Addr, Port, CtxName, Oids, Expire, ExtraInfo) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- async_get_next(UserId, TargetName, CtxName, Oids, Expire,
- ExtraInfo);
- Error ->
- Error
- end.
-%% </DEPRECATED>
-
-
-
%% --- synchroneous set-request ---
%%
@@ -881,65 +655,7 @@ sync_set(UserId, TargetName, Context, VarsAndVals, Timeout, ExtraInfo) ->
%% </BACKWARD-COMPAT>
-%% <DEPRECATED>
-s(UserId, Addr, VarsAndVals) ->
- s(UserId, Addr, ?DEFAULT_AGENT_PORT, VarsAndVals).
-
-s(UserId, Addr, Port, VarsAndVals)
- when is_integer(Port) andalso is_list(VarsAndVals) ->
- s(UserId, Addr, Port, ?DEFAULT_CONTEXT, VarsAndVals);
-
-s(UserId, Addr, CtxName, VarsAndVals)
- when is_list(CtxName) andalso is_list(VarsAndVals) ->
- s(UserId, Addr, ?DEFAULT_AGENT_PORT, CtxName, VarsAndVals);
-
-s(UserId, Addr, VarsAndVals, Timeout)
- when is_list(VarsAndVals) andalso is_integer(Timeout) ->
- s(UserId, Addr, ?DEFAULT_AGENT_PORT, VarsAndVals, Timeout).
-
-s(UserId, Addr, Port, CtxName, VarsAndVals)
- when is_integer(Port) andalso
- is_list(CtxName) andalso
- is_list(VarsAndVals) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- sync_set(UserId, TargetName, CtxName, VarsAndVals);
- Error ->
- Error
- end;
-
-s(UserId, Addr, Port, VarsAndVals, Timeout)
- when is_integer(Port) andalso
- is_list(VarsAndVals) andalso
- is_integer(Timeout) ->
- s(UserId, Addr, Port, ?DEFAULT_CONTEXT, VarsAndVals, Timeout);
-
-s(UserId, Addr, CtxName, VarsAndVals, Timeout)
- when is_list(CtxName) andalso
- is_list(VarsAndVals) andalso
- is_integer(Timeout) ->
- s(UserId, Addr, ?DEFAULT_AGENT_PORT, CtxName, VarsAndVals, Timeout).
-
-s(UserId, Addr, Port, CtxName, VarsAndVals, Timeout) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- sync_set(UserId, TargetName, CtxName, VarsAndVals, Timeout);
- Error ->
- Error
- end.
-
-s(UserId, Addr, Port, CtxName, VarsAndVals, Timeout, ExtraInfo) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- sync_set(UserId, TargetName, CtxName, VarsAndVals, Timeout, ExtraInfo);
- Error ->
- Error
- end.
-%% </DEPRECATED>
-
-
-
-%% --- asynchroneous set-request ---
+%% --- asynchronous set-request ---
%%
async_set2(UserId, TargetName, VarsAndVals) ->
@@ -972,63 +688,6 @@ async_set(UserId, TargetName, Context, VarsAndVals, Expire, ExtraInfo) ->
%% </BACKWARD-COMPAT>
-%% <DEPRECATED>
-as(UserId, Addr, VarsAndVals) ->
- as(UserId, Addr, ?DEFAULT_AGENT_PORT, VarsAndVals).
-
-as(UserId, Addr, Port, VarsAndVals)
- when is_integer(Port) andalso is_list(VarsAndVals) ->
- as(UserId, Addr, Port, ?DEFAULT_CONTEXT, VarsAndVals);
-
-as(UserId, Addr, CtxName, VarsAndVals)
- when is_list(CtxName) andalso is_list(VarsAndVals) ->
- as(UserId, Addr, ?DEFAULT_AGENT_PORT, CtxName, VarsAndVals);
-
-as(UserId, Addr, VarsAndVals, Expire)
- when is_list(VarsAndVals) andalso is_integer(Expire) ->
- as(UserId, Addr, ?DEFAULT_AGENT_PORT, VarsAndVals, Expire).
-
-as(UserId, Addr, Port, CtxName, VarsAndVals)
- when is_integer(Port) andalso
- is_list(CtxName) andalso
- is_list(VarsAndVals) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- async_set(UserId, TargetName, CtxName, VarsAndVals);
- Error ->
- Error
- end;
-
-as(UserId, Addr, Port, VarsAndVals, Expire)
- when is_integer(Port) andalso
- is_list(VarsAndVals) andalso
- is_integer(Expire) ->
- as(UserId, Addr, Port, ?DEFAULT_CONTEXT, VarsAndVals, Expire);
-
-as(UserId, Addr, CtxName, VarsAndVals, Expire)
- when is_list(CtxName) andalso
- is_list(VarsAndVals) andalso
- is_integer(Expire) ->
- as(UserId, Addr, ?DEFAULT_AGENT_PORT, CtxName, VarsAndVals, Expire).
-
-as(UserId, Addr, Port, CtxName, VarsAndVals, Expire) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- async_set(UserId, TargetName, CtxName, VarsAndVals, Expire);
- Error ->
- Error
- end.
-
-as(UserId, Addr, Port, CtxName, VarsAndVals, Expire, ExtraInfo) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- async_set(UserId, TargetName, CtxName, VarsAndVals, Expire, ExtraInfo);
- Error ->
- Error
- end.
-%% </DEPRECATED>
-
-
%% --- synchroneous get-bulk ---
%%
@@ -1088,163 +747,7 @@ sync_get_bulk(UserId, TargetName, NonRep, MaxRep, Context, Oids, Timeout,
%% </BACKWARD-COMPAT>
-%% <DEPRECATED>
-gb(UserId, Addr, NonRep, MaxRep, Oids) ->
- %% p("gb -> entry with"
- %% "~n UserId: ~p"
- %% "~n Addr: ~p"
- %% "~n NonRep: ~p"
- %% "~n MaxRep: ~p"
- %% "~n Oids: ~p",
- %% [UserId, Addr, NonRep, MaxRep, Oids]),
- gb(UserId, Addr, ?DEFAULT_AGENT_PORT, NonRep, MaxRep, Oids).
-
-gb(UserId, Addr, Port, NonRep, MaxRep, Oids)
- when is_integer(Port) andalso
- is_integer(NonRep) andalso
- is_integer(MaxRep) andalso
- is_list(Oids) ->
- %% p("gb -> entry with"
- %% "~n UserId: ~p"
- %% "~n Addr: ~p"
- %% "~n Port: ~p"
- %% "~n NonRep: ~p"
- %% "~n MaxRep: ~p"
- %% "~n Oids: ~p",
- %% [UserId, Addr, Port, NonRep, MaxRep, Oids]),
- gb(UserId, Addr, Port, NonRep, MaxRep, ?DEFAULT_CONTEXT, Oids);
-
-gb(UserId, Addr, NonRep, MaxRep, CtxName, Oids)
- when is_integer(NonRep) andalso
- is_integer(MaxRep) andalso
- is_list(CtxName) andalso
- is_list(Oids) ->
- %% p("gb -> entry with"
- %% "~n UserId: ~p"
- %% "~n Addr: ~p"
- %% "~n NonRep: ~p"
- %% "~n MaxRep: ~p"
- %% "~n CtxName: ~p"
- %% "~n Oids: ~p",
- %% [UserId, Addr, NonRep, MaxRep, CtxName, Oids]),
- gb(UserId, Addr, ?DEFAULT_AGENT_PORT, NonRep, MaxRep, CtxName, Oids);
-
-gb(UserId, Addr, NonRep, MaxRep, Oids, Timeout)
- when is_integer(NonRep) andalso
- is_integer(MaxRep) andalso
- is_list(Oids) andalso
- is_integer(Timeout) ->
- %% p("gb -> entry with"
- %% "~n UserId: ~p"
- %% "~n Addr: ~p"
- %% "~n NonRep: ~p"
- %% "~n MaxRep: ~p"
- %% "~n Oids: ~p"
- %% "~n Timeout: ~p",
- %% [UserId, Addr, NonRep, MaxRep, Oids, Timeout]),
- gb(UserId, Addr, ?DEFAULT_AGENT_PORT, NonRep, MaxRep, Oids, Timeout).
-
-gb(UserId, Addr, Port, NonRep, MaxRep, CtxName, Oids)
- when is_integer(Port) andalso
- is_integer(NonRep) andalso
- is_integer(MaxRep) andalso
- is_list(CtxName) andalso
- is_list(Oids) ->
- %% p("gb -> entry with"
- %% "~n UserId: ~p"
- %% "~n Addr: ~p"
- %% "~n Port: ~p"
- %% "~n NonRep: ~p"
- %% "~n MaxRep: ~p"
- %% "~n CtxName: ~p"
- %% "~n Oids: ~p",
- %% [UserId, Addr, Port, NonRep, MaxRep, CtxName, Oids]),
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- %% p("gb -> TargetName: ~p", [TargetName]),
- sync_get_bulk(UserId, TargetName, NonRep, MaxRep, CtxName, Oids);
- Error ->
- Error
- end;
-
-gb(UserId, Addr, Port, NonRep, MaxRep, Oids, Timeout)
- when is_integer(Port) andalso
- is_integer(NonRep) andalso
- is_integer(MaxRep) andalso
- is_list(Oids) andalso
- is_integer(Timeout) ->
- %% p("gb -> entry with"
- %% "~n UserId: ~p"
- %% "~n Addr: ~p"
- %% "~n Port: ~p"
- %% "~n NonRep: ~p"
- %% "~n MaxRep: ~p"
- %% "~n Oids: ~p"
- %% "~n Timeout: ~p",
- %% [UserId, Addr, Port, NonRep, MaxRep, Oids, Timeout]),
- gb(UserId, Addr, Port, NonRep, MaxRep, ?DEFAULT_CONTEXT, Oids, Timeout);
-
-gb(UserId, Addr, NonRep, MaxRep, CtxName, Oids, Timeout)
- when is_integer(NonRep) andalso
- is_integer(MaxRep) andalso
- is_list(CtxName) andalso
- is_list(Oids) andalso
- is_integer(Timeout) ->
- %% p("gb -> entry with"
- %% "~n UserId: ~p"
- %% "~n Addr: ~p"
- %% "~n NonRep: ~p"
- %% "~n MaxRep: ~p"
- %% "~n CtxName: ~p"
- %% "~n Oids: ~p"
- %% "~n Timeout: ~p",
- %% [UserId, Addr, NonRep, MaxRep, CtxName, Oids, Timeout]),
- gb(UserId, Addr, ?DEFAULT_AGENT_PORT, NonRep, MaxRep, CtxName, Oids,
- Timeout).
-
-gb(UserId, Addr, Port, NonRep, MaxRep, CtxName, Oids, Timeout) ->
- %% p("gb -> entry with"
- %% "~n UserId: ~p"
- %% "~n Addr: ~p"
- %% "~n Port: ~p"
- %% "~n NonRep: ~p"
- %% "~n MaxRep: ~p"
- %% "~n CtxName: ~p"
- %% "~n Oids: ~p"
- %% "~n Timeout: ~p",
- %% [UserId, Addr, Port, NonRep, MaxRep, CtxName, Oids, Timeout]),
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- sync_get_bulk(UserId, TargetName,
- NonRep, MaxRep, CtxName, Oids, Timeout);
- Error ->
- Error
- end.
-
-gb(UserId, Addr, Port, NonRep, MaxRep, CtxName, Oids, Timeout, ExtraInfo) ->
- %% p("gb -> entry with"
- %% "~n UserId: ~p"
- %% "~n Addr: ~p"
- %% "~n Port: ~p"
- %% "~n NonRep: ~p"
- %% "~n MaxRep: ~p"
- %% "~n CtxName: ~p"
- %% "~n Oids: ~p"
- %% "~n Timeout: ~p"
- %% "~n ExtraInfo: ~p",
- %% [UserId, Addr, Port, NonRep, MaxRep, CtxName, Oids, Timeout, ExtraInfo]),
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- sync_get_bulk(UserId, TargetName,
- NonRep, MaxRep, CtxName, Oids, Timeout, ExtraInfo);
- Error ->
- Error
- end.
-%% </DEPRECATED>
-
-
-
-%% --- asynchroneous get-bulk ---
+%% --- asynchronous get-bulk ---
%%
async_get_bulk2(UserId, TargetName, NonRep, MaxRep, Oids) ->
@@ -1288,81 +791,6 @@ async_get_bulk(UserId, TargetName, NonRep, MaxRep, Context, Oids, Expire,
%% </BACKWARD-COMPAT>
-%% <DEPRECATED>
-agb(UserId, Addr, NonRep, MaxRep, Oids) ->
- agb(UserId, Addr, ?DEFAULT_AGENT_PORT, NonRep, MaxRep, Oids).
-
-agb(UserId, Addr, Port, NonRep, MaxRep, Oids)
- when is_integer(Port) andalso
- is_integer(NonRep) andalso
- is_integer(MaxRep) andalso
- is_list(Oids) ->
- agb(UserId, Addr, Port, NonRep, MaxRep, ?DEFAULT_CONTEXT, Oids);
-
-agb(UserId, Addr, NonRep, MaxRep, CtxName, Oids)
- when is_integer(NonRep) andalso
- is_integer(MaxRep) andalso
- is_list(CtxName) andalso
- is_list(Oids) ->
- agb(UserId, Addr, ?DEFAULT_AGENT_PORT, NonRep, MaxRep, CtxName, Oids);
-
-agb(UserId, Addr, NonRep, MaxRep, Oids, Expire)
- when is_integer(NonRep) andalso
- is_integer(MaxRep) andalso
- is_list(Oids) andalso
- is_integer(Expire) ->
- agb(UserId, Addr, ?DEFAULT_AGENT_PORT, NonRep, MaxRep, Oids, Expire).
-
-agb(UserId, Addr, Port, NonRep, MaxRep, CtxName, Oids)
- when is_integer(Port) andalso
- is_integer(NonRep) andalso
- is_integer(MaxRep),
- is_list(CtxName) andalso
- is_list(Oids) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- async_get_bulk(UserId, TargetName,
- NonRep, MaxRep, CtxName, Oids);
- Error ->
- Error
- end;
-
-agb(UserId, Addr, Port, NonRep, MaxRep, Oids, Expire)
- when is_integer(Port) andalso
- is_integer(NonRep) andalso
- is_integer(MaxRep) andalso
- is_list(Oids) andalso
- is_integer(Expire) ->
- agb(UserId, Addr, Port, NonRep, MaxRep, ?DEFAULT_CONTEXT, Oids, Expire);
-
-agb(UserId, Addr, NonRep, MaxRep, CtxName, Oids, Expire)
- when is_integer(NonRep) andalso
- is_integer(MaxRep) andalso
- is_list(CtxName) andalso
- is_list(Oids) andalso
- is_integer(Expire) ->
- agb(UserId, Addr, ?DEFAULT_AGENT_PORT, NonRep, MaxRep, CtxName, Oids).
-
-agb(UserId, Addr, Port, NonRep, MaxRep, CtxName, Oids, Expire) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- async_get_bulk(UserId, TargetName,
- NonRep, MaxRep, CtxName, Oids, Expire);
- Error ->
- Error
- end.
-
-agb(UserId, Addr, Port, NonRep, MaxRep, CtxName, Oids, Expire, ExtraInfo) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- async_get_bulk(UserId, TargetName,
- NonRep, MaxRep, CtxName, Oids, Expire,
- ExtraInfo);
- Error ->
- Error
- end.
-%% </DEPRECATED>
-
cancel_async_request(UserId, ReqId) ->
snmpm_server:cancel_async_request(UserId, ReqId).
@@ -1371,25 +799,206 @@ cancel_async_request(UserId, ReqId) ->
%%%-----------------------------------------------------------------
%%% Audit Trail Log functions (for backward compatibility)
%%%-----------------------------------------------------------------
+
+-spec log_to_txt(LogDir :: snmp:dir()) ->
+ snmp:void().
+
+log_to_txt(LogDir) ->
+ log_to_txt(LogDir, []).
+
+-spec log_to_txt(LogDir :: snmp:dir(),
+ Block :: boolean()) ->
+ snmp:void();
+ (LogDir :: snmp:dir(),
+ Mibs :: [snmp:mib_name()]) ->
+ snmp:void().
+
+log_to_txt(LogDir, Block)
+ when ((Block =:= true) orelse (Block =:= false)) ->
+ Mibs = [],
+ OutFile = "snmpm_log.txt",
+ LogName = ?audit_trail_log_name,
+ LogFile = ?audit_trail_log_file,
+ snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block);
log_to_txt(LogDir, Mibs) ->
+ Block = ?ATL_BLOCK_DEFAULT,
+ OutFile = "snmpm_log.txt",
+ LogName = ?audit_trail_log_name,
+ LogFile = ?audit_trail_log_file,
+ snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block).
+
+-spec log_to_txt(LogDir :: snmp:dir(),
+ Mibs :: [snmp:mib_name()],
+ Block :: boolean()) ->
+ snmp:void();
+ (LogDir :: snmp:dir(),
+ Mibs :: [snmp:mib_name()],
+ OutFile :: file:filename()) ->
+ snmp:void().
+
+log_to_txt(LogDir, Mibs, Block)
+ when ((Block =:= true) orelse (Block =:= false)) ->
OutFile = "snmpm_log.txt",
LogName = ?audit_trail_log_name,
LogFile = ?audit_trail_log_file,
- snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile).
+ snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block);
log_to_txt(LogDir, Mibs, OutFile) ->
+ Block = ?ATL_BLOCK_DEFAULT,
+ LogName = ?audit_trail_log_name,
+ LogFile = ?audit_trail_log_file,
+ snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block).
+
+-spec log_to_txt(LogDir :: snmp:dir(),
+ Mibs :: [snmp:mib_name()],
+ OutFile :: file:filename(),
+ Block :: boolean()) ->
+ snmp:void();
+ (LogDir :: snmp:dir(),
+ Mibs :: [snmp:mib_name()],
+ OutFile :: file:filename(),
+ LogName :: string()) ->
+ snmp:void().
+
+log_to_txt(LogDir, Mibs, OutFile, Block)
+ when ((Block =:= true) orelse (Block =:= false)) ->
LogName = ?audit_trail_log_name,
LogFile = ?audit_trail_log_file,
- snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile).
+ snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block);
log_to_txt(LogDir, Mibs, OutFile, LogName) ->
+ Block = ?ATL_BLOCK_DEFAULT,
+ LogFile = ?audit_trail_log_file,
+ snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block).
+
+-spec log_to_txt(LogDir :: snmp:dir(),
+ Mibs :: [snmp:mib_name()],
+ OutFile :: file:filename(),
+ LogName :: string(),
+ Block :: boolean()) ->
+ snmp:void();
+ (LogDir :: snmp:dir(),
+ Mibs :: [snmp:mib_name()],
+ OutFile :: file:filename(),
+ LogName :: string(),
+ LogFile :: string()) ->
+ snmp:void().
+
+log_to_txt(LogDir, Mibs, OutFile, LogName, Block)
+ when ((Block =:= true) orelse (Block =:= false)) ->
LogFile = ?audit_trail_log_file,
- snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile).
+ snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block);
log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile) ->
- snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile).
+ Block = ?ATL_BLOCK_DEFAULT,
+ snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block).
+
+-spec log_to_txt(LogDir :: snmp:dir(),
+ Mibs :: [snmp:mib_name()],
+ OutFile :: file:filename(),
+ LogName :: string(),
+ LogFile :: string(),
+ Block :: boolean()) ->
+ snmp:void();
+ (LogDir :: snmp:dir(),
+ Mibs :: [snmp:mib_name()],
+ OutFile :: file:filename(),
+ LogName :: string(),
+ LogFile :: string(),
+ Start :: snmp_log:log_time()) ->
+ snmp:void().
+
+log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block)
+ when ((Block =:= true) orelse (Block =:= false)) ->
+ snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block);
log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start) ->
- snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start).
+ Block = ?ATL_BLOCK_DEFAULT,
+ snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start).
+
+-spec log_to_txt(LogDir :: snmp:dir(),
+ Mibs :: [snmp:mib_name()],
+ OutFile :: file:filename(),
+ LogName :: string(),
+ LogFile :: string(),
+ Block :: boolean(),
+ Start :: snmp_log:log_time()) ->
+ snmp:void();
+ (LogDir :: snmp:dir(),
+ Mibs :: [snmp:mib_name()],
+ OutFile :: file:filename(),
+ LogName :: string(),
+ LogFile :: string(),
+ Start :: snmp_log:log_time(),
+ Stop :: snmp_log:log_time()) ->
+ snmp:void().
+
+log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start)
+ when ((Block =:= true) orelse (Block =:= false)) ->
+ snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start);
log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) ->
- snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop).
+ Block = ?ATL_BLOCK_DEFAULT,
+ snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop).
+-spec log_to_txt(LogDir :: snmp:dir(),
+ Mibs :: [snmp:mib_name()],
+ OutFile :: file:filename(),
+ LogName :: string(),
+ LogFile :: string(),
+ Block :: boolean(),
+ Start :: snmp_log:log_time(),
+ Stop :: snmp_log:log_time()) ->
+ snmp:void().
+
+log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop) ->
+ snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop).
+
+
+log_to_io(LogDir) ->
+ log_to_io(LogDir, []).
+
+log_to_io(LogDir, Block)
+ when ((Block =:= true) orelse (Block =:= false)) ->
+ Mibs = [],
+ LogName = ?audit_trail_log_name,
+ LogFile = ?audit_trail_log_file,
+ snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block);
+log_to_io(LogDir, Mibs) ->
+ LogName = ?audit_trail_log_name,
+ LogFile = ?audit_trail_log_file,
+ snmp:log_to_io(LogDir, Mibs, LogName, LogFile).
+
+log_to_io(LogDir, Mibs, Block)
+ when ((Block =:= true) orelse (Block =:= false)) ->
+ LogName = ?audit_trail_log_name,
+ LogFile = ?audit_trail_log_file,
+ snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block);
+log_to_io(LogDir, Mibs, LogName) ->
+ Block = ?ATL_BLOCK_DEFAULT,
+ LogFile = ?audit_trail_log_file,
+ snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block).
+
+log_to_io(LogDir, Mibs, LogName, Block)
+ when ((Block =:= true) orelse (Block =:= false)) ->
+ LogFile = ?audit_trail_log_file,
+ snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block);
+log_to_io(LogDir, Mibs, LogName, LogFile) ->
+ Block = ?ATL_BLOCK_DEFAULT,
+ snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block).
+
+log_to_io(LogDir, Mibs, LogName, LogFile, Block)
+ when ((Block =:= true) orelse (Block =:= false)) ->
+ snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block);
+log_to_io(LogDir, Mibs, LogName, LogFile, Start) ->
+ Block = ?ATL_BLOCK_DEFAULT,
+ snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start).
+
+log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start)
+ when ((Block =:= true) orelse (Block =:= false)) ->
+ snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start);
+log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop) ->
+ Block = ?ATL_BLOCK_DEFAULT,
+ snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop).
+
+log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop) ->
+ snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop).
+
change_log_size(NewSize) ->
LogName = ?audit_trail_log_name,
@@ -1434,7 +1043,7 @@ sys_up_time() ->
format_reason(Reason) ->
format_reason("", Reason).
-format_reason(Prefix, Reason) when is_integer(Prefix) and (Prefix >= 0) ->
+format_reason(Prefix, Reason) when is_integer(Prefix) andalso (Prefix >= 0) ->
format_reason(lists:duplicate(Prefix, $ ), Reason);
format_reason(Prefix, Reason) when is_list(Prefix) ->
case (catch do_format_reason(Prefix, Reason)) of
@@ -1668,11 +1277,17 @@ format_vb_value(Prefix, _Type, Val) ->
%% --- Internal utility functions ---
%%
-target_name(Addr, Port) ->
- snmpm_config:agent_info(Addr, Port, target_name).
+target_name(Ip) ->
+ target_name(Ip, ?DEFAULT_AGENT_PORT).
+
+target_name(DomainIp, AddressPort) ->
+ snmpm_config:agent_info(DomainIp, AddressPort, target_name).
mk_target_name(Addr, Port, Config) ->
- snmpm_config:mk_target_name(Addr, Port, Config).
+ R = snmpm_config:mk_target_name(Addr, Port, Config),
+ p(?MODULE_STRING":mk_target_name(~p, ~p, ~p) -> ~p.~n",
+ [Addr, Port, Config, R]),
+ R.
ensure_engine_id(Config) ->
case lists:keymember(engine_id, 1, Config) of
@@ -1688,5 +1303,5 @@ ensure_engine_id(Config) ->
%% p(F) ->
%% p(F, []).
-%% p(F, A) ->
-%% io:format("~w:" ++ F ++ "~n", [?MODULE | A]).
+p(F, A) ->
+ io:format("~w:" ++ F ++ "~n", [?MODULE | A]).
diff --git a/lib/snmp/src/manager/snmpm_atl.hrl b/lib/snmp/src/manager/snmpm_atl.hrl
index d99ee05ae6..988b75d9bd 100644
--- a/lib/snmp/src/manager/snmpm_atl.hrl
+++ b/lib/snmp/src/manager/snmpm_atl.hrl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
diff --git a/lib/snmp/src/manager/snmpm_conf.erl b/lib/snmp/src/manager/snmpm_conf.erl
index e50508c489..0421f49c88 100644
--- a/lib/snmp/src/manager/snmpm_conf.erl
+++ b/lib/snmp/src/manager/snmpm_conf.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -78,42 +79,25 @@ write_manager_config(Dir, Conf) ->
Hdr = header() ++ Comment,
write_manager_config(Dir, Hdr, Conf).
-write_manager_config(Dir, Hdr, Conf)
- when is_list(Dir) andalso is_list(Hdr) andalso is_list(Conf) ->
- Verify = fun() -> verify_manager_conf(Conf) end,
- Write = fun(Fid) -> write_manager_conf(Fid, Hdr, Conf) end,
- write_config_file(Dir, ?MANAGER_CONF_FILE, Verify, Write).
-
+write_manager_config(Dir, Hdr, Conf)
+ when is_list(Dir), is_list(Hdr), is_list(Conf) ->
+ Order = fun snmpm_config:order_manager_config/2,
+ Check = fun snmpm_config:check_manager_config/2,
+ Write = fun (Fd, Entries) -> write_manager_conf(Fd, Hdr, Entries) end,
+ write_config_file(Dir, ?MANAGER_CONF_FILE, Order, Check, Write, Conf).
append_manager_config(Dir, Conf)
- when is_list(Dir) andalso is_list(Conf) ->
- Verify = fun() -> verify_manager_conf(Conf) end,
- Write = fun(Fid) -> write_manager_conf(Fid, Conf) end,
- append_config_file(Dir, ?MANAGER_CONF_FILE, Verify, Write).
-
-
-read_manager_config(Dir) ->
- Verify = fun(Entry) -> verify_manager_conf_entry(Entry) end,
- read_config_file(Dir, ?MANAGER_CONF_FILE, Verify).
+ when is_list(Dir), is_list(Conf) ->
+ Order = fun snmpm_config:order_manager_config/2,
+ Check = fun snmpm_config:check_manager_config/2,
+ Write = fun write_manager_conf/2,
+ append_config_file(Dir, ?MANAGER_CONF_FILE, Order, Check, Write, Conf).
+read_manager_config(Dir) when is_list(Dir) ->
+ Order = fun snmpm_config:order_manager_config/2,
+ Check = fun snmpm_config:check_manager_config/2,
+ read_config_file(Dir, ?MANAGER_CONF_FILE, Order, Check).
-verify_manager_conf([]) ->
- ok;
-verify_manager_conf([H|T]) ->
- verify_manager_conf_entry(H),
- verify_manager_conf(T);
-verify_manager_conf(X) ->
- error({bad_manager_config, X}).
-
-verify_manager_conf_entry(Entry) ->
- case snmpm_config:check_manager_config(Entry) of
- ok ->
- ok;
-%% {ok, _} ->
-%% ok;
- Error ->
- throw(Error)
- end.
write_manager_conf(Fd, "", Conf) ->
write_manager_conf(Fd, Conf);
@@ -127,14 +111,16 @@ write_manager_conf(Fd, [H|T]) ->
do_write_manager_conf(Fd, H),
write_manager_conf(Fd, T).
-do_write_manager_conf(Fd, {address = Tag, Val}) ->
+do_write_manager_conf(Fd, {Tag, Val})
+ when Tag =:= domain;
+ Tag =:= address;
+ Tag =:= port;
+ Tag =:= transports;
+ Tag =:= max_message_size ->
io:format(Fd, "{~w, ~w}.~n", [Tag, Val]);
-do_write_manager_conf(Fd, {port = Tag, Val} ) ->
- io:format(Fd, "{~w, ~w}.~n", [Tag, Val]);
-do_write_manager_conf(Fd, {engine_id = Tag, Val} ) ->
+do_write_manager_conf(Fd, {Tag, Val})
+ when Tag =:= engine_id ->
io:format(Fd, "{~w, \"~s\"}.~n", [Tag, Val]);
-do_write_manager_conf(Fd, {max_message_size = Tag, Val} ) ->
- io:format(Fd, "{~w, ~w}.~n", [Tag, Val]);
do_write_manager_conf(_Fd, Crap) ->
error({bad_manager_config, Crap}).
@@ -167,36 +153,29 @@ write_users_config(Dir, Conf) ->
Hdr = header() ++ Comment,
write_users_config(Dir, Hdr, Conf).
-write_users_config(Dir, Hdr, Conf)
+write_users_config(Dir, Hdr, Conf)
when is_list(Dir) andalso is_list(Hdr) andalso is_list(Conf) ->
- Verify = fun() -> verify_users_conf(Conf) end,
- Write = fun(Fd) -> write_users_conf(Fd, Hdr, Conf) end,
- write_config_file(Dir, ?USERS_CONF_FILE, Verify, Write).
+ Order = fun snmp_conf:no_order/2,
+ Check = fun check_user_config/2,
+ Write = fun (Fd, Entries) -> write_users_conf(Fd, Hdr, Entries) end,
+ write_config_file(Dir, ?USERS_CONF_FILE, Order, Check, Write, Conf).
-
-append_users_config(Dir, Conf)
+append_users_config(Dir, Conf)
when is_list(Dir) andalso is_list(Conf) ->
- Verify = fun() -> verify_users_conf(Conf) end,
- Write = fun(Fd) -> write_users_conf(Fd, Conf) end,
- append_config_file(Dir, ?USERS_CONF_FILE, Verify, Write).
-
+ Order = fun snmp_conf:no_order/2,
+ Check = fun check_user_config/2,
+ Write = fun write_users_conf/2,
+ append_config_file(Dir, ?USERS_CONF_FILE, Order, Check, Write, Conf).
read_users_config(Dir) when is_list(Dir) ->
- Verify = fun(Entry) -> verify_users_conf_entry(Entry) end,
- read_config_file(Dir, ?USERS_CONF_FILE, Verify).
+ Order = fun snmp_conf:no_order/2,
+ Check = fun check_user_config/2,
+ read_config_file(Dir, ?USERS_CONF_FILE, Order, Check).
-
-verify_users_conf([]) ->
- ok;
-verify_users_conf([H|T]) ->
- verify_users_conf_entry(H),
- verify_users_conf(T);
-verify_users_conf(X) ->
- error({bad_users_conf, X}).
-
-verify_users_conf_entry(Entry) ->
- {ok, _} = snmpm_config:check_user_config(Entry),
- ok.
+
+check_user_config(Entry, State) ->
+ {check_ok(snmpm_config:check_user_config(Entry)),
+ State}.
write_users_conf(Fd, "", Conf) ->
write_users_conf(Fd, Conf);
@@ -222,9 +201,10 @@ do_write_users_conf(_Fd, Crap) ->
%% ------ agents.conf ------
%%
-agents_entry(UserId, TargetName, Comm, Ip, Port, EngineID, Timeout,
- MaxMessageSize, Version, SecModel, SecName, SecLevel) ->
- {UserId, TargetName, Comm, Ip, Port, EngineID, Timeout,
+agents_entry(
+ UserId, TargetName, Comm, Domain_or_Ip, Addr_or_Port, EngineID, Timeout,
+ MaxMessageSize, Version, SecModel, SecName, SecLevel) ->
+ {UserId, TargetName, Comm, Domain_or_Ip, Addr_or_Port, EngineID, Timeout,
MaxMessageSize, Version, SecModel, SecName, SecLevel}.
@@ -239,36 +219,29 @@ write_agents_config(Dir, Conf) ->
Hdr = header() ++ Comment,
write_agents_config(Dir, Hdr, Conf).
-write_agents_config(Dir, Hdr, Conf)
+write_agents_config(Dir, Hdr, Conf)
when is_list(Dir) andalso is_list(Hdr) andalso is_list(Conf) ->
- Verify = fun() -> verify_agents_conf(Conf) end,
- Write = fun(Fd) -> write_agents_conf(Fd, Hdr, Conf) end,
- write_config_file(Dir, ?AGENTS_CONF_FILE, Verify, Write).
-
+ Order = fun snmp_conf:no_order/2,
+ Check = fun check_agent_config/2,
+ Write = fun (Fd, Entries) -> write_agents_conf(Fd, Hdr, Entries) end,
+ write_config_file(Dir, ?AGENTS_CONF_FILE, Order, Check, Write, Conf).
-append_agents_config(Dir, Conf)
+append_agents_config(Dir, Conf)
when is_list(Dir) andalso is_list(Conf) ->
- Verify = fun() -> verify_agents_conf(Conf) end,
- Write = fun(Fd) -> write_agents_conf(Fd, Conf) end,
- append_config_file(Dir, ?AGENTS_CONF_FILE, Verify, Write).
-
+ Order = fun snmp_conf:no_order/2,
+ Check = fun check_agent_config/2,
+ Write = fun write_agents_conf/2,
+ append_config_file(Dir, ?AGENTS_CONF_FILE, Order, Check, Write, Conf).
read_agents_config(Dir) ->
- Verify = fun(Entry) -> verify_agents_conf_entry(Entry) end,
- read_config_file(Dir, ?AGENTS_CONF_FILE, Verify).
+ Order = fun snmp_conf:no_order/2,
+ Check = fun check_agent_config/2,
+ read_config_file(Dir, ?AGENTS_CONF_FILE, Order, Check).
-verify_agents_conf([]) ->
- ok;
-verify_agents_conf([H|T]) ->
- verify_agents_conf_entry(H),
- verify_agents_conf(T);
-verify_agents_conf(X) ->
- error({bad_agents_config, X}).
-
-verify_agents_conf_entry(Entry) ->
- {ok, _} = snmpm_config:check_agent_config(Entry),
- ok.
+check_agent_config(Entry, State) ->
+ {check_ok(snmpm_config:check_agent_config(Entry)),
+ State}.
write_agents_conf(Fd, "", Conf) ->
write_agents_conf(Fd, Conf);
@@ -282,13 +255,15 @@ write_agents_conf(Fd, [H|T]) ->
do_write_agents_conf(Fd, H),
write_agents_conf(Fd, T).
-do_write_agents_conf(Fd,
- {UserId,
- TargetName, Comm, Ip, Port, EngineID,
- Timeout, MaxMessageSize, Version,
- SecModel, SecName, SecLevel} = _A) ->
- io:format(Fd,
- "{~w, \"~s\", \"~s\", ~w, ~w, \"~s\", ~w, ~w, ~w, ~w, \"~s\", ~w}.~n", [UserId, TargetName, Comm, Ip, Port, EngineID, Timeout, MaxMessageSize, Version, SecModel, SecName, SecLevel]);
+do_write_agents_conf(
+ Fd,
+ {UserId, TargetName, Comm, Ip, Port, EngineID,
+ Timeout, MaxMessageSize, Version, SecModel, SecName, SecLevel} = _A) ->
+ io:format(
+ Fd,
+ "{~w, \"~s\", \"~s\", ~w, ~w, \"~s\", ~w, ~w, ~w, ~w, \"~s\", ~w}.~n",
+ [UserId, TargetName, Comm, Ip, Port, EngineID,
+ Timeout, MaxMessageSize, Version, SecModel, SecName, SecLevel]);
do_write_agents_conf(_Fd, Crap) ->
error({bad_agents_config, Crap}).
@@ -314,37 +289,30 @@ write_usm_config(Dir, Conf) ->
Hdr = header() ++ Comment,
write_usm_config(Dir, Hdr, Conf).
-write_usm_config(Dir, Hdr, Conf)
+write_usm_config(Dir, Hdr, Conf)
when is_list(Dir) andalso is_list(Hdr) andalso is_list(Conf) ->
- Verify = fun() -> verify_usm_conf(Conf) end,
- Write = fun(Fd) -> write_usm_conf(Fd, Hdr, Conf) end,
- write_config_file(Dir, ?USM_USERS_CONF_FILE, Verify, Write).
-
+ Order = fun snmp_conf:no_order/2,
+ Check = fun check_usm_user_config/2,
+ Write = fun (Fd, Entries) -> write_usm_conf(Fd, Hdr, Entries) end,
+ write_config_file(Dir, ?USM_USERS_CONF_FILE, Order, Check, Write, Conf).
-append_usm_config(Dir, Conf)
+append_usm_config(Dir, Conf)
when is_list(Dir) andalso is_list(Conf) ->
- Verify = fun() -> verify_usm_conf(Conf) end,
- Write = fun(Fd) -> write_usm_conf(Fd, Conf) end,
- append_config_file(Dir, ?USM_USERS_CONF_FILE, Verify, Write).
-
+ Order = fun snmp_conf:no_order/2,
+ Check = fun check_usm_user_config/2,
+ Write = fun write_usm_conf/2,
+ append_config_file(Dir, ?USM_USERS_CONF_FILE, Order, Check, Write, Conf).
read_usm_config(Dir)
when is_list(Dir) ->
- Verify = fun(Entry) -> verify_usm_conf_entry(Entry) end,
- read_config_file(Dir, ?USM_USERS_CONF_FILE, Verify).
+ Order = fun snmp_conf:no_order/2,
+ Check = fun check_usm_user_config/2,
+ read_config_file(Dir, ?USM_USERS_CONF_FILE, Order, Check).
-verify_usm_conf([]) ->
- ok;
-verify_usm_conf([H|T]) ->
- verify_usm_conf_entry(H),
- verify_usm_conf(T);
-verify_usm_conf(X) ->
- error({bad_usm_conf, X}).
-
-verify_usm_conf_entry(Entry) ->
- {ok, _} = snmpm_config:check_usm_user_config(Entry),
- ok.
+check_usm_user_config(Entry, State) ->
+ {check_ok(snmpm_config:check_usm_user_config(Entry)),
+ State}.
write_usm_conf(Fd, "", Conf) ->
write_usm_conf(Fd, Conf);
@@ -358,41 +326,49 @@ write_usm_conf(Fd, [H|T]) ->
do_write_usm_conf(Fd, H),
write_usm_conf(Fd, T).
-do_write_usm_conf(Fd,
- {EngineID, UserName, AuthP, AuthKey, PrivP, PrivKey}) ->
- io:format(Fd, "{\"~s\", \"~s\", ~w, ~w, ~w, ~w}.~n",
- [EngineID, UserName, AuthP, AuthKey, PrivP, PrivKey]);
-do_write_usm_conf(Fd,
- {EngineID, UserName, SecName,
- AuthP, AuthKey, PrivP, PrivKey}) ->
- io:format(Fd, "{\"~s\", \"~s\", \"~s\", �~w, ~w, ~w, ~w}.~n",
- [EngineID, UserName, SecName, AuthP, AuthKey, PrivP, PrivKey]);
+do_write_usm_conf(
+ Fd,
+ {EngineID, UserName, AuthP, AuthKey, PrivP, PrivKey}) ->
+ io:format(
+ Fd, "{\"~s\", \"~s\", ~w, ~w, ~w, ~w}.~n",
+ [EngineID, UserName, AuthP, AuthKey, PrivP, PrivKey]);
+do_write_usm_conf(
+ Fd,
+ {EngineID, UserName, SecName,
+ AuthP, AuthKey, PrivP, PrivKey}) ->
+ io:format(
+ Fd, "{\"~s\", \"~s\", \"~s\", í~w, ~w, ~w, ~w}.~n",
+ [EngineID, UserName, SecName, AuthP, AuthKey, PrivP, PrivKey]);
do_write_usm_conf(_Fd, Crap) ->
error({bad_usm_conf, Crap}).
%% ---- config file wrapper functions ----
-write_config_file(Dir, File, Verify, Write) ->
- snmp_config:write_config_file(Dir, File, Verify, Write).
+write_config_file(Dir, File, Order, Check, Write, Conf) ->
+ snmp_config:write_config_file(Dir, File, Order, Check, Write, Conf).
-append_config_file(Dir, File, Verify, Write) ->
- snmp_config:append_config_file(Dir, File, Verify, Write).
-
-read_config_file(Dir, File, Verify) ->
- snmp_config:read_config_file(Dir, File, Verify).
+append_config_file(Dir, File, Order, Check, Write, Conf) ->
+ snmp_config:append_config_file(Dir, File, Order, Check, Write, Conf).
+read_config_file(Dir, File, Order, Check) ->
+ snmp_config:read_config_file(Dir, File, Order, Check).
%% ---- config file utility functions ----
+check_ok(ok) ->
+ ok;
+check_ok({ok, _}) ->
+ ok.
+
header() ->
{Y,Mo,D} = date(),
{H,Mi,S} = time(),
- io_lib:format("%% This file was generated by "
- "~w (version-~s) ~w-~2.2.0w-~2.2.0w "
- "~2.2.0w:~2.2.0w:~2.2.0w\n",
- [?MODULE, ?version, Y, Mo, D, H, Mi, S]).
-
+ io_lib:format(
+ "%% This file was generated by "
+ "~w (version-~s) ~w-~2.2.0w-~2.2.0w "
+ "~2.2.0w:~2.2.0w:~2.2.0w\n",
+ [?MODULE, ?version, Y, Mo, D, H, Mi, S]).
error(R) ->
throw({error, R}).
diff --git a/lib/snmp/src/manager/snmpm_config.erl b/lib/snmp/src/manager/snmpm_config.erl
index c2e57abddb..118cdcd1df 100644
--- a/lib/snmp/src/manager/snmpm_config.erl
+++ b/lib/snmp/src/manager/snmpm_config.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
+%% 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
%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -103,8 +104,10 @@
get_agent_mp_model/2
]).
--export([check_manager_config/1,
- check_user_config/1,
+-export([
+ order_manager_config/2,
+ check_manager_config/2,
+ check_user_config/1,
check_agent_config/1,
check_usm_user_config/1]).
@@ -165,7 +168,7 @@
%%%-------------------------------------------------------------------
default_transport_domain() ->
- transportDomainUdpIpv4.
+ snmpUDPDomain.
start_link(Opts) ->
@@ -190,7 +193,11 @@ register_user(UserId, UserMod, UserData, DefaultAgentConfig)
when (UserId =/= ?DEFAULT_USER) andalso is_list(DefaultAgentConfig) ->
case (catch verify_user_behaviour(UserMod)) of
ok ->
- Config = default_agent_config(DefaultAgentConfig),
+ {ok, SystemDefaultAgentConfig} = agent_info(),
+ Config =
+ ensure_config(SystemDefaultAgentConfig,
+ DefaultAgentConfig),
+%% Config = default_agent_config(DefaultAgentConfig),
call({register_user, UserId, UserMod, UserData, Config});
Error ->
Error
@@ -201,19 +208,19 @@ register_user(UserId, _UserMod, _UserData, DefaultAgentConfig)
register_user(UserId, _, _, _) ->
{error, {bad_user_id, UserId}}.
-default_agent_config(DefaultAgentConfig) ->
- {ok, SystemDefaultAgentConfig} = agent_info(),
- default_agent_config(SystemDefaultAgentConfig, DefaultAgentConfig).
+%% default_agent_config(DefaultAgentConfig) ->
+%% {ok, SystemDefaultAgentConfig} = agent_info(),
+%% default_agent_config(SystemDefaultAgentConfig, DefaultAgentConfig).
-default_agent_config([], DefaultAgentConfig) ->
- DefaultAgentConfig;
-default_agent_config([{Key, _} = Entry|T], DefaultAgentConfig) ->
- case lists:keysearch(Key, 1, DefaultAgentConfig) of
- {value, _} ->
- default_agent_config(T, DefaultAgentConfig);
- false ->
- default_agent_config(T, [Entry|DefaultAgentConfig])
- end.
+%% default_agent_config([], DefaultAgentConfig) ->
+%% DefaultAgentConfig;
+%% default_agent_config([{Key, _} = Entry|T], DefaultAgentConfig) ->
+%% case lists:keymember(Key, 1, DefaultAgentConfig) of
+%% true ->
+%% default_agent_config(T, DefaultAgentConfig);
+%% false ->
+%% default_agent_config(T, [Entry|DefaultAgentConfig])
+%% end.
verify_user_behaviour(UserMod) ->
@@ -280,9 +287,10 @@ do_user_info(_UserId, BadItem) ->
%% A target-name constructed in this way is a string with the following:
%% <IP-address>:<Port>-<Version>
-%% This is intended for backward compatibility and therefor has
+%% This is intended for backward compatibility and therefore has
%% only support for IPv4 addresses and *no* other transport domain.
-mk_target_name(Addr0, Port, Config) when is_list(Config) ->
+mk_target_name(Domain, Addr, Config)
+ when is_atom(Domain), is_list(Config) ->
Version =
case lists:keysearch(version, 1, Config) of
{value, {_, V}} ->
@@ -290,18 +298,35 @@ mk_target_name(Addr0, Port, Config) when is_list(Config) ->
false ->
select_lowest_supported_version()
end,
- case normalize_address(Addr0) of
- {A, B, C, D} ->
- lists:flatten(
- io_lib:format("~w.~w.~w.~w:~w-~w", [A, B, C, D, Port, Version]));
- [A, B, C, D] ->
+ try
+ lists:flatten(
+ io_lib:format(
+ "~s-~w", [snmp_conf:mk_addr_string({Domain, Addr}), Version]))
+ catch
+ _ ->
lists:flatten(
- io_lib:format("~w.~w.~w.~w:~w-~w", [A, B, C, D, Port, Version]));
- _ ->
+ io_lib:format("~p-~w", [Addr, Version]))
+ end;
+mk_target_name(Ip, Port, Config)
+ when is_integer(Port), is_list(Config) ->
+ Domain = default_transport_domain(),
+ try fix_address(Domain, {Ip, Port}) of
+ Address ->
+ mk_target_name(Domain, Address, Config)
+ catch
+ _ ->
+ Version =
+ case lists:keysearch(version, 1, Config) of
+ {value, {_, V}} ->
+ V;
+ false ->
+ select_lowest_supported_version()
+ end,
lists:flatten(
- io_lib:format("~p:~w-~w", [Addr0, Port, Version]))
+ io_lib:format("~p:~w-~w", [Ip, Port, Version]))
end.
-
+
+
select_lowest_supported_version() ->
{ok, Versions} = system_info(versions),
select_lowest_supported_version([v1, v2, v3], Versions).
@@ -335,27 +360,17 @@ register_agent(UserId, TargetName, Config0)
%% is not present
%% 3) Check that there are no invalid or erroneous configs
%% 4) Check that the manager is capable of using the selected version
- case verify_agent_config(Config0) of
- {ok, Config} ->
- call({register_agent, UserId, TargetName, Config});
- Error ->
- Error
- end.
-
-
-verify_agent_config(Conf0) ->
try
- begin
- verify_mandatory(Conf0, [engine_id, address, reg_type]),
- verify_invalid(Conf0, [user_id]),
- Conf = verify_agent_config3(Conf0),
- Vsns = versions(),
- Vsn = which_version(Conf),
- verify_version(Vsn, Vsns),
- {ok, Conf}
- end
+ verify_mandatory(Config0, [engine_id, reg_type]),
+ verify_someof(Config0, [address, taddress]),
+ verify_illegal(Config0, [user_id]),
+ Config = verify_agent_config(Config0),
+ Vsns = versions(),
+ Vsn = which_version(Config),
+ verify_version(Vsn, Vsns),
+ call({register_agent, UserId, TargetName, Config})
catch
- throw:Error ->
+ Error ->
Error
end.
@@ -381,52 +396,43 @@ verify_version(Vsn, Vsns) ->
ok;
false ->
Reason = {version_not_supported_by_manager, Vsn, Vsns},
- throw({error, Reason})
- end.
-
-verify_agent_config3(Conf0) ->
- %% Fix (transport) address and domain
- {TDomain, Conf1} =
- case lists:keysearch(tdomain, 1, Conf0) of
- {value, {tdomain, Dom}} ->
- {Dom, Conf0};
- false ->
- Dom = default_transport_domain(),
- {Dom, [{tdomain, Dom} | Conf0]}
- end,
- Conf2 = case lists:keysearch(address, 1, Conf1) of
- {value, {address, Address}} ->
- lists:keyreplace(address, 1, Conf1,
- {address, {TDomain, Address}});
- false ->
- %% This is a mandatory config option,
- %% a later test will detect this
- Conf1
- end,
- case verify_agent2(Conf2) of
- {ok, Conf} ->
- Conf;
- {error, _} = ERROR ->
- throw(ERROR)
+ error(Reason)
end.
-verify_agent_config2(Conf) ->
- verify_agent2(Conf).
unregister_agent(UserId, TargetName) ->
call({unregister_agent, UserId, TargetName}).
%% This is the old style agent unregistration (using Addr and Port).
-unregister_agent(UserId, Addr0, Port) ->
- Addr = normalize_address(Addr0),
- case do_agent_info(Addr, Port, target_name) of
+unregister_agent(UserId, Domain, Address) when is_atom(Domain) ->
+ try fix_address(Domain, Address) of
+ NAddress ->
+ do_unregister_agent(UserId, Domain, NAddress)
+ catch
+ _ ->
+ {error, not_found}
+ end;
+unregister_agent(UserId, Ip, Port) when is_integer(Port) ->
+ Domain = default_transport_domain(),
+ try fix_address(Domain, {Ip, Port}) of
+ Address ->
+ do_unregister_agent(UserId, Domain, Address)
+ catch
+ _ ->
+ {error, not_found}
+ end.
+
+do_unregister_agent(UserId, Domain, Address) ->
+ case do_agent_info(Domain, Address, target_name) of
{ok, TargetName} ->
unregister_agent(UserId, TargetName);
Error ->
Error
end.
+
+
agent_info() ->
agent_info(?DEFAULT_TARGETNAME, all).
@@ -437,27 +443,76 @@ agent_info(TargetName, all) ->
All ->
{ok, [{Item, Val} || {{_, Item}, Val} <- All]}
end;
+%% Begin backwards compatibility
+agent_info(TargetName, address) ->
+ case agent_info({TargetName, taddress}) of
+ {ok, Val} ->
+ {Addr, _} = Val,
+ {ok, Addr};
+ _ ->
+ %% This should be redundant since 'taddress' should exist
+ agent_info({TargetName, address})
+ end;
+agent_info(TargetName, port) ->
+ case agent_info({TargetName, taddress}) of
+ {ok, Val} ->
+ {_, Port} = Val,
+ {ok, Port};
+ _ ->
+ %% This should be redundant since 'taddress' should exist
+ agent_info({TargetName, port})
+ end;
+%% End backwards compatibility
agent_info(TargetName, Item) ->
- case ets:lookup(snmpm_agent_table, {TargetName, Item}) of
+ agent_info({TargetName, Item}).
+
+agent_info(Key) ->
+ case ets:lookup(snmpm_agent_table, Key) of
[{_, Val}] ->
{ok, Val};
[] ->
{error, not_found}
end.
-
-agent_info(Addr0, Port, Item) ->
- Addr = normalize_address(Addr0),
- do_agent_info(Addr, Port, Item).
-do_agent_info(Addr, Port, target_name = Item) ->
- case ets:lookup(snmpm_agent_table, {Addr, Port, Item}) of
+agent_info(Domain, Address, Item) when is_atom(Domain) ->
+ try fix_address(Domain, Address) of
+ 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()]),
+ {error, not_found}
+ end;
+agent_info(Ip, Port, Item) when is_integer(Port) ->
+ %% p(?MODULE_STRING":agent_info(~p, ~p, ~p) entry~n",
+ %% [Ip, Port, Item]),
+ Domain = default_transport_domain(),
+ try fix_address(Domain, {Ip, Port}) of
+ 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()]),
+ {error, not_found}
+ end.
+
+do_agent_info(Domain, Address, target_name = Item) ->
+ %% p(?MODULE_STRING":do_agent_info(~p, ~p, ~p) entry~n",
+ %% [Domain, Address, Item]),
+ case ets:lookup(snmpm_agent_table, {Domain, Address, Item}) of
[{_, Val}] ->
{ok, Val};
[] ->
{error, not_found}
end;
-do_agent_info(Addr, Port, Item) ->
- case do_agent_info(Addr, Port, target_name) of
+do_agent_info(Domain, Address, Item) ->
+ %% p(?MODULE_STRING":do_agent_info(~p, ~p, ~p) entry~n",
+ %% [Domain, Address, Item]),
+ case do_agent_info(Domain, Address, target_name) of
{ok, TargetName} ->
agent_info(TargetName, Item);
Error ->
@@ -465,6 +520,19 @@ do_agent_info(Addr, Port, Item) ->
end.
+ensure_agent_info(_, [], Info) ->
+ Info;
+ensure_agent_info(TargetName, [Item|Items], Info) ->
+ case lists:keymember(Item, 1, Info) of
+ true ->
+ ensure_agent_info(TargetName, Items, Info);
+ false ->
+ {ok, Value} = agent_info(TargetName, Item),
+ ensure_agent_info(TargetName, Items, [{Item, Value}|Info])
+ end.
+
+
+
which_agents() ->
which_agents('_').
@@ -474,38 +542,6 @@ which_agents(UserId) ->
[TargetName || [TargetName] <- Agents].
-verify_agent_info(TargetName, Info0) ->
- try
- begin
- verify_invalid(Info0, [user_id]),
- %% Check if address is part of the list and
- %% if so update it with the domain info.
- Info =
- case lists:keysearch(address, 1, Info0) of
- {value, {address, Addr}} ->
- %% If domain is part of the info, then use it.
- %% If not, lookup what is already stored for
- %% this agent and use that.
- Domain =
- case lists:keysearch(tdomain, 1, Info0) of
- {value, {tdomain, Dom}} ->
- Dom;
- false ->
- {ok, Dom} =
- agent_info(TargetName, tdomain),
- Dom
- end,
- Addr2 = {Domain, Addr},
- lists:keyreplace(address, 1, Info0, {address, Addr2});
- false ->
- Info0
- end,
- verify_agent2(Info)
- end
- catch
- throw:Error ->
- Error
- end.
update_agent_info(UserId, TargetName, Info) ->
call({update_agent_info, UserId, TargetName, Info}).
@@ -740,7 +776,7 @@ verify_usm_user_config(EngineID, Name, Config) ->
try
begin
verify_mandatory(Config, []),
- verify_invalid(Config, [engine_id, name]),
+ verify_illegal(Config, [engine_id, name]),
verify_usm_user_config2(EngineID, Name, Config)
end
catch
@@ -1073,7 +1109,11 @@ do_init(Opts) ->
%% -- Prio (optional) --
Prio = get_opt(priority, Opts, normal),
ets:insert(snmpm_config_table, {prio, Prio}),
- process_flag(priority, Prio),
+ try process_flag(priority, Prio)
+ catch
+ error:badarg ->
+ error({invalid_priority,Prio})
+ end,
%% -- Server (optional) --
ServerOpts = get_opt(server, Opts, []),
@@ -1215,6 +1255,12 @@ dets_open(Dir, DbInitError, Repair, AutoSave) ->
end
end;
_ ->
+ case DbInitError of
+ create_db_and_dir ->
+ ok = filelib:ensure_dir(Filename);
+ _ ->
+ ok
+ end,
case do_dets_open(Name, Filename, Repair, AutoSave) of
{ok, _Dets} ->
ok;
@@ -1265,36 +1311,6 @@ verify_options(Opts, Mandatory) ->
verify_mandatory_options(Opts, Mandatory),
verify_options(Opts).
-%% mandatory() -> [mand()]
-%% mand() -> atom() | {atom, [atom()]}
-verify_mandatory_options(_Opts, []) ->
- ok;
-verify_mandatory_options(Opts, [Mand|Mands]) ->
- verify_mandatory_option(Opts, Mand),
- verify_mandatory_options(Opts, Mands).
-
-verify_mandatory_option(Opts, {Mand, MandSubOpts}) ->
- ?d("verify_mandatory_option -> entry with"
- "~n Mand: ~p"
- "~n MandSubObjs: ~p", [Mand, MandSubOpts]),
- case lists:keysearch(Mand, 1, Opts) of
- {value, {Mand, SubOpts}} ->
- verify_mandatory_options(SubOpts, MandSubOpts);
- false ->
- ?d("missing mandatory option: ~w [~p]", [Mand, MandSubOpts]),
- error({missing_mandatory, Mand, MandSubOpts})
- end;
-verify_mandatory_option(Opts, Mand) ->
- ?d("verify_mandatory_option -> entry with"
- "~n Mand: ~p", [Mand]),
- case lists:keymember(Mand, 1, Opts) of
- true ->
- ok;
- false ->
- ?d("missing mandatory option: ~w", [Mand]),
- error({missing_mandatory, Mand})
- end.
-
verify_options([]) ->
?d("verify_options -> done", []),
ok;
@@ -1316,7 +1332,14 @@ verify_option({server, ServerOpts}) ->
verify_server_opts(ServerOpts);
verify_option({note_store, NoteStoreOpts}) ->
verify_note_store_opts(NoteStoreOpts);
-verify_option({config, ConfOpts}) ->
+verify_option({config, ConfOpts0}) ->
+ %% Make sure any db_dir option is first in the options list to make it
+ %% easier to check if the db_init_error option specifies that a missing
+ %% db_dir should be created.
+ ConfOpts = case lists:keytake(db_dir, 1, ConfOpts0) of
+ false -> ConfOpts0;
+ {value, Result, OtherOpts} -> [Result|OtherOpts]
+ end,
verify_config_opts(ConfOpts);
verify_option({versions, Vsns}) ->
verify_versions(Vsns);
@@ -1365,7 +1388,12 @@ verify_config_opts([{dir, Dir}|Opts]) ->
verify_conf_dir(Dir),
verify_config_opts(Opts);
verify_config_opts([{db_dir, Dir}|Opts]) ->
- verify_conf_db_dir(Dir),
+ case lists:keyfind(db_init_error, 1, Opts) of
+ {db_init_error, create_db_and_dir} ->
+ verify_conf_db_dir(Dir, false);
+ _ ->
+ verify_conf_db_dir(Dir, true)
+ end,
verify_config_opts(Opts);
verify_config_opts([{db_init_error, DbInitErr}|Opts]) ->
verify_conf_db_init_error(DbInitErr),
@@ -1443,7 +1471,7 @@ verify_conf_dir(Dir) ->
error({invalid_conf_dir, Dir})
end.
-verify_conf_db_dir(Dir) ->
+verify_conf_db_dir(Dir, true) ->
case (catch verify_dir(Dir)) of
ok ->
ok;
@@ -1451,13 +1479,16 @@ verify_conf_db_dir(Dir) ->
error({invalid_conf_db_dir, Dir, Reason});
_ ->
error({invalid_conf_db_dir, Dir})
- end.
-
+ end;
+verify_conf_db_dir(_Dir, false) ->
+ ok.
verify_conf_db_init_error(terminate) ->
ok;
verify_conf_db_init_error(create) ->
ok;
+verify_conf_db_init_error(create_db_and_dir) ->
+ ok;
verify_conf_db_init_error(InvalidDbInitError) ->
error({invalid_conf_db_init_error, InvalidDbInitError}).
@@ -1485,7 +1516,9 @@ verify_versions([]) ->
ok;
verify_versions([Vsn|Vsns]) ->
verify_version(Vsn),
- verify_versions(Vsns).
+ verify_versions(Vsns);
+verify_versions(Vsns) ->
+ error({invalid_versions, Vsns}).
verify_version(v1) ->
ok;
@@ -1593,7 +1626,38 @@ verify_verbosity(Verbosity) ->
_ ->
error({invalid_verbosity, Verbosity})
end.
+
+%% mandatory() -> [mand()]
+%% mand() -> atom() | {atom, [atom()]}
+verify_mandatory_options(_Opts, []) ->
+ ok;
+verify_mandatory_options(Opts, [Mand|Mands]) ->
+ verify_mandatory_option(Opts, Mand),
+ verify_mandatory_options(Opts, Mands).
+
+verify_mandatory_option(Opts, {Mand, MandSubOpts}) ->
+ ?d("verify_mandatory_option -> entry with"
+ "~n Mand: ~p"
+ "~n MandSubObjs: ~p", [Mand, MandSubOpts]),
+ case lists:keysearch(Mand, 1, Opts) of
+ {value, {Mand, SubOpts}} ->
+ verify_mandatory_options(SubOpts, MandSubOpts);
+ false ->
+ ?d("missing mandatory option: ~w [~p]", [Mand, MandSubOpts]),
+ error({missing_mandatory, Mand, MandSubOpts})
+ end;
+verify_mandatory_option(Opts, Mand) ->
+ ?d("verify_mandatory_option -> entry with"
+ "~n Mand: ~p", [Mand]),
+ case lists:keymember(Mand, 1, Opts) of
+ true ->
+ ok;
+ false ->
+ ?d("missing mandatory option: ~w", [Mand]),
+ error({missing_mandatory, Mand})
+ end.
+
%% ------------------------------------------------------------------------
init_manager_config([]) ->
@@ -1608,181 +1672,91 @@ init_agent_default() ->
%% The purpose of the default_agent is only to have a place
%% to store system wide default values related to agents.
%%
-
- %% Port
- init_agent_default(port, ?DEFAULT_AGENT_PORT),
-
- %% Timeout
- init_agent_default(timeout, 10000),
-
- %% Max message (packet) size
- init_agent_default(max_message_size, 484),
-
- %% MPModel
- init_agent_default(version, v2),
-
- %% SecModel
- init_agent_default(sec_model, v2c),
-
- %% SecName
- init_agent_default(sec_name, "initial"),
-
- %% SecLevel
- init_agent_default(sec_level, noAuthNoPriv),
-
- %% Community
- init_agent_default(community, "all-rights"),
- ok.
-
-
-init_agent_default(Item, Val) when Item =/= user_id ->
- case do_update_agent_info(default_agent, Item, Val) of
- ok ->
- ok;
- {error, Reason} ->
- error(Reason)
- end.
-
+ AgentDefaultConfig =
+ [{port, ?DEFAULT_AGENT_PORT}, % Port
+ {timeout, 10000}, % Timeout
+ {max_message_size, 484}, % Max message (packet) size
+ {version, v2}, % MPModel
+ {sec_model, v2c}, % SecModel
+ {sec_name, "initial"}, % SecName
+ {sec_level, noAuthNoPriv}, % SecLevel
+ {community, "all-rights"}], % Community
+ do_update_agent_info(default_agent, AgentDefaultConfig).
read_agents_config_file(Dir) ->
- Check = fun(C) -> check_agent_config2(C) end,
- case read_file(Dir, "agents.conf", Check, []) of
- {ok, Conf} ->
- Conf;
- Error ->
+ Order = fun snmp_conf:no_order/2,
+ Check = fun check_agent_config/2,
+ try read_file(Dir, "agents.conf", Order, Check, [])
+ catch
+ throw:Error ->
?vlog("agent config error: ~p", [Error]),
- throw(Error)
+ erlang:raise(throw, Error, erlang:get_stacktrace())
end.
-check_agent_config2(Agent) ->
- case (catch check_agent_config(Agent)) of
- {ok, {UserId, TargetName, Conf, Version}} ->
- {ok, Vsns} = system_info(versions),
- case lists:member(Version, Vsns) of
- true ->
- {ok, {UserId, TargetName, Conf}};
- false ->
- error({version_not_supported_by_manager,
- Version, Vsns})
- end;
- Err ->
- throw(Err)
+check_agent_config(Agent, State) ->
+ {ok, {UserId, TargetName, Conf, Version}} = check_agent_config(Agent),
+ {ok, Vsns} = system_info(versions),
+ case lists:member(Version, Vsns) of
+ true ->
+ {{ok, {UserId, TargetName, Conf}}, State};
+ false ->
+ error({version_not_supported_by_manager, Version, Vsns})
end.
%% For backward compatibility
-check_agent_config({UserId,
- TargetName,
- Community,
- Ip, Port,
- EngineId,
- Timeout, MaxMessageSize,
- Version, SecModel, SecName, SecLevel}) ->
- TDomain = default_transport_domain(),
- check_agent_config({UserId,
- TargetName,
- Community,
- TDomain, Ip, Port,
- EngineId,
- Timeout, MaxMessageSize,
- Version, SecModel, SecName, SecLevel});
-
-check_agent_config({UserId,
- TargetName,
- Community,
- TDomain, Ip, Port,
- EngineId,
- Timeout, MaxMessageSize,
- Version, SecModel, SecName, SecLevel}) ->
- ?vtrace("check_agent_config -> entry with"
- "~n UserId: ~p"
- "~n TargetName: ~p"
- "~n Community: ~p"
- "~n TDomain: ~p"
- "~n Ip: ~p"
- "~n Port: ~p"
- "~n EngineId: ~p"
- "~n Timeout: ~p"
- "~n MaxMessageSize: ~p"
- "~n Version: ~p"
- "~n SecModel: ~p"
- "~n SecName: ~p"
- "~n SecLevel: ~p",
- [UserId, TargetName, Community,
- TDomain, Ip, Port,
- EngineId, Timeout, MaxMessageSize,
- Version, SecModel, SecName, SecLevel]),
- Addr = normalize_address(TDomain, Ip),
- ?vtrace("check_agent_config -> Addr: ~p", [Addr]),
- Agent = {UserId,
- TargetName,
- Community,
- TDomain, Addr, Port,
- EngineId,
- Timeout, MaxMessageSize,
- Version, SecModel, SecName, SecLevel},
- {ok, verify_agent(Agent)};
+check_agent_config(
+ {UserId, TargetName, Community, Domain, Addr,
+ EngineId, Timeout, MaxMessageSize,
+ Version, SecModel, SecName, SecLevel}) when is_atom(Domain) ->
+ check_agent_config(
+ UserId, TargetName, Community, Domain, Addr,
+ EngineId, Timeout, MaxMessageSize,
+ Version, SecModel, SecName, SecLevel);
+check_agent_config(
+ {UserId, TargetName, Community, Ip, Port,
+ EngineId, Timeout, MaxMessageSize,
+ Version, SecModel, SecName, SecLevel}) when is_integer(Port) ->
+ Domain = default_transport_domain(),
+ Addr = {Ip, Port},
+ check_agent_config(
+ UserId, TargetName, Community, Domain, Addr,
+ EngineId, Timeout, MaxMessageSize,
+ Version, SecModel, SecName, SecLevel);
+check_agent_config(
+ {_UserId, _TargetName, _Community, Domain, Addr,
+ _EngineId, _Timeout, _MaxMessageSize,
+ _Version, _SecModel, _SecName, _SecLevel}) ->
+ error({bad_address, {Domain, Addr}});
+check_agent_config(
+ {UserId, TargetName, Community, Domain, Ip, Port,
+ EngineId, Timeout, MaxMessageSize,
+ Version, SecModel, SecName, SecLevel}) ->
+ Addr = {Ip, Port},
+ check_agent_config(
+ UserId, TargetName, Community, Domain, Addr,
+ EngineId, Timeout, MaxMessageSize,
+ Version, SecModel, SecName, SecLevel);
check_agent_config(Agent) ->
error({bad_agent_config, Agent}).
-
-init_agents_config([]) ->
- ok;
-init_agents_config([Agent|Agents]) ->
- init_agent_config(Agent),
- init_agents_config(Agents).
-
-init_agent_config({_UserId, ?DEFAULT_TARGETNAME = TargetName, _Config}) ->
- throw({error, {invalid_target_name, TargetName}});
-init_agent_config({UserId, TargetName, Config}) ->
- case handle_register_agent(UserId, TargetName, Config) of
- ok ->
- ok;
- Error ->
- throw(Error)
- end.
-
-
-%% For backward compatibility
-verify_agent({UserId,
- TargetName,
- Comm,
- Ip, Port,
- EngineId,
- Timeout, MMS,
- Version, SecModel, SecName, SecLevel}) ->
- TDomain = default_transport_domain(),
- verify_agent({UserId,
- TargetName,
- Comm,
- TDomain, Ip, Port,
- EngineId,
- Timeout, MMS,
- Version, SecModel, SecName, SecLevel});
-
-verify_agent({UserId,
- TargetName,
- Comm,
- TDomain, Ip, Port,
- EngineId,
- Timeout, MMS,
- Version, SecModel, SecName, SecLevel}) ->
- ?vdebug("verify_agent -> entry with"
+check_agent_config(
+ UserId, TargetName, Comm, Domain, Addr,
+ EngineId, Timeout, MMS,
+ Version, SecModel, SecName, SecLevel) ->
+ ?vdebug("check_agent_config -> entry with"
"~n UserId: ~p"
"~n TargetName: ~p", [UserId, TargetName]),
snmp_conf:check_string(TargetName, {gt, 0}),
- snmp_conf:check_integer(Port, {gt, 0}),
%% Note that the order of Conf *is* important.
%% Some properties may depend on others, so that
%% in order to verify one property, another must
%% be already verified (and present). An example
- %% of this is the property 'address', for which
+ %% of this is the property 'taddress', for which
%% the property tdomain is needed.
- Conf0 =
+ Conf =
[{reg_type, target_name},
- {tdomain, TDomain},
- %% This should be taddress, but what the*...
- {address, {TDomain, Ip}},
- {port, Port},
+ {tdomain, Domain},
+ {taddress, fix_address(Domain, Addr)},
{community, Comm},
{engine_id, EngineId},
{timeout, Timeout},
@@ -1792,40 +1766,180 @@ verify_agent({UserId,
{sec_name, SecName},
{sec_level, SecLevel}
],
- case verify_agent2(Conf0) of
- {ok, Conf} ->
- {UserId, TargetName, Conf, Version};
- Err ->
- throw(Err)
+ {ok, {UserId, TargetName, verify_agent_config(Conf), Version}}.
+
+
+
+init_agents_config([]) ->
+ ok;
+init_agents_config([Agent|Agents]) ->
+ init_agent_config(Agent),
+ init_agents_config(Agents).
+
+init_agent_config({_UserId, ?DEFAULT_TARGETNAME = TargetName, _Config}) ->
+ error({invalid_target_name, TargetName});
+init_agent_config({UserId, TargetName, Config}) ->
+ case handle_register_agent(UserId, TargetName, Config) of
+ ok ->
+ ok;
+ Error ->
+ throw(Error)
end.
-verify_agent2(Conf) ->
- verify_agent2(Conf, []).
-verify_agent2([], VerifiedConf) ->
- {ok, VerifiedConf};
-verify_agent2([{Item, Val0}|Items], VerifiedConf) ->
- case verify_val(Item, Val0) of
- {ok, Val} ->
- verify_agent2(Items, [{Item, Val} | VerifiedConf]);
- Err ->
- Err
+
+%% Sort 'tdomain' first then 'port' to ensure both
+%% sorts before 'taddress'. Keep the order of other items.
+order_agent(ItemA, ItemB) ->
+ snmp_conf:keyorder(1, ItemA, ItemB, [tdomain, port]).
+
+fix_agent_config(Conf) ->
+ ?vdebug("fix_agent_config -> entry with~n~n"
+ " Conf: ~p", [Conf]),
+ fix_agent_config(lists:sort(fun order_agent/2, Conf), []).
+
+fix_agent_config([], FixedConf) ->
+ Ret = lists:reverse(FixedConf),
+ ?vdebug("fix_agent_config -> returns:~n"
+ " ~p", [Ret]),
+ Ret;
+fix_agent_config([{taddress = Item, Address} = Entry|Conf], FixedConf) ->
+ {value, {tdomain, TDomain}} = lists:keysearch(tdomain, 1, FixedConf),
+ {value, {port, DefaultPort}} = lists:keysearch(port, 1, FixedConf),
+ case snmp_conf:check_address(TDomain, Address, DefaultPort) of
+ ok ->
+ fix_agent_config(Conf, [Entry|FixedConf]);
+ {ok, NAddress} ->
+ fix_agent_config(Conf, [{Item, NAddress}|FixedConf])
+ end;
+fix_agent_config([Entry|Conf], FixedConf) ->
+ fix_agent_config(Conf, [Entry|FixedConf]).
+
+
+
+verify_agent_config(Conf) ->
+ verify_agent_config(lists:sort(fun order_agent/2, Conf), []).
+
+verify_agent_config([], VerifiedConf) ->
+ Ret = lists:reverse(VerifiedConf),
+ ?vdebug("verify_agent_config -> returns:~n"
+ " ~p", [Ret]),
+ Ret;
+verify_agent_config([{Item, _} = Entry|Conf], VerifiedConf) ->
+ verify_illegal(VerifiedConf, [Item]), % Duplicates are hereby illegal
+ verify_agent_config(Conf, VerifiedConf, Entry);
+verify_agent_config([Bad|_], _VerifiedConf) ->
+ error({bad_agent_config, Bad}).
+
+verify_agent_config(
+ Conf, VerifiedConf, {taddress = Item, Address} = Entry) ->
+ verify_illegal(VerifiedConf, [address]),
+ {TDomain, VC} =
+ case lists:keysearch(tdomain, 1, VerifiedConf) of
+ {value, {tdomain,TD}} ->
+ {TD, VerifiedConf};
+ _ ->
+ %% Insert tdomain since it is missing
+ %% Note: not default_transport_domain() since
+ %% taddress is the new format hence the application
+ %% should be tdomain aware and therefore addresses
+ %% on the Domain, Addr format should be used and understood.
+ TD = transportDomainUdpIpv4,
+ {TD, [{tdomain, TD}|VerifiedConf]}
+ end,
+ case snmp_conf:check_address(TDomain, Address, 0) of
+ ok ->
+ verify_agent_config(Conf, [Entry|VC]);
+ {ok, NAddress} ->
+ verify_agent_config(Conf, [{Item, NAddress}|VC])
end;
-verify_agent2([Bad|_], _VerifiedConf) ->
- {error, {bad_agent_config, Bad}}.
+verify_agent_config(Conf, VerifiedConf, {address, Address}) ->
+ Item = taddress,
+ verify_illegal(VerifiedConf, [Item]),
+ {TDomain, VC} =
+ case lists:keysearch(tdomain, 1, VerifiedConf) of
+ {value, {tdomain, TD}} ->
+ {TD, VerifiedConf};
+ _ ->
+ %% Insert tdomain since it is missing
+ TD = default_transport_domain(),
+ {TD, [{tdomain, TD}|VerifiedConf]}
+ end,
+ case snmp_conf:check_address(TDomain, Address, 0) of
+ ok ->
+ verify_agent_config(Conf, [{Item, Address}|VC]);
+ {ok, NAddress} ->
+ verify_agent_config(Conf, [{Item, NAddress}|VC])
+ end;
+verify_agent_config(Conf, VerifiedConf, {Item, Val} = Entry) ->
+ case verify_agent_entry(Item, Val) of
+ ok ->
+ verify_agent_config(Conf, [Entry|VerifiedConf]);
+ {ok, NewVal} ->
+ verify_agent_config(Conf, [{Item, NewVal}|VerifiedConf])
+ end.
+
+verify_agent_entry(user_id, _UserId) ->
+ ok;
+verify_agent_entry(reg_type, RegType) ->
+ if
+ RegType =:= addr_port;
+ RegType =:= target_name ->
+ ok;
+ true ->
+ error({bad_reg_type, RegType})
+ end;
+verify_agent_entry(tdomain, TDomain) ->
+ snmp_conf:check_domain(TDomain);
+verify_agent_entry(port, Port) ->
+ snmp_conf:check_port(Port);
+verify_agent_entry(community, Comm) ->
+ snmp_conf:check_string(Comm);
+verify_agent_entry(engine_id, EngineId) ->
+ case EngineId of
+ discovery ->
+ ok;
+ _ ->
+ snmp_conf:check_string(EngineId)
+ end;
+verify_agent_entry(timeout, Timeout) ->
+ snmp_conf:check_timer(Timeout);
+verify_agent_entry(max_message_size, MMS) ->
+ snmp_conf:check_packet_size(MMS);
+verify_agent_entry(version, V) ->
+ if
+ V =:= v1;
+ V =:= v2;
+ V =:= v3 ->
+ ok;
+ true ->
+ error({bad_version, V})
+ end;
+verify_agent_entry(sec_model, Model) ->
+ snmp_conf:check_sec_model(Model);
+verify_agent_entry(sec_name, Name) ->
+ try snmp_conf:check_string(Name)
+ catch
+ _ ->
+ error({bad_sec_name, Name})
+ end;
+verify_agent_entry(sec_level, Level) ->
+ snmp_conf:check_sec_level(Level);
+verify_agent_entry(Item, _) ->
+ error({unknown_item, Item}).
+
read_users_config_file(Dir) ->
- Check = fun(C) -> check_user_config(C) end,
- case read_file(Dir, "users.conf", Check, []) of
- {ok, Conf} ->
- Conf;
- Error ->
+ Order = fun snmp_conf:no_order/2,
+ 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]),
- throw(Error)
+ erlang:raise(throw, Error, erlang:get_stacktrace())
end.
-
check_user_config({Id, Mod, Data}) ->
?vtrace("check_user_config -> entry with"
"~n Id: ~p"
@@ -1843,21 +1957,18 @@ check_user_config({Id, Mod, Data, DefaultAgentConfig} = _User)
case (catch verify_user_behaviour(Mod)) of
ok ->
?vtrace("check_user_config -> user behaviour verified", []),
- case verify_user_agent_config(DefaultAgentConfig) of
- {ok, DefAgentConf} ->
- ?vtrace("check_user_config -> "
- "user agent (default) config verified", []),
- User2 = {Id, Mod, Data, DefAgentConf},
- {ok, User2};
- {error, Reason} ->
- error({bad_default_agent_config, Reason})
- end;
+ DefAgentConf =
+ verify_default_agent_config(DefaultAgentConfig),
+ ?vtrace("check_user_config -> "
+ "user agent (default) config verified", []),
+ User2 = {Id, Mod, Data, DefAgentConf},
+ {ok, User2};
Error ->
throw(Error)
end;
check_user_config({Id, _Mod, _Data, DefaultAgentConfig})
when (Id =/= ?DEFAULT_USER) ->
- {error, {bad_default_agent_config, DefaultAgentConfig}};
+ error({bad_default_agent_config, DefaultAgentConfig});
check_user_config({Id, _Mod, _Data, _DefaultAgentConfig}) ->
error({bad_user_id, Id});
check_user_config(User) ->
@@ -1883,7 +1994,7 @@ init_user_config(User) ->
error_msg("user config check failed: "
"~n~w~n~w", [User, Reason])
end.
-
+
verify_user({Id, UserMod, UserData}) ->
verify_user({Id, UserMod, UserData, []});
verify_user({Id, UserMod, UserData, DefaultAgentConfig})
@@ -1896,15 +2007,24 @@ verify_user({Id, UserMod, UserData, DefaultAgentConfig})
[Id, UserMod, UserData, DefaultAgentConfig]),
case (catch verify_user_behaviour(UserMod)) of
ok ->
- case verify_user_agent_config(DefaultAgentConfig) of
- {ok, DefAgentConf} ->
- Config = default_agent_config(DefAgentConf),
- {ok, #user{id = Id,
- mod = UserMod,
- data = UserData,
- default_agent_config = Config}};
- {error, Reason} ->
- error({bad_default_agent_config, Reason})
+ try
+ {ok, SystemDefaultAgentConfig} = agent_info(),
+ Config =
+ ensure_config(
+ SystemDefaultAgentConfig,
+ verify_default_agent_config(DefaultAgentConfig)),
+%% Config =
+%% default_agent_config(
+%% verify_default_agent_config(DefaultAgentConfig)),
+ {ok, #user{id = Id,
+ mod = UserMod,
+ data = UserData,
+ default_agent_config = Config}}
+ catch
+ Error ->
+ ?vdebug("verify_user default_agent_config -> throw"
+ "~n Error: ~p", [Error]),
+ error({bad_default_agent_config, Error})
end;
Error ->
throw(Error)
@@ -1915,27 +2035,24 @@ verify_user({Id, _UserMod, _UserData, DefaultAgentConfig})
verify_user({Id, _, _, _}) ->
{error, {bad_user_id, Id}}.
-verify_user_agent_config(Conf) ->
+verify_default_agent_config(Conf) ->
try
- begin
- verify_invalid(Conf, [user_id, engine_id, address]),
- verify_agent_config2(Conf)
- end
+ verify_illegal(
+ Conf,
+ [user_id, engine_id, address, tdomain, taddress]),
+ verify_agent_config(Conf)
catch
- throw:Error ->
- ?vdebug("verify_user_agent_config -> throw"
+ Error ->
+ ?vdebug("verify_default_agent_config -> throw"
"~n Error: ~p", [Error]),
- Error
+ error({bad_default_agent_config, Error})
end.
+
read_usm_config_file(Dir) ->
- Check = fun(C) -> check_usm_user_config(C) end,
- case read_file(Dir, "usm.conf", Check, []) of
- {ok, Conf} ->
- Conf;
- Error ->
- throw(Error)
- end.
+ Order = fun snmp_conf:no_order/2,
+ Check = fun (User, State) -> {check_usm_user_config(User), State} end,
+ read_file(Dir, "usm.conf", Order, Check, []).
%% Identity-function
check_usm_user_config({EngineId, Name,
@@ -2028,7 +2145,7 @@ verify_usm_user_auth(usmNoAuthProtocol, AuthKey) ->
end;
verify_usm_user_auth(usmHMACMD5AuthProtocol, AuthKey)
when is_list(AuthKey) andalso (length(AuthKey) =:= 16) ->
- case is_crypto_supported(md5_mac_96) of
+ case is_crypto_supported(md5) of
true ->
case snmp_conf:all_integer(AuthKey) of
true ->
@@ -2037,7 +2154,7 @@ verify_usm_user_auth(usmHMACMD5AuthProtocol, AuthKey)
error({invalid_auth_key, usmHMACMD5AuthProtocol})
end;
false ->
- error({unsupported_crypto, md5_mac_96})
+ error({unsupported_crypto, md5})
end;
verify_usm_user_auth(usmHMACMD5AuthProtocol, AuthKey) when is_list(AuthKey) ->
Len = length(AuthKey),
@@ -2046,7 +2163,7 @@ verify_usm_user_auth(usmHMACMD5AuthProtocol, _AuthKey) ->
error({invalid_auth_key, usmHMACMD5AuthProtocol});
verify_usm_user_auth(usmHMACSHAAuthProtocol, AuthKey)
when is_list(AuthKey) andalso (length(AuthKey) =:= 20) ->
- case is_crypto_supported(sha_mac_96) of
+ case is_crypto_supported(sha) of
true ->
case snmp_conf:all_integer(AuthKey) of
true ->
@@ -2055,7 +2172,7 @@ verify_usm_user_auth(usmHMACSHAAuthProtocol, AuthKey)
error({invalid_auth_key, usmHMACSHAAuthProtocol})
end;
false ->
- error({unsupported_crypto, sha_mac_96})
+ error({unsupported_crypto, sha})
end;
verify_usm_user_auth(usmHMACSHAAuthProtocol, AuthKey) when is_list(AuthKey) ->
Len = length(AuthKey),
@@ -2074,7 +2191,7 @@ verify_usm_user_priv(usmNoPrivProtocol, PrivKey) ->
end;
verify_usm_user_priv(usmDESPrivProtocol, PrivKey)
when (length(PrivKey) =:= 16) ->
- case is_crypto_supported(des_cbc_decrypt) of
+ case is_crypto_supported(des_cbc) of
true ->
case snmp_conf:all_integer(PrivKey) of
true ->
@@ -2083,7 +2200,7 @@ verify_usm_user_priv(usmDESPrivProtocol, PrivKey)
error({invalid_priv_key, usmDESPrivProtocol})
end;
false ->
- error({unsupported_crypto, des_cbc_decrypt})
+ error({unsupported_crypto, des_cbc})
end;
verify_usm_user_priv(usmDESPrivProtocol, PrivKey) when is_list(PrivKey) ->
Len = length(PrivKey),
@@ -2092,7 +2209,7 @@ verify_usm_user_priv(usmDESPrivProtocol, _PrivKey) ->
error({invalid_priv_key, usmDESPrivProtocol});
verify_usm_user_priv(usmAesCfb128Protocol, PrivKey)
when (length(PrivKey) =:= 16) ->
- case is_crypto_supported(aes_cfb_128_decrypt) of
+ case is_crypto_supported(aes_cfb128) of
true ->
case snmp_conf:all_integer(PrivKey) of
true ->
@@ -2101,7 +2218,7 @@ verify_usm_user_priv(usmAesCfb128Protocol, PrivKey)
error({invalid_priv_key, usmAesCfb128Protocol})
end;
false ->
- error({unsupported_crypto, aes_cfb_128_decrypt})
+ error({unsupported_crypto, aes_cfb128})
end;
verify_usm_user_priv(usmAesCfb128Protocol, PrivKey) when is_list(PrivKey) ->
Len = length(PrivKey),
@@ -2111,135 +2228,135 @@ verify_usm_user_priv(usmAesCfb128Protocol, _PrivKey) ->
verify_usm_user_priv(PrivP, _PrivKey) ->
error({invalid_priv_protocol, PrivP}).
+
+-compile({inline, [{is_crypto_supported,1}]}).
is_crypto_supported(Func) ->
- %% The 'catch' handles the case when 'crypto' is
- %% not present in the system (or not started).
- case (catch lists:member(Func, crypto:info())) of
- true -> true;
- _ -> false
- end.
+ snmp_misc:is_crypto_supported(Func).
read_manager_config_file(Dir) ->
- Check = fun(Conf) -> check_manager_config(Conf) end,
- case read_file(Dir, "manager.conf", Check) of
- {ok, Conf} ->
- ?d("read_manager_config_file -> ok: "
- "~n Conf: ~p", [Conf]),
- %% If the address is not specified, then we assume
- %% it should be the local host.
- %% If the address is not possible to determine
- %% that way, then we give up...
- check_mandatory_manager_config(Conf),
- ensure_manager_config(Conf);
- Error ->
- throw(Error)
- end.
+ Order = fun order_manager_config/2,
+ Check = fun check_manager_config/2,
+ Conf = read_file(Dir, "manager.conf", Order, Check),
+ ?d("read_manager_config_file -> ok: "
+ "~n Conf: ~p", [Conf]),
+ %% If the address is not specified, then we assume
+ %% it should be the local host.
+ %% If the address is not possible to determine
+ %% that way, then we give up...
+ verify_someof(Conf, [port, transports]),
+ verify_mandatory(Conf, [engine_id, max_message_size]),
+ default_manager_config(Conf).
+
+default_manager_config(Conf) ->
+ %% Ensure valid transports entry
+ case lists:keyfind(transports, 1, Conf) of
+ false ->
+ {port, Port} = lists:keyfind(port, 1, Conf),
+ Domain =
+ case lists:keyfind(domain, 1, Conf) of
+ false ->
+ default_transport_domain();
+ {_, D} ->
+ D
+ end,
+ Family = snmp_conf:tdomain_to_family(Domain),
+ {ok, Hostname} = inet:gethostname(),
+ case inet:getaddr(Hostname, Family) of
+ {ok, Address} ->
+ lists:sort(
+ fun order_manager_config/2,
+ [{transports, [{Domain, {Address, Port}}]} | Conf]);
+ {error, _Reason} ->
+ ?d("default_manager_config -> "
+ "failed getting ~w address for ~s:~n"
+ " _Reason: ~p", [Family, Hostname, _Reason]),
+ Conf
+ end;
+ _ ->
+ Conf
+ end.
+
+order_manager_config(EntryA, EntryB) ->
+ snmp_conf:keyorder(1, EntryA, EntryB, [domain, port]).
+
+check_manager_config(Entry, undefined) ->
+ check_manager_config(Entry, {default_transport_domain(), undefined});
+check_manager_config({domain, Domain}, {_, Port}) ->
+ {snmp_conf:check_domain(Domain), {Domain, Port}};
+check_manager_config({port, Port}, {Domain, _}) ->
+ {ok = snmp_conf:check_port(Port), {Domain, Port}};
+check_manager_config({address, _}, {_, undefined}) ->
+ error({missing_mandatory, port});
+check_manager_config({address = Tag, Ip} = Entry, {Domain, Port} = State) ->
+ {case snmp_conf:check_ip(Domain, Ip) of
+ ok ->
+ [Entry,
+ {transports, [{Domain, {Ip, Port}}]}];
+ {ok, FixedIp} ->
+ [{Tag, FixedIp},
+ {transports, [{Domain, {FixedIp, Port}}]}]
+ end, State};
+check_manager_config({transports = Tag, Transports}, {_, Port} = State)
+ when is_list(Transports) ->
+ CheckedTransports =
+ [case Transport of
+ {Domain, Address} ->
+ case
+ case Port of
+ undefined ->
+ snmp_conf:check_address(Domain, Address);
+ _ ->
+ snmp_conf:check_address(Domain, Address, Port)
+ end
+ of
+ ok ->
+ Transport;
+ {ok, FixedAddress} ->
+ {Domain, FixedAddress}
+ end;
+ _Domain when Port =:= undefined->
+ error({missing_mandatory, port});
+ Domain ->
+ Family = snmp_conf:tdomain_to_family(Domain),
+ {ok, Hostname} = inet:gethostname(),
+ case inet:getaddr(Hostname, Family) of
+ {ok, IpAddr} ->
+ {Domain, {IpAddr, Port}};
+ {error, _} ->
+ error({bad_address, {Domain, Hostname}})
+ end
+ end
+ || Transport <- Transports],
+ {{ok, {Tag, CheckedTransports}}, State};
+check_manager_config(Entry, State) ->
+ {check_manager_config(Entry), State}.
-default_manager_config() ->
- {ok, HostName} = inet:gethostname(),
- case inet:getaddr(HostName, inet) of
- {ok, A} ->
- [{address, tuple_to_list(A)}];
- {error, _Reason} ->
- ?d("default_manager_config -> failed getting address: "
- "~n _Reason: ~p", [_Reason]),
- []
- end.
-
-check_manager_config({address, Addr}) ->
- snmp_conf:check_ip(Addr);
-check_manager_config({port, Port}) ->
- snmp_conf:check_integer(Port, {gt, 0});
check_manager_config({engine_id, EngineID}) ->
snmp_conf:check_string(EngineID);
check_manager_config({max_message_size, Max}) ->
snmp_conf:check_integer(Max, {gte, 484});
check_manager_config(Conf) ->
- {error, {unknown_config, Conf}}.
-
+ error({unknown_config, Conf}).
-check_mandatory_manager_config(Conf) ->
- Mand = [port, engine_id, max_message_size],
- check_mandatory_manager_config(Mand, Conf).
-
-check_mandatory_manager_config([], _Conf) ->
- ok;
-check_mandatory_manager_config([Item|Mand], Conf) ->
- case lists:keysearch(Item, 1, Conf) of
- false ->
- error({missing_mandatory_manager_config, Item});
- _ ->
- check_mandatory_manager_config(Mand, Conf)
- end.
-
-ensure_manager_config(Confs) ->
- ensure_manager_config(Confs, default_manager_config()).
-
-ensure_manager_config(Confs, []) ->
- Confs;
-ensure_manager_config(Confs, [{Key,_} = DefKeyVal|Defs]) ->
- case lists:keysearch(Key, 1, Confs) of
- false ->
- ensure_manager_config([DefKeyVal|Confs], Defs);
- {value, _Conf} ->
- ensure_manager_config(Confs, Defs)
- end.
-
-% ensure_manager_config([], Defs, Confs) ->
-% Confs ++ Defs;
-% ensure_manager_config(Confs0, [{Key, DefVal}|Defs], Acc) ->
-% case lists:keysearch(Key, 1, Confs0) of
-% false ->
-% ensure_manager_config(Confs0, Defs, [{Key, DefVal}|Acc]);
-% {value, Conf} ->
-% Confs = lists:keydelete(Key, 1, Confs0),
-% ensure_manager_config(Confs, Defs, [Conf|Acc])
-% end.
-
-
-
-read_file(Dir, FileName, Check, Default) ->
- File = filename:join(Dir, FileName),
- case file:read_file_info(File) of
- {ok, _} ->
- case (catch do_read(File, Check)) of
- {ok, Conf} ->
- {ok, Conf};
- Error ->
- ?vtrace("read_file -> read failed:"
- "~n Error: ~p", [Error]),
- Error
- end;
- {error, Reason} ->
+read_file(Dir, FileName, Order, Check, Default) ->
+ try snmp_conf:read(filename:join(Dir, FileName), Order, Check)
+ catch
+ {error, Reason} when element(1, Reason) =:= failed_open ->
?vlog("failed reading config from ~s: ~p", [FileName, Reason]),
- {ok, Default}
+ Default
end.
-read_file(Dir, FileName, Check) ->
- File = filename:join(Dir, FileName),
- case file:read_file_info(File) of
- {ok, _} ->
- case (catch do_read(File, Check)) of
- {ok, Conf} ->
- ?vtrace("read_file -> read ok"
- "~n Conf: ~p", [Conf]),
- {ok, Conf};
- Error ->
- ?vtrace("read_file -> read failed:"
- "~n Error: ~p", [Error]),
- Error
- end;
- {error, Reason} ->
+read_file(Dir, FileName, Order, Check) ->
+ try snmp_conf:read(filename:join(Dir, FileName), Order, Check)
+ catch
+ throw:{error, Reason} = Error
+ when element(1, Reason) =:= failed_open ->
error_msg("failed reading config from ~s: ~p", [FileName, Reason]),
- {error, {failed_reading, FileName, Reason}}
+ erlang:raise(throw, Error, erlang:get_stacktrace())
end.
-do_read(File, Check) ->
- {ok, snmp_conf:read(File, Check)}.
-
-
%%--------------------------------------------------------------------
%% Func: handle_call/3
%% Returns: {reply, Reply, State} |
@@ -2666,30 +2783,50 @@ handle_register_agent(UserId, TargetName, Config) ->
"~n Config: ~p", [UserId, TargetName, Config]),
case (catch agent_info(TargetName, user_id)) of
{error, _} ->
- ?vtrace("handle_register_agent -> user_id not found in config", []),
+ ?vtrace(
+ "handle_register_agent -> user_id not found in config", []),
case ets:lookup(snmpm_user_table, UserId) of
[#user{default_agent_config = DefConfig}] ->
- ?vtrace("handle_register_agent -> "
- "~n DefConfig: ~p", [DefConfig]),
- %% First, insert this users default config
- ?vtrace("handle_register_agent -> store default config", []),
- do_handle_register_agent(TargetName, DefConfig),
- %% Second, insert the config for this agent
- ?vtrace("handle_register_agent -> store config", []),
- do_handle_register_agent(TargetName,
- [{user_id, UserId}|Config]),
+ ?vtrace("handle_register_agent ->~n"
+ " DefConfig: ~p", [DefConfig]),
+ FixedConfig =
+ fix_agent_config(ensure_config(DefConfig, Config)),
+ ?vtrace("handle_register_agent ->~n"
+ " FixedConfig: ~p", [FixedConfig]),
+ do_handle_register_agent(
+ TargetName, [{user_id, UserId}|FixedConfig]),
%% <DIRTY-BACKWARD-COMPATIBILLITY>
- %% And now for some (backward compatibillity)
+ %% And now for some (backward compatibillity)
%% dirty crossref stuff
- ?vtrace("handle_register_agent -> lookup address", []),
- {ok, Addr} = agent_info(TargetName, address),
- ?vtrace("handle_register_agent -> Addr: ~p, lookup Port",
- [Addr]),
- {ok, Port} = agent_info(TargetName, port),
- ?vtrace("handle_register_agent -> register cross-ref fix", []),
- ets:insert(snmpm_agent_table,
- {{Addr, Port, target_name}, TargetName}),
+ {value, {_, Domain}} =
+ lists:keysearch(tdomain, 1, FixedConfig),
+ {value, {_, Address}} =
+ lists:keysearch(taddress, 1, FixedConfig),
+ ?vtrace(
+ "handle_register_agent -> register cross-ref fix", []),
+ ets:insert(snmpm_agent_table,
+ {{Domain, Address, target_name}, TargetName}),
%% </DIRTY-BACKWARD-COMPATIBILLITY>
+
+%% %% First, insert this users default config
+%% ?vtrace("handle_register_agent -> store default config", []),
+%% do_handle_register_agent(TargetName, DefConfig),
+%% %% Second, insert the config for this agent
+%% ?vtrace("handle_register_agent -> store config", []),
+%% do_handle_register_agent(TargetName,
+%% [{user_id, UserId}|Config]),
+%% %% <DIRTY-BACKWARD-COMPATIBILLITY>
+%% %% And now for some (backward compatibillity)
+%% %% dirty crossref stuff
+%% ?vtrace("handle_register_agent -> lookup taddress", []),
+%% {ok, {Addr, Port} = TAddress} =
+%% agent_info(TargetName, taddress),
+%% ?vtrace("handle_register_agent -> taddress: ~p",
+%% [TAddress]),
+%% ?vtrace("handle_register_agent -> register cross-ref fix", []),
+%% ets:insert(snmpm_agent_table,
+%% {{Addr, Port, target_name}, TargetName}),
+%% %% </DIRTY-BACKWARD-COMPATIBILLITY>
ok;
_ ->
{error, {not_found, UserId}}
@@ -2711,7 +2848,7 @@ handle_register_agent(UserId, TargetName, Config) ->
do_handle_register_agent(_TargetName, []) ->
ok;
do_handle_register_agent(TargetName, [{Item, Val}|Rest]) ->
- ?vtrace("handle_register_agent -> entry with"
+ ?vtrace("do_handle_register_agent -> entry with"
"~n TargetName: ~p"
"~n Item: ~p"
"~n Val: ~p"
@@ -2720,7 +2857,7 @@ do_handle_register_agent(TargetName, [{Item, Val}|Rest]) ->
ok ->
do_handle_register_agent(TargetName, Rest);
{error, Reason} ->
- ?vtrace("handle_register_agent -> failed updating ~p"
+ ?vtrace("do_handle_register_agent -> failed updating ~p"
"~n Item: ~p"
"~n Reason: ~p", [Item, Reason]),
ets:match_delete(snmpm_agent_table, {TargetName, '_'}),
@@ -2744,9 +2881,9 @@ handle_unregister_agent(UserId, TargetName) ->
%% <DIRTY-BACKWARD-COMPATIBILLITY>
%% And now for some (backward compatibillity)
%% dirty crossref stuff
- {ok, Addr} = agent_info(TargetName, address),
- {ok, Port} = agent_info(TargetName, port),
- ets:delete(snmpm_agent_table, {Addr, Port, target_name}),
+ {ok, Domain} = agent_info(TargetName, tdomain),
+ {ok, Address} = agent_info(TargetName, taddress),
+ ets:delete(snmpm_agent_table, {Domain, Address, target_name}),
%% </DIRTY-BACKWARD-COMPATIBILLITY>
ets:match_delete(snmpm_agent_table, {{TargetName, '_'}, '_'}),
ok;
@@ -2772,21 +2909,26 @@ handle_update_agent_info(UserId, TargetName, Info) ->
Error
end.
-handle_update_agent_info(TargetName, Info0) ->
+handle_update_agent_info(TargetName, Info) ->
?vtrace("handle_update_agent_info -> entry with"
"~n TargetName: ~p"
- "~n Info0: ~p", [TargetName, Info0]),
+ "~n Info: ~p", [TargetName, Info]),
%% Verify info
- try verify_agent_info(TargetName, Info0) of
- {ok, Info} ->
- do_update_agent_info(TargetName, Info);
+ try
+ verify_illegal(Info, [user_id]),
+ %% If port or domain is part of the info, then use it.
+ %% If not, lookup what is already stored for
+ %% this agent and use that.
+ do_update_agent_info(
+ TargetName,
+ fix_agent_config(
+ verify_agent_config(
+ ensure_agent_info(TargetName, [port,tdomain], Info))))
+ catch
Error ->
- Error
- catch
- throw:Error ->
Error;
T:E ->
- {error, {failed_info_verification, Info0, T, E}}
+ {error, {failed_info_verification, Info, T, E}}
end.
handle_update_agent_info(UserId, TargetName, Item, Val) ->
@@ -2798,6 +2940,9 @@ handle_update_agent_info(UserId, TargetName, Item, Val) ->
handle_update_agent_info(TargetName, [{Item, Val}]).
do_update_agent_info(TargetName, Info) ->
+ ?vtrace("do_update_agent_info -> entry with~n"
+ " TargetName: ~p~n"
+ " Info: ~p", [TargetName,Info]),
InsertItem =
fun({Item, Val}) ->
ets:insert(snmpm_agent_table, {{TargetName, Item}, Val})
@@ -2879,11 +3024,11 @@ do_update_usm_user_info(Key,
#usm_user{auth = usmHMACMD5AuthProtocol} = User,
auth_key, Val)
when length(Val) =:= 16 ->
- case is_crypto_supported(md5_mac_96) of
+ case is_crypto_supported(md5) of
true ->
do_update_usm_user_info(Key, User#usm_user{auth_key = Val});
false ->
- {error, {unsupported_crypto, md5_mac_96}}
+ {error, {unsupported_crypto, md5}}
end;
do_update_usm_user_info(_Key,
#usm_user{auth = usmHMACMD5AuthProtocol},
@@ -2898,11 +3043,11 @@ do_update_usm_user_info(Key,
#usm_user{auth = usmHMACSHAAuthProtocol} = User,
auth_key, Val)
when length(Val) =:= 20 ->
- case is_crypto_supported(sha_mac_96) of
+ case is_crypto_supported(sha) of
true ->
do_update_usm_user_info(Key, User#usm_user{auth_key = Val});
false ->
- {error, {unsupported_crypto, sha_mac_96}}
+ {error, {unsupported_crypto, sha}}
end;
do_update_usm_user_info(_Key,
#usm_user{auth = usmHMACSHAAuthProtocol},
@@ -2933,21 +3078,21 @@ do_update_usm_user_info(Key,
#usm_user{priv = usmDESPrivProtocol} = User,
priv_key, Val)
when length(Val) =:= 16 ->
- case is_crypto_supported(des_cbc_decrypt) of
+ case is_crypto_supported(des_cbc) of
true ->
do_update_usm_user_info(Key, User#usm_user{priv_key = Val});
false ->
- {error, {unsupported_crypto, des_cbc_decrypt}}
+ {error, {unsupported_crypto, des_cbc}}
end;
do_update_usm_user_info(Key,
#usm_user{priv = usmAesCfb128Protocoll} = User,
priv_key, Val)
when length(Val) =:= 16 ->
- case is_crypto_supported(aes_cfb_128_decrypt) of
+ case is_crypto_supported(aes_cfb128) of
true ->
do_update_usm_user_info(Key, User#usm_user{priv_key = Val});
false ->
- {error, {unsupported_crypto, aes_cfb_128_decrypt}}
+ {error, {unsupported_crypto, aes_cfb128}}
end;
do_update_usm_user_info(_Key,
#usm_user{auth = usmHMACSHAAuthProtocol},
@@ -2979,109 +3124,42 @@ verify_mandatory(Conf, [Mand|Mands]) ->
true ->
verify_mandatory(Conf, Mands);
false ->
- throw({error, {missing_mandatory_config, Mand}})
+ error({missing_mandatory_config, Mand})
end.
-verify_invalid(_, []) ->
+verify_illegal(_, []) ->
ok;
-verify_invalid(Conf, [Inv|Invs]) ->
+verify_illegal(Conf, [Inv|Invs]) ->
case lists:member(Inv, Conf) of
false ->
- verify_invalid(Conf, Invs);
+ verify_illegal(Conf, Invs);
true ->
- throw({error, {illegal_config, Inv}})
+ error({illegal_config, Inv})
end.
-
-verify_val(user_id, UserId) ->
- {ok, UserId};
-verify_val(reg_type, RegType)
- when (RegType =:= addr_port) orelse (RegType =:= target_name) ->
- {ok, RegType};
-verify_val(tdomain = Item, snmpUDPDomain = _Domain) ->
- verify_val(Item, transportDomainUdpIpv4);
-verify_val(tdomain, Domain) ->
- case lists:member(Domain, ?SUPPORTED_DOMAINS) of
+verify_someof(Conf, [Mand|Mands]) ->
+ case lists:keymember(Mand, 1, Conf) of
true ->
- {ok, Domain};
+ ok;
false ->
- case lists:member(Domain, snmp_conf:all_domains()) of
- true ->
- error({unsupported_domain, Domain});
- false ->
- error({unknown_domain, Domain})
+ case Mands of
+ [] ->
+ error({missing_mandatory_config, Mand});
+ _ ->
+ verify_someof(Conf, Mands)
end
- end;
-verify_val(address, {Domain, Addr0}) ->
- case normalize_address(Domain, Addr0) of
- {_A1, _A2, _A3, _A4} = Addr ->
- {ok, Addr};
- {_A1, _A2, _A3, _A4, _A5, _A6, _A7, _A8} = Addr ->
- {ok, Addr};
- _ when is_list(Addr0) ->
- case (catch snmp_conf:check_ip(Addr0)) of
- ok ->
- {ok, list_to_tuple(Addr0)};
- Err ->
- Err
- end;
- _ ->
- error({bad_address, Addr0})
- end;
-verify_val(address, BadAddress) ->
- error({bad_address, BadAddress});
-verify_val(port, Port) ->
- case (catch snmp_conf:check_integer(Port, {gt, 0})) of
- ok ->
- {ok, Port};
- Err ->
- Err
- end;
-verify_val(community, Comm) ->
- case (catch snmp_conf:check_string(Comm)) of
- ok ->
- {ok, Comm};
- Err ->
- Err
- end;
-verify_val(engine_id, discovery = EngineId) ->
- {ok, EngineId};
-verify_val(engine_id, EngineId) ->
- case (catch snmp_conf:check_string(EngineId)) of
- ok ->
- {ok, EngineId};
- Err ->
- Err
- end;
-verify_val(timeout, Timeout) ->
- (catch snmp_conf:check_timer(Timeout));
-verify_val(max_message_size, MMS) ->
- case (catch snmp_conf:check_packet_size(MMS)) of
- ok ->
- {ok, MMS};
- Err ->
- Err
- end;
-verify_val(version, V)
- when (V =:= v1) orelse (V =:= v2) orelse (V =:= v3) ->
- {ok, V};
-verify_val(version, BadVersion) ->
- error({bad_version, BadVersion});
-verify_val(sec_model, Model) ->
- (catch snmp_conf:check_sec_model(Model));
-verify_val(sec_name, Name) when is_list(Name) ->
- case (catch snmp_conf:check_string(Name)) of
- ok ->
- {ok, Name};
- Err ->
- Err
- end;
-verify_val(sec_name, BadName) ->
- error({bad_sec_name, BadName});
-verify_val(sec_level, Level) ->
- (catch snmp_conf:check_sec_level(Level));
-verify_val(Item, _) ->
- {error, {unknown_item, Item}}.
+ end.
+
+ensure_config([], Config) ->
+ Config;
+ensure_config([Default|Defaults], Config) ->
+ case lists:keymember(element(1, Default), 1, Config) of
+ true ->
+ ensure_config(Defaults, Config);
+ false ->
+ ensure_config(Defaults, [Default|Config])
+ end.
+
%%%-------------------------------------------------------------------
@@ -3239,31 +3317,14 @@ init_mini_mib_elems(MibName, [_|T], Res) ->
%%----------------------------------------------------------------------
-normalize_address(Addr) ->
- normalize_address(snmpUDPDomain, Addr).
-
-normalize_address(snmpUDPDomain, Addr) ->
- normalize_address(transportDomainUdpIpv4, Addr);
-
-normalize_address(Domain, Addr) ->
- case inet:getaddr(Addr, td2fam(Domain)) of
- {ok, Addr2} ->
- Addr2;
- _ when is_list(Addr) ->
- case (catch snmp_conf:check_ip(Domain, Addr)) of
- ok ->
- list_to_tuple(Addr);
- _ ->
- Addr
- end;
- _ ->
- Addr
+fix_address(Domain, Address) ->
+ case snmp_conf:check_address(Domain, Address) of
+ ok ->
+ Address;
+ {ok, NAddress} ->
+ NAddress
end.
-td2fam(transportDomainUdpIpv4) -> inet;
-td2fam(transportDomainUdpIpv6) -> inet6.
-
-
%%----------------------------------------------------------------------
call(Req) ->
@@ -3373,4 +3434,3 @@ error_msg(F, A) ->
%% p(F, A) ->
%% io:format("~w:" ++ F ++ "~n", [?MODULE | A]).
-
diff --git a/lib/snmp/src/manager/snmpm_internal.hrl b/lib/snmp/src/manager/snmpm_internal.hrl
index 53ad41c6b0..e917206f13 100644
--- a/lib/snmp/src/manager/snmpm_internal.hrl
+++ b/lib/snmp/src/manager/snmpm_internal.hrl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
diff --git a/lib/snmp/src/manager/snmpm_misc_sup.erl b/lib/snmp/src/manager/snmpm_misc_sup.erl
index 1a5d7676df..6ff82b322b 100644
--- a/lib/snmp/src/manager/snmpm_misc_sup.erl
+++ b/lib/snmp/src/manager/snmpm_misc_sup.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
diff --git a/lib/snmp/src/manager/snmpm_mpd.erl b/lib/snmp/src/manager/snmpm_mpd.erl
index 103c87d32b..191dc2c281 100644
--- a/lib/snmp/src/manager/snmpm_mpd.erl
+++ b/lib/snmp/src/manager/snmpm_mpd.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2015. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
+%% 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
%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -21,7 +22,7 @@
-export([init/1,
- process_msg/7,
+ process_msg/7, process_msg/6,
generate_msg/5, generate_response_msg/4,
next_msg_id/0,
@@ -67,8 +68,9 @@
%%%-----------------------------------------------------------------
init(Vsns) ->
?vdebug("init -> entry with ~p", [Vsns]),
- {A,B,C} = erlang:now(),
- random:seed(A,B,C),
+ 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)),
init_counters(),
@@ -92,8 +94,10 @@ reset(#state{v3 = V3}) ->
%% Purpose: This is the main Message Dispatching function. (see
%% section 4.2.1 in rfc2272)
%%-----------------------------------------------------------------
-process_msg(Msg, Domain, Addr, Port, State, NoteStore, Logger) ->
+process_msg(Msg, Domain, Ip, Port, State, NoteStore, Logger) ->
+ process_msg(Msg, Domain, {Ip, Port}, State, NoteStore, Logger).
+process_msg(Msg, Domain, Addr, State, NoteStore, Logger) ->
inc(snmpInPkts),
case (catch snmp_pdus:dec_message_only(binary_to_list(Msg))) of
@@ -102,17 +106,17 @@ process_msg(Msg, Domain, Addr, Port, State, NoteStore, Logger) ->
#message{version = 'version-1', vsn_hdr = Community, data = Data}
when State#state.v1 =:= true ->
HS = ?empty_msg_size + length(Community),
- process_v1_v2c_msg('version-1', NoteStore, Msg,
- Domain, Addr, Port,
- Community, Data, HS, Logger);
+ process_v1_v2c_msg(
+ 'version-1', NoteStore, Msg, Domain, Addr,
+ Community, Data, HS, Logger);
%% Version 2
#message{version = 'version-2', vsn_hdr = Community, data = Data}
when State#state.v2c =:= true ->
HS = ?empty_msg_size + length(Community),
- (catch process_v1_v2c_msg('version-2', NoteStore, Msg,
- Domain, Addr, Port,
- Community, Data, HS, Logger));
+ process_v1_v2c_msg(
+ 'version-2', NoteStore, Msg, Domain, Addr,
+ Community, Data, HS, Logger);
%% Version 3
#message{version = 'version-3', vsn_hdr = H, data = Data}
@@ -122,7 +126,7 @@ process_msg(Msg, Domain, Addr, Port, State, NoteStore, Logger) ->
"~n msgFlags: ~p"
"~n msgSecModel: ~p",
[H#v3_hdr.msgID,H#v3_hdr.msgFlags,H#v3_hdr.msgSecurityModel]),
- process_v3_msg(NoteStore, Msg, H, Data, Addr, Port, Logger);
+ process_v3_msg(NoteStore, Msg, H, Data, Addr, Logger);
%% Crap
{'EXIT', {bad_version, Vsn}} ->
@@ -148,32 +152,27 @@ process_msg(Msg, Domain, Addr, Port, State, NoteStore, Logger) ->
%%-----------------------------------------------------------------
%% Handles a Community based message (v1 or v2c).
%%-----------------------------------------------------------------
-process_v1_v2c_msg(Vsn, _NoteStore, Msg, Domain,
- Addr, Port,
- Community, Data, HS, Log) ->
+process_v1_v2c_msg(
+ Vsn, _NoteStore, Msg, Domain, Addr, Community, Data, HS, Log) ->
?vdebug("process_v1_v2c_msg -> entry with"
"~n Vsn: ~p"
"~n Domain: ~p"
"~n Addr: ~p"
- "~n Port: ~p"
"~n Community: ~p"
- "~n HS: ~p", [Vsn, Domain, Addr, Port, Community, HS]),
-
+ "~n HS: ~p", [Vsn, Domain, Addr, Community, HS]),
+
{TDomain, TAddress} =
try
- begin
- TD = snmp_conf:mk_tdomain(Domain),
- TA = snmp_conf:mk_taddress(Domain, Addr, Port),
- {TD, TA}
- end
+ {snmp_conf:mk_tdomain(Domain),
+ snmp_conf:mk_taddress(Domain, Addr)}
catch
throw:{error, TReason} ->
throw({discarded, {badarg, Domain, TReason}})
end,
Max = get_max_message_size(),
- AgentMax = get_agent_max_message_size(Addr, Port),
+ AgentMax = get_agent_max_message_size(Domain, Addr),
PduMS = pdu_ms(Max, AgentMax, HS),
?vtrace("process_v1_v2c_msg -> PduMS: ~p", [PduMS]),
@@ -213,13 +212,12 @@ sec_model('version-2') -> ?SEC_V2C.
%% Handles a SNMPv3 Message, following the procedures in rfc2272,
%% section 4.2 and 7.2
%%-----------------------------------------------------------------
-process_v3_msg(NoteStore, Msg, Hdr, Data, Addr, Port, Log) ->
+process_v3_msg(NoteStore, Msg, Hdr, Data, Address, Log) ->
+ ?vdebug(
+ "process_v3_msg -> entry with~n"
+ " Hdr: ~p~n"
+ " Address: ~p", [Hdr, Address]),
- ?vdebug("process_v3_msg -> entry with"
- "~n Hdr: ~p"
- "~n Addr: ~p"
- "~n Port: ~p", [Hdr, Addr, Port]),
-
%% 7.2.3
#v3_hdr{msgID = MsgID,
msgMaxSize = MMS,
@@ -352,8 +350,8 @@ process_v3_msg(NoteStore, Msg, Hdr, Data, Addr, Port, Log) ->
%% 4.2.2.1.1 - we don't handle proxys yet => we only
%% handle CtxEngineID to ourselves
%% Check that we actually know of an agent with this
- %% CtxEngineID and Addr/Port
- case is_known_engine_id(CtxEngineID, Addr, Port) of
+ %% CtxEngineID and Address
+ case is_known_engine_id(CtxEngineID, Address) of
true ->
?vtrace("and the agent EngineID (~p) "
"is know to us", [CtxEngineID]),
@@ -591,8 +589,8 @@ sec_engine_id(TargetName) ->
%% BMK BMK BMK
-%% Denna verkar v�ldigt lik generate_v1_v2c_response_msg!
-%% Gemensam? Borde det finnas olikheter?
+%% This one looks very similar to lik generate_v1_v2c_response_msg!
+%% Common/shared? Should there be differences?
%%
generate_v1_v2c_msg(Vsn, Pdu, Community, Log) ->
?vdebug("generate_v1_v2c_msg -> encode pdu", []),
@@ -866,14 +864,23 @@ get_max_message_size() ->
end.
%% The the MMS of the agent
-get_agent_max_message_size(Addr, Port) ->
- case snmpm_config:get_agent_engine_max_message_size(Addr, Port) of
+get_agent_max_message_size(Domain, Addr) ->
+ case snmpm_config:get_agent_engine_max_message_size(Domain, Addr) of
{ok, MMS} ->
MMS;
_Error ->
- ?vlog("unknown agent: ~w:~w", [Addr, Port]),
+ ?vlog("unknown agent: ~s",
+ [snmp_conf:mk_addr_string({Domain, Addr})]),
get_max_message_size()
end.
+%% get_agent_max_message_size(Addr, Port) ->
+%% case snmpm_config:get_agent_engine_max_message_size(Addr, Port) of
+%% {ok, MMS} ->
+%% MMS;
+%% _Error ->
+%% ?vlog("unknown agent: ~w:~w", [Addr, Port]),
+%% get_max_message_size()
+%% end.
%% Get "our" (manager) engine id
get_engine_id() ->
@@ -888,17 +895,9 @@ get_engine_id() ->
get_agent_engine_id(Name) ->
snmpm_config:get_agent_engine_id(Name).
-is_known_engine_id(EngineID, Addr, Port) ->
+is_known_engine_id(EngineID, {Addr, Port}) ->
snmpm_config:is_known_engine_id(EngineID, Addr, Port).
-% get_agent_engine_id(Addr, Port) ->
-% case snmpm_config:get_agent_engine_id(Addr, Port) of
-% {ok, Id} ->
-% Id;
-% _Error ->
-% ""
-% end.
-
%%-----------------------------------------------------------------
%% Sequence number (msg-id & req-id) functions
diff --git a/lib/snmp/src/manager/snmpm_net_if.erl b/lib/snmp/src/manager/snmpm_net_if.erl
index 4d6bd9aa33..93c987eb0f 100644
--- a/lib/snmp/src/manager/snmpm_net_if.erl
+++ b/lib/snmp/src/manager/snmpm_net_if.erl
@@ -1,23 +1,26 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2015. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
+%% 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
%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
+-ifndef(snmpm_net_if_mt).
-module(snmpm_net_if).
+-endif.
-behaviour(gen_server).
-behaviour(snmpm_network_interface).
@@ -27,9 +30,9 @@
-export([
start_link/2,
stop/1,
- send_pdu/6, % Backward compatibillity
- send_pdu/7, % Backward compatibillity
- send_pdu/8,
+ send_pdu/6, % Backward compatibility
+ send_pdu/7, % Partly backward compatibility
+ send_pdu/8, % Backward compatibility
inform_response/4,
@@ -55,11 +58,11 @@
%% -define(VMODULE,"NET_IF").
-include("snmp_verbosity.hrl").
--record(state,
+-record(state,
{
server,
note_store,
- sock,
+ transports = [],
mpd_state,
log,
irb = auto, % auto | {user, integer()}
@@ -67,6 +70,9 @@
filter
}).
+-record(transport,
+ {socket,
+ domain = snmpUDPDomain}).
-define(DEFAULT_FILTER_MODULE, snmpm_net_if_filter).
-define(DEFAULT_FILTER_OPTS, [{module, ?DEFAULT_FILTER_MODULE}]).
@@ -99,30 +105,32 @@ start_link(Server, NoteStore) ->
stop(Pid) ->
call(Pid, stop).
-send_pdu(Pid, Pdu, Vsn, MsgData, Addr, Port) ->
- send_pdu(Pid, Pdu, Vsn, MsgData, Addr, Port, ?DEFAULT_EXTRA_INFO).
-
-send_pdu(Pid, Pdu, Vsn, MsgData, Addr, Port, ExtraInfo) ->
- Domain = snmpm_config:default_transport_domain(),
- send_pdu(Pid, Pdu, Vsn, MsgData, Domain, Addr, Port, ExtraInfo).
+send_pdu(Pid, Pdu, Vsn, MsgData, Domain_or_Ip, Addr_or_Port) ->
+ send_pdu(
+ Pid, Pdu, Vsn, MsgData, Domain_or_Ip, Addr_or_Port, ?DEFAULT_EXTRA_INFO).
-send_pdu(Pid, Pdu, Vsn, MsgData, Domain, Addr, Port, ExtraInfo)
+send_pdu(Pid, Pdu, Vsn, MsgData, Domain_or_Ip, Addr_or_Port, ExtraInfo)
when is_record(Pdu, pdu) ->
- ?d("send_pdu -> entry with"
- "~n Pid: ~p"
- "~n Pdu: ~p"
- "~n Vsn: ~p"
- "~n MsgData: ~p"
- "~n Domain: ~p"
- "~n Addr: ~p"
- "~n Port: ~p", [Pid, Pdu, Vsn, MsgData, Domain, Addr, Port]),
- cast(Pid, {send_pdu, Pdu, Vsn, MsgData, Domain, Addr, Port, ExtraInfo}).
+ ?d("send_pdu -> entry with~n"
+ " Pid: ~p~n"
+ " Pdu: ~p~n"
+ " Vsn: ~p~n"
+ " MsgData: ~p~n"
+ " Domain/IP: ~p~n"
+ " Addr/Port: ~p",
+ [Pid, Pdu, Vsn, MsgData, Domain_or_Ip, Addr_or_Port]),
+ {Domain, Addr} = address(Domain_or_Ip, Addr_or_Port),
+ cast(Pid, {send_pdu, Pdu, Vsn, MsgData, Domain, Addr, ExtraInfo}).
+
+send_pdu(Pid, Pdu, Vsn, MsgData, Domain, Ip, Port, ExtraInfo) ->
+ send_pdu(Pid, Pdu, Vsn, MsgData, Domain, {Ip, Port}, ExtraInfo).
note_store(Pid, NoteStore) ->
call(Pid, {note_store, NoteStore}).
-inform_response(Pid, Ref, Addr, Port) ->
- cast(Pid, {inform_response, Ref, Addr, Port}).
+inform_response(Pid, Ref, Domain_or_Ip, Addr_or_Port) ->
+ {Domain, Addr} = address(Domain_or_Ip, Addr_or_Port),
+ cast(Pid, {inform_response, Ref, Domain, Addr}).
info(Pid) ->
call(Pid, info).
@@ -144,6 +152,64 @@ filter_reset(Pid) ->
%%%-------------------------------------------------------------------
+%%% Multi-thread manager
+%%%-------------------------------------------------------------------
+
+-ifdef(snmpm_net_if_mt).
+
+%% This function is called through the macro below to
+%% (in the not multithreaded case) avoid creating the
+%% Failer/4 fun, and to avoid calling the Worker through a fun
+%% (now it shall not be a fun, just a code snippet).
+
+worker(Worker, Failer, #state{log = Log} = State) ->
+ Verbosity = get(verbosity),
+ spawn_opt(
+ fun () ->
+ try
+ put(sname, mnifw),
+ put(verbosity, Verbosity),
+ NewState =
+ case do_reopen_log(Log) of
+ Log ->
+ State;
+ NewLog ->
+ State#state{log = NewLog}
+ end,
+ Worker(NewState)
+ of
+ Result ->
+ %% Winds up in handle_info {'DOWN', ...}
+ erlang:exit({net_if_worker, Result})
+ catch
+ Class:Reason ->
+ %% Winds up in handle_info {'DOWN', ...}
+ erlang:exit(
+ {net_if_worker, Failer,
+ Class, Reason, erlang:get_stacktrace()})
+ end
+ end,
+ [monitor]).
+-define(
+ worker(S, Worker, Failer, State),
+ begin
+ worker(
+ fun (S) -> begin Worker end end,
+ begin Failer end,
+ (State))
+ end).
+
+-else.
+
+-define(
+ worker(S, Worker, _Failer, State),
+ begin (S) = (State), begin Worker end end).
+
+-endif.
+
+
+
+%%%-------------------------------------------------------------------
%%% Callback functions from gen_server
%%%-------------------------------------------------------------------
@@ -158,12 +224,19 @@ init([Server, NoteStore]) ->
?d("init -> entry with"
"~n Server: ~p"
"~n NoteStore: ~p", [Server, NoteStore]),
- case (catch do_init(Server, NoteStore)) of
+ try do_init(Server, NoteStore)
+ catch
{error, Reason} ->
- {stop, Reason};
- {ok, State} ->
- {ok, State}
+ {stop, Reason}
end.
+
+-ifdef(snmpm_net_if_mt).
+%% This should really be protected, but it also needs to
+%% be writable for the worker processes, so...
+-define(inform_table_opts, [set, public, named_table, {keypos, 1}]).
+-else.
+-define(inform_table_opts, [set, protected, named_table, {keypos, 1}]).
+-endif.
do_init(Server, NoteStore) ->
process_flag(trap_exit, true),
@@ -173,18 +246,18 @@ do_init(Server, NoteStore) ->
process_flag(priority, Prio),
%% -- Create inform request table --
- ets:new(snmpm_inform_request_table,
- [set, protected, named_table, {keypos, 1}]),
+ ets:new(snmpm_inform_request_table, ?inform_table_opts),
%% -- Verbosity --
{ok, Verbosity} = snmpm_config:system_info(net_if_verbosity),
- put(sname,mnif),
- put(verbosity,Verbosity),
+ put(sname, mnif),
+ put(verbosity, Verbosity),
?vlog("starting", []),
%% -- MPD --
{ok, Vsns} = snmpm_config:system_info(versions),
MpdState = snmpm_mpd:init(Vsns),
+ ?vdebug("MpdState: ~w", [MpdState]),
%% -- Module dependent options --
{ok, Opts} = snmpm_config:system_info(net_if_options),
@@ -193,14 +266,6 @@ do_init(Server, NoteStore) ->
{ok, IRB} = snmpm_config:system_info(net_if_irb),
IrGcRef = irgc_start(IRB),
- %% -- Socket --
- SndBuf = get_opt(Opts, sndbuf, default),
- RecBuf = get_opt(Opts, recbuf, default),
- BindTo = get_opt(Opts, bind_to, false),
- NoReuse = get_opt(Opts, no_reuse, false),
- {ok, Port} = snmpm_config:system_info(port),
- {ok, Sock} = do_open_port(Port, SndBuf, RecBuf, BindTo, NoReuse),
-
%% Flow control --
FilterOpts = get_opt(Opts, filter, []),
FilterMod = create_filter(FilterOpts),
@@ -209,77 +274,107 @@ do_init(Server, NoteStore) ->
%% -- Audit trail log ---
{ok, ATL} = snmpm_config:system_info(audit_trail_log),
Log = do_init_log(ATL),
+ ?vdebug("Log: ~w", [Log]),
+
+ {ok, DomainAddresses} = snmpm_config:system_info(transports),
+ ?vdebug("DomainAddresses: ~w",[DomainAddresses]),
+ CommonSocketOpts = common_socket_opts(Opts),
+ BindTo = get_opt(Opts, bind_to, false),
+ case
+ [begin
+ {IpPort, SocketOpts} =
+ socket_params(Domain, Address, BindTo, CommonSocketOpts),
+ Socket = socket_open(IpPort, SocketOpts),
+ #transport{socket = Socket, domain = Domain}
+ end || {Domain, Address} <- DomainAddresses]
+ of
+ [] ->
+ ?vinfo("No transports configured: ~p", [DomainAddresses]),
+ throw({error, {no_transports,DomainAddresses}});
+ Transports ->
+ %% -- Initiate counters ---
+ init_counters(),
+
+ %% -- We are done ---
+ State = #state{
+ server = Server,
+ note_store = NoteStore,
+ mpd_state = MpdState,
+ transports = Transports,
+ log = Log,
+ irb = IRB,
+ irgc = IrGcRef,
+ filter = FilterMod},
+ ?vdebug("started", []),
+ {ok, State}
+ end.
- %% -- Initiate counters ---
- init_counters(),
-
- %% -- We are done ---
- State = #state{server = Server,
- note_store = NoteStore,
- mpd_state = MpdState,
- sock = Sock,
- log = Log,
- irb = IRB,
- irgc = IrGcRef,
- filter = FilterMod},
- ?vdebug("started", []),
- {ok, State}.
-
-
-%% Open port
-do_open_port(Port, SendSz, RecvSz, BindTo, NoReuse) ->
- ?vtrace("do_open_port -> entry with"
- "~n Port: ~p"
- "~n SendSz: ~p"
- "~n RecvSz: ~p"
- "~n BindTo: ~p"
- "~n NoReuse: ~p", [Port, SendSz, RecvSz, BindTo, NoReuse]),
- IpOpts1 = bind_to(BindTo),
- IpOpts2 = no_reuse(NoReuse),
- IpOpts3 = recbuf(RecvSz),
- IpOpts4 = sndbuf(SendSz),
- IpOpts = [binary | IpOpts1 ++ IpOpts2 ++ IpOpts3 ++ IpOpts4],
- OpenRes =
- case init:get_argument(snmpm_fd) of
- {ok, [[FdStr]]} ->
- Fd = list_to_integer(FdStr),
- gen_udp:open(0, [{fd, Fd}|IpOpts]);
- error ->
- gen_udp:open(Port, IpOpts)
- end,
- case OpenRes of
+socket_open(IpPort, SocketOpts) ->
+ ?vtrace("socket_open -> entry with~n"
+ " IpPort: ~p~n"
+ " SocketOpts: ~p", [IpPort, SocketOpts]),
+ case gen_udp:open(IpPort, SocketOpts) of
{error, _} = Error ->
throw(Error);
- OK ->
- OK
+ {ok, Socket} ->
+ Socket
end.
-bind_to(true) ->
- case snmpm_config:system_info(address) of
- {ok, Addr} when is_list(Addr) ->
- [{ip, list_to_tuple(Addr)}];
- {ok, Addr} ->
- [{ip, Addr}];
+socket_params(Domain, {IpAddr, IpPort} = Addr, BindTo, CommonSocketOpts) ->
+ Family = snmp_conf:tdomain_to_family(Domain),
+ SocketOpts =
+ case Family of
+ inet6 ->
+ [Family, {ipv6_v6only, true} | CommonSocketOpts];
+ Family ->
+ [Family | CommonSocketOpts]
+ end,
+ case Family of
+ inet ->
+ case init:get_argument(snmpm_fd) of
+ {ok, [[FdStr]]} ->
+ Fd = list_to_integer(FdStr),
+ case BindTo of
+ true ->
+ {IpPort, [{ip, IpAddr}, {fd, Fd} | SocketOpts]};
+ _ ->
+ {0, [{fd, Fd} | SocketOpts]}
+ end;
+ error ->
+ socket_params(SocketOpts, Addr, BindTo)
+ end;
_ ->
- []
- end;
-bind_to(_) ->
- [].
-
-no_reuse(false) ->
- [{reuseaddr, true}];
-no_reuse(_) ->
- [].
-
-recbuf(default) ->
- [];
-recbuf(Sz) ->
- [{recbuf, Sz}].
+ socket_params(SocketOpts, Addr, BindTo)
+ end.
+%%
+socket_params(SocketOpts, {IpAddr, IpPort}, BindTo) ->
+ case BindTo of
+ true ->
+ {IpPort, [{ip, IpAddr} | SocketOpts]};
+ _ ->
+ {IpPort, SocketOpts}
+ end.
-sndbuf(default) ->
- [];
-sndbuf(Sz) ->
- [{sndbuf, Sz}].
+common_socket_opts(Opts) ->
+ [binary
+ | case get_opt(Opts, sndbuf, default) of
+ default ->
+ [];
+ Sz ->
+ [{sndbuf, Sz}]
+ end ++
+ case get_opt(Opts, recbuf, default) of
+ default ->
+ [];
+ Sz ->
+ [{sndbuf, Sz}]
+ end ++
+ case get_opt(Opts, no_reuse, false) of
+ false ->
+ [{reuseaddr, true}];
+ _ ->
+ []
+ end].
create_filter(Opts) when is_list(Opts) ->
@@ -294,6 +389,10 @@ create_filter(BadOpts) ->
throw({error, {bad_filter_opts, BadOpts}}).
+%% ----------------------------------------------------------------------
+%% Audit Trail Logger
+%% ----------------------------------------------------------------------
+
%% Open log
do_init_log(false) ->
?vtrace("do_init_log(false) -> entry", []),
@@ -314,24 +413,69 @@ do_init_log(true) ->
Function = increment_counter,
Args = [atl_seqno, Initial, Max],
SeqNoGen = {Module, Function, Args},
- case snmp_log:create(Name, File,
- SeqNoGen, Size, Repair, true) of
+ case snmp_log:create(
+ Name, File, SeqNoGen, Size, Repair, true) of
{ok, Log} ->
?vdebug("log created: ~w", [Log]),
- {Log, Type};
+ {Name, Log, Type};
{error, Reason} ->
throw({error, {failed_create_audit_log, Reason}})
end;
_ ->
case snmp_log:create(Name, File, Size, Repair, true) of
{ok, Log} ->
- {Log, Type};
+ ?vdebug("log created: ~w", [Log]),
+ {Name, Log, Type};
{error, Reason} ->
throw({error, {failed_create_audit_log, Reason}})
end
end.
-
+-ifdef(snmpm_net_if_mt).
+do_reopen_log(undefined) ->
+ undefined;
+do_reopen_log({Name, Log, Type}) ->
+ case snmp_log:open(Name, Log) of
+ {ok, NewLog} ->
+ {Name, NewLog, Type};
+ {error, Reason} ->
+ warning_msg(
+ "NetIf worker ~p failed to open ATL:~n"
+ " ~p", [self(), Reason]),
+ undefined
+ end.
+-endif.
+
+%% Close log
+do_close_log(undefined) ->
+ ok;
+do_close_log({_Name, Log, _Type}) ->
+ (catch snmp_log:sync(Log)),
+ (catch snmp_log:close(Log)),
+ ok;
+do_close_log(_) ->
+ ok.
+
+%% Log
+logger(undefined, _Type, _Domain, _Addr) ->
+ fun(_) ->
+ ok
+ end;
+logger({_Name, Log, Types}, Type, Domain, Addr) ->
+ case lists:member(Type, Types) of
+ true ->
+ AddrString =
+ iolist_to_binary(snmp_conf:mk_addr_string({Domain, Addr})),
+ fun(Msg) ->
+ snmp_log:log(Log, Msg, AddrString)
+ end;
+ false ->
+ fun(_) ->
+ ok
+ end
+ end.
+
+
%%--------------------------------------------------------------------
%% Func: handle_call/3
%% Returns: {reply, Reply, State} |
@@ -346,11 +490,6 @@ handle_call({verbosity, Verbosity}, _From, State) ->
put(verbosity, Verbosity),
{reply, ok, State};
-%% handle_call({system_info_updated, What}, _From, State) ->
-%% ?vlog("received system_info_updated request with What = ~p", [What]),
-%% {NewState, Reply} = handle_system_info_updated(State, What),
-%% {reply, Reply, NewState};
-
handle_call(get_log_type, _From, State) ->
?vlog("received get-log-type request", []),
Reply = (catch handle_get_log_type(State)),
@@ -386,25 +525,24 @@ handle_call(Req, From, State) ->
%% {noreply, State, Timeout} |
%% {stop, Reason, State} (terminate/2 is called)
%%--------------------------------------------------------------------
-handle_cast({send_pdu, Pdu, Vsn, MsgData, Domain, Addr, Port, ExtraInfo},
+handle_cast({send_pdu, Pdu, Vsn, MsgData, Domain, Addr, ExtraInfo},
State) ->
- ?vlog("received send_pdu message with"
- "~n Pdu: ~p"
- "~n Vsn: ~p"
- "~n MsgData: ~p"
- "~n Domain: ~p"
- "~n Addr: ~p"
- "~n Port: ~p", [Pdu, Vsn, MsgData, Domain, Addr, Port]),
- maybe_process_extra_info(ExtraInfo),
- maybe_handle_send_pdu(Pdu, Vsn, MsgData, Domain, Addr, Port, State),
+ ?vlog("received send_pdu message with~n"
+ " Pdu: ~p~n"
+ " Vsn: ~p~n"
+ " MsgData: ~p~n"
+ " Domain: ~p~n"
+ " Addr: ~p", [Pdu, Vsn, MsgData, Domain, Addr]),
+ maybe_process_extra_info(ExtraInfo),
+ maybe_handle_send_pdu(Pdu, Vsn, MsgData, Domain, Addr, State),
{noreply, State};
-handle_cast({inform_response, Ref, Addr, Port}, State) ->
- ?vlog("received inform_response message with"
- "~n Ref: ~p"
- "~n Addr: ~p"
- "~n Port: ~p", [Ref, Addr, Port]),
- handle_inform_response(Ref, Addr, Port, State),
+handle_cast({inform_response, Ref, Domain, Addr}, State) ->
+ ?vlog("received inform_response message with~n"
+ " Ref: ~p~n"
+ " Domain: ~p~n"
+ " Addr: ~p", [Ref, Domain, Addr]),
+ handle_inform_response(Ref, Domain, Addr, State),
{noreply, State};
handle_cast(filter_reset, State) ->
@@ -423,10 +561,21 @@ handle_cast(Msg, State) ->
%% {noreply, State, Timeout} |
%% {stop, Reason, State} (terminate/2 is called)
%%--------------------------------------------------------------------
-handle_info({udp, Sock, Ip, Port, Bytes}, #state{sock = Sock} = State) ->
- ?vlog("received ~w bytes from ~p:~p [~w]", [size(Bytes), Ip, Port, Sock]),
- maybe_handle_recv_msg(Ip, Port, Bytes, State),
- {noreply, State};
+handle_info(
+ {udp, Socket, IpAddr, IpPort, Bytes},
+ #state{transports = Transports} = State) ->
+ Size = byte_size(Bytes),
+ case lists:keyfind(Socket, #transport.socket, Transports) of
+ #transport{socket = Socket, domain = Domain} ->
+ ?vlog("received ~w bytes from ~p:~p [~w]",
+ [Size, IpAddr, IpPort, Socket]),
+ maybe_handle_recv_msg(Domain, {IpAddr, IpPort}, Bytes, State),
+ {noreply, State};
+ false ->
+ warning_msg("Received ~w bytes on unknown port: ~p from ~s",
+ [Size, Socket, format_address({IpAddr, IpPort})]),
+ {noreply, State}
+ end;
handle_info(inform_response_gc, State) ->
?vlog("received inform_response_gc message", []),
@@ -439,11 +588,42 @@ handle_info({disk_log, _Node, Log, Info}, State) ->
State2 = handle_disk_log(Log, Info, State),
{noreply, State2};
+handle_info({'DOWN', _, _, _, _} = Info, State) ->
+ handle_info_down(Info, State);
+
handle_info(Info, State) ->
+ handle_info_unknown(Info, State).
+
+
+handle_info_unknown(Info, State) ->
warning_msg("received unknown info: ~n~p", [Info]),
{noreply, State}.
+-ifdef(snmpm_net_if_mt).
+handle_info_down(
+ {'DOWN', _MRef, process, _Pid,
+ {net_if_worker, _Result}},
+ State) ->
+ ?vdebug("received DOWN message from net_if worker [~w]: "
+ "~n Result: ~p", [_Pid, _Result]),
+ {noreply, State};
+handle_info_down(
+ {'DOWN', _MRef, process, Pid,
+ {net_if_worker, Failer, Class, Reason, Stacktrace} = _ExitStatus},
+ State) ->
+ ?vdebug("received DOWN message from net_if worker [~w]: "
+ "~n ExitStatus: ~p", [Pid, _ExitStatus]),
+ Failer(Pid, Class, Reason, Stacktrace),
+ {noreply, State};
+handle_info_down(Info, State) ->
+ handle_info_unknown(Info, State).
+-else.
+handle_info_down(Info, State) ->
+ handle_info_unknown(Info, State).
+-endif.
+
+
%%--------------------------------------------------------------------
%% Func: terminate/2
%% Purpose: Shutdown the server
@@ -457,68 +637,12 @@ terminate(Reason, #state{log = Log, irgc = IrGcRef}) ->
ok.
-do_close_log({Log, _Type}) ->
- (catch snmp_log:sync(Log)),
- (catch snmp_log:close(Log)),
- ok;
-do_close_log(_) ->
- ok.
-
-
%%----------------------------------------------------------------------
%% Func: code_change/3
%% Purpose: Convert process state when code is changed
%% Returns: {ok, NewState}
%%----------------------------------------------------------------------
-code_change({down, _Vsn}, OldState, downgrade_to_pre_4_14) ->
- ?d("code_change(down, downgrade_to_pre_4_14) -> entry with"
- "~n OldState: ~p", [OldState]),
- #state{server = Server,
- note_store = NoteStore,
- sock = Sock,
- mpd_state = MpdState,
- log = {OldLog, Type},
- irb = IRB,
- irgc = IRGC} = OldState,
- NewLog = snmp_log:downgrade(OldLog),
- State =
- {state, Server, NoteStore, Sock, MpdState, {NewLog, Type}, IRB, IRGC},
- {ok, State};
-
-code_change({down, _Vsn}, OldState, downgrade_to_pre_4_16) ->
- ?d("code_change(down, downgrade_to_pre_4_16) -> entry with"
- "~n OldState: ~p", [OldState]),
- {OldLog, Type} = OldState#state.log,
- NewLog = snmp_log:downgrade(OldLog),
- State = OldState#state{log = {NewLog, Type}},
- {ok, State};
-
-% upgrade
-code_change(_Vsn, OldState, upgrade_from_pre_4_14) ->
- ?d("code_change(up, upgrade_from_pre_4_14) -> entry with"
- "~n OldState: ~p", [OldState]),
- {state, Server, NoteStore, Sock, MpdState, {OldLog, Type}, IRB, IRGC} =
- OldState,
- NewLog = snmp_log:upgrade(OldLog),
- State = #state{server = Server,
- note_store = NoteStore,
- sock = Sock,
- mpd_state = MpdState,
- log = {NewLog, Type},
- irb = IRB,
- irgc = IRGC,
- filter = ?DEFAULT_FILTER_MODULE},
- {ok, State};
-
-code_change(_Vsn, OldState, upgrade_from_pre_4_16) ->
- ?d("code_change(up, upgrade_from_pre_4_16) -> entry with"
- "~n OldState: ~p", [OldState]),
- {OldLog, Type} = OldState#state.log,
- NewLog = snmp_log:upgrade(OldLog),
- State = OldState#state{log = {NewLog, Type}},
- {ok, State};
-
code_change(_Vsn, State, _Extra) ->
?d("code_change -> entry with"
"~n Vsn: ~p"
@@ -531,139 +655,155 @@ code_change(_Vsn, State, _Extra) ->
%%% Internal functions
%%%-------------------------------------------------------------------
-maybe_handle_recv_msg(Addr, Port, Bytes, #state{filter = FilterMod} = State) ->
- case (catch FilterMod:accept_recv(Addr, Port)) of
+maybe_handle_recv_msg(Domain, Addr, Bytes, State) ->
+ ?worker(
+ S, maybe_handle_recv_msg_mt(Domain, Addr, Bytes, S),
+ fun (Pid, Class, Reason, Stacktrace) ->
+ warning_msg(
+ "Worker process (~p) terminated "
+ "while processing (incomming) message from %s:~n"
+ "~w:~w at ~p",
+ [Pid, snmp_conf:mk_addr_string({Domain, Addr}),
+ Class, Reason, Stacktrace])
+ end,
+ State).
+
+maybe_handle_recv_msg_mt(
+ Domain, Addr, Bytes,
+ #state{filter = FilterMod, transports = Transports} = State) ->
+ {Arg1, Arg2} = fix_filter_address(Transports, {Domain, Addr}),
+ case (catch FilterMod:accept_recv(Arg1, Arg2)) of
false ->
%% Drop the received packet
- inc(netIfMsgInDrops),
- ok;
+ inc(netIfMsgInDrops);
_ ->
- handle_recv_msg(Addr, Port, Bytes, State)
- end.
+ handle_recv_msg(Domain, Addr, Bytes, State)
+ end,
+ ok.
-handle_recv_msg(Addr, Port, Bytes, #state{server = Pid})
+handle_recv_msg(Domain, Addr, Bytes, #state{server = Pid})
when is_binary(Bytes) andalso (size(Bytes) =:= 0) ->
- Pid ! {snmp_error, {empty_message, Addr, Port}, Addr, Port},
- ok;
-
-handle_recv_msg(Addr, Port, Bytes,
- #state{server = Pid,
- note_store = NoteStore,
- mpd_state = MpdState,
- sock = Sock,
- log = Log} = State) ->
- Domain = snmp_conf:which_domain(Addr), % What the ****...
- Logger = logger(Log, read, Addr, Port),
- case (catch snmpm_mpd:process_msg(Bytes, Domain, Addr, Port,
- MpdState, NoteStore, Logger)) of
+ Pid ! {snmp_error, {empty_message, Domain, Addr}, Domain, Addr};
+%%
+handle_recv_msg(
+ Domain, Addr, Bytes,
+ #state{
+ server = Pid,
+ note_store = NoteStore,
+ mpd_state = MpdState,
+ log = Log} = State) ->
+ Logger = logger(Log, read, Domain, Addr),
+ case (catch snmpm_mpd:process_msg(
+ Bytes, Domain, Addr, MpdState, NoteStore, Logger)) of
{ok, Vsn, Pdu, MS, ACM} ->
- maybe_handle_recv_pdu(Addr, Port, Vsn, Pdu, MS, ACM,
- Logger, State);
+ maybe_handle_recv_pdu(
+ Domain, Addr, Vsn, Pdu, MS, ACM, Logger, State);
{discarded, Reason, Report} ->
?vdebug("discarded: ~p", [Reason]),
ErrorInfo = {failed_processing_message, Reason},
- Pid ! {snmp_error, ErrorInfo, Addr, Port},
- maybe_udp_send(State#state.filter, Sock, Addr, Port, Report),
- ok;
+ Pid ! {snmp_error, ErrorInfo, Domain, Addr},
+ maybe_udp_send(Domain, Addr, Report, State);
{discarded, Reason} ->
?vdebug("discarded: ~p", [Reason]),
ErrorInfo = {failed_processing_message, Reason},
- Pid ! {snmp_error, ErrorInfo, Addr, Port},
- ok;
+ Pid ! {snmp_error, ErrorInfo, Domain, Addr};
Error ->
error_msg("processing of received message failed: "
- "~n ~p", [Error]),
- ok
+ "~n ~p", [Error])
end.
-maybe_handle_recv_pdu(Addr, Port,
- Vsn, #pdu{type = Type} = Pdu, PduMS, ACM,
- Logger,
- #state{filter = FilterMod} = State) ->
- case (catch FilterMod:accept_recv_pdu(Addr, Port, Type)) of
+maybe_handle_recv_pdu(
+ Domain, Addr, Vsn, #pdu{type = Type} = Pdu, PduMS, ACM, Logger,
+ #state{filter = FilterMod, transports = Transports} = State) ->
+ {Arg1, Arg2} = fix_filter_address(Transports, {Domain, Addr}),
+ case (catch FilterMod:accept_recv_pdu(Arg1, Arg2, Type)) of
false ->
- inc(netIfPduInDrops),
- ok;
+ inc(netIfPduInDrops);
_ ->
- handle_recv_pdu(Addr, Port, Vsn, Pdu, PduMS, ACM, Logger, State)
+ handle_recv_pdu(
+ Domain, Addr, Vsn, Pdu, PduMS, ACM, Logger, State)
end;
-maybe_handle_recv_pdu(Addr, Port, Vsn, Trap, PduMS, ACM, Logger,
- #state{filter = FilterMod} = State)
+maybe_handle_recv_pdu(
+ Domain, Addr, Vsn, Trap, PduMS, ACM, Logger,
+ #state{filter = FilterMod, transports = Transports} = State)
when is_record(Trap, trappdu) ->
- case (catch FilterMod:accept_recv_pdu(Addr, Port, trappdu)) of
+ {Arg1, Arg2} = fix_filter_address(Transports, {Domain, Addr}),
+ case (catch FilterMod:accept_recv_pdu(Arg1, Arg2, trappdu)) of
false ->
- inc(netIfPduInDrops),
- ok;
+ inc(netIfPduInDrops);
_ ->
- handle_recv_pdu(Addr, Port, Vsn, Trap, PduMS, ACM, Logger, State)
+ handle_recv_pdu(
+ Domain, Addr, Vsn, Trap, PduMS, ACM, Logger, State)
end;
-maybe_handle_recv_pdu(Addr, Port, Vsn, Pdu, PduMS, ACM, Logger, State) ->
- handle_recv_pdu(Addr, Port, Vsn, Pdu, PduMS, ACM, Logger, State).
-
-
-handle_recv_pdu(Addr, Port,
- Vsn, #pdu{type = 'inform-request'} = Pdu, _PduMS, ACM,
- Logger, #state{server = Pid, irb = IRB} = State) ->
- handle_inform_request(IRB, Pid, Vsn, Pdu, ACM,
- Addr, Port, Logger, State);
-handle_recv_pdu(Addr, Port,
- _Vsn, #pdu{type = report} = Pdu, _PduMS, ok,
- _Logger,
- #state{server = Pid} = _State) ->
+maybe_handle_recv_pdu(
+ Domain, Addr, Vsn, Pdu, PduMS, ACM, Logger, State) ->
+ handle_recv_pdu(Domain, Addr, Vsn, Pdu, PduMS, ACM, Logger, State).
+
+
+handle_recv_pdu(
+ Domain, Addr, Vsn,
+ #pdu{type = 'inform-request'} = Pdu, _PduMS, ACM, Logger,
+ #state{server = Pid, irb = IRB} = State) ->
+ handle_inform_request(
+ IRB, Pid, Vsn, Pdu, ACM, Domain, Addr, Logger, State);
+handle_recv_pdu(
+ Domain, Addr, _Vsn,
+ #pdu{type = report} = Pdu, _PduMS, ok, _Logger,
+ #state{server = Pid} = _State) ->
?vtrace("received report - ok", []),
- Pid ! {snmp_report, {ok, Pdu}, Addr, Port};
-handle_recv_pdu(Addr, Port,
- _Vsn, #pdu{type = report} = Pdu, _PduMS,
- {error, ReqId, Reason},
- _Logger,
- #state{server = Pid} = _State) ->
+ Pid ! {snmp_report, {ok, Pdu}, Domain, Addr};
+handle_recv_pdu(
+ Domain, Addr, _Vsn,
+ #pdu{type = report} = Pdu, _PduMS, {error, ReqId, Reason}, _Logger,
+ #state{server = Pid} = _State) ->
?vtrace("received report - error", []),
- Pid ! {snmp_report, {error, ReqId, Reason, Pdu}, Addr, Port};
-handle_recv_pdu(Addr, Port,
- _Vsn, #pdu{type = 'snmpv2-trap'} = Pdu, _PduMS, _ACM,
- _Logger,
- #state{server = Pid} = _State) ->
+ Pid ! {snmp_report, {error, ReqId, Reason, Pdu}, Domain, Addr};
+handle_recv_pdu(
+ Domain, Addr, _Vsn,
+ #pdu{type = 'snmpv2-trap'} = Pdu, _PduMS, _ACM, _Logger,
+ #state{server = Pid} = _State) ->
?vtrace("received snmpv2-trap", []),
- Pid ! {snmp_trap, Pdu, Addr, Port};
-handle_recv_pdu(Addr, Port,
- _Vsn, Trap, _PduMS, _ACM,
- _Logger,
- #state{server = Pid} = _State) when is_record(Trap, trappdu) ->
+ Pid ! {snmp_trap, Pdu, Domain, Addr};
+handle_recv_pdu(
+ Domain, Addr, _Vsn, Trap, _PduMS, _ACM, _Logger,
+ #state{server = Pid} = _State) when is_record(Trap, trappdu) ->
?vtrace("received trappdu", []),
- Pid ! {snmp_trap, Trap, Addr, Port};
-handle_recv_pdu(Addr, Port,
- _Vsn, Pdu, _PduMS, _ACM,
- _Logger,
- #state{server = Pid} = _State) when is_record(Pdu, pdu) ->
+ Pid ! {snmp_trap, Trap, Domain, Addr};
+handle_recv_pdu(
+ Domain, Addr, _Vsn, Pdu, _PduMS, _ACM, _Logger,
+ #state{server = Pid} = _State) when is_record(Pdu, pdu) ->
?vtrace("received pdu", []),
- Pid ! {snmp_pdu, Pdu, Addr, Port};
-handle_recv_pdu(_Addr, _Port, _Vsn, Pdu, _PduMS, ACM, _Logger, _State) ->
+ Pid ! {snmp_pdu, Pdu, Domain, Addr};
+handle_recv_pdu(
+ _Domain, _Addr, _Vsn, Pdu, _PduMS, ACM, _Logger, _State) ->
?vlog("received unexpected pdu: "
- "~n Pdu: ~p"
- "~n ACM: ~p", [Pdu, ACM]).
+ "~n Pdu: ~p"
+ "~n ACM: ~p", [Pdu, ACM]).
-handle_inform_request(auto, Pid, Vsn, Pdu, ACM, Addr, Port, Logger, State) ->
+handle_inform_request(
+ auto, Pid, Vsn, Pdu, ACM, Domain, Addr, Logger, State) ->
?vtrace("received inform-request (true)", []),
- Pid ! {snmp_inform, ignore, Pdu, Addr, Port},
+ Pid ! {snmp_inform, ignore, Pdu, Domain, Addr},
RePdu = make_response_pdu(Pdu),
- maybe_send_inform_response(RePdu, Vsn, ACM, Addr, Port, Logger, State);
-handle_inform_request({user, To}, Pid, Vsn, #pdu{request_id = ReqId} = Pdu,
- ACM, Addr, Port, _Logger, _State) ->
+ maybe_send_inform_response(RePdu, Vsn, ACM, Domain, Addr, Logger, State);
+handle_inform_request(
+ {user, To}, Pid, Vsn, #pdu{request_id = ReqId} = Pdu,
+ ACM, Domain, Addr, _Logger, _State) ->
?vtrace("received inform-request (false)", []),
- Pid ! {snmp_inform, ReqId, Pdu, Addr, Port},
+ Pid ! {snmp_inform, ReqId, Pdu, Domain, Addr},
%% Before we go any further, we need to check that we have not
%% already received this message (possible resend).
- Key = {ReqId, Addr, Port},
+ Key = {ReqId, Domain, Addr},
case ets:lookup(snmpm_inform_request_table, Key) of
[_] ->
%% OK, we already know about this. We assume this
@@ -672,50 +812,67 @@ handle_inform_request({user, To}, Pid, Vsn, #pdu{request_id = ReqId} = Pdu,
ok;
[] ->
RePdu = make_response_pdu(Pdu),
- Expire = t() + To,
+ Expire = snmp_misc:now(ms) + To,
Rec = {Key, Expire, {Vsn, ACM, RePdu}},
ets:insert(snmpm_inform_request_table, Rec)
end.
-
-handle_inform_response(Ref, Addr, Port, State) ->
- Key = {Ref, Addr, Port},
+
+handle_inform_response(Ref, Domain, Addr, State) ->
+ ?worker(
+ S, handle_inform_response_mt(Ref, Domain, Addr, S),
+ fun (Pid, Class, Reason, Stacktrace) ->
+ warning_msg(
+ "Worker process (~p) terminated "
+ "while processing (outgoing) inform response for %s:~n"
+ "~w:~w at ~p",
+ [Pid, snmp_conf:mk_addr_string({Domain, Addr}),
+ Class, Reason, Stacktrace])
+ end,
+ State).
+
+handle_inform_response_mt(Ref, Domain, Addr, State) ->
+ Key = {Ref, Domain, Addr},
case ets:lookup(snmpm_inform_request_table, Key) of
[{Key, _, {Vsn, ACM, RePdu}}] ->
- Logger = logger(State#state.log, read, Addr, Port),
+ Logger = logger(State#state.log, read, Domain, Addr),
ets:delete(snmpm_inform_request_table, Key),
- maybe_send_inform_response(RePdu, Vsn, ACM, Addr, Port,
- Logger, State);
+ maybe_send_inform_response(
+ RePdu, Vsn, ACM, Domain, Addr, Logger, State);
[] ->
%% Already acknowledged, or the user was to slow to reply...
ok
end,
ok.
-maybe_send_inform_response(RePdu, Vsn, ACM, Addr, Port, Logger,
- #state{server = Pid,
- sock = Sock,
- filter = FilterMod}) ->
- case (catch FilterMod:accept_send_pdu(Addr, Port, pdu_type_of(RePdu))) of
+maybe_send_inform_response(
+ RePdu, Vsn, ACM, Domain, Addr, Logger,
+ #state{
+ server = Pid,
+ filter = FilterMod,
+ transports = Transports} = State) ->
+ {Arg1, Arg2} = fix_filter_address(Transports, {Domain, Addr}),
+ case (catch FilterMod:accept_send_pdu(
+ Arg1, Arg2, pdu_type_of(RePdu)))
+ of
false ->
inc(netIfPduOutDrops),
ok;
_ ->
case snmpm_mpd:generate_response_msg(Vsn, RePdu, ACM, Logger) of
{ok, Msg} ->
- maybe_udp_send(FilterMod, Sock, Addr, Port, Msg);
+ maybe_udp_send(Domain, Addr, Msg, State);
{discarded, Reason} ->
?vlog("failed generating response message:"
"~n Reason: ~p", [Reason]),
ReqId = RePdu#pdu.request_id,
ErrorInfo = {failed_generating_response, {RePdu, Reason}},
- Pid ! {snmp_error, ReqId, ErrorInfo, Addr, Port},
- ok
+ Pid ! {snmp_error, ReqId, ErrorInfo, Domain, Addr}
end
end.
handle_inform_response_gc(#state{irb = IRB} = State) ->
ets:safe_fixtable(snmpm_inform_request_table, true),
- do_irgc(ets:first(snmpm_inform_request_table), t()),
+ do_irgc(ets:first(snmpm_inform_request_table), snmp_misc:now(ms)),
ets:safe_fixtable(snmpm_inform_request_table, false),
State#state{irgc = irgc_start(IRB)}.
@@ -742,64 +899,99 @@ irgc_stop(undefined) ->
irgc_stop(Ref) ->
(catch erlang:cancel_timer(Ref)).
-
-maybe_handle_send_pdu(Pdu, Vsn, MsgData, Domain, Addr, Port,
- #state{filter = FilterMod} = State) ->
- case (catch FilterMod:accept_send_pdu(Addr, Port, pdu_type_of(Pdu))) of
+maybe_handle_send_pdu(Pdu, Vsn, MsgData, Domain, Addr, State) ->
+ ?worker(
+ S, maybe_handle_send_pdu_mt(Pdu, Vsn, MsgData, Domain, Addr, S),
+ fun (Pid, Class, Reason, Stacktrace) ->
+ warning_msg(
+ "Worker process (~p) terminated "
+ "while processing (outgoing) pdu for %s:~n"
+ "~w:~w at ~p",
+ [Pid, snmp_conf:mk_addr_string({Domain, Addr}),
+ Class, Reason, Stacktrace])
+ end,
+ State).
+
+maybe_handle_send_pdu_mt(
+ Pdu, Vsn, MsgData, Domain, Addr,
+ #state{filter = FilterMod, transports = Transports} = State) ->
+ {Arg1, Arg2} = fix_filter_address(Transports, {Domain, Addr}),
+ case (catch FilterMod:accept_send_pdu(Arg1, Arg2, pdu_type_of(Pdu))) of
false ->
- inc(netIfPduOutDrops),
- ok;
+ inc(netIfPduOutDrops);
_ ->
- handle_send_pdu(Pdu, Vsn, MsgData, Domain, Addr, Port, State)
- end.
+ handle_send_pdu(Pdu, Vsn, MsgData, Domain, Addr, State)
+ end,
+ ok.
-handle_send_pdu(Pdu, Vsn, MsgData, _Domain, Addr, Port,
- #state{server = Pid,
- note_store = NoteStore,
- sock = Sock,
- log = Log,
- filter = FilterMod}) ->
- Logger = logger(Log, write, Addr, Port),
- case (catch snmpm_mpd:generate_msg(Vsn, NoteStore,
- Pdu, MsgData, Logger)) of
+handle_send_pdu(
+ Pdu, Vsn, MsgData, Domain, Addr,
+ #state{
+ server = Pid,
+ note_store = NoteStore,
+ log = Log} = State) ->
+ Logger = logger(Log, write, Domain, Addr),
+ case (catch snmpm_mpd:generate_msg(
+ Vsn, NoteStore, Pdu, MsgData, Logger)) of
{ok, Msg} ->
?vtrace("handle_send_pdu -> message generated", []),
- maybe_udp_send(FilterMod, Sock, Addr, Port, Msg);
+ maybe_udp_send(Domain, Addr, Msg, State);
{discarded, Reason} ->
?vlog("PDU not sent: "
"~n PDU: ~p"
"~n Reason: ~p", [Pdu, Reason]),
- Pid ! {snmp_error, Pdu, Reason},
- ok
+ Pid ! {snmp_error, Pdu, Reason}
end.
-maybe_udp_send(FilterMod, Sock, Addr, Port, Msg) ->
- case (catch FilterMod:accept_send(Addr, Port)) of
+maybe_udp_send(
+ Domain, Addr, Msg,
+ #state{filter = FilterMod, transports = Transports}) ->
+ To = {Domain, Addr},
+ {Arg1, Arg2} = fix_filter_address(Transports, To),
+ case (catch FilterMod:accept_send(Arg1, Arg2)) of
false ->
inc(netIfMsgOutDrops),
ok;
_ ->
- udp_send(Sock, Addr, Port, Msg)
+ case select_transport_from_domain(Domain, Transports) of
+ false ->
+ error_msg(
+ "Can not find transport~n"
+ " size: ~p~n"
+ " to: ~s",
+ [sz(Msg), format_address(To)]);
+ #transport{socket = Socket} ->
+ udp_send(Socket, Addr, Msg)
+ end
end.
-
-
-udp_send(Sock, Addr, Port, Msg) ->
- case (catch gen_udp:send(Sock, Addr, Port, Msg)) of
+
+udp_send(Sock, To, Msg) ->
+ {IpAddr, IpPort} =
+ case To of
+ {Domain, Addr} when is_atom(Domain) ->
+ Addr;
+ {_, P} = Addr when is_integer(P) ->
+ Addr
+ end,
+ try gen_udp:send(Sock, IpAddr, IpPort, Msg) of
ok ->
?vdebug("sent ~w bytes to ~w:~w [~w]",
- [sz(Msg), Addr, Port, Sock]),
+ [sz(Msg), IpAddr, IpPort, Sock]),
ok;
{error, Reason} ->
- error_msg("failed sending message to ~p:~p: "
- "~n ~p",[Addr, Port, Reason]);
- Error ->
- error_msg("failed sending message to ~p:~p: "
- "~n ~p",[Addr, Port, Error])
+ 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()])
end.
sz(B) when is_binary(B) ->
- size(B);
+ byte_size(B);
sz(L) when is_list(L) ->
length(L);
sz(_) ->
@@ -827,110 +1019,6 @@ handle_disk_log(_Log, _Info, State) ->
State.
-%% mk_discovery_msg('version-3', Pdu, _VsnHdr, UserName) ->
-%% ScopedPDU = #scopedPdu{contextEngineID = "",
-%% contextName = "",
-%% data = Pdu},
-%% Bytes = snmp_pdus:enc_scoped_pdu(ScopedPDU),
-%% MsgID = get(msg_id),
-%% put(msg_id,MsgID+1),
-%% UsmSecParams =
-%% #usmSecurityParameters{msgAuthoritativeEngineID = "",
-%% msgAuthoritativeEngineBoots = 0,
-%% msgAuthoritativeEngineTime = 0,
-%% msgUserName = UserName,
-%% msgPrivacyParameters = "",
-%% msgAuthenticationParameters = ""},
-%% SecBytes = snmp_pdus:enc_usm_security_parameters(UsmSecParams),
-%% PduType = Pdu#pdu.type,
-%% Hdr = #v3_hdr{msgID = MsgID,
-%% msgMaxSize = 1000,
-%% msgFlags = snmp_misc:mk_msg_flags(PduType, 0),
-%% msgSecurityModel = ?SEC_USM,
-%% msgSecurityParameters = SecBytes},
-%% Msg = #message{version = 'version-3', vsn_hdr = Hdr, data = Bytes},
-%% case (catch snmp_pdus:enc_message_only(Msg)) of
-%% {'EXIT', Reason} ->
-%% error("Encoding error. Pdu: ~w. Reason: ~w",[Pdu, Reason]),
-%% error;
-%% L when list(L) ->
-%% {Msg, L}
-%% end;
-%% mk_discovery_msg(Version, Pdu, {Com, _, _, _, _}, UserName) ->
-%% Msg = #message{version = Version, vsn_hdr = Com, data = Pdu},
-%% case catch snmp_pdus:enc_message(Msg) of
-%% {'EXIT', Reason} ->
-%% error("Encoding error. Pdu: ~w. Reason: ~w",[Pdu, Reason]),
-%% error;
-%% L when list(L) ->
-%% {Msg, L}
-%% end.
-
-
-%% mk_msg('version-3', Pdu, {Context, User, EngineID, CtxEngineId, SecLevel},
-%% MsgData) ->
-%% %% Code copied from snmp_mpd.erl
-%% {MsgId, SecName, SecData} =
-%% if
-%% tuple(MsgData), Pdu#pdu.type == 'get-response' ->
-%% MsgData;
-%% true ->
-%% Md = get(msg_id),
-%% put(msg_id, Md + 1),
-%% {Md, User, []}
-%% end,
-%% ScopedPDU = #scopedPdu{contextEngineID = CtxEngineId,
-%% contextName = Context,
-%% data = Pdu},
-%% ScopedPDUBytes = snmp_pdus:enc_scoped_pdu(ScopedPDU),
-
-%% PduType = Pdu#pdu.type,
-%% V3Hdr = #v3_hdr{msgID = MsgId,
-%% msgMaxSize = 1000,
-%% msgFlags = snmp_misc:mk_msg_flags(PduType, SecLevel),
-%% msgSecurityModel = ?SEC_USM},
-%% Message = #message{version = 'version-3', vsn_hdr = V3Hdr,
-%% data = ScopedPDUBytes},
-%% SecEngineID = case PduType of
-%% 'get-response' -> snmp_framework_mib:get_engine_id();
-%% _ -> EngineID
-%% end,
-%% case catch snmp_usm:generate_outgoing_msg(Message, SecEngineID,
-%% SecName, SecData, SecLevel) of
-%% {'EXIT', Reason} ->
-%% error("Encoding error. Pdu: ~w. Reason: ~w",[Pdu, Reason]),
-%% error;
-%% {error, Reason} ->
-%% error("Encoding error. Pdu: ~w. Reason: ~w",[Pdu, Reason]),
-%% error;
-%% Packet ->
-%% Packet
-%% end;
-%% mk_msg(Version, Pdu, {Com, _User, _EngineID, _Ctx, _SecLevel}, _SecData) ->
-%% Msg = #message{version = Version, vsn_hdr = Com, data = Pdu},
-%% case catch snmp_pdus:enc_message(Msg) of
-%% {'EXIT', Reason} ->
-%% error("Encoding error. Pdu: ~w. Reason: ~w",[Pdu, Reason]),
-%% error;
-%% B when list(B) ->
-%% B
-%% end.
-
-
-%% handle_system_info_updated(#state{log = {Log, _OldType}} = State,
-%% audit_trail_log_type = _What) ->
-%% %% Just to make sure, check that ATL is actually enabled
-%% case snmpm_config:system_info(audit_trail_log) of
-%% {ok, true} ->
-%% {ok, Type} = snmpm_config:system_info(audit_trail_log_type),
-%% NewState = State#state{log = {Log, Type}},
-%% {NewState, ok};
-%% _ ->
-%% {State, {error, {adt_not_enabled}}}
-%% end;
-%% handle_system_info_updated(_State, _What) ->
-%% ok.
-
handle_get_log_type(#state{log = {_Log, Value}} = State) ->
%% Just to make sure, check that ATL is actually enabled
case snmpm_config:system_info(audit_trail_log) of
@@ -989,6 +1077,45 @@ handle_set_log_type(State, _NewType) ->
{State, {error, not_enabled}}.
+select_transport_from_domain(Domain, Transports) when is_atom(Domain) ->
+ Pos = #transport.domain,
+ case lists:keyfind(Domain, Pos, Transports) of
+ #transport{domain = Domain} = Transport ->
+ Transport;
+ false when Domain == snmpUDPDomain ->
+ lists:keyfind(transportDomainUdpIpv4, Pos, Transports);
+ false when Domain == transportDomainUdpIpv4 ->
+ lists:keyfind(snmpUDPDomain, Pos, Transports);
+ false ->
+ false
+ end.
+
+%% If the manager uses legacy snmpUDPDomain e.g has not set
+%% {domain, _}, then make sure snmpm_network_interface_filter
+%% gets legacy arguments to not break backwards compatibility.
+%%
+fix_filter_address(Transports, Address) ->
+ DefaultDomain = snmpm_config:default_transport_domain(),
+ case Transports of
+ [#transport{domain = DefaultDomain}, DefaultDomain] ->
+ case Address of
+ {Domain, Addr} when is_atom(Domain) ->
+ Addr;
+ {_, IpPort} = Addr when is_integer(IpPort) ->
+ Addr
+ end;
+ _ ->
+ Address
+ end.
+
+address(Domain, Addr) when is_atom(Domain) ->
+ {Domain, Addr};
+address(Ip, Port) when is_integer(Port) ->
+ {snmpm_config:default_transport_domain(), {Ip, Port}}.
+
+format_address(Address) ->
+ iolist_to_binary(snmp_conf:mk_addr_string(Address)).
+
%% -------------------------------------------------------------------
make_response_pdu(#pdu{request_id = ReqId, varbinds = Vbs}) ->
@@ -1022,32 +1149,6 @@ maybe_process_extra_info(_ExtraInfo) ->
%% -------------------------------------------------------------------
-t() ->
- {A,B,C} = erlang:now(),
- A*1000000000+B*1000+(C div 1000).
-
-
-%% -------------------------------------------------------------------
-
-logger(undefined, _Type, _Addr, _Port) ->
- fun(_) ->
- ok
- end;
-logger({Log, Types}, Type, Addr, Port) ->
- case lists:member(Type, Types) of
- true ->
- fun(Msg) ->
- snmp_log:log(Log, Msg, Addr, Port)
- end;
- false ->
- fun(_) ->
- ok
- end
- end.
-
-
-%% -------------------------------------------------------------------
-
%% info_msg(F, A) ->
%% ?snmpm_info("NET-IF server: " ++ F, A).
@@ -1072,10 +1173,11 @@ get_opt(Opts, Key, Def) ->
%% -------------------------------------------------------------------
-get_info(#state{sock = Id}) ->
+get_info(#state{transports = Transports}) ->
ProcSize = proc_mem(self()),
- PortInfo = get_port_info(Id),
- [{process_memory, ProcSize}, {port_info, PortInfo}].
+ [{process_memory, ProcSize}
+ | [{port_info, get_port_info(Socket)}
+ || #transport{socket = Socket} <- Transports]].
proc_mem(P) when is_pid(P) ->
case (catch erlang:process_info(P, memory)) of
@@ -1084,8 +1186,6 @@ proc_mem(P) when is_pid(P) ->
_ ->
undefined
end.
-%% proc_mem(_) ->
-%% undefined.
get_port_info(Id) ->
@@ -1165,20 +1265,6 @@ counters() ->
inc(Name) -> inc(Name, 1).
inc(Name, N) -> snmpm_config:incr_stats_counter(Name, N).
-%% get_counters() ->
-%% Counters = counters(),
-%% get_counters(Counters, []).
-
-%% get_counters([], Acc) ->
-%% lists:reverse(Acc);
-%% get_counters([Counter|Counters], Acc) ->
-%% case snmpm_config:get_stats_counter(Counter) of
-%% {ok, CounterVal} ->
-%% get_counters(Counters, [{Counter, CounterVal}|Acc]);
-%% _ ->
-%% get_counters(Counters, Acc)
-%% end.
-
%% ----------------------------------------------------------------
@@ -1190,4 +1276,3 @@ call(Pid, Req, Timeout) ->
cast(Pid, Msg) ->
gen_server:cast(Pid, Msg).
-
diff --git a/lib/snmp/src/manager/snmpm_net_if_filter.erl b/lib/snmp/src/manager/snmpm_net_if_filter.erl
index eb0c6efb11..e5aef0756b 100644
--- a/lib/snmp/src/manager/snmpm_net_if_filter.erl
+++ b/lib/snmp/src/manager/snmpm_net_if_filter.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -25,29 +26,51 @@
-include("snmp_debug.hrl").
-accept_recv(_Addr, _Port) ->
- ?d("accept_recv -> entry with"
- "~n Addr: ~p"
- "~n Port: ~p", [_Addr, _Port]),
+accept_recv(Domain, _Address) when is_atom(Domain) ->
+ ?d("accept_recv -> entry with~n"
+ " Domain: ~p~n"
+ " Address: ~p", [Domain, _Address]),
+ true;
+accept_recv(_Addr, Port) when is_integer(Port) ->
+ ?d("accept_recv -> entry with~n"
+ " Addr: ~p~n"
+ " Port: ~p", [_Addr, Port]),
true.
-accept_send(_Addr, _Port) ->
- ?d("accept_send -> entry with"
- "~n Addr: ~p"
- "~n Port: ~p", [_Addr, _Port]),
+accept_send(Domain, _Address) when is_atom(Domain) ->
+ ?d("accept_send -> entry with~n"
+ " Domain: ~p~n"
+ " Address: ~p", [Domain, _Address]),
+ true;
+accept_send(_Addr, Port) when is_integer(Port) ->
+ ?d("accept_send -> entry with~n"
+ " Addr: ~p~n"
+ " Port: ~p", [_Addr, Port]),
true.
-accept_recv_pdu(_Addr, _Port, _PduType) ->
- ?d("accept_recv_pdu -> entry with"
- "~n Addr: ~p"
- "~n Port: ~p"
- "~n PduType: ~p", [_Addr, _Port, _PduType]),
+accept_recv_pdu(Domain, _Address, _PduType) when is_atom(Domain) ->
+ ?d("accept_recv_pdu -> entry with~n"
+ " Domain: ~p~n"
+ " Address: ~p~n"
+ " PduType: ~p", [Domain, _Address, _PduType]),
+ true;
+accept_recv_pdu(_Addr, Port, _PduType) when is_integer(Port) ->
+ ?d("accept_recv_pdu -> entry with~n"
+ " Addr: ~p~n"
+ " Port: ~p~n"
+ " PduType: ~p", [_Addr, Port, _PduType]),
true.
-accept_send_pdu(_Addr, _Port, _PduType) ->
- ?d("accept_send_pdu -> entry with"
- "~n Addr: ~p"
- "~n Port: ~p"
- "~n PduType: ~p", [_Addr, _Port, _PduType]),
+accept_send_pdu(Domain, _Address, _PduType) when is_atom(Domain) ->
+ ?d("accept_send_pdu -> entry with~n"
+ " Domain: ~p~n"
+ " Address: ~p~n"
+ " PduType: ~p", [Domain, _Address, _PduType]),
+ true;
+accept_send_pdu(_Addr, Port, _PduType) when is_integer(Port) ->
+ ?d("accept_send_pdu -> entry with~n"
+ " Addr: ~p~n"
+ " Port: ~p~n"
+ " PduType: ~p", [_Addr, Port, _PduType]),
true.
diff --git a/lib/snmp/src/manager/snmpm_net_if_mt.erl b/lib/snmp/src/manager/snmpm_net_if_mt.erl
new file mode 100644
index 0000000000..238e212e14
--- /dev/null
+++ b/lib/snmp/src/manager/snmpm_net_if_mt.erl
@@ -0,0 +1,24 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-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%
+%%
+
+
+-define(snmpm_net_if_mt, true).
+-module(snmpm_net_if_mt).
+-include("snmpm_net_if.erl").
diff --git a/lib/snmp/src/manager/snmpm_network_interface.erl b/lib/snmp/src/manager/snmpm_network_interface.erl
index b830d45ce7..d0f6f709d3 100644
--- a/lib/snmp/src/manager/snmpm_network_interface.erl
+++ b/lib/snmp/src/manager/snmpm_network_interface.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
diff --git a/lib/snmp/src/manager/snmpm_network_interface_filter.erl b/lib/snmp/src/manager/snmpm_network_interface_filter.erl
index ae8b7cfce1..35bec4e7e7 100644
--- a/lib/snmp/src/manager/snmpm_network_interface_filter.erl
+++ b/lib/snmp/src/manager/snmpm_network_interface_filter.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
diff --git a/lib/snmp/src/manager/snmpm_server.erl b/lib/snmp/src/manager/snmpm_server.erl
index 484954addb..c8d7fa1e8b 100644
--- a/lib/snmp/src/manager/snmpm_server.erl
+++ b/lib/snmp/src/manager/snmpm_server.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2015. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
+%% 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
%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -163,8 +164,7 @@
reg_type,
target,
domain,
- addr,
- port,
+ address,
type,
data,
ref,
@@ -468,27 +468,6 @@ cancel_async_request(UserId, ReqId) ->
call({cancel_async_request, UserId, ReqId}).
-%% discovery(UserId, BAddr) ->
-%% discovery(UserId, BAddr, ?SNMP_AGENT_PORT, [],
-%% ?DEFAULT_ASYNC_EXPIRE, ?EXTRA_INFO).
-
-%% discovery(UserId, BAddr, Config) when is_list(Config) ->
-%% discovery(UserId, BAddr, ?SNMP_AGENT_PORT, Config,
-%% ?DEFAULT_ASYNC_EXPIRE, ?EXTRA_INFO);
-
-%% discovery(UserId, BAddr, Expire) when is_integer(Expire) ->
-%% discovery(UserId, BAddr, ?SNMP_AGENT_PORT, [], Expire, ?EXTRA_INFO).
-
-%% discovery(UserId, BAddr, Config, Expire) ->
-%% discovery(UserId, BAddr, ?SNMP_AGENT_PORT, Config, Expire, ?EXTRA_INFO).
-
-%% discovery(UserId, BAddr, Port, Config, Expire) ->
-%% discovery(UserId, BAddr, Port, Config, Expire, ?EXTRA_INFO).
-
-%% discovery(UserId, BAddr, Port, Config, Expire, ExtraInfo) ->
-%% call({discovery, self(), UserId, BAddr, Port, Config, Expire, ExtraInfo}).
-
-
verbosity(Verbosity) ->
case ?vvalidate(Verbosity) of
Verbosity ->
@@ -928,14 +907,6 @@ handle_call({cancel_async_request, UserId, ReqId}, _From, State) ->
{reply, Reply, State};
-%% handle_call({discovery, Pid, UserId, BAddr, Port, Config, Expire, ExtraInfo},
-%% _From, State) ->
-%% ?vlog("received discovery request", []),
-%% Reply = (catch handle_discovery(Pid, UserId, BAddr, Port, Config,
-%% Expire, ExtraInfo, State)),
-%% {reply, Reply, State};
-
-
handle_call({load_mib, Mib}, _From, State) ->
?vlog("received load_mib request", []),
case snmpm_config:load_mib(Mib) of
@@ -989,13 +960,6 @@ handle_call(is_started, _From, State) ->
IsStarted = is_started(State),
{reply, IsStarted, State};
-%% handle_call({system_info_updated, Target, What}, _From, State) ->
-%% ?vlog("received system_info_updated request: "
-%% "~n Target: ~p"
-%% "~n What: ~p", [Target, What]),
-%% Reply = handle_system_info_updated(State, Target, What),
-%% {reply, Reply, State};
-
handle_call(get_log_type, _From, State) ->
?vlog("received get_log_type request", []),
Reply = handle_get_log_type(State),
@@ -1033,46 +997,41 @@ handle_info({snmp_error, Pdu, Reason}, State) ->
handle_snmp_error(Pdu, Reason, State),
{noreply, State};
-handle_info({snmp_error, Reason, Addr, Port}, State) ->
+handle_info({snmp_error, Reason, Domain, Addr}, State) ->
?vlog("received snmp_error message", []),
- handle_snmp_error(Addr, Port, -1, Reason, State),
+ handle_snmp_error(Domain, Addr, -1, Reason, State),
{noreply, State};
-handle_info({snmp_error, ReqId, Reason, Addr, Port}, State) ->
+handle_info({snmp_error, ReqId, Reason, Domain, Addr}, State) ->
?vlog("received snmp_error message", []),
- handle_snmp_error(Addr, Port, ReqId, Reason, State),
+ handle_snmp_error(Domain, Addr, ReqId, Reason, State),
{noreply, State};
-%% handle_info({snmp_error, ReqId, Pdu, Reason, Addr, Port}, State) ->
-%% ?vlog("received snmp_error message", []),
-%% handle_snmp_error(Pdu, ReqId, Reason, Addr, Port, State),
-%% {noreply, State};
-
-handle_info({snmp_pdu, Pdu, Addr, Port}, State) ->
+handle_info({snmp_pdu, Pdu, Domain, Addr}, State) ->
?vlog("received snmp_pdu message", []),
- handle_snmp_pdu(Pdu, Addr, Port, State),
+ handle_snmp_pdu(Pdu, Domain, Addr, State),
{noreply, State};
-handle_info({snmp_trap, Trap, Addr, Port}, State) ->
+handle_info({snmp_trap, Trap, Domain, Addr}, State) ->
?vlog("received snmp_trap message", []),
- handle_snmp_trap(Trap, Addr, Port, State),
+ handle_snmp_trap(Trap, Domain, Addr, State),
{noreply, State};
-handle_info({snmp_inform, Ref, Pdu, Addr, Port}, State) ->
+handle_info({snmp_inform, Ref, Pdu, Domain, Addr}, State) ->
?vlog("received snmp_inform message", []),
- handle_snmp_inform(Ref, Pdu, Addr, Port, State),
+ handle_snmp_inform(Ref, Pdu, Domain, Addr, State),
{noreply, State};
-handle_info({snmp_report, {ok, Pdu}, Addr, Port}, State) ->
- handle_snmp_report(Pdu, Addr, Port, State),
+handle_info({snmp_report, {ok, Pdu}, Domain, Addr}, State) ->
+ handle_snmp_report(Pdu, Domain, Addr, State),
{noreply, State};
-handle_info({snmp_report, {error, ReqId, Info, Pdu}, Addr, Port}, State) ->
- handle_snmp_report(ReqId, Pdu, Info, Addr, Port, State),
+handle_info({snmp_report, {error, ReqId, Info, Pdu}, Domain, Addr}, State) ->
+ handle_snmp_report(ReqId, Pdu, Info, Domain, Addr, State),
{noreply, State};
@@ -1176,11 +1135,11 @@ handle_sync_get(Pid, UserId, TargetName, Oids, SendOpts, From, State) ->
"~n From: ~p",
[Pid, UserId, TargetName, Oids, SendOpts, From]),
case agent_data(TargetName, SendOpts) of
- {ok, RegType, Domain, Addr, Port, Vsn, MsgData} ->
+ {ok, RegType, Domain, Addr, Vsn, MsgData} ->
?vtrace("handle_sync_get -> send a ~p message", [Vsn]),
Extra = ?GET_EXTRA(SendOpts),
ReqId = send_get_request(Oids, Vsn, MsgData,
- Domain, Addr, Port,
+ Domain, Addr,
Extra, State),
?vdebug("handle_sync_get -> ReqId: ~p", [ReqId]),
Msg = {sync_timeout, ReqId, From},
@@ -1193,8 +1152,7 @@ handle_sync_get(Pid, UserId, TargetName, Oids, SendOpts, From, State) ->
reg_type = RegType,
target = TargetName,
domain = Domain,
- addr = Addr,
- port = Port,
+ address = Addr,
type = get,
data = MsgData,
ref = Ref,
@@ -1230,11 +1188,11 @@ handle_sync_get_next(Pid, UserId, TargetName, Oids, SendOpts,
"~n From: ~p",
[Pid, UserId, TargetName, Oids, SendOpts, From]),
case agent_data(TargetName, SendOpts) of
- {ok, RegType, Domain, Addr, Port, Vsn, MsgData} ->
+ {ok, RegType, Domain, Addr, Vsn, MsgData} ->
?vtrace("handle_sync_get_next -> send a ~p message", [Vsn]),
Extra = ?GET_EXTRA(SendOpts),
ReqId = send_get_next_request(Oids, Vsn, MsgData,
- Domain, Addr, Port,
+ Domain, Addr,
Extra, State),
?vdebug("handle_sync_get_next -> ReqId: ~p", [ReqId]),
Msg = {sync_timeout, ReqId, From},
@@ -1247,12 +1205,11 @@ handle_sync_get_next(Pid, UserId, TargetName, Oids, SendOpts,
reg_type = RegType,
target = TargetName,
domain = Domain,
- addr = Addr,
- port = Port,
+ address = Addr,
type = get_next,
data = MsgData,
ref = Ref,
- mon = MonRef,
+ mon = MonRef,
from = From},
ets:insert(snmpm_request_table, Req),
ok;
@@ -1290,11 +1247,11 @@ handle_sync_get_bulk(Pid, UserId, TargetName, NonRep, MaxRep, Oids, SendOpts,
"~n From: ~p",
[Pid, UserId, TargetName, NonRep, MaxRep, Oids, SendOpts, From]),
case agent_data(TargetName, SendOpts) of
- {ok, RegType, Domain, Addr, Port, Vsn, MsgData} ->
+ {ok, RegType, Domain, Addr, Vsn, MsgData} ->
?vtrace("handle_sync_get_bulk -> send a ~p message", [Vsn]),
Extra = ?GET_EXTRA(SendOpts),
ReqId = send_get_bulk_request(Oids, Vsn, MsgData,
- Domain, Addr, Port,
+ Domain, Addr,
NonRep, MaxRep, Extra, State),
?vdebug("handle_sync_get_bulk -> ReqId: ~p", [ReqId]),
Msg = {sync_timeout, ReqId, From},
@@ -1307,8 +1264,7 @@ handle_sync_get_bulk(Pid, UserId, TargetName, NonRep, MaxRep, Oids, SendOpts,
reg_type = RegType,
target = TargetName,
domain = Domain,
- addr = Addr,
- port = Port,
+ address = Addr,
type = get_bulk,
data = MsgData,
ref = Ref,
@@ -1346,11 +1302,11 @@ handle_sync_set(Pid, UserId, TargetName, VarsAndVals, SendOpts, From, State) ->
"~n From: ~p",
[Pid, UserId, TargetName, VarsAndVals, From]),
case agent_data(TargetName, SendOpts) of
- {ok, RegType, Domain, Addr, Port, Vsn, MsgData} ->
+ {ok, RegType, Domain, Addr, Vsn, MsgData} ->
?vtrace("handle_sync_set -> send a ~p message", [Vsn]),
Extra = ?GET_EXTRA(SendOpts),
ReqId = send_set_request(VarsAndVals, Vsn, MsgData,
- Domain, Addr, Port,
+ Domain, Addr,
Extra, State),
?vdebug("handle_sync_set -> ReqId: ~p", [ReqId]),
Msg = {sync_timeout, ReqId, From},
@@ -1363,8 +1319,7 @@ handle_sync_set(Pid, UserId, TargetName, VarsAndVals, SendOpts, From, State) ->
reg_type = RegType,
target = TargetName,
domain = Domain,
- addr = Addr,
- port = Port,
+ address = Addr,
type = set,
data = MsgData,
ref = Ref,
@@ -1400,11 +1355,11 @@ handle_async_get(Pid, UserId, TargetName, Oids, SendOpts, State) ->
"~n SendOpts: ~p",
[Pid, UserId, TargetName, Oids, SendOpts]),
case agent_data(TargetName, SendOpts) of
- {ok, RegType, Domain, Addr, Port, Vsn, MsgData} ->
+ {ok, RegType, Domain, Addr, Vsn, MsgData} ->
?vtrace("handle_async_get -> send a ~p message", [Vsn]),
Extra = ?GET_EXTRA(SendOpts),
ReqId = send_get_request(Oids, Vsn, MsgData,
- Domain, Addr, Port,
+ Domain, Addr,
Extra, State),
?vdebug("handle_async_get -> ReqId: ~p", [ReqId]),
Expire = ?ASYNC_GET_TIMEOUT(SendOpts),
@@ -1413,11 +1368,10 @@ handle_async_get(Pid, UserId, TargetName, Oids, SendOpts, State) ->
reg_type = RegType,
target = TargetName,
domain = Domain,
- addr = Addr,
- port = Port,
+ address = Addr,
type = get,
data = MsgData,
- expire = t() + Expire},
+ expire = snmp_misc:now(ms) + Expire},
ets:insert(snmpm_request_table, Req),
gct_activate(State#state.gct),
@@ -1450,11 +1404,11 @@ handle_async_get_next(Pid, UserId, TargetName, Oids, SendOpts, State) ->
"~n SendOpts: ~p",
[Pid, UserId, TargetName, Oids, SendOpts]),
case agent_data(TargetName, SendOpts) of
- {ok, RegType, Domain, Addr, Port, Vsn, MsgData} ->
+ {ok, RegType, Domain, Addr, Vsn, MsgData} ->
?vtrace("handle_async_get_next -> send a ~p message", [Vsn]),
Extra = ?GET_EXTRA(SendOpts),
ReqId = send_get_next_request(Oids, Vsn, MsgData,
- Domain, Addr, Port,
+ Domain, Addr,
Extra, State),
?vdebug("handle_async_get_next -> ReqId: ~p", [ReqId]),
Expire = ?ASYNC_GET_NEXT_TIMEOUT(SendOpts),
@@ -1463,11 +1417,10 @@ handle_async_get_next(Pid, UserId, TargetName, Oids, SendOpts, State) ->
reg_type = RegType,
target = TargetName,
domain = Domain,
- addr = Addr,
- port = Port,
+ address = Addr,
type = get_next,
data = MsgData,
- expire = t() + Expire},
+ expire = snmp_misc:now(ms) + Expire},
ets:insert(snmpm_request_table, Req),
gct_activate(State#state.gct),
@@ -1507,11 +1460,11 @@ handle_async_get_bulk(Pid,
"~n SendOpts: ~p",
[Pid, UserId, TargetName, NonRep, MaxRep, Oids, SendOpts]),
case agent_data(TargetName, SendOpts) of
- {ok, RegType, Domain, Addr, Port, Vsn, MsgData} ->
+ {ok, RegType, Domain, Addr, Vsn, MsgData} ->
?vtrace("handle_async_get_bulk -> send a ~p message", [Vsn]),
Extra = ?GET_EXTRA(SendOpts),
ReqId = send_get_bulk_request(Oids, Vsn, MsgData,
- Domain, Addr, Port,
+ Domain, Addr,
NonRep, MaxRep, Extra, State),
?vdebug("handle_async_get_bulk -> ReqId: ~p", [ReqId]),
Expire = ?ASYNC_GET_BULK_TIMEOUT(SendOpts),
@@ -1520,11 +1473,10 @@ handle_async_get_bulk(Pid,
reg_type = RegType,
target = TargetName,
domain = Domain,
- addr = Addr,
- port = Port,
+ address = Addr,
type = get_bulk,
data = MsgData,
- expire = t() + Expire},
+ expire = snmp_misc:now(ms) + Expire},
ets:insert(snmpm_request_table, Req),
gct_activate(State#state.gct),
{ok, ReqId};
@@ -1556,11 +1508,11 @@ handle_async_set(Pid, UserId, TargetName, VarsAndVals, SendOpts, State) ->
"~n SendOpts: ~p",
[Pid, UserId, TargetName, VarsAndVals, SendOpts]),
case agent_data(TargetName, SendOpts) of
- {ok, RegType, Domain, Addr, Port, Vsn, MsgData} ->
+ {ok, RegType, Domain, Addr, Vsn, MsgData} ->
?vtrace("handle_async_set -> send a ~p message", [Vsn]),
Extra = ?GET_EXTRA(SendOpts),
ReqId = send_set_request(VarsAndVals, Vsn, MsgData,
- Domain, Addr, Port,
+ Domain, Addr,
Extra, State),
?vdebug("handle_async_set -> ReqId: ~p", [ReqId]),
Expire = ?ASYNC_SET_TIMEOUT(SendOpts),
@@ -1569,11 +1521,10 @@ handle_async_set(Pid, UserId, TargetName, VarsAndVals, SendOpts, State) ->
reg_type = RegType,
target = TargetName,
domain = Domain,
- addr = Addr,
- port = Port,
+ address = Addr,
type = set,
data = MsgData,
- expire = t() + Expire},
+ expire = snmp_misc:now(ms) + Expire},
ets:insert(snmpm_request_table, Req),
gct_activate(State#state.gct),
@@ -1609,18 +1560,6 @@ handle_cancel_async_request(UserId, ReqId, _State) ->
?vlog("handle_cancel_async_request -> not found", []),
{error, not_found}
end.
-
-
-%% handle_system_info_updated(#state{net_if = Pid, net_if_mod = Mod} = _State,
-%% net_if = _Target, What) ->
-%% case (catch Mod:system_info_updated(Pid, What)) of
-%% {'EXIT', _} ->
-%% {error, not_supported};
-%% Else ->
-%% Else
-%% end;
-%% handle_system_info_updated(_State, Target, What) ->
-%% {error, {bad_target, Target, What}}.
handle_get_log_type(#state{net_if = Pid, net_if_mod = Mod}) ->
case (catch Mod:get_log_type(Pid)) of
@@ -1638,47 +1577,6 @@ handle_set_log_type(#state{net_if = Pid, net_if_mod = Mod}, NewType) ->
Else
end.
-
-%% handle_discovery(Pid, UserId, BAddr, Port, Config, Expire, ExtraInfo, State) ->
-%% ?vtrace("handle_discovery -> entry with"
-%% "~n Pid: ~p"
-%% "~n UserId: ~p"
-%% "~n BAddr: ~p"
-%% "~n Port: ~p"
-%% "~n Config: ~p"
-%% "~n Expire: ~p",
-%% [Pid, UserId, BAddr, Port, Config, Expire]),
-%% case agent_data(default, default, "", Config) of
-%% {ok, Addr, Port, Vsn, MsgData} ->
-%% ?vtrace("handle_discovery -> send a ~p disco message", [Vsn]),
-%% ReqId = send_discovery(Vsn, MsgData, BAddr, Port, ExtraInfo,
-%% State),
-%% ?vdebug("handle_discovery -> ReqId: ~p", [ReqId]),
-%% MonRef = erlang:monitor(process, Pid),
-%% ?vtrace("handle_discovery -> MonRef: ~p", [MonRef]),
-%% Req = #request{id = ReqId,
-%% user_id = UserId,
-%% target = TargetName,
-%% addr = BAddr,
-%% port = Port,
-%% type = get,
-%% data = MsgData,
-%% mon = MonRef,
-%% discovery = true,
-%% expire = t() + Expire},
-%% ets:insert(snmpm_request_table, Req),
-%% gct_activate(State#state.gct),
-%% {ok, ReqId};
-
-%% Error ->
-%% ?vinfo("failed retrieving agent data for discovery (get):"
-%% "~n BAddr: ~p"
-%% "~n Port: ~p"
-%% "~n Error: ~p", [BAddr, Port, Error]),
-%% Error
-%% end.
-
-
handle_sync_timeout(ReqId, From, State) ->
?vtrace("handle_sync_timeout -> entry with"
"~n ReqId: ~p"
@@ -1702,7 +1600,7 @@ handle_sync_timeout(ReqId, From, State) ->
Req = Req0#request{ref = undefined,
mon = undefined,
from = undefined,
- expire = t()},
+ expire = snmp_misc:now(ms)},
ets:insert(snmpm_request_table, Req),
gct_activate(State#state.gct),
ok;
@@ -1808,15 +1706,15 @@ handle_snmp_error(CrapError, Reason, _State) ->
"~n~p~n~p", [CrapError, Reason]),
ok.
-handle_snmp_error(Addr, Port, ReqId, Reason, State) ->
+handle_snmp_error(Domain, Addr, ReqId, Reason, State) ->
- ?vtrace("handle_snmp_error -> entry with"
- "~n Addr: ~p"
- "~n Port: ~p"
- "~n ReqId: ~p"
- "~n Reason: ~p", [Addr, Port, ReqId, Reason]),
+ ?vtrace("handle_snmp_error -> entry with~n"
+ " Domain: ~p~n"
+ " Addr: ~p~n"
+ " ReqId: ~p~n"
+ " Reason: ~p", [Domain, Addr, ReqId, Reason]),
- case snmpm_config:get_agent_user_id(Addr, Port) of
+ case snmpm_config:get_agent_user_id(Domain, Addr) of
{ok, UserId} ->
case snmpm_config:user_info(UserId) of
{ok, UserMod, UserData} ->
@@ -1831,7 +1729,7 @@ handle_snmp_error(Addr, Port, ReqId, Reason, State) ->
error_msg("failed retreiving the default user "
"info handling snmp error "
"<~p,~p>: ~n~w~n~w",
- [Addr, Port, ReqId, Reason])
+ [Domain, Addr, ReqId, Reason])
end
end;
_Error ->
@@ -1843,7 +1741,7 @@ handle_snmp_error(Addr, Port, ReqId, Reason, State) ->
error_msg("failed retreiving the default user "
"info handling snmp error "
"<~p,~p>: ~n~w~n~w",
- [Addr, Port, ReqId, Reason])
+ [Domain, Addr, ReqId, Reason])
end
end.
@@ -1851,18 +1749,28 @@ handle_snmp_error(Addr, Port, ReqId, Reason, State) ->
handle_error(_UserId, Mod, Reason, ReqId, Data, _State) ->
?vtrace("handle_error -> entry when"
"~n Mod: ~p", [Mod]),
- F = fun() -> (catch Mod:handle_error(ReqId, Reason, Data)) end,
+ F = fun() ->
+ try
+ begin
+ Mod:handle_error(ReqId, Reason, Data)
+ end
+ catch
+ T:E ->
+ CallbackArgs = [ReqId, Reason, Data],
+ handle_invalid_result(handle_error, CallbackArgs, T, E)
+ end
+ end,
handle_callback(F),
ok.
handle_snmp_pdu(#pdu{type = 'get-response', request_id = ReqId} = Pdu,
- Addr, Port, State) ->
+ Domain, Addr, State) ->
- ?vtrace("handle_snmp_pdu(get-response) -> entry with"
- "~n Addr: ~p"
- "~n Port: ~p"
- "~n Pdu: ~p", [Addr, Port, Pdu]),
+ ?vtrace("handle_snmp_pdu(get-response) -> entry with~n"
+ " Domain: ~p~n"
+ " Addr: ~p~n"
+ " Pdu: ~p", [Domain, Addr, Pdu]),
case ets:lookup(snmpm_request_table, ReqId) of
@@ -1892,9 +1800,10 @@ handle_snmp_pdu(#pdu{type = 'get-response', request_id = ReqId} = Pdu,
SnmpResponse = {EStatus, EIndex, Varbinds2},
case snmpm_config:user_info(UserId) of
{ok, UserMod, UserData} ->
- handle_pdu(UserId, UserMod,
- RegType, Target, Addr, Port,
- ReqId, SnmpResponse, UserData, State),
+ handle_pdu(
+ UserId, UserMod,
+ RegType, Target, Domain, Addr,
+ ReqId, SnmpResponse, UserData, State),
maybe_delete(Disco, ReqId);
_Error ->
%% reply to outstanding request, for which there is no
@@ -1902,15 +1811,16 @@ handle_snmp_pdu(#pdu{type = 'get-response', request_id = ReqId} = Pdu,
%% Therefor send it to the default user
case snmpm_config:user_info() of
{ok, DefUserId, DefMod, DefData} ->
- handle_pdu(DefUserId, DefMod,
- RegType, Target, Addr, Port,
- ReqId, SnmpResponse, DefData, State),
+ handle_pdu(
+ DefUserId, DefMod,
+ RegType, Target, Domain, Addr,
+ ReqId, SnmpResponse, DefData, State),
maybe_delete(Disco, ReqId);
Error ->
error_msg("failed retreiving the default user "
"info handling pdu from "
"~p <~p,~p>: ~n~w~n~w",
- [Target, Addr, Port, Error, Pdu])
+ [Target, Domain, Addr, Error, Pdu])
end
end;
@@ -1964,7 +1874,7 @@ handle_snmp_pdu(#pdu{type = 'get-response', request_id = ReqId} = Pdu,
varbinds = Varbinds} = Pdu,
Varbinds2 = fix_vbs_BITS(Varbinds),
SnmpInfo = {EStatus, EIndex, Varbinds2},
- case snmpm_config:get_agent_user_id(Addr, Port) of
+ case snmpm_config:get_agent_user_id(Domain, Addr) of
{ok, UserId} ->
%% A very late reply or a reply to a request
%% that has been cancelled.
@@ -1989,7 +1899,7 @@ handle_snmp_pdu(#pdu{type = 'get-response', request_id = ReqId} = Pdu,
"user info handling (old) "
"pdu from "
"<~p,~p>: ~n~w~n~w",
- [Addr, Port, Error, Pdu])
+ [Domain, Addr, Error, Pdu])
end
end;
@@ -2006,86 +1916,141 @@ handle_snmp_pdu(#pdu{type = 'get-response', request_id = ReqId} = Pdu,
"no agent info found", []),
case snmpm_config:user_info() of
{ok, DefUserId, DefMod, DefData} ->
- handle_agent(DefUserId, DefMod,
- Addr, Port,
- pdu, ignore,
- SnmpInfo, DefData, State);
+ handle_agent(
+ DefUserId, DefMod,
+ Domain, Addr,
+ pdu, ignore,
+ SnmpInfo, DefData, State);
Error ->
error_msg("failed retreiving the default user "
"info handling (old) pdu when no user "
"found from "
"<~p,~p>: ~n~w~n~w",
- [Addr, Port, Error, Pdu])
+ [Domain, Addr, Error, Pdu])
end
end
end;
-handle_snmp_pdu(CrapPdu, Addr, Port, _State) ->
+handle_snmp_pdu(CrapPdu, Domain, Addr, _State) ->
error_msg("received crap (snmp) Pdu from ~w:~w =>"
- "~p", [Addr, Port, CrapPdu]),
+ "~p", [Domain, Addr, CrapPdu]),
ok.
-handle_pdu(_UserId, Mod, target_name = _RegType, TargetName, _Addr, _Port,
- ReqId, SnmpResponse, Data, _State) ->
+handle_pdu(
+ _UserId, Mod, target_name = _RegType, TargetName, _Domain, _Addr,
+ ReqId, SnmpResponse, Data, _State) ->
?vtrace("handle_pdu(target_name) -> entry when"
"~n Mod: ~p", [Mod]),
F = fun() ->
- (catch Mod:handle_pdu(TargetName, ReqId, SnmpResponse, Data))
+ try
+ begin
+ Mod:handle_pdu(TargetName, ReqId, SnmpResponse, Data)
+ end
+ catch
+ T:E ->
+ CallbackArgs = [TargetName, ReqId, SnmpResponse, Data],
+ handle_invalid_result(handle_pdu, CallbackArgs, T, E)
+ end
end,
handle_callback(F),
ok;
-handle_pdu(_UserId, Mod, addr_port = _RegType, _TargetName, Addr, Port,
- ReqId, SnmpResponse, Data, _State) ->
+handle_pdu(
+ _UserId, Mod, addr_port = _RegType, _TargetName, _Domain, Addr,
+ ReqId, SnmpResponse, Data, _State) ->
?vtrace("handle_pdu(addr_port) -> entry when"
"~n Mod: ~p", [Mod]),
F = fun() ->
- (catch Mod:handle_pdu(Addr, Port, ReqId, SnmpResponse, Data))
+ {Ip, Port} = Addr,
+ (catch Mod:handle_pdu(Ip, Port, ReqId, SnmpResponse, Data))
end,
handle_callback(F),
ok.
-handle_agent(UserId, Mod, Addr, Port, Type, Ref, SnmpInfo, Data, State) ->
+handle_agent(UserId, Mod, Domain, Addr, Type, Ref, SnmpInfo, Data, State) ->
?vtrace("handle_agent -> entry when"
"~n UserId: ~p"
"~n Type: ~p"
"~n Mod: ~p", [UserId, Type, Mod]),
F = fun() ->
- do_handle_agent(UserId, Mod, Addr, Port,
+ do_handle_agent(UserId, Mod, Domain, Addr,
Type, Ref, SnmpInfo, Data, State)
end,
handle_callback(F),
ok.
do_handle_agent(DefUserId, DefMod,
- Addr, Port,
+ Domain, Addr,
Type, Ref,
SnmpInfo, DefData, State) ->
?vdebug("do_handle_agent -> entry when"
"~n DefUserId: ~p", [DefUserId]),
- case (catch DefMod:handle_agent(Addr, Port, Type, SnmpInfo, DefData)) of
- {'EXIT', {undef, _}} when Type =:= pdu ->
+ {Domain_or_Ip, Addr_or_Port} =
+ case Domain of
+ snmpUDPDomain ->
+ Addr;
+ _ ->
+ {Domain, Addr}
+ end,
+ try DefMod:handle_agent(
+ Domain_or_Ip, Addr_or_Port, Type, SnmpInfo, DefData)
+ of
+ {register, UserId2, TargetName, Config} ->
+ ?vtrace("do_handle_agent -> register: "
+ "~n UserId2: ~p"
+ "~n TargetName: ~p"
+ "~n Config: ~p",
+ [UserId2, TargetName, Config]),
+ Config2 =
+ ensure_present(
+ [{tdomain, Domain}, {taddress, Addr}], Config),
+ Config3 = [{reg_type, target_name} | Config2],
+ case snmpm_config:register_agent(UserId2,
+ TargetName, Config3) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ error_msg("failed registering agent - "
+ "handling agent "
+ "~p <~p,~p>: ~n~w",
+ [TargetName, Domain, Addr, Reason]),
+ ok
+ end;
+
+ ignore ->
+ ?vdebug("do_handle_agent -> ignore", []),
+ ok;
+
+ InvalidResult ->
+ CallbackArgs =
+ [Domain_or_Ip, Addr_or_Port, Type, SnmpInfo, DefData],
+ handle_invalid_result(handle_agent, CallbackArgs, InvalidResult)
+
+ catch
+ error:{undef, _} when Type =:= pdu ->
%% Maybe, still on the old API
?vdebug("do_handle_agent -> maybe still on the old api", []),
- case (catch DefMod:handle_agent(Addr, Port, SnmpInfo, DefData)) of
+ {Ip, Port} = Addr,
+ case (catch DefMod:handle_agent(Ip, Port, SnmpInfo, DefData)) of
{register, UserId2, Config} ->
?vtrace("do_handle_agent -> register: "
"~n UserId2: ~p"
"~n Config: ~p", [UserId2, Config]),
- TargetName = mk_target_name(Addr, Port, Config),
- Config2 = [{reg_type, addr_port},
- {address, Addr},
- {port, Port} | Config],
- case snmpm_config:register_agent(UserId2,
- TargetName, Config2) of
+ TargetName = mk_target_name(Domain, Addr, Config),
+ Config2 =
+ ensure_present(
+ [{tdomain, Domain}, {taddress, Addr}], Config),
+ Config3 = [{reg_type, addr_port} | Config2],
+ case snmpm_config:register_agent(
+ UserId2, TargetName, Config3) of
ok ->
ok;
{error, Reason} ->
error_msg("failed registering agent - "
"handling agent "
"~p <~p,~p>: ~n~w",
- [TargetName, Addr, Port, Reason]),
+ [TargetName, Domain, Addr, Reason]),
ok
end;
{register, UserId2, TargetName, Config} ->
@@ -2094,18 +2059,19 @@ do_handle_agent(DefUserId, DefMod,
"~n TargetName: ~p"
"~n Config: ~p",
[UserId2, TargetName, Config]),
- Config2 = ensure_present([{address, Addr}, {port, Port}],
- Config),
+ Config2 =
+ ensure_present(
+ [{tdomain, Domain}, {taddress, Addr}], Config),
Config3 = [{reg_type, target_name} | Config2],
- case snmpm_config:register_agent(UserId2,
- TargetName, Config3) of
+ case snmpm_config:register_agent(
+ UserId2, TargetName, Config3) of
ok ->
ok;
{error, Reason} ->
error_msg("failed registering agent - "
"handling agent "
"~p <~p,~p>: ~n~w",
- [TargetName, Addr, Port, Reason]),
+ [TargetName, Domain, Addr, Reason]),
ok
end;
_Ignore ->
@@ -2113,66 +2079,51 @@ do_handle_agent(DefUserId, DefMod,
ok
end;
- {'EXIT', {undef, _}} ->
+ error:{undef, _} ->
%% If the user does not implement the new API (but the
%% old), then this clause catches all non-pdu handle_agent
- %% calls. These calls was previously never made,so we make
+ %% calls. These calls was previously never made, so we make
%% a best-effert call (using reg-type target_name) to the
%% various callback functions, and leave it to the user to
%% figure out
%% Backward compatibillity crap
RegType = target_name,
- Target = mk_target_name(Addr, Port, default_agent_config()),
+ Target = mk_target_name(Domain, Addr, default_agent_config()),
case Type of
report ->
SnmpInform = SnmpInfo,
- handle_report(DefUserId, DefMod,
- RegType, Target, Addr, Port,
- SnmpInform, DefData, State);
+ handle_report(
+ DefUserId, DefMod,
+ RegType, Target, Domain, Addr,
+ SnmpInform, DefData, State);
inform ->
SnmpInform = SnmpInfo,
- handle_inform(DefUserId, DefMod, Ref,
- RegType, Target, Addr, Port,
- SnmpInform, DefData, State);
+ handle_inform(
+ DefUserId, DefMod, Ref,
+ RegType, Target, Domain, Addr,
+ SnmpInform, DefData, State);
trap ->
SnmpTrapInfo = SnmpInfo,
- handle_trap(DefUserId, DefMod,
- RegType, Target, Addr, Port,
- SnmpTrapInfo, DefData, State);
+ handle_trap(
+ DefUserId, DefMod,
+ RegType, Target, Domain, Addr,
+ SnmpTrapInfo, DefData, State);
_ ->
- error_msg("failed delivering ~w info to default user - "
- "regarding agent "
- "<~p,~p>: ~n~w", [Type, Addr, Port, SnmpInfo])
- end;
-
- {register, UserId2, TargetName, Config} ->
- ?vtrace("do_handle_agent -> register: "
- "~n UserId2: ~p"
- "~n TargetName: ~p"
- "~n Config: ~p",
- [UserId2, TargetName, Config]),
- Config2 = ensure_present([{address, Addr}, {port, Port}], Config),
- Config3 = [{reg_type, target_name} | Config2],
- case snmpm_config:register_agent(UserId2,
- TargetName, Config3) of
- ok ->
- ok;
- {error, Reason} ->
- error_msg("failed registering agent - "
- "handling agent "
- "~p <~p,~p>: ~n~w",
- [TargetName, Addr, Port, Reason]),
- ok
+ error_msg(
+ "failed delivering ~w info to default user - "
+ "regarding agent "
+ "<~p,~p>: ~n~w", [Type, Domain, Addr, SnmpInfo])
end;
- _Ignore ->
- ?vdebug("do_handle_agent -> ignore", []),
- ok
-
+ T:E ->
+ CallbackArgs =
+ [Domain_or_Ip, Addr_or_Port, Type, SnmpInfo, DefData],
+ handle_invalid_result(handle_agent, CallbackArgs, T, E)
+
end.
ensure_present([], Config) ->
@@ -2188,50 +2139,51 @@ ensure_present([{Key, _Val} = Elem|Ensure], Config) ->
%% Retrieve user info for this agent.
%% If this is an unknown agent, then use the default user
-handle_snmp_trap(#trappdu{enterprise = Enteprise,
- generic_trap = Generic,
- specific_trap = Spec,
- time_stamp = Timestamp,
- varbinds = Varbinds} = Trap,
- Addr, Port, State) ->
-
- ?vtrace("handle_snmp_trap [trappdu] -> entry with"
- "~n Addr: ~p"
- "~n Port: ~p"
- "~n Trap: ~p", [Addr, Port, Trap]),
+handle_snmp_trap(
+ #trappdu{enterprise = Enteprise,
+ generic_trap = Generic,
+ specific_trap = Spec,
+ time_stamp = Timestamp,
+ varbinds = Varbinds} = Trap, Domain, Addr, State) ->
+
+ ?vtrace("handle_snmp_trap [trappdu] -> entry with~n"
+ " Domain: ~p~n"
+ " Addr: ~p~n"
+ " Trap: ~p", [Domain, Addr, Trap]),
Varbinds2 = fix_vbs_BITS(Varbinds),
SnmpTrapInfo = {Enteprise, Generic, Spec, Timestamp, Varbinds2},
- do_handle_snmp_trap(SnmpTrapInfo, Addr, Port, State);
+ do_handle_snmp_trap(SnmpTrapInfo, Domain, Addr, State);
handle_snmp_trap(#pdu{error_status = EStatus,
error_index = EIndex,
varbinds = Varbinds} = Trap,
- Addr, Port, State) ->
+ Domain, Addr, State) ->
- ?vtrace("handle_snmp_trap [pdu] -> entry with"
- "~n Addr: ~p"
- "~n Port: ~p"
- "~n Trap: ~p", [Addr, Port, Trap]),
+ ?vtrace("handle_snmp_trap [pdu] -> entry with~n"
+ " Domain: ~p~n"
+ " Addr: ~p~n"
+ " Trap: ~p", [Domain, Addr, Trap]),
Varbinds2 = fix_vbs_BITS(Varbinds),
SnmpTrapInfo = {EStatus, EIndex, Varbinds2},
- do_handle_snmp_trap(SnmpTrapInfo, Addr, Port, State);
+ do_handle_snmp_trap(SnmpTrapInfo, Domain, Addr, State);
-handle_snmp_trap(CrapTrap, Addr, Port, _State) ->
+handle_snmp_trap(CrapTrap, Domain, Addr, _State) ->
error_msg("received crap (snmp) trap from ~w:~w =>"
- "~p", [Addr, Port, CrapTrap]),
+ "~p", [Domain, Addr, CrapTrap]),
ok.
-do_handle_snmp_trap(SnmpTrapInfo, Addr, Port, State) ->
- case snmpm_config:get_agent_user_info(Addr, Port) of
+do_handle_snmp_trap(SnmpTrapInfo, Domain, Addr, State) ->
+ case snmpm_config:get_agent_user_info(Domain, Addr) of
{ok, UserId, Target, RegType} ->
?vtrace("handle_snmp_trap -> found user: ~p", [UserId]),
case snmpm_config:user_info(UserId) of
{ok, Mod, Data} ->
- handle_trap(UserId, Mod,
- RegType, Target, Addr, Port,
- SnmpTrapInfo, Data, State);
+ handle_trap(
+ UserId, Mod,
+ RegType, Target, Domain, Addr,
+ SnmpTrapInfo, Data, State);
Error1 ->
%% User no longer exists, unregister agent
@@ -2243,84 +2195,94 @@ do_handle_snmp_trap(SnmpTrapInfo, Addr, Port, State) ->
%% Try use the default user
case snmpm_config:user_info() of
{ok, DefUserId, DefMod, DefData} ->
- handle_agent(DefUserId, DefMod,
- Addr, Port,
- trap, ignore,
- SnmpTrapInfo, DefData, State);
+ handle_agent(
+ DefUserId, DefMod,
+ Domain, Addr,
+ trap, ignore,
+ SnmpTrapInfo, DefData, State);
Error2 ->
- error_msg("failed retreiving the default "
- "user info handling report from "
- "~p <~p,~p>: ~n~w~n~w",
- [Target, Addr, Port,
- Error2, SnmpTrapInfo])
+ error_msg(
+ "failed retreiving the default "
+ "user info handling report from "
+ "~p <~p,~p>: ~n~w~n~w",
+ [Target, Domain, Addr,
+ Error2, SnmpTrapInfo])
end;
Error3 ->
%% Failed unregister agent,
%% now its getting messy...
- warning_msg("failed unregister agent ~p <~p,~p> "
- "belonging to non-existing "
- "user ~p, handling trap: "
- "~n Error: ~w"
- "~n Trap info: ~w",
- [Target, Addr, Port, UserId,
- Error3, SnmpTrapInfo])
+ warning_msg(
+ "failed unregister agent ~p <~p,~p> "
+ "belonging to non-existing "
+ "user ~p, handling trap: "
+ "~n Error: ~w"
+ "~n Trap info: ~w",
+ [Target, Domain, Addr, UserId,
+ Error3, SnmpTrapInfo])
end
end;
Error4 ->
%% Unknown agent, pass it on to the default user
?vlog("[trap] failed retreiving user id for agent <~p,~p>: "
- "~n ~p", [Addr, Port, Error4]),
+ "~n ~p", [Domain, Addr, Error4]),
case snmpm_config:user_info() of
{ok, DefUserId, DefMod, DefData} ->
- handle_agent(DefUserId, DefMod,
- Addr, Port,
- trap, ignore,
- SnmpTrapInfo, DefData, State);
+ handle_agent(
+ DefUserId, DefMod,
+ Domain, Addr,
+ trap, ignore,
+ SnmpTrapInfo, DefData, State);
Error5 ->
- error_msg("failed retreiving "
- "the default user info handling trap from "
- "<~p,~p>: ~n~w~n~w",
- [Addr, Port, Error5, SnmpTrapInfo])
+ error_msg(
+ "failed retreiving "
+ "the default user info handling trap from "
+ "<~p,~p>: ~n~w~n~w",
+ [Domain, Addr, Error5, SnmpTrapInfo])
end
end,
ok.
-handle_trap(UserId, Mod,
- RegType, Target, Addr, Port, SnmpTrapInfo, Data, State) ->
+handle_trap(
+ UserId, Mod, RegType, Target, Domain, Addr, SnmpTrapInfo, Data, State) ->
?vtrace("handle_trap -> entry with"
"~n UserId: ~p"
"~n Mod: ~p", [UserId, Mod]),
F = fun() ->
- do_handle_trap(UserId, Mod,
- RegType, Target, Addr, Port,
- SnmpTrapInfo, Data, State)
+ do_handle_trap(
+ UserId, Mod,
+ RegType, Target, Domain, Addr,
+ SnmpTrapInfo, Data, State)
end,
handle_callback(F),
ok.
-do_handle_trap(UserId, Mod,
- RegType, Target, Addr, Port, SnmpTrapInfo, Data, _State) ->
+do_handle_trap(
+ UserId, Mod, RegType, Target, Domain, Addr, SnmpTrapInfo, Data, _State) ->
?vdebug("do_handle_trap -> entry with"
"~n UserId: ~p", [UserId]),
- HandleTrap =
+ {HandleTrap, CallbackArgs} =
case RegType of
target_name ->
- fun() -> Mod:handle_trap(Target, SnmpTrapInfo, Data) end;
+ {fun() -> Mod:handle_trap(Target, SnmpTrapInfo, Data) end,
+ [Target, SnmpTrapInfo, Data]};
addr_port ->
- fun() -> Mod:handle_trap(Addr, Port, SnmpTrapInfo, Data) end
+ {Ip, Port} = Addr,
+ {fun() -> Mod:handle_trap(Ip, Port, SnmpTrapInfo, Data) end,
+ [Ip, Port, SnmpTrapInfo, Data]}
end,
- case (catch HandleTrap()) of
+ try HandleTrap() of
{register, UserId2, Config} ->
?vtrace("do_handle_trap -> register: "
"~n UserId2: ~p"
"~n Config: ~p", [UserId2, Config]),
- Target2 = mk_target_name(Addr, Port, Config),
- Config2 = [{reg_type, target_name},
- {address, Addr}, {port, Port} | Config],
+ Target2 = mk_target_name(Domain, Addr, Config),
+ Config2 =
+ [{reg_type, target_name},
+ {tdomain, Domain}, {taddress, Addr} | Config],
case snmpm_config:register_agent(UserId2, Target2, Config2) of
ok ->
ok;
@@ -2328,7 +2290,7 @@ do_handle_trap(UserId, Mod,
error_msg("failed registering agent "
"handling trap "
"<~p,~p>: ~n~w",
- [Addr, Port, Reason]),
+ [Domain, Addr, Reason]),
ok
end;
{register, UserId2, Target2, Config} ->
@@ -2346,50 +2308,59 @@ do_handle_trap(UserId, Mod,
error_msg("failed registering agent "
"handling trap "
"~p <~p,~p>: ~n~w",
- [Target2, Addr, Port, Reason]),
+ [Target2, Domain, Addr, Reason]),
reply
end;
unregister ->
?vtrace("do_handle_trap -> unregister", []),
- case snmpm_config:unregister_agent(UserId,
- Addr, Port) of
+ case snmpm_config:unregister_agent(UserId, Domain, Addr) of
ok ->
ok;
{error, Reason} ->
error_msg("failed unregistering agent "
"handling trap "
"<~p,~p>: ~n~w",
- [Addr, Port, Reason]),
+ [Domain, Addr, Reason]),
ok
end;
- _Ignore ->
+ ignore ->
?vtrace("do_handle_trap -> ignore", []),
- ok
+ ok;
+
+ InvalidResult ->
+ handle_invalid_result(handle_trap, CallbackArgs, InvalidResult)
+
+ catch
+ T:E ->
+ handle_invalid_result(handle_trap, CallbackArgs, T, E)
+
end.
-handle_snmp_inform(Ref,
- #pdu{error_status = EStatus,
- error_index = EIndex,
- varbinds = Varbinds} = Pdu, Addr, Port, State) ->
+handle_snmp_inform(
+ Ref,
+ #pdu{error_status = EStatus,
+ error_index = EIndex,
+ varbinds = Varbinds} = Pdu, Domain, Addr, State) ->
- ?vtrace("handle_snmp_inform -> entry with"
- "~n Addr: ~p"
- "~n Port: ~p"
- "~n Pdu: ~p", [Addr, Port, Pdu]),
+ ?vtrace("handle_snmp_inform -> entry with~n"
+ " Domain: ~p~n"
+ " Addr: ~p~n"
+ " Pdu: ~p", [Domain, Addr, Pdu]),
Varbinds2 = fix_vbs_BITS(Varbinds),
SnmpInform = {EStatus, EIndex, Varbinds2},
- case snmpm_config:get_agent_user_info(Addr, Port) of
+ case snmpm_config:get_agent_user_info(Domain, Addr) of
{ok, UserId, Target, RegType} ->
case snmpm_config:user_info(UserId) of
{ok, Mod, Data} ->
?vdebug("[inform] callback handle_inform with: "
"~n UserId: ~p"
"~n Mod: ~p", [UserId, Mod]),
- handle_inform(UserId, Mod, Ref,
- RegType, Target, Addr, Port,
- SnmpInform, Data, State);
+ handle_inform(
+ UserId, Mod, Ref,
+ RegType, Target, Domain, Addr,
+ SnmpInform, Data, State);
Error1 ->
%% User no longer exists, unregister agent
case snmpm_config:unregister_agent(UserId, Target) of
@@ -2400,15 +2371,16 @@ handle_snmp_inform(Ref,
"~n ~p", [UserId, Error1]),
case snmpm_config:user_info() of
{ok, DefUserId, DefMod, DefData} ->
- handle_agent(DefUserId, DefMod,
- Addr, Port,
- inform, Ref,
- SnmpInform, DefData, State);
+ handle_agent(
+ DefUserId, DefMod,
+ Domain, Addr,
+ inform, Ref,
+ SnmpInform, DefData, State);
Error2 ->
error_msg("failed retreiving the default "
"user info handling inform from "
"~p <~p,~p>: ~n~w~n~w",
- [Target, Addr, Port,
+ [Target, Domain, Addr,
Error2, Pdu])
end;
Error3 ->
@@ -2419,7 +2391,7 @@ handle_snmp_inform(Ref,
"user ~p, handling inform: "
"~n Error: ~w"
"~n Pdu: ~w",
- [Target, Addr, Port, UserId,
+ [Target, Domain, Addr, UserId,
Error3, Pdu])
end
end;
@@ -2427,63 +2399,72 @@ handle_snmp_inform(Ref,
Error4 ->
%% Unknown agent, pass it on to the default user
?vlog("[inform] failed retreiving user id for agent <~p,~p>: "
- "~n ~p", [Addr, Port, Error4]),
+ "~n ~p", [Domain, Addr, Error4]),
case snmpm_config:user_info() of
{ok, DefUserId, DefMod, DefData} ->
- handle_agent(DefUserId, DefMod,
- Addr, Port,
- inform, Ref,
- SnmpInform, DefData, State);
+ handle_agent(
+ DefUserId, DefMod,
+ Domain, Addr,
+ inform, Ref,
+ SnmpInform, DefData, State);
Error5 ->
error_msg("failed retreiving "
"the default user info handling inform from "
"<~p,~p>: ~n~w~n~w",
- [Addr, Port, Error5, Pdu])
+ [Domain, Addr, Error5, Pdu])
end
end,
ok;
-handle_snmp_inform(_Ref, CrapInform, Addr, Port, _State) ->
+handle_snmp_inform(_Ref, CrapInform, Domain, Addr, _State) ->
error_msg("received crap (snmp) inform from ~w:~w =>"
- "~p", [Addr, Port, CrapInform]),
+ "~p", [Domain, Addr, CrapInform]),
ok.
-handle_inform(UserId, Mod, Ref,
- RegType, Target, Addr, Port, SnmpInform, Data, State) ->
+handle_inform(
+ UserId, Mod, Ref,
+ RegType, Target, Domain, Addr, SnmpInform, Data, State) ->
?vtrace("handle_inform -> entry with"
"~n UserId: ~p"
"~n Mod: ~p", [UserId, Mod]),
F = fun() ->
- do_handle_inform(UserId, Mod, Ref,
- RegType, Target, Addr, Port, SnmpInform,
- Data, State)
+ do_handle_inform(
+ UserId, Mod, Ref,
+ RegType, Target, Domain, Addr, SnmpInform,
+ Data, State)
end,
handle_callback(F),
ok.
-do_handle_inform(UserId, Mod, Ref,
- RegType, Target, Addr, Port, SnmpInform, Data, State) ->
+do_handle_inform(
+ UserId, Mod, Ref,
+ RegType, Target, Domain, Addr, SnmpInform, Data, State) ->
?vdebug("do_handle_inform -> entry with"
"~n UserId: ~p", [UserId]),
- HandleInform =
+ {HandleInform, CallbackArgs} =
case RegType of
target_name ->
- fun() -> Mod:handle_inform(Target, SnmpInform, Data) end;
+ {fun() -> Mod:handle_inform(Target, SnmpInform, Data) end,
+ [Target, SnmpInform, Data]};
addr_port ->
- fun() -> Mod:handle_inform(Addr, Port, SnmpInform, Data) end
+ {Ip, Port} = Addr,
+ {fun() -> Mod:handle_inform(Ip, Port, SnmpInform, Data) end,
+ [Ip, Port, SnmpInform, Data]}
end,
Rep =
- case (catch HandleInform()) of
+ try HandleInform() of
{register, UserId2, Config} ->
?vtrace("do_handle_inform -> register: "
"~n UserId2: ~p"
"~n Config: ~p", [UserId2, Config]),
%% The only user which would do this is the
%% default user
- Target2 = mk_target_name(Addr, Port, Config),
- Config2 = [{reg_type, target_name},
- {address, Addr}, {port, Port} | Config],
+ Target2 = mk_target_name(Domain, Addr, Config),
+ Config2 =
+ [{reg_type, target_name} |
+ ensure_present(
+ [{tdomain, Domain}, {taddress, Addr}], Config)],
case snmpm_config:register_agent(UserId2, Target2, Config2) of
ok ->
reply;
@@ -2491,9 +2472,10 @@ do_handle_inform(UserId, Mod, Ref,
error_msg("failed registering agent "
"handling inform "
"~p <~p,~p>: ~n~w",
- [Target2, Addr, Port, Reason]),
+ [Target2, Domain, Addr, Reason]),
reply
end;
+
{register, UserId2, Target2, Config} ->
?vtrace("do_handle_inform -> register: "
"~n UserId2: ~p"
@@ -2509,54 +2491,71 @@ do_handle_inform(UserId, Mod, Ref,
error_msg("failed registering agent "
"handling inform "
"~p <~p,~p>: ~n~w",
- [Target2, Addr, Port, Reason]),
+ [Target2, Domain, Addr, Reason]),
reply
end;
+
unregister ->
?vtrace("do_handle_inform -> unregister", []),
- case snmpm_config:unregister_agent(UserId,
- Addr, Port) of
+ case snmpm_config:unregister_agent(
+ UserId, Domain, Addr) of
ok ->
reply;
{error, Reason} ->
error_msg("failed unregistering agent "
"handling inform "
"<~p,~p>: ~n~w",
- [Addr, Port, Reason]),
+ [Domain, Addr, Reason]),
reply
end;
+
no_reply ->
?vtrace("do_handle_inform -> no_reply", []),
no_reply;
- _Ignore ->
+
+ ignore ->
?vtrace("do_handle_inform -> ignore", []),
+ reply;
+
+ InvalidResult ->
+ handle_invalid_result(
+ handle_inform, CallbackArgs, InvalidResult),
+ reply
+
+ catch
+ T:E ->
+ handle_invalid_result(handle_inform, CallbackArgs, T, E),
reply
+
end,
- handle_inform_response(Rep, Ref, Addr, Port, State),
+ handle_inform_response(Rep, Ref, Domain, Addr, State),
ok.
-handle_inform_response(_, ignore, _Addr, _Port, _State) ->
+handle_inform_response(_, ignore, _Domain, _Addr, _State) ->
ignore;
-handle_inform_response(no_reply, _Ref, _Addr, _Port, _State) ->
+handle_inform_response(no_reply, _Ref, _Domain, _Addr, _State) ->
no_reply;
-handle_inform_response(_, Ref, Addr, Port,
- #state{net_if = Pid, net_if_mod = Mod}) ->
+handle_inform_response(
+ _, Ref, Domain, Addr,
+ #state{net_if = Pid, net_if_mod = Mod}) ->
?vdebug("handle_inform -> response", []),
- (catch Mod:inform_response(Pid, Ref, Addr, Port)).
+ (catch Mod:inform_response(Pid, Ref, Domain, Addr)).
-handle_snmp_report(#pdu{error_status = EStatus,
- error_index = EIndex,
- varbinds = Varbinds} = Pdu, Addr, Port, State) ->
+handle_snmp_report(
+ #pdu{error_status = EStatus,
+ error_index = EIndex,
+ varbinds = Varbinds} = Pdu,
+ Domain, Addr, State) ->
- ?vtrace("handle_snmp_report -> entry with"
- "~n Addr: ~p"
- "~n Port: ~p"
- "~n Pdu: ~p", [Addr, Port, Pdu]),
+ ?vtrace("handle_snmp_report -> entry with~n"
+ " Domain: ~p~n"
+ " Addr: ~p~n"
+ " Pdu: ~p", [Domain, Addr, Pdu]),
Varbinds2 = fix_vbs_BITS(Varbinds),
SnmpReport = {EStatus, EIndex, Varbinds2},
- case snmpm_config:get_agent_user_info(Addr, Port) of
+ case snmpm_config:get_agent_user_info(Domain, Addr) of
{ok, UserId, Target, RegType} ->
case snmpm_config:user_info(UserId) of
{ok, Mod, Data} ->
@@ -2566,7 +2565,7 @@ handle_snmp_report(#pdu{error_status = EStatus,
"~n ~p"
"~n ~p", [UserId, Mod, Target, SnmpReport]),
handle_report(UserId, Mod,
- RegType, Target, Addr, Port,
+ RegType, Target, Domain, Addr,
SnmpReport, Data, State);
Error1 ->
%% User no longer exists, unregister agent
@@ -2579,7 +2578,7 @@ handle_snmp_report(#pdu{error_status = EStatus,
case snmpm_config:user_info() of
{ok, DefUserId, DefMod, DefData} ->
handle_agent(DefUserId, DefMod,
- Addr, Port,
+ Domain, Addr,
report, ignore,
SnmpReport, DefData, State);
@@ -2587,7 +2586,7 @@ handle_snmp_report(#pdu{error_status = EStatus,
error_msg("failed retreiving the default "
"user info handling report from "
"~p <~p,~p>: ~n~w~n~w",
- [Target, Addr, Port,
+ [Target, Domain, Addr,
Error2, Pdu])
end;
Error3 ->
@@ -2598,7 +2597,7 @@ handle_snmp_report(#pdu{error_status = EStatus,
"user ~p, handling report: "
"~n Error: ~w"
"~n Report: ~w",
- [Target, Addr, Port, UserId,
+ [Target, Domain, Addr, UserId,
Error3, Pdu])
end
end;
@@ -2606,25 +2605,25 @@ handle_snmp_report(#pdu{error_status = EStatus,
Error4 ->
%% Unknown agent, pass it on to the default user
?vlog("[report] failed retreiving user id for agent <~p,~p>: "
- "~n ~p", [Addr, Port, Error4]),
+ "~n ~p", [Domain, Addr, Error4]),
case snmpm_config:user_info() of
{ok, DefUserId, DefMod, DefData} ->
handle_agent(DefUserId, DefMod,
- Addr, Port,
+ Domain, Addr,
report, ignore,
SnmpReport, DefData, State);
Error5 ->
error_msg("failed retreiving "
"the default user info handling report from "
"<~p,~p>: ~n~w~n~w",
- [Addr, Port, Error5, Pdu])
+ [Domain, Addr, Error5, Pdu])
end
end,
ok;
-handle_snmp_report(CrapReport, Addr, Port, _State) ->
+handle_snmp_report(CrapReport, Domain, Addr, _State) ->
error_msg("received crap (snmp) report from ~w:~w =>"
- "~p", [Addr, Port, CrapReport]),
+ "~p", [Domain, Addr, CrapReport]),
ok.
%% This could be from a failed get-request, so we might have a user
@@ -2632,20 +2631,20 @@ handle_snmp_report(CrapReport, Addr, Port, _State) ->
%% get-response (except for tha data which is different). Otherwise,
%% we handle it as an error (reported via the handle_error callback
%% function).
-handle_snmp_report(ReqId,
- #pdu{error_status = EStatus,
- error_index = EIndex,
- varbinds = Varbinds} = Pdu,
- {ReportReason, Info} = Rep,
- Addr, Port, State)
- when is_integer(ReqId) ->
-
- ?vtrace("handle_snmp_report -> entry with"
- "~n Addr: ~p"
- "~n Port: ~p"
- "~n ReqId: ~p"
- "~n Rep: ~p"
- "~n Pdu: ~p", [Addr, Port, ReqId, Rep, Pdu]),
+handle_snmp_report(
+ ReqId,
+ #pdu{error_status = EStatus,
+ error_index = EIndex,
+ varbinds = Varbinds} = Pdu,
+ {ReportReason, Info} = Rep,
+ Domain, Addr, State) when is_integer(ReqId) ->
+
+ ?vtrace("handle_snmp_report -> entry with~n"
+ " Domain: ~p~n"
+ " Addr: ~p~n"
+ " ReqId: ~p~n"
+ " Rep: ~p~n"
+ " Pdu: ~p", [Domain, Addr, ReqId, Rep, Pdu]),
Varbinds2 = fix_vbs_BITS(Varbinds),
SnmpReport = {EStatus, EIndex, Varbinds2},
@@ -2690,7 +2689,7 @@ handle_snmp_report(ReqId,
%% Either not a sync request or no such request. Either
%% way, this is error info, so handle it as such.
- case snmpm_config:get_agent_user_id(Addr, Port) of
+ case snmpm_config:get_agent_user_id(Domain, Addr) of
{ok, UserId} ->
case snmpm_config:user_info(UserId) of
{ok, Mod, Data} ->
@@ -2714,7 +2713,7 @@ handle_snmp_report(ReqId,
"default user "
"info handling report from "
"<~p,~p>: ~n~w~n~w~n~w",
- [Addr, Port, Error,
+ [Domain, Addr, Error,
ReqId, Reason])
end
end;
@@ -2722,7 +2721,7 @@ handle_snmp_report(ReqId,
%% Unknown agent, pass it on to the default user
?vlog("[report] failed retreiving user id for "
"agent <~p,~p>: "
- "~n ~p", [Addr, Port, Error]),
+ "~n ~p", [Domain, Addr, Error]),
case snmpm_config:user_info() of
{ok, DefUserId, DefMod, DefData} ->
handle_error(DefUserId, DefMod, Reason, ReqId,
@@ -2732,62 +2731,71 @@ handle_snmp_report(ReqId,
"the default user info handling "
"report from "
"<~p,~p>: ~n~w~n~w~n~w",
- [Addr, Port, Error, ReqId, Reason])
+ [Domain, Addr, Error, ReqId, Reason])
end
end
end,
ok;
-handle_snmp_report(CrapReqId, CrapReport, CrapInfo, Addr, Port, _State) ->
- error_msg("received crap (snmp) report from ~w:~w =>"
- "~n~p~n~p~n~p", [Addr, Port, CrapReqId, CrapReport, CrapInfo]),
+handle_snmp_report(CrapReqId, CrapReport, CrapInfo, Domain, Addr, _State) ->
+ error_msg(
+ "received crap (snmp) report from ~w:~w =>"
+ "~n~p~n~p~n~p",
+ [Domain, Addr, CrapReqId, CrapReport, CrapInfo]),
ok.
-handle_report(UserId, Mod, RegType, Target, Addr, Port,
+handle_report(UserId, Mod, RegType, Target, Domain, Addr,
SnmpReport, Data, State) ->
?vtrace("handle_report -> entry with"
"~n UserId: ~p"
"~n Mod: ~p", [UserId, Mod]),
F = fun() ->
- do_handle_report(UserId, Mod, RegType, Target, Addr, Port,
- SnmpReport, Data, State)
+ do_handle_report(
+ UserId, Mod, RegType, Target, Domain, Addr,
+ SnmpReport, Data, State)
end,
handle_callback(F),
ok.
-do_handle_report(UserId, Mod,
- RegType, Target, Addr, Port, SnmpReport, Data, _State) ->
+do_handle_report(
+ UserId, Mod, RegType, Target, Domain, Addr,
+ SnmpReport, Data, _State) ->
?vdebug("do_handle_report -> entry with"
"~n UserId: ~p", [UserId]),
- HandleReport =
+ {HandleReport, CallbackArgs} =
case RegType of
target_name ->
- fun() -> Mod:handle_report(Target, SnmpReport, Data) end;
+ {fun() -> Mod:handle_report(Target, SnmpReport, Data) end,
+ [Target, SnmpReport, Data]};
addr_port ->
- fun() -> Mod:handle_report(Addr, Port, SnmpReport, Data) end
+ {Ip, Port} = Addr,
+ {fun() -> Mod:handle_report(Ip, Port, SnmpReport, Data) end,
+ [Ip, Port, SnmpReport, Data]}
end,
- case (catch HandleReport()) of
+ try HandleReport() of
{register, UserId2, Config} ->
?vtrace("do_handle_report -> register: "
"~n UserId2: ~p"
"~n Config: ~p", [UserId2, Config]),
%% The only user which would do this is the
%% default user
- Target2 = mk_target_name(Addr, Port, Config),
- Config2 = [{reg_type, target_name},
- {address, Addr}, {port, Port} | Config],
+ Target2 = mk_target_name(Domain, Addr, Config),
+ Config2 =
+ [{reg_type, target_name},
+ {tdomain, Domain}, {taddress, Addr} | Config],
case snmpm_config:register_agent(UserId2, Target2, Config2) of
ok ->
ok;
{error, Reason} ->
error_msg("failed registering agent "
"handling report "
- "<~p,~p>: ~n~w",
- [Addr, Port, Reason]),
+ "<~p,~p>: ~n~w",
+ [Domain, Addr, Reason]),
ok
end;
+
{register, UserId2, Target2, Config} ->
?vtrace("do_handle_report -> register: "
"~n UserId2: ~p"
@@ -2803,25 +2811,36 @@ do_handle_report(UserId, Mod,
error_msg("failed registering agent "
"handling report "
"~p <~p,~p>: ~n~w",
- [Target2, Addr, Port, Reason]),
+ [Target2, Domain, Addr, Reason]),
reply
end;
+
unregister ->
?vtrace("do_handle_trap -> unregister", []),
- case snmpm_config:unregister_agent(UserId,
- Addr, Port) of
+ case snmpm_config:unregister_agent(UserId, Domain, Addr) of
ok ->
ok;
{error, Reason} ->
error_msg("failed unregistering agent "
"handling report "
"<~p,~p>: ~n~w",
- [Addr, Port, Reason]),
+ [Domain, Addr, Reason]),
ok
end;
- _Ignore ->
+
+ ignore ->
?vtrace("do_handle_report -> ignore", []),
- ok
+ ok;
+
+ InvalidResult ->
+ handle_invalid_result(handle_report, CallbackArgs, InvalidResult),
+ reply
+
+ catch
+ T:E ->
+ handle_invalid_result(handle_report, CallbackArgs, T, E),
+ reply
+
end.
@@ -2835,6 +2854,25 @@ handle_callback(F) ->
end).
+
+handle_invalid_result(Func, Args, T, E) ->
+ Stacktrace = ?STACK(),
+ error_msg("Callback function failed: "
+ "~n Function: ~p"
+ "~n Args: ~p"
+ "~n Error Type: ~p"
+ "~n Error: ~p"
+ "~n Stacktrace: ~p",
+ [Func, Args, T, E, Stacktrace]).
+
+handle_invalid_result(Func, Args, InvalidResult) ->
+ error_msg("Callback function returned invalid result: "
+ "~n Function: ~p"
+ "~n Args: ~p"
+ "~n Invalid result: ~p",
+ [Func, Args, InvalidResult]).
+
+
handle_down(MonRef) ->
(catch do_handle_down(MonRef)).
@@ -2895,7 +2933,7 @@ cancel_timer(Ref) ->
handle_gc(GCT) ->
ets:safe_fixtable(snmpm_request_table, true),
- case do_gc(ets:first(snmpm_request_table), t()) of
+ case do_gc(ets:first(snmpm_request_table), snmp_misc:now(ms)) of
0 ->
gct_deactivate(GCT);
_ ->
@@ -2924,69 +2962,56 @@ do_gc(Key, Now) ->
%%
%%----------------------------------------------------------------------
-send_get_request(Oids, Vsn, MsgData, Domain, Addr, Port, ExtraInfo,
+send_get_request(Oids, Vsn, MsgData, Domain, Addr, ExtraInfo,
#state{net_if = NetIf,
net_if_mod = Mod,
mini_mib = MiniMIB}) ->
Pdu = make_pdu(get, Oids, MiniMIB),
- ?vtrace("send_get_request -> send get-request:"
- "~n Mod: ~p"
- "~n NetIf: ~p"
- "~n Pdu: ~p"
- "~n Vsn: ~p"
- "~n MsgData: ~p"
- "~n Domain: ~p"
- "~n Addr: ~p"
- "~n Port: ~p",
- [Mod, NetIf, Pdu, Vsn, MsgData, Domain, Addr, Port]),
+ ?vtrace("send_get_request -> send get-request:~n"
+ " Mod: ~p~n"
+ " NetIf: ~p~n"
+ " Pdu: ~p~n"
+ " Vsn: ~p~n"
+ " MsgData: ~p~n"
+ " Domain: ~p~n"
+ " Addr: ~p",
+ [Mod, NetIf, Pdu, Vsn, MsgData, Domain, Addr]),
Res = (catch Mod:send_pdu(NetIf, Pdu, Vsn, MsgData,
- Domain, Addr, Port, ExtraInfo)),
+ Domain, Addr, ExtraInfo)),
?vtrace("send_get_request -> send result:"
"~n ~p", [Res]),
Pdu#pdu.request_id.
-send_get_next_request(Oids, Vsn, MsgData, Domain, Addr, Port, ExtraInfo,
+send_get_next_request(Oids, Vsn, MsgData, Domain, Addr, ExtraInfo,
#state{mini_mib = MiniMIB,
net_if = NetIf,
net_if_mod = Mod}) ->
Pdu = make_pdu(get_next, Oids, MiniMIB),
- Mod:send_pdu(NetIf, Pdu, Vsn, MsgData, Domain, Addr, Port, ExtraInfo),
+ Mod:send_pdu(NetIf, Pdu, Vsn, MsgData, Domain, Addr, ExtraInfo),
Pdu#pdu.request_id.
-send_get_bulk_request(Oids, Vsn, MsgData, Domain, Addr, Port,
+send_get_bulk_request(Oids, Vsn, MsgData, Domain, Addr,
NonRep, MaxRep, ExtraInfo,
#state{mini_mib = MiniMIB,
net_if = NetIf,
net_if_mod = Mod}) ->
Pdu = make_pdu(bulk, {NonRep, MaxRep, Oids}, MiniMIB),
- Mod:send_pdu(NetIf, Pdu, Vsn, MsgData, Domain, Addr, Port, ExtraInfo),
+ Mod:send_pdu(NetIf, Pdu, Vsn, MsgData, Domain, Addr, ExtraInfo),
Pdu#pdu.request_id.
-send_set_request(VarsAndVals, Vsn, MsgData, Domain, Addr, Port, ExtraInfo,
+send_set_request(VarsAndVals, Vsn, MsgData, Domain, Addr, ExtraInfo,
#state{mini_mib = MiniMIB,
net_if = NetIf,
net_if_mod = Mod}) ->
Pdu = make_pdu(set, VarsAndVals, MiniMIB),
- Mod:send_pdu(NetIf, Pdu, Vsn, MsgData, Domain, Addr, Port, ExtraInfo),
+ Mod:send_pdu(NetIf, Pdu, Vsn, MsgData, Domain, Addr, ExtraInfo),
Pdu#pdu.request_id.
-%% send_discovery(Vsn, MsgData, Addr, Port, ExtraInfo,
-%% #state{net_if = NetIf,
-%% net_if_mod = Mod}) ->
-%% Pdu = make_discovery_pdu(),
-%% Mod:send_pdu(NetIf, Pdu, Vsn, MsgData, Addr, Port, ExtraInfo),
-%% Pdu#pdu.request_id.
-
-
%%----------------------------------------------------------------------
%%
%%----------------------------------------------------------------------
-%% make_discovery_pdu() ->
-%% Oids = [?sysObjectID_instance, ?sysDescr_instance, ?sysUpTime_instance],
-%% make_pdu_impl(get, Oids).
-
make_pdu(set, VarsAndVals, MiniMIB) ->
VBs = [var_and_value_to_varbind(VAV, MiniMIB) || VAV <- VarsAndVals],
make_pdu_impl(set, VBs);
@@ -3163,17 +3188,16 @@ request_id() ->
%%----------------------------------------------------------------------
agent_data(TargetName, SendOpts) ->
- case snmpm_config:agent_info(TargetName, all) of
- {ok, Info} ->
- Version = agent_data_item(version, Info),
+ case snmpm_config:agent_info(TargetName, version) of
+ {ok, Version} ->
MsgData =
case Version of
v3 ->
- DefSecModel = agent_data_item(sec_model, Info),
- DefSecName = agent_data_item(sec_name, Info),
- DefSecLevel = agent_data_item(sec_level, Info),
+ DefSecModel = agent_data_item(sec_model, TargetName),
+ DefSecName = agent_data_item(sec_name, TargetName),
+ DefSecLevel = agent_data_item(sec_level, TargetName),
- EngineId = agent_data_item(engine_id, Info),
+ EngineId = agent_data_item(engine_id, TargetName),
CtxName = agent_data_item(context,
SendOpts,
?DEFAULT_CONTEXT),
@@ -3191,8 +3215,8 @@ agent_data(TargetName, SendOpts) ->
{SecModel, SecName, mk_sec_level_flag(SecLevel),
EngineId, CtxName, TargetName};
_ ->
- DefComm = agent_data_item(community, Info),
- DefSecModel = agent_data_item(sec_model, Info),
+ DefComm = agent_data_item(community, TargetName),
+ DefSecModel = agent_data_item(sec_model, TargetName),
Comm = agent_data_item(community,
SendOpts,
@@ -3203,21 +3227,20 @@ agent_data(TargetName, SendOpts) ->
{Comm, SecModel}
end,
- Domain = agent_data_item(tdomain, Info),
- Addr = agent_data_item(address, Info),
- Port = agent_data_item(port, Info),
- RegType = agent_data_item(reg_type, Info),
- {ok, RegType, Domain, Addr, Port, version(Version), MsgData};
+ Domain = agent_data_item(tdomain, TargetName),
+ Addr = agent_data_item(taddress, TargetName),
+ RegType = agent_data_item(reg_type, TargetName),
+ {ok, RegType, Domain, Addr, version(Version), MsgData};
Error ->
Error
end.
-agent_data_item(Item, Info) ->
- case lists:keysearch(Item, 1, Info) of
- {value, {_, Val}} ->
+agent_data_item(Item, TargetName) ->
+ case snmpm_config:agent_info(TargetName, Item) of
+ {ok, Val} ->
Val;
- false ->
- throw({error, {not_found, Item, Info}})
+ {error, not_found} ->
+ throw({error, {not_found, Item, TargetName}})
end.
agent_data_item(Item, Info, Default) ->
@@ -3271,7 +3294,7 @@ gct_init(#gct{parent = Parent, timeout = Timeout} = State) ->
gct(State, Timeout).
gct(#gct{parent = Parent, state = active} = State, Timeout) ->
- T = t(),
+ T = snmp_misc:now(ms),
receive
{stop, Parent} ->
ok;
@@ -3329,7 +3352,7 @@ gct(#gct{parent = Parent, state = idle} = State, Timeout) ->
end.
new_timeout(T1, T2) ->
- case T1 - (t() - T2) of
+ case T1 - (snmp_misc:now(ms) - T2) of
T when (T > 0) ->
T;
_ ->
@@ -3349,13 +3372,8 @@ maybe_demonitor(undefined) ->
maybe_demonitor(MonRef) ->
erlang:demonitor(MonRef).
-%% Time in milli seconds
-t() ->
- {A,B,C} = erlang:now(),
- A*1000000000+B*1000+(C div 1000).
-
-mk_target_name(Addr, Port, Config) ->
- snmpm_config:mk_target_name(Addr, Port, Config).
+mk_target_name(Domain, Addr, Config) ->
+ snmpm_config:mk_target_name(Domain, Addr, Config).
default_agent_config() ->
case snmpm_config:agent_info() of
@@ -3392,12 +3410,6 @@ call(Req) ->
call(Req, To) ->
gen_server:call(?SERVER, Req, To).
-%% cast(Msg) ->
-%% gen_server:cast(?SERVER, Msg).
-
-%% info_msg(F, A) ->
-%% ?snmpm_info("Server: " ++ F, A).
-
warning_msg(F, A) ->
?snmpm_warning("Server: " ++ F, A).
@@ -3473,20 +3485,3 @@ note_store_info(Pid) ->
%%----------------------------------------------------------------------
-
-
-%%----------------------------------------------------------------------
-%% Debug
-%%----------------------------------------------------------------------
-
-% sz(L) when is_list(L) ->
-% length(lists:flatten(L));
-% sz(B) when is_binary(B) ->
-% size(B).
-
-%% p(F) ->
-%% p(F, []).
-
-%% p(F, A) ->
-%% io:format("~w:" ++ F ++ "~n", [?MODULE | A]).
-
diff --git a/lib/snmp/src/manager/snmpm_server_sup.erl b/lib/snmp/src/manager/snmpm_server_sup.erl
index 16238e4aaf..842a5761ce 100644
--- a/lib/snmp/src/manager/snmpm_server_sup.erl
+++ b/lib/snmp/src/manager/snmpm_server_sup.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
diff --git a/lib/snmp/src/manager/snmpm_supervisor.erl b/lib/snmp/src/manager/snmpm_supervisor.erl
index 8f43310c14..c36bbe1bdd 100644
--- a/lib/snmp/src/manager/snmpm_supervisor.erl
+++ b/lib/snmp/src/manager/snmpm_supervisor.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
diff --git a/lib/snmp/src/manager/snmpm_user.erl b/lib/snmp/src/manager/snmpm_user.erl
index 78aa560b2e..c0100d372f 100644
--- a/lib/snmp/src/manager/snmpm_user.erl
+++ b/lib/snmp/src/manager/snmpm_user.erl
@@ -1,97 +1,124 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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(snmpm_user).
--export([behaviour_info/1]).
-
-behaviour_info(callbacks) ->
- [{handle_error, 3},
- {handle_agent, 5},
- {handle_pdu, 4},
- {handle_trap, 3},
- {handle_inform, 3},
- {handle_report, 3}];
-behaviour_info(_) ->
- undefined.
-
-
-%% handle_error(ReqId, Reason, UserData) -> Reply
-%% ReqId -> integer()
-%% Reason -> term()
-%% UserData -> term() (supplied when the user register)
-%% Reply -> ignore
-
-%% handle_agent(Addr, Port, Type, SnmpInfo, UserData) -> Reply
-%% Addr -> term()
-%% Port -> integer()
-%% Type -> pdu | trap | inform | report
-%% SnmpInfo -> {ErrorStatus, ErrorIndex, Varbinds}
-%% UserId -> term()
-%% ErrorStatus -> atom()
-%% ErrorIndex -> integer()
-%% Varbinds -> [varbind()]
-%% UserData -> term() (supplied when the user register)
-%% Reply -> ignore | {register, UserId, agent_info()}
-%% agent_info() -> [{agent_info_item(), agent_info_value()}]
-%% This is the same info as in update_agent_info/4
-
-%% handle_pdu(TargetName, ReqId, SnmpResponse, UserData) -> Reply
-%% TargetName -> target_name()
-%% ReqId -> term() (returned when calling ag(...), ...)
-%% SnmpResponse -> {ErrorStatus, ErrorIndex, Varbinds}
-%% ErrorStatus -> atom()
-%% ErrorIndex -> integer()
-%% Varbinds -> [varbind()]
-%% UserData -> term() (supplied when the user register)
-%% Reply -> ignore
-
-%% handle_trap(TargetName, SnmpTrapInfo, UserData) -> Reply
-%% TargetName -> target_name()
-%% SnmpTrapInfo -> {Enteprise, Generic, Spec, Timestamp, Varbinds} |
-%% {ErrorStatus, ErrorIndex, Varbinds}
-%% Enteprise -> oid()
-%% Generic -> integer()
-%% Spec -> integer()
-%% Timestamp -> integer()
-%% ErrorStatus -> atom()
-%% ErrorIndex -> integer()
-%% Varbinds -> [varbind()]
-%% UserData -> term() (supplied when the user register)
-%% Reply -> ignore | unregister | {register, UserId, agent_info()}
-
-%% handle_inform(TargetName, SnmpInform, UserData) -> Reply
-%% TargetName -> target_name()
-%% SnmpInform -> {ErrorStatus, ErrorIndex, Varbinds}
-%% ErrorStatus -> atom()
-%% ErrorIndex -> integer()
-%% Varbinds -> [varbind()]
-%% UserData -> term() (supplied when the user register)
-%% Reply -> ignore | unregister | {register, UserId, agent_info()}
-%%
-
-%% handle_report(TargetName, SnmpReport, UserData) -> Reply
-%% TargetName -> target_name()
-%% SnmpReport -> {ErrorStatus, ErrorIndex, Varbinds}
-%% ErrorStatus -> integer()
-%% ErrorIndex -> integer()
-%% Varbinds -> [varbind()]
-%% UserData -> term() (supplied when the user register)
-%% Reply -> ignore | unregister | {register, UserId, agent_info()}
+-export_type([
+ snmp_gen_info/0,
+ snmp_v1_trap_info/0
+ ]).
+
+-type snmp_gen_info() :: {ErrorStatus :: atom(),
+ ErrorIndex :: pos_integer(),
+ Varbinds :: [snmp:varbind()]}.
+-type snmp_v1_trap_info() :: {Enteprise :: snmp:oid(),
+ Generic :: integer(),
+ Spec :: integer(),
+ Timestamp :: integer(),
+ Varbinds :: [snmp:varbind()]}.
+-type ip_address() :: inet:ip_address().
+-type port_number() :: inet:port_number().
+
+
+%% *** handle_error ***
+%% An "asynchronous" error has been detected
+
+-callback handle_error(
+ ReqId :: integer(),
+ Reason :: {unexpected_pdu, SnmpInfo :: snmp_gen_info()} |
+ {invalid_sec_info,
+ SecInfo :: term(),
+ SnmpInfo :: snmp_gen_info()} |
+ {empty_message,
+ TransportDomain :: atom(),
+ {Addr :: ip_address(), Port :: port_number()}} |
+ term(),
+ UserData :: term()) ->
+ snmp:void().
+
+
+%% *** handle_agent ***
+%% A message was received from an unknown agent
+
+-callback handle_agent(Domain :: atom(),
+ Address :: term(),
+ Type :: pdu | trap | inform | report,
+ SnmpInfo :: snmp_gen_info() | snmp_v1_trap_info(),
+ UserData :: term()) ->
+ Reply :: ignore |
+ {register,
+ UserId :: term(),
+ RTargetName :: snmpm:target_name(),
+ AgentConfig :: [snmpm:agent_config()]}.
+
+
+%% *** handle_pdu ***
+%% Handle the reply to an async request (such as get, get-next and set).
+
+-callback handle_pdu(TargetName :: snmpm:target_name(),
+ ReqId :: term(),
+ SnmpResponse :: snmp_gen_info(),
+ UserData :: term()) ->
+ snmp:void().
+
+
+%% *** handle_trap ***
+%% Handle a trap/notification message received from an agent
+
+-callback handle_trap(TargetName :: snmpm:target_name(),
+ SnmpTrapInfo :: snmp_gen_info() | snmp_v1_trap_info(),
+ UserData :: term()) ->
+ Reply :: ignore |
+ unregister |
+ {register,
+ UserId :: term(),
+ RTargetName :: snmpm:target_name(),
+ AgentConfig :: [snmpm:agent_config()]}.
+
+
+%% *** handle_inform ***
+%% Handle a inform message received from an agent
+
+-callback handle_inform(TargetName :: snmpm:target_name(),
+ SnmpInform :: snmp_gen_info(),
+ UserData :: term()) ->
+ Reply :: ignore | no_reply |
+ unregister |
+ {register,
+ UserId :: term(),
+ RTargetName :: snmpm:target_name(),
+ AgentConfig :: [snmpm:agent_config()]}.
+
+
+%% *** handle_report ***
+%% Handle a report message received from an agent
+
+-callback handle_report(TargetName :: snmpm:target_name(),
+ SnmpReport :: snmp_gen_info(),
+ UserData :: term()) ->
+ Reply :: ignore |
+ unregister |
+ {register,
+ UserId :: term(),
+ RTargetName :: snmpm:target_name(),
+ AgentConfig :: [snmpm:agent_config()]}.
+
+
diff --git a/lib/snmp/src/manager/snmpm_user_default.erl b/lib/snmp/src/manager/snmpm_user_default.erl
index d90fc3f258..bc2b82a38b 100644
--- a/lib/snmp/src/manager/snmpm_user_default.erl
+++ b/lib/snmp/src/manager/snmpm_user_default.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -36,13 +37,13 @@ handle_error(ReqId, Reason, UserData) ->
ignore.
-handle_agent(Addr, Port, Type, SnmpInfo, UserData) ->
- info("received handle_agent:"
- "~n Addr: ~p"
- "~n Port: ~p"
- "~n Type: ~p"
- "~n SnmpInfo: ~p"
- "~n UserData: ~p", [Addr, Port, Type, SnmpInfo, UserData]),
+handle_agent(Domain, Address, Type, SnmpInfo, UserData) ->
+ info("received handle_agent:~n"
+ " Domain: ~p~n"
+ " Address: ~p~n"
+ " Type: ~p~n"
+ " SnmpInfo: ~p~n"
+ " UserData: ~p", [Domain, Address, Type, SnmpInfo, UserData]),
ignore.
@@ -62,7 +63,7 @@ handle_trap(TargetName, SnmpTrap, UserData) ->
"~n SnmpTrap: ~p"
"~n UserData: ~p",
[TargetName, SnmpTrap, UserData]),
- ok.
+ ignore.
handle_inform(TargetName, SnmpInform, UserData) ->
@@ -80,7 +81,7 @@ handle_report(TargetName, SnmpReport, UserData) ->
"~n SnmpReport: ~p"
"~n UserData: ~p",
[TargetName, SnmpReport, UserData]),
- ok.
+ ignore.
info(F, A) ->
diff --git a/lib/snmp/src/manager/snmpm_user_old.erl b/lib/snmp/src/manager/snmpm_user_old.erl
index 69b1470790..bc15ad445b 100644
--- a/lib/snmp/src/manager/snmpm_user_old.erl
+++ b/lib/snmp/src/manager/snmpm_user_old.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
diff --git a/lib/snmp/src/manager/snmpm_usm.erl b/lib/snmp/src/manager/snmpm_usm.erl
index 497d6d6102..7dd79e703a 100644
--- a/lib/snmp/src/manager/snmpm_usm.erl
+++ b/lib/snmp/src/manager/snmpm_usm.erl
@@ -1,24 +1,28 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
%%-----------------------------------------------------------------
%% This module implements the User Based Security Model for SNMP,
%% as defined in rfc2274.
+%%
+%% AES: RFC 3826
+%%
%%-----------------------------------------------------------------
-module(snmpm_usm).
@@ -416,11 +420,14 @@ get_des_salt() ->
[?i32(EngineBoots), ?i32(SaltInt)].
aes_encrypt(PrivKey, Data) ->
- snmp_usm:aes_encrypt(PrivKey, Data, fun get_aes_salt/0).
+ EngineBoots = get_engine_boots(),
+ EngineTime = get_engine_time(),
+ snmp_usm:aes_encrypt(PrivKey, Data, fun get_aes_salt/0,
+ EngineBoots, EngineTime).
aes_decrypt(PrivKey, UsmSecParams, EncData) ->
- #usmSecurityParameters{msgPrivacyParameters = MsgPrivParams,
- msgAuthoritativeEngineTime = EngineTime,
+ #usmSecurityParameters{msgPrivacyParameters = MsgPrivParams,
+ msgAuthoritativeEngineTime = EngineTime,
msgAuthoritativeEngineBoots = EngineBoots} =
UsmSecParams,
snmp_usm:aes_decrypt(PrivKey, MsgPrivParams, EncData,
diff --git a/lib/snmp/src/manager/snmpm_usm.hrl b/lib/snmp/src/manager/snmpm_usm.hrl
index 1939ad6ed9..38d4a1a07e 100644
--- a/lib/snmp/src/manager/snmpm_usm.hrl
+++ b/lib/snmp/src/manager/snmpm_usm.hrl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
diff --git a/lib/snmp/src/misc/Makefile b/lib/snmp/src/misc/Makefile
index 48d76bdbed..adc2c4858f 100644
--- a/lib/snmp/src/misc/Makefile
+++ b/lib/snmp/src/misc/Makefile
@@ -2,18 +2,19 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2003-2009. All Rights Reserved.
+# Copyright Ericsson AB 2003-2016. All Rights Reserved.
#
-# The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved online at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
+# 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%
@@ -109,13 +110,13 @@ info:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/src/misc
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)/src/misc
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
-# $(INSTALL_DIR) $(RELSYSDIR)/include
-# $(INSTALL_DATA) $(EXT_HRL_FILES) $(RELSYSDIR)/include
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src/misc"
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)/src/misc"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
+# $(INSTALL_DIR) "$(RELSYSDIR)/include"
+# $(INSTALL_DATA) $(EXT_HRL_FILES) "$(RELSYSDIR)/include"
release_docs_spec:
diff --git a/lib/snmp/src/misc/depend.mk b/lib/snmp/src/misc/depend.mk
index dea0f75048..b2e0a92997 100644
--- a/lib/snmp/src/misc/depend.mk
+++ b/lib/snmp/src/misc/depend.mk
@@ -2,18 +2,19 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2009. All Rights Reserved.
+# Copyright Ericsson AB 2004-2016. All Rights Reserved.
#
-# The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved online at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
+# 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%
diff --git a/lib/snmp/src/misc/modules.mk b/lib/snmp/src/misc/modules.mk
index 32092aaae2..ac42128724 100644
--- a/lib/snmp/src/misc/modules.mk
+++ b/lib/snmp/src/misc/modules.mk
@@ -2,18 +2,19 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2009. All Rights Reserved.
+# Copyright Ericsson AB 2004-2016. All Rights Reserved.
#
-# The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved online at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
+# 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%
diff --git a/lib/snmp/src/misc/snmp_conf.erl b/lib/snmp/src/misc/snmp_conf.erl
index 7249def24e..513616a285 100644
--- a/lib/snmp/src/misc/snmp_conf.erl
+++ b/lib/snmp/src/misc/snmp_conf.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -25,34 +26,42 @@
%% External exports
%% Avoid warning for local function error/1 clashing with autoimported BIF.
-compile({no_auto_import,[error/1]}).
--export([read_files/2, read/2]).
+-export([read_files/2, no_gen/2, no_order/2, no_filter/1, keyorder/4]).
+-export([read/2, read/3]).
%% Basic (type) check functions
-export([check_mandatory/2,
check_integer/1, check_integer/2,
-
+
check_string/1, check_string/2,
- check_atom/2,
+ check_atom/2,
check_timer/1,
- all_domains/0,
- check_domain/1,
- all_tdomains/0,
- check_tdomain/1,
- mk_tdomain/1,
- which_domain/1,
- check_ip/1, check_ip/2,
- check_taddress/1, check_taddress/2,
- mk_taddress/3,
-
- check_packet_size/1,
+ all_domains/0,
+ check_domain/1,
+ domain_to_name/1,
+ all_tdomains/0,
+ check_tdomain/1,
+ mk_tdomain/0, mk_tdomain/1,
+ tdomain_to_family/1, tdomain_to_domain/1,
+ which_domain/1,
+ mk_addr_string/1,
+ check_ip/1, check_ip/2,
+ check_port/1,
+%% ip_port_to_domaddr/2,
+ check_address/2, check_address/3,
+ check_taddress/2,
+ mk_taddress/1, mk_taddress/2,
+
+ check_packet_size/1,
check_oid/1,
-
- check_mp_model/1,
- check_sec_model/1, check_sec_model/2, check_sec_model/3,
+ check_imask/1, check_emask/1,
+
+ check_mp_model/1,
+ check_sec_model/1, check_sec_model/2, check_sec_model/3,
check_sec_level/1,
all_integer/1
@@ -69,105 +78,198 @@
-include("snmp_verbosity.hrl").
+-define(is_word(P), (((P) band (bnot 65535)) =:= 0)).
+-define(is_word(P0, P1), ((((P0) bor (P1)) band (bnot 255)) =:= 0)).
+
+mk_word(B0, B1) -> ((B0) bsl 8) bor (B1).
+mk_bytes(W) -> [(W) bsr 8,(W) band 255].
+
+-define(
+ is_ipv4_addr(A0, A1, A2, A3),
+ ((((A0) bor (A1) bor (A2) bor (A3)) band (bnot 255)) =:= 0)).
+
+-define(
+ is_ipv6_addr(A0, A1, A2, A3, A4, A5, A6, A7),
+ ((((A0) bor (A1) bor (A2) bor (A3) bor (A4) bor (A5) bor (A6) bor (A7))
+ band (bnot 65535)) =:= 0)).
+-define(
+ is_ipv6_addr(
+ A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15),
+ ((((A0) bor (A1) bor (A2) bor (A3) bor
+ (A4) bor (A5) bor (A6) bor (A7) bor
+ (A8) bor (A9) bor (A10) bor (A11) bor
+ (A12) bor (A13) bor (A14) bor (A15))
+ band (bnot 65535)) =:= 0)).
+
+
%%-----------------------------------------------------------------
+%% read_files(Dir, Files) -> Configs
+%% Dir - string() - Full path to the config dir.
+%% Files - [{FileName, Gen, Order, Check, Filter}]
+%% FileName - string() - Name of the config file.
+%% Gen - function/2 - In case of failure when reading the config file,
+%% this function is called to either generate a
+%% default file or issue the error.
+%% Returns a generated config list corresponding
+%% to the written file.
+%% (Dir, Error) -> Configs.
+%% Order - function/2 - An ordering function that is used to process
+%% the read config entries using lists:sort/2.
+%% Returns true if arg 1 compares less than or
+%% equal to arg 2, false otherwise.
+%% Check - function/2 - Check each entry as they are read from the file.
+%% (Entry, State) ->
+%% {ok,NewState} | {{ok,NewEntry},NewState} |
+%% throw(Error)
+%% State =:= 'undefined' the first time.
+%% Filter - function/1 - Process all the config entries read from the file
+%% (Configs) -> [config_entry()].
+%% Configs - [config_entry()]
+%% config_entry() - term()
+
read_files(Dir, Files) when is_list(Dir) andalso is_list(Files) ->
read_files(Dir, Files, []).
read_files(_Dir, [], Res) ->
lists:reverse(Res);
-read_files(Dir, [{Gen, Filter, Check, FileName}|Files], Res)
- when is_function(Filter) andalso
- is_function(Check) andalso
- is_list(FileName) ->
- ?vdebug("read_files -> entry with"
- "~n FileName: ~p", [FileName]),
+read_files(Dir, [{FileName, Gen, Order, Check, Filter}|Files], Res)
+ when is_list(FileName),
+ is_function(Gen),
+ is_function(Order),
+ is_function(Check),
+ is_function(Filter) ->
+ ?vdebug("read_files -> entry with~n"
+ " FileName: ~p", [FileName]),
File = filename:join(Dir, FileName),
- case file:read_file_info(File) of
- {ok, _} ->
- Confs = read(File, Check),
- read_files(Dir, Files, [Filter(Confs)|Res]);
- {error, R} ->
- ?vlog("failed reading file info for ~s: "
- "~n ~p", [FileName, R]),
- Gen(Dir),
- read_files(Dir, Files, [Filter([])|Res])
- end.
-
+ Confs =
+ case file:read_file_info(File) of
+ {ok,_} ->
+ read(File, Order, Check);
+ {error, R} ->
+ ?vlog("failed reading file info for ~s: ~n"
+ " ~p", [FileName, R]),
+ Gen(Dir, R)
+ end,
+ read_files(Dir, Files, [Filter(Confs)|Res]).
+
+
+
+no_gen(_Dir, _R) -> [].
+no_order(_, _) -> true.
+no_filter(X) -> X.
+
+%% Order tuples on element N with Keys first in appearence order.
+%%
+%% 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.
+keyorder(N, A, B, _) when element(N, A) == element(N, B) ->
+ true;
+keyorder(N, A, B, [Key | _])
+ when tuple_size(A) >= 1, element(N, B) == Key ->
+ false;
+keyorder(N, A, B, [Key | _])
+ when element(N, A) == Key, tuple_size(B) >= 1 ->
+ true;
+keyorder(N, A, B, [_ | Keys]) ->
+ keyorder(N, A, B, Keys);
+keyorder(_, A, B, []) when tuple_size(A) >= 1, tuple_size(B) >= 1 ->
+ %% Do not order other keys
+ true;
+keyorder(N, A, B, sort) ->
+ %% Order other keys according to standard sort order
+ element(N, A) =< element(N, B).
+
+
+read(File, Verify) ->
+ Check = fun (Row, State) -> {Verify(Row), State} end,
+ read(File, fun no_order/2, Check).
%% Ret. Res | exit(Reason)
-read(File, Check) when is_function(Check) ->
- ?vdebug("read -> entry with"
- "~n File: ~p", [File]),
+read(File, Order, Check) when is_function(Order), is_function(Check) ->
+ ?vdebug("read -> entry with~n"
+ " File: ~p", [File]),
Fd = open_file(File),
+ read_fd(File, Order, Check, Fd, 1, []).
+
+read_fd(File, Order, Check, Fd, StartLine, Res) ->
+ case do_read(Fd, "", StartLine) of
+ {ok, Row, EndLine} ->
+ ?vtrace("read_fd ->~n"
+ " Row: ~p~n"
+ " EndLine: ~p", [Row,EndLine]),
+ read_fd(
+ File, Order, Check, Fd, EndLine,
+ [{StartLine, Row, EndLine}|Res]);
+ {error, Error, EndLine} ->
+ ?vtrace("read_fd -> read failure:~n"
+ " Error: ~p~n"
+ " EndLine: ~p", [Error,EndLine]),
+ file:close(Fd),
+ error({failed_reading, File, StartLine, EndLine, Error});
+ {eof, _EndLine} ->
+ Lines =
+ lists:sort(
+ fun ({_, RowA, _}, {_, RowB, _}) ->
+ Order(RowA, RowB)
+ end,
+ lists:reverse(Res)),
+ ?vtrace("read_fd to read_check ->~n"
+ " Lines: ~p", [Lines]),
+ read_check(File, Check, Lines, undefined, [])
+ end.
- case loop(Fd, [], Check, 1, File) of
- {error, Reason} ->
- file:close(Fd),
- error(Reason);
- {ok, Res} ->
- file:close(Fd),
- Res
+read_check(_, _, [], _, Res) ->
+ lists:reverse(Res);
+read_check(File, Check, [{StartLine, Row, EndLine}|Lines], State, Res) ->
+ try Check(Row, State) of
+ {Rows, NewState} when is_list(Rows) ->
+ ?vtrace("read_check -> ok:~n"
+ " Rows: ~p~n", [Rows]),
+ read_check(File, Check, Lines, NewState, Rows ++ Res);
+ {ok, NewState} ->
+ ?vtrace("read_check -> ok", []),
+ read_check(File, Check, Lines, NewState, [Row | Res]);
+ {{ok, NewRow}, NewState} ->
+ ?vtrace("read_check -> ok:~n"
+ " NewRow: ~p~n", [NewRow]),
+ read_check(File, Check, Lines, NewState, [NewRow | Res])
+ catch
+ {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})
end.
open_file(File) ->
case file:open(File, [read]) of
- {ok, Fd} ->
- Fd;
- {error, Reason} ->
- error({failed_open, File, Reason})
- end.
-
-loop(Fd, Res, Check, StartLine, File) ->
- case do_read(Fd, "", StartLine) of
- {ok, Row, EndLine} ->
- ?vtrace("loop -> "
- "~n Row: ~p"
- "~n EndLine: ~p", [Row, EndLine]),
- case (catch Check(Row)) of
- ok ->
- ?vtrace("loop -> ok", []),
- loop(Fd, [Row | Res], Check, EndLine, File);
- {ok, NewRow} ->
- ?vtrace("loop -> ok: "
- "~n NewRow: ~p", [NewRow]),
- loop(Fd, [NewRow | Res], Check, EndLine, File);
- {error, Reason} ->
- ?vtrace("loop -> check error: "
- "~n Reason: ~p", [Reason]),
- {error, {failed_check, File, StartLine, EndLine, Reason}};
- Error ->
- ?vtrace("loop -> check failure: "
- "~n Error: ~p", [Error]),
- {error, {failed_check, File, StartLine, EndLine, Error}}
- end;
- {error, EndLine, Error} ->
- ?vtrace("loop -> read failure: "
- "~n Error: ~p", [Error]),
- {error, {failed_reading, File, StartLine, EndLine, Error}};
- eof ->
- {ok, Res}
+ {ok, Fd} ->
+ Fd;
+ {error, Reason} ->
+ error({failed_open, File, Reason})
end.
-
do_read(Io, Prompt, StartLine) ->
case io:request(Io, {get_until,Prompt,erl_scan,tokens,[StartLine]}) of
- {ok, Toks, EndLine} ->
- case erl_parse:parse_term(Toks) of
- {ok, Term} ->
- {ok, Term, EndLine};
- {error, {Line, erl_parse, Error}} ->
- {error, Line, {parse_error, Error}}
- end;
- {error,E,EndLine} ->
- {error, EndLine, E};
- {eof, _EndLine} ->
- eof;
- Other ->
- Other
+ {ok, Toks, EndLine} ->
+ case erl_parse:parse_term(Toks) of
+ {ok, Term} ->
+ {ok, Term, EndLine};
+ {error, {Line, erl_parse, Error}} ->
+ {error, {parse_error, Error}, Line}
+ end;
+ Other ->
+ Other
end.
+
%%-----------------------------------------------------------------
@@ -370,7 +472,7 @@ all_tdomains() ->
check_tdomain(TDomain) ->
SupportedTDomains =
[
- ?snmpUDPDomain,
+ ?snmpUDPDomain, % Legacy
?transportDomainUdpIpv4,
?transportDomainUdpIpv6
],
@@ -390,6 +492,9 @@ check_tdomain(TDomain) ->
%% ---------
+mk_tdomain() ->
+ mk_tdomain(snmpUDPDomain).
+
mk_tdomain(snmpUDPDomain) ->
mk_tdomain(transportDomainUdpIpv4);
mk_tdomain(transportDomainUdpIpv4) ->
@@ -402,40 +507,64 @@ mk_tdomain(BadDomain) ->
%% ---------
-check_taddress(X) ->
- check_taddress(snmpUDPDomain, X).
+tdomain_to_family(snmpUDPDomain) ->
+ inet;
+tdomain_to_family(transportDomainUdpIpv4) ->
+ inet;
+tdomain_to_family(transportDomainUdpIpv6) ->
+ inet6;
+tdomain_to_family(?snmpUDPDomain) ->
+ inet;
+tdomain_to_family(?transportDomainUdpIpv4) ->
+ inet;
+tdomain_to_family(?transportDomainUdpIpv6) ->
+ inet6;
+tdomain_to_family(BadDomain) ->
+ error({bad_domain, BadDomain}).
+
+
+%% ---------
+
+tdomain_to_domain(?snmpUDPDomain) ->
+ snmpUDPDomain;
+tdomain_to_domain(?transportDomainUdpIpv4) ->
+ transportDomainUdpIpv4;
+tdomain_to_domain(?transportDomainUdpIpv6) ->
+ transportDomainUdpIpv6;
+tdomain_to_domain(BadTDomain) ->
+ error({bad_tdomain, BadTDomain}).
+
+
+%% ---------
check_taddress(?snmpUDPDomain, X) ->
check_taddress(transportDomainUdpIpv4, X);
check_taddress(snmpUDPDomain, X) ->
check_taddress(transportDomainUdpIpv4, X);
-
+%%
check_taddress(?transportDomainUdpIpv4, X) ->
check_taddress(transportDomainUdpIpv4, X);
-check_taddress(transportDomainUdpIpv4, X)
- when is_list(X) andalso (length(X) =:= 6) ->
- case (catch all_integer(X)) of
- true ->
+check_taddress(transportDomainUdpIpv4, X) ->
+ case X of
+ [A0,A1,A2,A3,P0,P1]
+ when ?is_ipv4_addr(A0, A1, A2, A3), ?is_word(P0, P1) ->
ok;
- false ->
+ _ ->
error({invalid_taddress, X})
end;
-check_taddress(transportDomainUdpIpv4, X) ->
- error({invalid_taddress, X});
-
+%%
check_taddress(?transportDomainUdpIpv6, X) ->
check_taddress(transportDomainUdpIpv6, X);
-check_taddress(transportDomainUdpIpv6, X)
- when is_list(X) andalso (length(X) =:= 10) ->
- case (catch all_integer(X)) of
- true ->
+check_taddress(transportDomainUdpIpv6, X) ->
+ case X of
+ [A0,A1,A2,A3,A4,A5,A6,A7,P0,P1]
+ when ?is_ipv6_addr(A0, A1, A2, A3, A4, A5, A6, A7),
+ ?is_word(P0, P1) ->
ok;
- false ->
+ _ ->
error({invalid_taddress, X})
end;
-check_taddress(transportDomainUdpIpv6, X) ->
- error({invalid_taddress, X});
-
+%%
check_taddress(BadDomain, _X) ->
error({invalid_tdomain, BadDomain}).
@@ -475,6 +604,7 @@ do_check_timer(WaitFor, Factor, Incr, Retry) ->
check_integer(Retry, {gte, 0}),
ok.
+
%% ---------
all_domains() ->
@@ -497,96 +627,359 @@ all_domains() ->
transportDomainSctpDns
].
+check_domain(snmpUDPDomain) -> ok;
+check_domain(transportDomainUdpIpv4) -> ok;
+check_domain(transportDomainUdpIpv6) -> ok;
check_domain(Domain) ->
- SupportedDomains =
- [
- snmpUDPDomain,
- transportDomainUdpIpv4,
- transportDomainUdpIpv6
- ],
- AllDomains = all_domains(),
- case lists:member(Domain, SupportedDomains) of
+ case lists:member(Domain, all_domains()) of
true ->
- ok;
+ error({unsupported_domain, Domain});
false ->
- case lists:member(Domain, AllDomains) of
- true ->
- error({unsupported_domain, Domain});
- false ->
- error({unknown_domain, Domain})
- end
+ error({unknown_domain, Domain})
end.
-
+
+domain_to_name(snmpUDPDomain) ->
+ undefined;
+domain_to_name(transportDomainUdpIpv4) ->
+ udpIpv4;
+domain_to_name(transportDomainUdpIpv6) ->
+ udpIpv6;
+domain_to_name(transportDomainUdpIpv4z) ->
+ udpIpv4z;
+domain_to_name(transportDomainUdpIpv6z) ->
+ udpIpv6z;
+domain_to_name(transportDomainTcpIpv4) ->
+ tcpIpv4;
+domain_to_name(transportDomainTcpIpv6) ->
+ tcpIpv6;
+domain_to_name(transportDomainTcpIpv4z) ->
+ tcpIpv4z;
+domain_to_name(transportDomainTcpIpv6z) ->
+ tcpIpv6z;
+domain_to_name(transportDomainSctpIpv4) ->
+ sctpIpv4;
+domain_to_name(transportDomainSctpIpv6) ->
+ sctpIpv6;
+domain_to_name(transportDomainSctpIpv4z) ->
+ sctpIpv4z;
+domain_to_name(transportDomainSctpIpv6z) ->
+ sctpIpv6z;
+domain_to_name(transportDomainLocal) ->
+ local;
+domain_to_name(transportDomainUdpDns) ->
+ udpDns;
+domain_to_name(transportDomainTcpDns) ->
+ tcpDns;
+domain_to_name(transportDomainSctpDns) ->
+ sctpDns;
+domain_to_name(BadDomain) ->
+ error({bad_domain, BadDomain}).
%% ---------
-%% The values of Ip and Port has both been checked at this
-%% point, so we dont need to do that again.
-mk_taddress(snmpUDPDomain, Ip, Port) ->
- mk_taddress(transportDomainUdpIpv4, Ip, Port);
-mk_taddress(transportDomainUdpIpv4, Ip, Port) when is_list(Ip) ->
- Ip ++ [Port div 256, Port rem 256];
-mk_taddress(transportDomainUdpIpv4 = Domain, Ip, Port) when is_tuple(Ip) ->
- mk_taddress(Domain, tuple_to_list(Ip), Port);
-mk_taddress(transportDomainUdpIpv6, Ip, Port) when is_list(Ip) ->
- Ip ++ [Port div 256, Port rem 256];
-mk_taddress(transportDomainUdpIpv6 = Domain, Ip, Port) when is_tuple(Ip) ->
- mk_taddress(Domain, tuple_to_list(Ip), Port);
+mk_taddress(Address) ->
+ mk_taddress(snmpUDPDomain, Address).
+%% The values of Domain, Ip and Port has both been checked at this
+%% point, so we dont need to do that again, but this function is
+%% also used on incoming packets from net_if so a little
+%% check that net_if does not supply bad arguments is in order.
+%%
%% These are just for convenience
-mk_taddress(?snmpUDPDomain, Ip, Port) ->
- mk_taddress(snmpUDPDomain, Ip, Port);
-mk_taddress(?transportDomainUdpIpv4, Ip, Port) ->
- mk_taddress(transportDomainUdpIpv4, Ip, Port);
-mk_taddress(?transportDomainUdpIpv6, Ip, Port) ->
- mk_taddress(transportDomainUdpIpv6, Ip, Port);
-
+mk_taddress(?snmpUDPDomain, Address) ->
+ mk_taddress(snmpUDPDomain, Address);
+mk_taddress(?transportDomainUdpIpv4, Address) ->
+ mk_taddress(transportDomainUdpIpv4, Address);
+mk_taddress(?transportDomainUdpIpv6, Address) ->
+ mk_taddress(transportDomainUdpIpv6, Address);
+%%
+mk_taddress(snmpUDPDomain, Address) -> % Legacy
+ mk_taddress(transportDomainUdpIpv4, Address);
+mk_taddress(transportDomainUdpIpv4 = Domain, Address) ->
+ case Address of
+ [] -> % Empty mask
+ [];
+ {Ip, Port} when tuple_size(Ip) =:= 4, is_integer(Port) ->
+ tuple_to_list(Ip) ++ mk_bytes(Port);
+ _ ->
+ erlang:error(badarg, [Domain,Address])
+ end;
+mk_taddress(transportDomainUdpIpv6 = Domain, Address) ->
+ case Address of
+ [] -> % Empty mask
+ [];
+ {{A, B, C, D, E, F, G, H}, Port} ->
+ [A bsr 8, A band 255,
+ B bsr 8, B band 255,
+ C bsr 8, C band 255,
+ D bsr 8, D band 255,
+ E bsr 8, E band 255,
+ F bsr 8, F band 255,
+ G bsr 8, G band 255,
+ H bsr 8, H band 255,
+ Port bsr 8, Port band 255];
+ _ ->
+ erlang:error(badarg, [Domain,Address])
+ end;
%% Bad domain
-mk_taddress(BadDomain, _Ip, _Port) ->
+mk_taddress(BadDomain, _) ->
error({bad_domain, BadDomain}).
-
+
%% ---------
-which_domain(Ip) when is_list(Ip) andalso (length(Ip) =:= 4) ->
+%% XXX remove, when net_if handles one socket per transport domain
+
+which_domain([A0,A1,A2,A3])
+ when ?is_ipv4_addr(A0, A1, A2, A3) ->
transportDomainUdpIpv4;
-which_domain(Ip) when is_tuple(Ip) andalso (size(Ip) =:= 4) ->
+which_domain({A0, A1, A2, A3})
+ when ?is_ipv4_addr(A0, A1, A2, A3) ->
transportDomainUdpIpv4;
-which_domain(Ip) when is_list(Ip) andalso (length(Ip) =:= 8) ->
+which_domain([A0,A1,A2,A3,A4,A5,A6,A7])
+ when ?is_ipv6_addr(A0, A1, A2, A3, A4, A5, A6, A7) ->
+ transportDomainUdpIpv6;
+which_domain([A0,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,A15])
+ when ?is_ipv6_addr(
+ A0, A1, A2, A3, A4, A5, A6, A7,
+ A8, A9, A10, A11, A12, A13, A14, A15) ->
transportDomainUdpIpv6;
-which_domain(Ip) when is_tuple(Ip) andalso (size(Ip) =:= 8) ->
+which_domain({A0, A1, A2, A3, A4, A5, A6, A7})
+ when ?is_ipv6_addr(A0, A1, A2, A3, A4, A5, A6, A7) ->
transportDomainUdpIpv6.
-
%% ---------
+mk_addr_string({Domain, Addr}) when is_atom(Domain) ->
+ %% XXX There is only code for IP domains here
+ case check_address_ip(Domain, Addr) of
+ false ->
+ case check_address_ip_port(Domain, Addr) of
+ false ->
+ error({bad_address, {Domain, Addr}});
+ true ->
+ {IP, Port} = Addr,
+ mk_addr_string_ntoa(Domain, IP, Port);
+ {IP, Port} ->
+ mk_addr_string_ntoa(Domain, IP, Port)
+ end;
+ true ->
+ mk_addr_string_ntoa(Domain, Addr);
+ IP ->
+ mk_addr_string_ntoa(Domain, IP)
+ end;
+mk_addr_string({_IP, Port} = Addr) when is_integer(Port) ->
+ mk_addr_string({snmpUDPDomain, Addr});
+mk_addr_string(Strange) ->
+ lists:flatten(io_lib:format("~w", [Strange])).
+
+
+mk_addr_string_ntoa({_, _, _, _} = IP) ->
+ inet:ntoa(IP);
+mk_addr_string_ntoa(IP) ->
+ lists:flatten(io_lib:format("[~s]", [inet:ntoa(IP)])).
+
+mk_addr_string_ntoa(Domain, IP) ->
+ case domain_to_name(Domain) of
+ undefined ->
+ mk_addr_string_ntoa(IP);
+ Name ->
+ lists:flatten(
+ io_lib:format("~w://~s", [Name, mk_addr_string_ntoa(IP)]))
+ end.
+
+mk_addr_string_ntoa(Domain, IP, Port) ->
+ lists:flatten(
+ io_lib:format(
+ "~s:~w", [mk_addr_string_ntoa(Domain, IP), Port])).
+
+%% ---------
+
check_ip(X) ->
check_ip(snmpUDPDomain, X).
-check_ip(snmpUDPDomain, X) ->
- check_ip(transportDomainUdpIpv4, X);
-check_ip(transportDomainUdpIpv4, X) when is_list(X) andalso (length(X) =:= 4) ->
- case (catch all_integer(X)) of
- true ->
+check_ip(Domain, IP) ->
+ %% XXX There is only code for IP domains here
+ case check_address_ip(Domain, IP) of
+ false ->
+ error({bad_address, {Domain, IP}});
+ true ->
ok;
- false ->
- error({invalid_ip_address, X})
- end;
-check_ip(transportDomainUdpIpv4, X) ->
- error({invalid_ip_address, X});
+ FixedIP ->
+ {ok, FixedIP}
+ end.
+
+
+%% ---------
-check_ip(transportDomainUdpIpv6, X) when is_list(X) andalso (length(X) =:= 8) ->
- case (catch all_integer(X)) of
- true ->
+check_port(Port) when ?is_word(Port) ->
+ ok;
+check_port(Port) ->
+ error({bad_port, Port}).
+
+%% ip_port_to_domaddr(IP, Port) when ?is_word(Port) ->
+%% %% XXX There is only code for IP domains here
+%% case check_address_ip(transportDomainUdpIpv4, IP) of
+%% false ->
+%% case check_address_ip(transportDomainUdpIpv6, IP) of
+%% false ->
+%% error({bad_address, {transportDomainUdpIpv4, {IP, Port}}});
+%% true ->
+%% {transportDomainUdpIpv6, {IP, Port}};
+%% FixedIP ->
+%% {transportDomainUdpIpv6, {FixedIP, Port}}
+%% end;
+%% true ->
+%% {transportDomainUdpIpv4, {IP, Port}};
+%% FixedIP ->
+%% {transportDomainUdpIpv4, {FixedIP, Port}}
+%% end;
+%% ip_port_to_domaddr(IP, Port) ->
+%% error({bad_address, {transportDomainUdpIpv4, {IP, Port}}}).
+
+%% Check a configuration term field from a file to see if it
+%% can be fixed to be fed to mk_taddress/2.
+
+check_address(Domain, Address, DefaultPort) ->
+ %% If Address does not contain Port or contains Port =:= 0
+ %% create an address containing DefaultPort
+ %%
+ %% XXX There is only code for IP domains here
+ case check_address_ip(Domain, Address) of
+ false ->
+ case check_address_ip_port(Domain, Address) of
+ false ->
+ error({bad_address, {Domain, Address}});
+ true ->
+ case Address of
+ {IP, 0} ->
+ {ok, {IP, DefaultPort}};
+ _ ->
+ ok
+ end;
+ {FixedIP, 0} ->
+ {ok, {FixedIP, DefaultPort}};
+ FixedAddress ->
+ {ok, FixedAddress}
+ end;
+ true ->
+ {ok, {Address, DefaultPort}};
+ FixedIP ->
+ {ok, {FixedIP, DefaultPort}}
+ end.
+
+check_address(Domain, Address) ->
+ %% Address has to contain Port
+ %%
+ %% XXX There is only code for IP domains here
+ case check_address_ip_port(Domain, Address) of
+ false ->
+ error({bad_address, {Domain, Address}});
+ true ->
ok;
- false ->
- error({invalid_ip_address, X})
+ FixedAddress ->
+ {ok, FixedAddress}
+ end.
+
+%% -> IP
+check_address_ip(Domain, Address)
+ when Domain =:= snmpUDPDomain;
+ Domain =:= transportDomainUdpIpv4 ->
+ case Address of
+ %% Erlang native format
+ {A0, A1, A2, A3}
+ when ?is_ipv4_addr(A0, A1, A2, A3) ->
+ true;
+ %% Erlangish format
+ [A0,A1,A2,A3]
+ when ?is_ipv4_addr(A0, A1, A2, A3) ->
+ {A0, A1, A2, A3};
+ _ ->
+ false
+ end;
+check_address_ip(transportDomainUdpIpv6, Address) ->
+ case Address of
+ %% Erlang native format
+ {A0, A1, A2, A3, A4, A5, A6, A7}
+ when ?is_ipv6_addr(A0, A1, A2, A3, A4, A5, A6, A7) ->
+ true;
+ %% Erlangish format
+ [A0,A1,A2,A3,A4,A5,A6,A7]
+ when ?is_ipv6_addr(A0, A1, A2, A3, A4, A5, A6, A7) ->
+ {A0, A1, A2, A3, A4, A5, A6, A7};
+ %% SNMP standards format
+ [A0,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,A15]
+ when ?is_ipv6_addr(
+ A0, A1, A2, A3, A4, A5, A6, A7,
+ A8, A9, A10, A11, A12, A13, A14, A15) ->
+ {mk_word(A0, A1), mk_word(A2, A3),
+ mk_word(A4, A5), mk_word(A6, A7),
+ mk_word(A8, A9), mk_word(A10, A11),
+ mk_word(A12, A13), mk_word(A14, A15)};
+ _ ->
+ false
end;
-check_ip(transportDomainUdpIpv6, X) ->
- error({invalid_ip_address, X});
+check_address_ip(BadDomain, _) ->
+ error({bad_domain, BadDomain}).
-check_ip(BadDomain, _X) ->
- error({invalid_domain, BadDomain}).
+%% -> {IP, Port}
+check_address_ip_port(Domain, Address)
+ when Domain =:= snmpUDPDomain;
+ Domain =:= transportDomainUdpIpv4 ->
+ case Address of
+ {IP, Port} when ?is_word(Port) ->
+ case check_address_ip(Domain, IP) of
+ false ->
+ false;
+ true ->
+ true;
+ FixedIP ->
+ {FixedIP, Port}
+ end;
+ %% SNMP standards format
+ [A0,A1,A2,A3,P0,P1]
+ when ?is_ipv4_addr(A0, A1, A2, A3), ?is_word(P0, P1) ->
+ {{A0, A1, A2, A3}, mk_word(P0, P1)};
+ _ ->
+ false
+ end;
+check_address_ip_port(transportDomainUdpIpv6 = Domain, Address) ->
+ case Address of
+ {IP, Port} when ?is_word(Port) ->
+ case check_address_ip(Domain, IP) of
+ false ->
+ false;
+ true ->
+ true;
+ FixedIP ->
+ {FixedIP, Port}
+ end;
+ %% Erlang friendly list format
+ [A0,A1,A2,A3,A4,A5,A6,A7,P]
+ when ?is_ipv6_addr(A0, A1, A2, A3, A4, A5, A6, A7),
+ ?is_word(P) ->
+ {{A0, A1, A2, A3, A4, A5, A6, A7}, P};
+ %% Strange hybrid format with port as bytes
+ [A0,A1,A2,A3,A4,A5,A6,A7,P0,P1]
+ when ?is_ipv6_addr(A0, A1, A2, A3, A4, A5, A6, A7),
+ ?is_word(P0, P1) ->
+ {{A0, A1, A2, A3, A4, A5, A6, A7}, mk_word(P0, P1)};
+ %% SNMP standards format
+ [A0,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,A15,P0,P1]
+ when ?is_ipv6_addr(
+ A0, A1, A2, A3, A4, A5, A6, A7,
+ A8, A9, A10, A11, A12, A13, A14, A15),
+ ?is_word(P0, P1) ->
+ {{mk_word(A0, A1), mk_word(A2, A3),
+ mk_word(A4, A5), mk_word(A6, A7),
+ mk_word(A8, A9), mk_word(A10, A11),
+ mk_word(A12, A13), mk_word(A14, A15)},
+ mk_word(P0, P1)};
+ _ ->
+ false
+ end;
+check_address_ip_port(BadDomain, _) ->
+ error({bad_domain, BadDomain}).
@@ -605,6 +998,39 @@ check_oid(X) ->
%% ---------
+%% Check a (view) mask in the internal form (all 0 and 1):
+check_imask(null) ->
+ {ok, []};
+check_imask(IMask) when is_list(IMask) ->
+ do_check_imask(IMask),
+ {ok, IMask}.
+
+do_check_imask([]) ->
+ ok;
+do_check_imask([0|IMask]) ->
+ do_check_imask(IMask);
+do_check_imask([1|IMask]) ->
+ do_check_imask(IMask);
+do_check_imask([X|_]) ->
+ error({invalid_internal_mask_element, X}).
+
+
+%% Check a (view) mask in the external form (according to MIB,
+%% an OCTET STRING of at most length 16).
+check_emask(EMask) when is_list(EMask) andalso (length(EMask) =< 16) ->
+ do_check_emask(EMask).
+
+do_check_emask([]) ->
+ ok;
+do_check_emask([X|EMask])
+ when is_integer(X) andalso (X >= 16#00) andalso (X =< 16#FF) ->
+ do_check_emask(EMask);
+do_check_emask([X|_]) ->
+ error({invalid_external_mask_element, X}).
+
+
+%% ---------
+
all_integer([H|T]) when is_integer(H) -> all_integer(T);
all_integer([_H|_T]) -> false;
all_integer([]) -> true.
diff --git a/lib/snmp/src/misc/snmp_config.erl b/lib/snmp/src/misc/snmp_config.erl
index 6ab20e3e48..45661b71a7 100644
--- a/lib/snmp/src/misc/snmp_config.erl
+++ b/lib/snmp/src/misc/snmp_config.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
+%% 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
%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -26,24 +27,29 @@
-compile({no_auto_import,[error/1]}).
-export([config/0]).
--export([write_config_file/4, append_config_file/4, read_config_file/3]).
+%%-export([write_config_file/4, append_config_file/4, read_config_file/4]).
+
+-export([write_config_file/6, append_config_file/6, read_config_file/4]).
-export([write_agent_snmp_files/7, write_agent_snmp_files/12,
+ write_agent_snmp_files/6, write_agent_snmp_files/11,
- write_agent_snmp_conf/5,
+ write_agent_snmp_conf/4, write_agent_snmp_conf/5,
write_agent_snmp_context_conf/1,
write_agent_snmp_community_conf/1,
write_agent_snmp_standard_conf/2,
- write_agent_snmp_target_addr_conf/4,
- write_agent_snmp_target_addr_conf/6,
+ write_agent_snmp_target_addr_conf/3,
+ write_agent_snmp_target_addr_conf/4,
+ write_agent_snmp_target_addr_conf/5,
+ write_agent_snmp_target_addr_conf/6,
write_agent_snmp_target_params_conf/2,
write_agent_snmp_notify_conf/2,
write_agent_snmp_usm_conf/5,
write_agent_snmp_vacm_conf/3,
write_manager_snmp_files/8,
- write_manager_snmp_conf/5,
- write_manager_snmp_users_conf/2,
+ write_manager_snmp_conf/4, write_manager_snmp_conf/5,
+ write_manager_snmp_users_conf/2,
write_manager_snmp_agents_conf/2,
write_manager_snmp_usm_conf/2
@@ -90,6 +96,17 @@
]).
+-export_type([void/0,
+ order_config_entry_function/0,
+ check_config_entry_function/0,
+ write_config_function/0]).
+
+
+%%----------------------------------------------------------------------
+
+-type void() :: term(). % Any value - ignored
+
+
%%----------------------------------------------------------------------
%% Handy SNMP configuration
%%----------------------------------------------------------------------
@@ -222,114 +239,124 @@ config_agent_sys() ->
fun verify_verbosity/1),
DbDir = ask("5. Database directory (absolute path)?", DefDir,
fun verify_dir/1),
- MibStorageType = ask("6. Mib storage type (ets/dets/mnesia)?", "ets",
+ DbInitError = ask("6. How to handle DB init error?",
+ "terminate", fun verify_db_init_error/1),
+ MibStorageType = ask("7. Mib storage type (ets/dets/mnesia)?", "ets",
fun verify_mib_storage_type/1),
MibStorage =
case MibStorageType of
ets ->
- ets;
+ [{module, snmpa_mib_storage_ets}];
dets ->
- DetsDir = ask("6b. Mib storage directory (absolute path)?",
+ DetsDir = ask("7b. Mib storage directory (absolute path)?",
DbDir, fun verify_dir/1),
- DetsAction = ask("6c. Mib storage [dets] database start "
+ DetsAction = ask("7c. Mib storage [dets] database start "
"action "
"(default/clear/keep)?",
"default", fun verify_mib_storage_action/1),
case DetsAction of
default ->
- {dets, DetsDir};
+ [{module, snmpa_mib_storage_dets},
+ {options, [{dir, DetsDir}]}];
_ ->
- {dets, DetsDir, DetsAction}
+ [{module, snmpa_mib_storage_dets},
+ {options, [{dir, DetsDir},
+ {action, DetsAction}]}]
end;
mnesia ->
-% Nodes = ask("Mib storage nodes?", "none",
-% fun verify_mib_storage_nodes/1),
Nodes = [],
- MnesiaAction = ask("6b. Mib storage [mnesia] database start "
+ MnesiaAction = ask("7b. Mib storage [mnesia] database start "
"action "
"(default/clear/keep)?",
"default", fun verify_mib_storage_action/1),
case MnesiaAction of
default ->
- {mnesia, Nodes};
+ [{module, snmpa_mib_storage_mnesia},
+ {options, [{nodes, Nodes}]}];
_ ->
- {mnesia, Nodes, MnesiaAction}
+ [{module, snmpa_mib_storage_mnesia},
+ {options, [{nodes, Nodes},
+ {action, MnesiaAction}]}]
end
end,
- TargetCacheVerb = ask("7. Target cache verbosity "
+
+ %% Here we should ask about mib-server data module,
+ %% but as we only have one at the moment...
+
+ TargetCacheVerb = ask("8. Target cache verbosity "
"(silence/info/log/debug/trace)?", "silence",
fun verify_verbosity/1),
- SymStoreVerb = ask("8. Symbolic store verbosity "
+ SymStoreVerb = ask("9. Symbolic store verbosity "
"(silence/info/log/debug/trace)?", "silence",
fun verify_verbosity/1),
- LocalDbVerb = ask("9. Local DB verbosity "
+ LocalDbVerb = ask("10. Local DB verbosity "
"(silence/info/log/debug/trace)?", "silence",
fun verify_verbosity/1),
- LocalDbRepair = ask("10. Local DB repair (true/false/force)?", "true",
+ LocalDbRepair = ask("11. Local DB repair (true/false/force)?", "true",
fun verify_dets_repair/1),
- LocalDbAutoSave = ask("11. Local DB auto save (infinity/milli seconds)?",
+ LocalDbAutoSave = ask("12. Local DB auto save (infinity/milli seconds)?",
"5000", fun verify_dets_auto_save/1),
- ErrorMod = ask("12. Error report module?", "snmpa_error_logger", fun verify_module/1),
- Type = ask("13. Agent type (master/sub)?", "master",
+ ErrorMod = ask("13. Error report module?", "snmpa_error_logger", fun verify_module/1),
+ Type = ask("14. Agent type (master/sub)?", "master",
fun verify_agent_type/1),
AgentConfig =
case Type of
master ->
- MasterAgentVerb = ask("14. Master-agent verbosity "
+ MasterAgentVerb = ask("15. Master-agent verbosity "
"(silence/info/log/debug/trace)?",
"silence",
fun verify_verbosity/1),
- ForceLoad = ask("15. Shall the agent re-read the "
+ ForceLoad = ask("16. Shall the agent re-read the "
"configuration files during startup ~n"
" (and ignore the configuration "
"database) (true/false)?", "true",
fun verify_bool/1),
- MultiThreaded = ask("16. Multi threaded agent (true/false)?",
+ MultiThreaded = ask("17. Multi threaded agent (true/false)?",
"false",
fun verify_bool/1),
- MeOverride = ask("17. Check for duplicate mib entries when "
+ MeOverride = ask("18. Check for duplicate mib entries when "
"installing a mib (true/false)?", "false",
fun verify_bool/1),
- TrapOverride = ask("18. Check for duplicate trap names when "
+ TrapOverride = ask("19. Check for duplicate trap names when "
"installing a mib (true/false)?", "false",
fun verify_bool/1),
- MibServerVerb = ask("19. Mib server verbosity "
+ MibServerVerb = ask("20. Mib server verbosity "
"(silence/info/log/debug/trace)?",
"silence",
fun verify_verbosity/1),
- MibServerCache = ask("20. Mib server cache "
+ MibServerCache = ask("21. Mib server cache "
"(true/false)?",
"true",
fun verify_bool/1),
- NoteStoreVerb = ask("21. Note store verbosity "
+ NoteStoreVerb = ask("22. Note store verbosity "
"(silence/info/log/debug/trace)?",
"silence",
fun verify_verbosity/1),
- NoteStoreTimeout = ask("22. Note store GC timeout?", "30000",
+ NoteStoreTimeout = ask("23. Note store GC timeout?", "30000",
fun verify_timeout/1),
ATL =
- case ask("23. Shall the agent use an audit trail log "
+ case ask("24. Shall the agent use an audit trail log "
"(y/n)?",
"n", fun verify_yes_or_no/1) of
yes ->
- ATLType = ask("23b. Audit trail log type "
+ ATLType = ask("24b. Audit trail log type "
"(write/read_write)?",
"read_write", fun verify_atl_type/1),
- ATLDir = ask("23c. Where to store the "
+ ATLDir = ask("24c. Where to store the "
"audit trail log?",
DefDir, fun verify_dir/1),
- ATLMaxFiles = ask("23d. Max number of files?",
+ ATLMaxFiles = ask("24d. Max number of files?",
"10",
fun verify_pos_integer/1),
- ATLMaxBytes = ask("23e. Max size (in bytes) "
+ ATLMaxBytes = ask("24e. Max size (in bytes) "
"of each file?",
"10240",
fun verify_pos_integer/1),
ATLSize = {ATLMaxBytes, ATLMaxFiles},
- ATLRepair = ask("23f. Audit trail log repair "
+ ATLRepair = ask("24f. Audit trail log repair "
"(true/false/truncate/snmp_repair)?", "true",
fun verify_atl_repair/1),
- ATLSeqNo = ask("23g. Audit trail log "
+ ATLSeqNo = ask("24g. Audit trail log "
"sequence-numbering (true/false)?",
"false",
fun verify_atl_seqno/1),
@@ -341,33 +368,33 @@ config_agent_sys() ->
no ->
[]
end,
- NetIfVerb = ask("24. Network interface verbosity "
+ NetIfVerb = ask("25. Network interface verbosity "
"(silence/info/log/debug/trace)?",
"silence",
fun verify_verbosity/1),
- NetIfMod = ask("25. Which network interface module shall be used?",
+ NetIfMod = ask("26. Which network interface module shall be used?",
"snmpa_net_if", fun verify_module/1),
NetIfOpts =
case NetIfMod of
snmpa_net_if ->
NetIfBindTo =
- ask("25a. Bind the agent IP address "
+ ask("26a. Bind the agent IP address "
"(true/false)?",
"false", fun verify_bool/1),
NetIfNoReuse =
- ask("25b. Shall the agents "
+ ask("26b. Shall the agents "
"IP address "
"and port be not reusable "
"(true/false)?",
"false", fun verify_bool/1),
NetIfReqLimit =
- ask("25c. Agent request limit "
+ ask("26c. Agent request limit "
"(used for flow control) "
"(infinity/pos integer)?",
"infinity",
fun verify_netif_req_limit/1),
NetIfRecbuf =
- case ask("25d. Receive buffer size of the "
+ case ask("26d. Receive buffer size of the "
"agent (in bytes) "
"(default/pos integer)?",
"default",
@@ -378,7 +405,7 @@ config_agent_sys() ->
[{recbuf, RecBufSz}]
end,
NetIfSndbuf =
- case ask("25e. Send buffer size of the agent "
+ case ask("26e. Send buffer size of the agent "
"(in bytes) (default/pos integer)?",
"default",
fun verify_netif_sndbuf/1) of
@@ -388,7 +415,7 @@ config_agent_sys() ->
[{sndbuf, SndBufSz}]
end,
NetIfFilter =
- case ask("25f. Do you wish to specify a "
+ case ask("26f. Do you wish to specify a "
"network interface filter module "
"(or use default)",
"default", fun verify_module/1) of
@@ -407,18 +434,18 @@ config_agent_sys() ->
NetIf = [{module, NetIfMod},
{verbosity, NetIfVerb},
{options, NetIfOpts}],
- TermDiscoEnable = ask("26a. Allow terminating discovery "
+ TermDiscoEnable = ask("27. Allow terminating discovery "
"(true/false)?", "true",
fun verify_bool/1),
TermDiscoConf =
case TermDiscoEnable of
true ->
TermDiscoStage2 =
- ask("26b. Second stage behaviour "
+ ask("27a. Second stage behaviour "
"(discovery/plain)?", "discovery",
fun verify_term_disco_behaviour/1),
TermDiscoTrigger =
- ask("26c. Trigger username "
+ ask("27b. Trigger username "
"(default/a string)?", "default",
fun verify_term_disco_trigger_username/1),
[{enable, TermDiscoEnable},
@@ -429,7 +456,7 @@ config_agent_sys() ->
{stage2, discovery},
{trigger_username, ""}]
end,
- OrigDiscoEnable = ask("27a. Allow originating discovery "
+ OrigDiscoEnable = ask("28. Allow originating discovery "
"(true/false)?", "true",
fun verify_bool/1),
OrigDiscoConf =
@@ -452,7 +479,7 @@ config_agent_sys() ->
{verbosity, NoteStoreVerb}]},
{net_if, NetIf}] ++ ATL;
sub ->
- SubAgentVerb = ask("14. Sub-agent verbosity "
+ SubAgentVerb = ask("15. Sub-agent verbosity "
"(silence/info/log/debug/trace)?",
"silence",
fun verify_verbosity/1),
@@ -461,11 +488,12 @@ config_agent_sys() ->
{config, [{dir, ConfigDir}]}]
end,
SysConfig =
- [{priority, Prio},
- {versions, Vsns},
- {db_dir, DbDir},
- {mib_storage, MibStorage},
- {target_cache, [{verbosity, TargetCacheVerb}]},
+ [{priority, Prio},
+ {versions, Vsns},
+ {db_dir, DbDir},
+ {db_init_error, DbInitError},
+ {mib_storage, MibStorage},
+ {target_cache, [{verbosity, TargetCacheVerb}]},
{symbolic_store, [{verbosity, SymStoreVerb}]},
{local_db, [{repair, LocalDbRepair},
{auto_save, LocalDbAutoSave},
@@ -545,11 +573,9 @@ config_agent_snmp(Dir, Vsns) ->
end,
NT
end,
- case (catch write_agent_snmp_files(Dir,
- Vsns, ManagerIP, TrapUdp,
- AgentIP, AgentUDP,
- SysName, NotifType, SecType,
- Passwd, EngineID, MMS)) of
+ case (catch write_agent_snmp_files(
+ Dir, Vsns, ManagerIP, TrapUdp, AgentIP, AgentUDP, SysName,
+ NotifType, SecType, Passwd, EngineID, MMS)) of
ok ->
i("~n- - - - - - - - - - - - -"),
i("Info: 1. SecurityName \"initial\" has noAuthNoPriv read access~n"
@@ -611,19 +637,21 @@ config_manager_sys() ->
fun verify_verbosity/1),
ConfigDbDir = ask("5. Database directory (absolute path)?",
DefDir, fun verify_dir/1),
- ConfigDbRepair = ask("6. Database repair "
+ ConfigDbInitError = ask("6. How to handle DB init error?",
+ "terminate", fun verify_db_init_error/1),
+ ConfigDbRepair = ask("7. Database repair "
"(true/false/force)?", "true",
fun verify_dets_repair/1),
- ConfigDbAutoSave = ask("7. Database auto save "
+ ConfigDbAutoSave = ask("8. Database auto save "
"(infinity/milli seconds)?",
"5000", fun verify_dets_auto_save/1),
IRB =
- case ask("8. Inform request behaviour (auto/user)?",
+ case ask("9. Inform request behaviour (auto/user)?",
"auto", fun verify_irb/1) of
auto ->
auto;
user ->
- case ask("8b. Use default GC timeout"
+ case ask("9b. Use default GC timeout"
"(default/seconds)?",
"default", fun verify_irb_user/1) of
default ->
@@ -632,31 +660,31 @@ config_manager_sys() ->
{user, IrbGcTo}
end
end,
- ServerVerb = ask("9. Server verbosity "
+ ServerVerb = ask("10. Server verbosity "
"(silence/info/log/debug/trace)?",
"silence",
fun verify_verbosity/1),
- ServerTimeout = ask("10. Server GC timeout?", "30000",
+ ServerTimeout = ask("11. Server GC timeout?", "30000",
fun verify_timeout/1),
- NoteStoreVerb = ask("11. Note store verbosity "
+ NoteStoreVerb = ask("12. Note store verbosity "
"(silence/info/log/debug/trace)?",
"silence",
fun verify_verbosity/1),
- NoteStoreTimeout = ask("12. Note store GC timeout?", "30000",
+ NoteStoreTimeout = ask("13. Note store GC timeout?", "30000",
fun verify_timeout/1),
- NetIfMod = ask("13. Which network interface module shall be used?",
+ NetIfMod = ask("14. Which network interface module shall be used?",
"snmpm_net_if", fun verify_module/1),
- NetIfVerb = ask("14. Network interface verbosity "
+ NetIfVerb = ask("15. Network interface verbosity "
"(silence/info/log/debug/trace)?", "silence",
fun verify_verbosity/1),
- NetIfBindTo = ask("15. Bind the manager IP address "
+ NetIfBindTo = ask("16. Bind the manager IP address "
"(true/false)?",
"false", fun verify_bool/1),
- NetIfNoReuse = ask("16. Shall the manager IP address and port "
+ NetIfNoReuse = ask("17. Shall the manager IP address and port "
"be not reusable (true/false)?",
"false", fun verify_bool/1),
NetIfRecbuf =
- case ask("17. Receive buffer size of the manager (in bytes) "
+ case ask("18. Receive buffer size of the manager (in bytes) "
"(default/pos integer)?", "default",
fun verify_netif_recbuf/1) of
default ->
@@ -665,7 +693,7 @@ config_manager_sys() ->
[{recbuf, RecBufSz}]
end,
NetIfSndbuf =
- case ask("18. Send buffer size of the manager (in bytes) "
+ case ask("19. Send buffer size of the manager (in bytes) "
"(default/pos integer)?", "default",
fun verify_netif_sndbuf/1) of
default ->
@@ -681,28 +709,28 @@ config_manager_sys() ->
{verbosity, NetIfVerb},
{options, NetIfOpts}],
ATL =
- case ask("19. Shall the manager use an audit trail log "
+ case ask("20. Shall the manager use an audit trail log "
"(y/n)?",
"n", fun verify_yes_or_no/1) of
yes ->
- ATLType = ask("19b. Audit trail log type "
+ ATLType = ask("20b. Audit trail log type "
"(write/read_write)?",
"read_write", fun verify_atl_type/1),
- ATLDir = ask("19c. Where to store the "
+ ATLDir = ask("20c. Where to store the "
"audit trail log?",
DefDir, fun verify_dir/1),
- ATLMaxFiles = ask("19d. Max number of files?",
+ ATLMaxFiles = ask("20d. Max number of files?",
"10",
fun verify_pos_integer/1),
- ATLMaxBytes = ask("19e. Max size (in bytes) "
+ ATLMaxBytes = ask("20e. Max size (in bytes) "
"of each file?",
"10240",
fun verify_pos_integer/1),
ATLSize = {ATLMaxBytes, ATLMaxFiles},
- ATLRepair = ask("19f. Audit trail log repair "
+ ATLRepair = ask("20f. Audit trail log repair "
"(true/false/truncate/snmp_repair)?", "true",
fun verify_atl_repair/1),
- ATLSeqNo = ask("19g. Audit trail log sequence-numbering "
+ ATLSeqNo = ask("20g. Audit trail log sequence-numbering "
"(true/false)?", "false",
fun verify_atl_seqno/1),
[{audit_trail_log, [{type, ATLType},
@@ -714,14 +742,14 @@ config_manager_sys() ->
[]
end,
DefUser =
- case ask("20. Do you wish to assign a default user [yes] or use~n"
+ case ask("21. Do you wish to assign a default user [yes] or use~n"
" the default settings [no] (y/n)?", "n",
fun verify_yes_or_no/1) of
yes ->
- DefUserMod = ask("20b. Default user module?",
+ DefUserMod = ask("21b. Default user module?",
"snmpm_user_default",
fun verify_module/1),
- DefUserData = ask("20c. Default user data?", "undefined",
+ DefUserData = ask("21c. Default user data?", "undefined",
fun verify_user_data/1),
[{def_user_mod, DefUserMod},
{def_user_data, DefUserData}];
@@ -731,11 +759,12 @@ config_manager_sys() ->
SysConfig =
[{priority, Prio},
{versions, Vsns},
- {config, [{dir, ConfigDir},
- {verbosity, ConfigVerb},
- {db_dir, ConfigDbDir},
- {repair, ConfigDbRepair},
- {auto_save, ConfigDbAutoSave}]},
+ {config, [{dir, ConfigDir},
+ {db_dir, ConfigDbDir},
+ {db_init_error, ConfigDbInitError},
+ {repair, ConfigDbRepair},
+ {auto_save, ConfigDbAutoSave},
+ {verbosity, ConfigVerb}]},
{inform_request_behaviour, IRB},
{mibs, []},
{server, [{timeout, ServerTimeout},
@@ -1050,6 +1079,16 @@ verify_dir(Dir) ->
_E ->
{error, "invalid directory (not absolute): " ++ Dir}
end.
+
+
+verify_db_init_error("terminate") ->
+ {ok, true};
+verify_db_init_error("create") ->
+ {ok, create};
+verify_db_init_error("create_db_and_dir") ->
+ {ok, create_db_and_dir};
+verify_db_init_error(R) ->
+ {error, "invalid DB init error: " ++ R}.
verify_notif_type("trap") -> {ok, trap};
@@ -1145,13 +1184,20 @@ verify_dets_auto_save(I0) ->
%% I know that this is a little of the edge, but...
+verify_module(M) when is_atom(M) ->
+ {ok, M};
+verify_module(M0) when is_list(M0) ->
+ {ok, list_to_atom(M0)};
verify_module(M0) ->
- case (catch list_to_atom(M0)) of
- M when is_atom(M) ->
- {ok, M};
- _ ->
- {error, "invalid module: " ++ M0}
- end.
+ {error, lists:flatten(io_lib:format("invalid module: ~p", [M0]))}.
+
+%% verify_module(M0) ->
+%% case (catch list_to_atom(M0)) of
+%% M when is_atom(M) ->
+%% {ok, M};
+%% _ ->
+%% {error, "invalid module: " ++ M0}
+%% end.
verify_agent_type("master") ->
@@ -1538,35 +1584,63 @@ remove_newline(Str) ->
%% File generation
%%======================================================================
+write_agent_snmp_files(
+ Dir, Vsns, Domain, ManagerAddr, AgentAddr, SysName)
+ when is_list(Dir),
+ is_list(Vsns),
+ is_atom(Domain),
+ is_list(SysName) ->
+ write_agent_snmp_files(
+ Dir, Vsns, Domain, ManagerAddr, AgentAddr, SysName,
+ trap, none, "", "agentEngine", 484).
+
%%----------------------------------------------------------------------
%% Dir: string() (ex: "../conf/")
%% ManagerIP, AgentIP: [int(),int(),int(),int()]
%% TrapUdp, AgentUDP: integer()
%% SysName: string()
%%----------------------------------------------------------------------
-write_agent_snmp_files(Dir, Vsns, ManagerIP, TrapUdp,
- AgentIP, AgentUDP, SysName)
- when is_list(Dir) andalso
- is_list(Vsns) andalso
- is_list(ManagerIP) andalso
- is_integer(TrapUdp) andalso
- is_list(AgentIP) andalso
- is_integer(AgentUDP) andalso
+write_agent_snmp_files(
+ Dir, Vsns, ManagerIP, TrapUDP, AgentIP, AgentUDP, SysName)
+ when is_list(Dir) andalso
+ is_list(Vsns) andalso
+ is_list(ManagerIP) andalso
+ is_integer(TrapUDP) andalso
+ is_list(AgentIP) andalso
+ is_integer(AgentUDP) andalso
is_list(SysName) ->
- write_agent_snmp_files(Dir, Vsns, ManagerIP, TrapUdp, AgentIP, AgentUDP,
- SysName, "trap", none, "", "agentEngine", 484).
+ write_agent_snmp_files(
+ Dir, Vsns, ManagerIP, TrapUDP, AgentIP, AgentUDP, SysName,
+ trap, none, "", "agentEngine", 484).
%%
%% ----- Agent config files generator functions -----
%%
-write_agent_snmp_files(Dir, Vsns, ManagerIP, TrapUdp, AgentIP, AgentUDP,
- SysName, NotifType, SecType, Passwd, EngineID, MMS) ->
+write_agent_snmp_files(
+ Dir, Vsns, Domain, ManagerAddr, AgentAddr, SysName,
+ NotifType, SecType, Passwd, EngineID, MMS) ->
+ write_agent_snmp_conf(Dir, Domain, AgentAddr, EngineID, MMS),
+ write_agent_snmp_context_conf(Dir),
+ write_agent_snmp_community_conf(Dir),
+ write_agent_snmp_standard_conf(Dir, SysName),
+ write_agent_snmp_target_addr_conf(Dir, Domain, ManagerAddr, Vsns),
+ write_agent_snmp_target_params_conf(Dir, Vsns),
+ write_agent_snmp_notify_conf(Dir, NotifType),
+ write_agent_snmp_usm_conf(Dir, Vsns, EngineID, SecType, Passwd),
+ write_agent_snmp_vacm_conf(Dir, Vsns, SecType),
+ ok.
+
+write_agent_snmp_files(
+ Dir, Vsns, ManagerIP, TrapUDP, AgentIP, AgentUDP, SysName,
+ NotifType, SecType, Passwd, EngineID, MMS) ->
+ Domain = snmp_target_mib:default_domain(),
+ ManagerAddr = {ManagerIP, TrapUDP},
write_agent_snmp_conf(Dir, AgentIP, AgentUDP, EngineID, MMS),
write_agent_snmp_context_conf(Dir),
write_agent_snmp_community_conf(Dir),
write_agent_snmp_standard_conf(Dir, SysName),
- write_agent_snmp_target_addr_conf(Dir, ManagerIP, TrapUdp, Vsns),
+ write_agent_snmp_target_addr_conf(Dir, Domain, ManagerAddr, Vsns),
write_agent_snmp_target_params_conf(Dir, Vsns),
write_agent_snmp_notify_conf(Dir, NotifType),
write_agent_snmp_usm_conf(Dir, Vsns, EngineID, SecType, Passwd),
@@ -1574,11 +1648,40 @@ write_agent_snmp_files(Dir, Vsns, ManagerIP, TrapUdp, AgentIP, AgentUDP,
ok.
+
%%
%% ------ [agent] agent.conf ------
%%
-write_agent_snmp_conf(Dir, AgentIP, AgentUDP, EngineID, MMS) ->
+write_agent_snmp_conf(Dir, Transports, EngineID, MMS) ->
+ Conf =
+ [{intAgentTransports, Transports},
+ {snmpEngineID, EngineID},
+ {snmpEngineMaxMessageSize, MMS}],
+ do_write_agent_snmp_conf(Dir, Conf).
+
+write_agent_snmp_conf(Dir, Domain, AgentAddr, EngineID, MMS)
+ when is_atom(Domain) ->
+ {AgentIP, AgentUDP} = AgentAddr,
+ Conf =
+ [{intAgentTransportDomain, Domain},
+ {intAgentUDPPort, AgentUDP},
+ {intAgentIpAddress, AgentIP},
+ {snmpEngineID, EngineID},
+ {snmpEngineMaxMessageSize, MMS}],
+ do_write_agent_snmp_conf(Dir, Conf);
+write_agent_snmp_conf(Dir, AgentIP, AgentUDP, EngineID, MMS)
+ when is_integer(AgentUDP) ->
+ Conf =
+ [{intAgentUDPPort, AgentUDP},
+ {intAgentIpAddress, AgentIP},
+ {snmpEngineID, EngineID},
+ {snmpEngineMaxMessageSize, MMS}],
+ do_write_agent_snmp_conf(Dir, Conf);
+write_agent_snmp_conf(_Dir, Domain, AgentAddr, _EngineID, _MMS) ->
+ error({bad_address, {Domain, AgentAddr}}).
+
+do_write_agent_snmp_conf(Dir, Conf) ->
Comment =
"%% This file defines the Agent local configuration info\n"
"%% The data is inserted into the snmpEngine* variables defined\n"
@@ -1593,11 +1696,7 @@ write_agent_snmp_conf(Dir, AgentIP, AgentUDP, EngineID, MMS) ->
"%% {snmpEngineID, \"agentEngine\"}.\n"
"%% {snmpEngineMaxMessageSize, 484}.\n"
"%%\n\n",
- Hdr = header() ++ Comment,
- Conf = [{intAgentUDPPort, AgentUDP},
- {intAgentIpAddress, AgentIP},
- {snmpEngineID, EngineID},
- {snmpEngineMaxMessageSize, MMS}],
+ Hdr = header() ++ Comment,
write_agent_config(Dir, Hdr, Conf).
write_agent_config(Dir, Hdr, Conf) ->
@@ -1703,17 +1802,19 @@ update_agent_standard_config(Dir, Conf) ->
%% ------ target_addr.conf ------
%%
-write_agent_snmp_target_addr_conf(Dir, ManagerIp, UDP, Vsns) ->
- Timeout = 1500,
- RetryCount = 3,
- write_agent_snmp_target_addr_conf(Dir, ManagerIp, UDP,
- Timeout, RetryCount,
- Vsns).
+write_agent_snmp_target_addr_conf(Dir, Addresses, Vsns) ->
+ Timeout = 1500,
+ RetryCount = 3,
+ write_agent_snmp_target_addr_conf(
+ Dir, Addresses, Timeout, RetryCount, Vsns).
-write_agent_snmp_target_addr_conf(Dir, ManagerIp, UDP,
- Timeout, RetryCount,
- Vsns) ->
- Comment =
+write_agent_snmp_target_addr_conf(Dir, Domain_or_Ip, Addr_or_Port, Vsns) ->
+ Addresses = [{Domain_or_Ip, Addr_or_Port}],
+ write_agent_snmp_target_addr_conf(Dir, Addresses, Vsns).
+
+write_agent_snmp_target_addr_conf(
+ Dir, Addresses, Timeout, RetryCount, Vsns) ->
+ Comment =
"%% This file defines the target address parameters.\n"
"%% The data is inserted into the snmpTargetAddrTable defined\n"
"%% in SNMP-TARGET-MIB, and in the snmpTargetAddrExtTable defined\n"
@@ -1732,36 +1833,59 @@ write_agent_snmp_target_addr_conf(Dir, ManagerIp, UDP,
"%% [127,0,0,0], 2048}.\n"
"%%\n\n",
Hdr = header() ++ Comment,
- F = fun(v1 = Vsn, Acc) ->
- [{mk_ip(ManagerIp, Vsn),
- snmp_target_mib:default_domain(),
- ManagerIp, UDP, Timeout, RetryCount,
- "std_trap", mk_param(Vsn), "", [], 2048}| Acc];
- (v2 = Vsn, Acc) ->
- [{mk_ip(ManagerIp, Vsn),
- snmp_target_mib:default_domain(),
- ManagerIp, UDP, Timeout, RetryCount,
- "std_trap", mk_param(Vsn), "", [], 2048},
- {lists:flatten(io_lib:format("~s.2",[mk_ip(ManagerIp, Vsn)])),
- ManagerIp, UDP, Timeout, RetryCount,
- "std_inform", mk_param(Vsn), "", [], 2048}| Acc];
- (v3 = Vsn, Acc) ->
- [{mk_ip(ManagerIp, Vsn),
- snmp_target_mib:default_domain(),
- ManagerIp, UDP, Timeout, RetryCount,
- "std_trap", mk_param(Vsn), "", [], 2048},
- {lists:flatten(io_lib:format("~s.3",[mk_ip(ManagerIp, Vsn)])),
- ManagerIp, UDP, Timeout, RetryCount,
- "std_inform", mk_param(Vsn), "mgrEngine", [], 2048}| Acc]
- end,
- Conf = lists:foldl(F, [], Vsns),
+ Conf =
+ lists:foldl(
+ fun ({Domain_or_Ip, Addr_or_Port} = Address, OuterAcc) ->
+ lists:foldl(
+ fun(v1 = Vsn, Acc) ->
+ [{mk_name(Address, Vsn),
+ Domain_or_Ip, Addr_or_Port,
+ Timeout, RetryCount,
+ "std_trap", mk_param(Vsn), "",
+ [], 2048}| Acc];
+ (v2 = Vsn, Acc) ->
+ [{mk_name(Address, Vsn),
+ Domain_or_Ip, Addr_or_Port,
+ Timeout, RetryCount,
+ "std_trap", mk_param(Vsn), "",
+ [], 2048},
+ {lists:flatten(
+ io_lib:format(
+ "~s.2", [mk_name(Address, Vsn)])),
+ Domain_or_Ip, Addr_or_Port,
+ Timeout, RetryCount,
+ "std_inform", mk_param(Vsn), "",
+ [], 2048}| Acc];
+ (v3 = Vsn, Acc) ->
+ [{mk_name(Address, Vsn),
+ Domain_or_Ip, Addr_or_Port,
+ Timeout, RetryCount,
+ "std_trap", mk_param(Vsn), "",
+ [], 2048},
+ {lists:flatten(
+ io_lib:format(
+ "~s.3", [mk_name(Address, Vsn)])),
+ Domain_or_Ip, Addr_or_Port,
+ Timeout, RetryCount,
+ "std_inform", mk_param(Vsn), "mgrEngine",
+ [], 2048} | Acc]
+ end, OuterAcc, Vsns)
+ end, [], Addresses),
write_agent_target_addr_config(Dir, Hdr, Conf).
+write_agent_snmp_target_addr_conf(
+ Dir, Domain_or_Ip, Addr_or_Port, Timeout, RetryCount, Vsns) ->
+ Addresses = [{Domain_or_Ip, Addr_or_Port}],
+ write_agent_snmp_target_addr_conf(
+ Dir, Addresses, Timeout, RetryCount, Vsns).
+
mk_param(Vsn) ->
lists:flatten(io_lib:format("target_~w", [Vsn])).
-mk_ip([A,B,C,D], Vsn) ->
- lists:flatten(io_lib:format("~w.~w.~w.~w ~w", [A,B,C,D,Vsn])).
+mk_name(Address, Vsn) ->
+ lists:flatten(
+ io_lib:format(
+ "~s ~w", [snmp_conf:mk_addr_string(Address), Vsn])).
write_agent_target_addr_config(Dir, Hdr, Conf) ->
snmpa_conf:write_target_addr_config(Dir, Hdr, Conf).
@@ -1995,7 +2119,24 @@ write_manager_snmp_files(Dir, IP, Port, MMS, EngineID,
%% ------ manager.conf ------
%%
-write_manager_snmp_conf(Dir, IP, Port, MMS, EngineID) ->
+write_manager_snmp_conf(Dir, Transports, MMS, EngineID) ->
+ Comment =
+"%% This file defines the Manager local configuration info\n"
+"%% Each row is a 2-tuple:\n"
+"%% {Variable, Value}.\n"
+"%% For example\n"
+"%% {transports, [{transportDomainUdpIpv4, {{127,42,17,5}, 5000}}]}.\n"
+"%% {engine_id, \"managerEngine\"}.\n"
+"%% {max_message_size, 484}.\n"
+"%%\n\n",
+ Hdr = header() ++ Comment,
+ Conf =
+ [{transports, Transports},
+ {engine_id, EngineID},
+ {max_message_size, MMS}],
+ write_manager_config(Dir, Hdr, Conf).
+
+write_manager_snmp_conf(Dir, Domain_or_IP, Addr_or_Port, MMS, EngineID) ->
Comment =
"%% This file defines the Manager local configuration info\n"
"%% Each row is a 2-tuple:\n"
@@ -2007,10 +2148,20 @@ write_manager_snmp_conf(Dir, IP, Port, MMS, EngineID) ->
"%% {max_message_size, 484}.\n"
"%%\n\n",
Hdr = header() ++ Comment,
- Conf = [{port, Port},
- {address, IP},
- {engine_id, EngineID},
- {max_message_size, MMS}],
+ Conf =
+ case Addr_or_Port of
+ {IP, Port} when is_integer(Port), is_atom(Domain_or_IP) ->
+ [{domain, Domain_or_IP},
+ {port, Port},
+ {address, IP}];
+ _ when is_integer(Addr_or_Port) ->
+ [{port, Addr_or_Port},
+ {address, Domain_or_IP}];
+ _ ->
+ error({bad_address, {Domain_or_IP, Addr_or_Port}})
+ end ++
+ [{engine_id, EngineID},
+ {max_message_size, MMS}],
write_manager_config(Dir, Hdr, Conf).
write_manager_config(Dir, Hdr, Conf) ->
@@ -2149,6 +2300,8 @@ write_sys_config_file_agent_opt(Fid, {config, Opts}) ->
ok = io:format(Fid, "}", []);
write_sys_config_file_agent_opt(Fid, {db_dir, Dir}) ->
ok = io:format(Fid, " {db_dir, \"~s\"}", [Dir]);
+write_sys_config_file_agent_opt(Fid, {db_init_error, Action}) ->
+ ok = io:format(Fid, " {db_init_error, ~w}", [Action]);
write_sys_config_file_agent_opt(Fid, {mib_storage, ets}) ->
ok = io:format(Fid, " {mib_storage, ets}", []);
write_sys_config_file_agent_opt(Fid, {mib_storage, {dets, Dir}}) ->
@@ -2325,6 +2478,8 @@ write_sys_config_file_manager_config_opt(Fid, {dir, Dir}) ->
ok = io:format(Fid, "{dir, \"~s\"}", [Dir]);
write_sys_config_file_manager_config_opt(Fid, {db_dir, Dir}) ->
ok = io:format(Fid, "{db_dir, \"~s\"}", [Dir]);
+write_sys_config_file_manager_config_opt(Fid, {db_init_error, Action}) ->
+ ok = io:format(Fid, "{db_init_error, ~w}", [Action]);
write_sys_config_file_manager_config_opt(Fid, {repair, Rep}) ->
ok = io:format(Fid, "{repair, ~w}", [Rep]);
write_sys_config_file_manager_config_opt(Fid, {auto_save, As}) ->
@@ -2356,101 +2511,262 @@ write_sys_config_file_manager_atl_opt(Fid, {seqno, SeqNo}) ->
header() ->
- {Y,Mo,D} = date(),
- {H,Mi,S} = time(),
+ {Y, Mo, D} = date(),
+ {H, Mi, S} = time(),
io_lib:format("%% This file was generated by "
- "snmp_config (version-~s) ~w-~2.2.0w-~2.2.0w "
+ "~w (version-~s) ~w-~2.2.0w-~2.2.0w "
"~2.2.0w:~2.2.0w:~2.2.0w\n",
- [?version,Y,Mo,D,H,Mi,S]).
-
-
-write_config_file(Dir, FileName, Verify, Write)
- when (is_list(Dir) andalso
- is_list(FileName) andalso
- is_function(Verify) andalso
- is_function(Write)) ->
- (catch do_write_config_file(Dir, FileName, Verify, Write)).
+ [?MODULE, ?version, Y, Mo, D, H, Mi, S]).
+
+
+%% *If* these functions are successfull, they successfully return
+%% (value is ignored), but they fail preferably with
+%% throw({error, Reason}). Other exceptions are also handled.
+
+%% Sorting order for config entries (see lists:sort/2)
+-type(order_config_entry_function() ::
+ fun((term(), term()) -> boolean())).
+
+%% Check of config entries. Initial State is 'undefined'
+-type(check_config_entry_function() ::
+ fun((Entry :: term(), State :: undefined | term()) ->
+ {ok | {ok, NewEntry :: term()}, NewState :: term()})).
+
+%% Write configuration entries to file descriptor Fd
+-type(write_config_function() ::
+ fun((Fd :: file:io_device(), [Entry :: term()]) -> ok)).
+
+-spec write_config_file(
+ Dir :: string(),
+ FileName :: string(),
+ Order :: order_config_entry_function(),
+ Check :: check_config_entry_function(),
+ Write :: write_config_function(),
+ Entries :: [term()]) ->
+ ok | {error, term()}.
+
+write_config_file(Dir, FileName, Order, Check, Write, Entries)
+ when is_list(Dir), is_list(FileName),
+ is_function(Order), is_function(Check), is_function(Write),
+ is_list(Entries) ->
+ try
+ SortedEntries = lists:sort(Order, Entries),
+ _ =
+ lists:foldl(
+ fun (Entry, State) ->
+ case Check(Entry, State) of
+ {Ok, NewState} when is_list(Ok) ->
+ NewState;
+ {ok, NewState} ->
+ NewState;
+ {{ok, _}, NewState} ->
+ NewState
+ end
+ end, undefined, SortedEntries),
+ ok
+ of
+ _ ->
+ case file:open(filename:join(Dir, FileName), [write]) of
+ {ok, Fd} ->
+ write_config_file(Dir, FileName, Write, Entries, Fd);
+ Error ->
+ 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]),
+ {error, {failed_write, Dir, FileName, {C, E, S}}}
+ end.
-do_write_config_file(Dir, FileName, Verify, Write) ->
- Verify(),
- case file:open(filename:join(Dir, FileName), [write]) of
- {ok, Fd} ->
- (catch Write(Fd)),
- file:close(Fd),
- ok;
+write_config_file(Dir, FileName, Write, Entries, Fd) ->
+ try Write(Fd, Entries) of
+ ok ->
+ close_config_file(Dir, FileName, Fd)
+ catch
Error ->
- Error
+ S = erlang:get_stacktrace(),
+ d("File write of ~s throwed: ~p~n ~p~n",
+ [FileName, Error, 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]),
+ close_config_file(Dir, FileName, Fd),
+ {error, {failed_write, Dir, FileName, {C, E, S}}}
+ end.
+
+close_config_file(Dir, FileName, Fd) ->
+ case file:sync(Fd) of
+ ok ->
+ case file:close(Fd) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ {error, {failed_closing, Dir, FileName, Reason}}
+ end;
+ {error, Reason} ->
+ _ = file:close(Fd),
+ {error, {failed_syncing, Dir, FileName, Reason}}
end.
-append_config_file(Dir, FileName, Verify, Write)
- when (is_list(Dir) andalso
- is_list(FileName) andalso
- is_function(Verify) andalso
- is_function(Write)) ->
- (catch do_append_config_file(Dir, FileName, Verify, Write)).
-do_append_config_file(Dir, FileName, Verify, Write) ->
- Verify(),
+-spec append_config_file(
+ Dir :: string(),
+ FileName :: string(),
+ Order :: order_config_entry_function(),
+ Check :: check_config_entry_function(),
+ Write :: write_config_function(),
+ Entries :: [term()]) ->
+ ok | {error, term()}.
+
+append_config_file(Dir, FileName, Order, Check, Write, Entries)
+ when is_list(Dir), is_list(FileName),
+ is_function(Order), is_function(Check), is_function(Write),
+ is_list(Entries) ->
case file:open(filename:join(Dir, FileName), [read, write]) of
{ok, Fd} ->
- file:position(Fd, eof),
- (catch Write(Fd)),
- file:close(Fd),
- ok;
+ append_config_file(
+ Dir, FileName, Order, Check, Write, Entries, Fd);
Error ->
Error
end.
+append_config_file(Dir, FileName, Order, Check, Write, Entries, Fd) ->
+ try
+ %% Verify the entries together with the file content
+ LinesInFileR = read_lines(Fd, [], 1),
+ StartLine =
+ case LinesInFileR of
+ [] ->
+ 1;
+ [{_, _, EndLine} | _] ->
+ EndLine
+ end,
+ LinesR = prepend_lines(LinesInFileR, Entries, StartLine),
+ SortedLines = sort_lines(lists:reverse(LinesR), Order),
+ _ = verify_lines(SortedLines, Check, undefined, []),
+ %% Append to the file
+ Write(Fd, Entries)
+ of
+ 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]),
+ 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]),
+ close_config_file(Dir, FileName, Fd),
+ {error, {failed_append, Dir, FileName, {C, E, S}}}
+ end.
+
+%% Fake line numbers, one per entry
+prepend_lines(Lines, [], _) ->
+ Lines;
+prepend_lines(Lines, [Entry | Entries], StartLine) ->
+ EndLine = StartLine + 1,
+ prepend_lines([{StartLine, Entry, EndLine} | Lines], Entries, EndLine).
-read_config_file(Dir, FileName, Verify)
- when is_list(Dir) andalso is_list(FileName) andalso is_function(Verify) ->
- (catch do_read_config_file(Dir, FileName, Verify)).
-do_read_config_file(Dir, FileName, Verify) ->
+
+-spec read_config_file(
+ Dir :: string(),
+ FileName :: string(),
+ Order :: order_config_entry_function(),
+ Check :: check_config_entry_function()) ->
+ {ok, Config :: [Entry :: term()]} |
+ {error, Reason :: term()}.
+
+read_config_file(Dir, FileName, Order, Check)
+ when is_list(Dir), is_list(FileName),
+ is_function(Order), is_function(Check) ->
case file:open(filename:join(Dir, FileName), [read]) of
{ok, Fd} ->
- Result = read_loop(Fd, [], Verify, 1),
- file:close(Fd),
- Result;
+ try
+ Lines = lists:reverse(read_lines(Fd, [], 1)),
+ 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}}}
+ after
+ file:close(Fd)
+ end;
{error, Reason} ->
{error, {Reason, FileName}}
end.
-read_loop(Fd, Acc, Check, StartLine) ->
- case read_term(Fd, StartLine) of
+read_lines(Fd, Acc, StartLine) ->
+ case read_and_parse_term(Fd, StartLine) of
{ok, Term, EndLine} ->
- case (catch Check(Term)) of
- ok ->
- read_loop(Fd, [Term | Acc], Check, EndLine);
- {error, Reason} ->
- {error, {failed_check, StartLine, EndLine, Reason}};
- Error ->
- {error, {failed_check, StartLine, EndLine, Error}}
- end;
- {error, EndLine, Error} ->
- {error, {failed_reading, StartLine, EndLine, Error}};
- eof ->
- {ok, lists:reverse(Acc)}
+ read_lines(Fd, [{StartLine, Term, EndLine}|Acc], EndLine);
+ {error, Error, EndLine} ->
+ throw({failed_reading, StartLine, EndLine, Error});
+ {eof, _EndLine} ->
+ Acc
end.
-
-read_term(Fd, StartLine) ->
+
+read_and_parse_term(Fd, StartLine) ->
case io:request(Fd, {get_until, "", erl_scan, tokens, [StartLine]}) of
{ok, Tokens, EndLine} ->
case erl_parse:parse_term(Tokens) of
{ok, Term} ->
{ok, Term, EndLine};
{error, {Line, erl_parse, Error}} ->
- {error, Line, {parse_error, Error}}
+ {error, {parse_error, Error}, Line}
end;
- {error, E, EndLine} ->
- {error, EndLine, E};
- {eof, _EndLine} ->
- eof;
Other ->
Other
end.
+sort_lines(Lines, Order) ->
+ lists:sort(
+ fun ({_, T1, _}, {_, T2, _}) ->
+ Order(T1, T2)
+ end, Lines).
+
+verify_lines([], _, _, Acc) ->
+ lists:reverse(Acc);
+verify_lines(
+ [{StartLine, Term, EndLine}|Lines], Check, State, Acc) ->
+ try Check(Term, State) of
+ {Terms, NewState} when is_list(Terms) ->
+ verify_lines(Lines, Check, NewState, Terms ++ Acc);
+ {ok, NewState} ->
+ verify_lines(Lines, Check, NewState, [Term|Acc]);
+ {{ok, NewTerm}, NewState} ->
+ verify_lines(Lines, Check, NewState, [NewTerm|Acc])
+ catch
+ {error, Reason} ->
+ throw({failed_check, StartLine, EndLine, Reason});
+ C:R ->
+ S = erlang:get_stacktrace(),
+ throw({failed_check, StartLine, EndLine, {C, R, S}})
+ end.
+
agent_snmp_mk_secret(Alg, Passwd, EngineID) ->
snmp_usm:passwd2localized_key(Alg, Passwd, EngineID).
@@ -2473,8 +2789,8 @@ ensure_started(App) ->
%% -------------------------------------------------------------------------
-% d(F, A) ->
-% i("DBG: " ++ F, A).
+d(F, A) ->
+ i("DBG: " ++ F, A).
i(F) ->
i(F, []).
diff --git a/lib/snmp/src/misc/snmp_debug.hrl b/lib/snmp/src/misc/snmp_debug.hrl
index dc916ac96a..6ed4af7d50 100644
--- a/lib/snmp/src/misc/snmp_debug.hrl
+++ b/lib/snmp/src/misc/snmp_debug.hrl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
diff --git a/lib/snmp/src/misc/snmp_log.erl b/lib/snmp/src/misc/snmp_log.erl
index 2c781810ef..767d801eee 100644
--- a/lib/snmp/src/misc/snmp_log.erl
+++ b/lib/snmp/src/misc/snmp_log.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
+%% 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
%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -21,11 +22,11 @@
-export([
- create/4, create/5, create/6,
+ create/4, create/5, create/6, open/1, open/2,
change_size/2, close/1, sync/1, info/1,
- log/4,
- log_to_txt/5, log_to_txt/6, log_to_txt/7,
- log_to_io/4, log_to_io/5, log_to_io/6
+ log/3, log/4,
+ log_to_txt/6, log_to_txt/7, log_to_txt/8,
+ log_to_io/5, log_to_io/6, log_to_io/7
]).
-export([
upgrade/1, upgrade/2,
@@ -34,7 +35,17 @@
-export([
validate/1, validate/2
]).
+%% <BACKWARD-COMPAT>
+-export([
+ log_to_txt/5,
+ log_to_io/4
+ ]).
+%% </BACKWARD-COMPAT>
+-export_type([
+ log/0,
+ log_time/0
+ ]).
-define(SNMP_USE_V3, true).
-include("snmp_types.hrl").
@@ -42,12 +53,24 @@
-define(VMODULE,"LOG").
-include("snmp_verbosity.hrl").
--define(LOG_FORMAT, internal).
--define(LOG_TYPE, wrap).
+-define(LOG_FORMAT, internal).
+-define(LOG_TYPE, wrap).
+-define(BLOCK_DEFAULT, true).
-record(snmp_log, {id, seqno}).
+%%-----------------------------------------------------------------
+%% Types
+%%-----------------------------------------------------------------
+
+-opaque log() :: #snmp_log{}.
+-type log_time() :: null |
+ calendar:datetime() |
+ {local_time, calendar:datetime()} |
+ {universal_time, calendar:datetime()}.
+
+
%% --------------------------------------------------------------------
%% Exported functions
%% --------------------------------------------------------------------
@@ -109,6 +132,24 @@ create(Name, File, SeqNoGen, Size, Repair, Notify) ->
{error, {bad_args, Name, File, SeqNoGen, Size, Repair, Notify}}.
+%% -- open ---
+
+%% Open an already existing ( = open ) log
+
+open(Name) ->
+ open(Name, #snmp_log{seqno = disabled}).
+open(Name, #snmp_log{seqno = SeqNoGen} = _OldLog) ->
+ %% We include mode in the opts just to be on the safe side
+ case disk_log:open([{name, Name}, {mode, read_write}]) of
+ {ok, Log} ->
+ %% SeqNo must be proprly initiated also
+ {ok, #snmp_log{id = Log, seqno = SeqNoGen}};
+ {repaired, Log, _RecBytes, _BadBytes} ->
+ {ok, #snmp_log{id = Log, seqno = SeqNoGen}};
+ ERROR ->
+ ERROR
+ end.
+
%% -- close ---
@@ -191,7 +232,20 @@ validate(Log, SeqNoReq)
validate_seqno(PrevSN, SeqNo),
{Timestamp, SeqNo};
- ({Timestamp, _Packet, _Addr, _Port}, {PrevTS, _PrevSN}) when SeqNoReq =:= true ->
+ ({Timestamp, SeqNo, _Packet, _AddrStr}, {PrevTS, PrevSN})
+ when is_integer(SeqNo) ->
+ ?vtrace("validating log entry when"
+ "~n Timestamp: ~p"
+ "~n SeqNo: ~p"
+ "~n PrevTS: ~p"
+ "~n PrevSN: ~p",
+ [Timestamp, SeqNo, PrevTS, PrevSN]),
+ validate_timestamp(PrevTS, Timestamp),
+ validate_seqno(PrevSN, SeqNo),
+ {Timestamp, SeqNo};
+
+ ({Timestamp, _Packet, _Addr, _Port}, {PrevTS, _PrevSN})
+ when SeqNoReq =:= true ->
?vtrace("validating log entry when"
"~n Timestamp: ~p"
"~n PrevTS: ~p",
@@ -304,13 +358,20 @@ validate_loop(Error, _Log, _Write, _PrevTS, _PrevSN) ->
%% log(Log, Packet, Addr, Port)
%%-----------------------------------------------------------------
+log(#snmp_log{id = Log, seqno = SeqNo}, Packet, AddrStr) ->
+ ?vtrace(
+ "log -> entry with~n"
+ " Log: ~p~n"
+ " AddrStr: ~s", [Log, AddrStr]),
+ Entry = make_entry(SeqNo, Packet, AddrStr),
+ disk_log:alog(Log, Entry).
-log(#snmp_log{id = Log, seqno = SeqNo}, Packet, Addr, Port) ->
+log(#snmp_log{id = Log, seqno = SeqNo}, Packet, Ip, Port) ->
?vtrace("log -> entry with"
"~n Log: ~p"
- "~n Addr: ~p"
- "~n Port: ~p", [Log, Addr, Port]),
- Entry = make_entry(SeqNo, Packet, Addr, Port),
+ "~n Ip: ~p"
+ "~n Port: ~p", [Log, Ip, Port]),
+ Entry = make_entry(SeqNo, Packet, Ip, Port),
%% io:format("log -> "
%% "~n Entry: ~p"
%% "~n Info: ~p"
@@ -322,18 +383,35 @@ log(#snmp_log{id = Log, seqno = SeqNo}, Packet, Addr, Port) ->
%% "~n", [Res, disk_log:info(Log)]),
%% disk_log:sync(Log),
Res.
-
-make_entry(SeqNoGen, Packet, Addr, Port) ->
+
+make_entry(SeqNoGen, Packet, AddrStr)
+ when is_integer(Packet);
+ is_tuple(AddrStr) ->
+ erlang:error(badarg, [SeqNoGen, Packet, AddrStr]);
+make_entry(SeqNoGen, Packet, AddrStr) ->
try next_seqno(SeqNoGen) of
disabled ->
- {timestamp(), Packet, Addr, Port};
- {ok, NextSeqNo} ->
- {timestamp(), NextSeqNo, Packet, Addr, Port}
+ {timestamp(), Packet, AddrStr};
+ {ok, NextSeqNo} when is_integer(NextSeqNo) ->
+ {timestamp(), NextSeqNo, Packet, AddrStr}
catch
_:_ ->
- {timestamp(), Packet, Addr, Port}
+ {timestamp(), Packet, AddrStr}
+ end.
+
+make_entry(SeqNoGen, Packet, Ip, Port) when is_integer(Packet) ->
+ erlang:error(badarg, [SeqNoGen, Packet, Ip, Port]);
+make_entry(SeqNoGen, Packet, Ip, Port) ->
+ try next_seqno(SeqNoGen) of
+ disabled ->
+ {timestamp(), Packet, Ip, Port};
+ {ok, NextSeqNo} when is_integer(NextSeqNo) ->
+ {timestamp(), NextSeqNo, Packet, Ip, Port}
+ catch
+ _:_ ->
+ {timestamp(), Packet, Ip, Port}
end.
next_seqno({M, F, A}) ->
@@ -360,107 +438,207 @@ do_change_size(Log, NewSize) ->
%% -- log_to_txt ---
+%% <BACKWARD-COMPAT>
log_to_txt(Log, FileName, Dir, Mibs, TextFile) ->
- log_to_txt(Log, FileName, Dir, Mibs, TextFile, null, null).
+ log_to_txt(Log, ?BLOCK_DEFAULT, FileName, Dir, Mibs, TextFile).
+%% </BACKWARD-COMPAT>
+log_to_txt(Log, Block, FileName, Dir, Mibs, TextFile)
+ when ((Block =:= true) orelse (Block =:= false)) ->
+ log_to_txt(Log, Block, FileName, Dir, Mibs, TextFile, null, null);
+%% <BACKWARD-COMPAT>
log_to_txt(Log, FileName, Dir, Mibs, TextFile, Start) ->
- log_to_txt(Log, FileName, Dir, Mibs, TextFile, Start, null).
-
-log_to_txt(Log, FileName, Dir, Mibs, TextFile, Start, Stop)
- when is_list(Mibs) andalso is_list(TextFile) ->
+ log_to_txt(Log, ?BLOCK_DEFAULT, FileName, Dir, Mibs, TextFile, Start, null).
+%% </BACKWARD-COMPAT>
+
+log_to_txt(Log, Block, FileName, Dir, Mibs, TextFile, Start)
+ when ((Block =:= true) orelse (Block =:= false)) ->
+ log_to_txt(Log, Block, FileName, Dir, Mibs, TextFile, Start, null);
+%% <BACKWARD-COMPAT>
+log_to_txt(Log, FileName, Dir, Mibs, TextFile, Start, Stop) ->
+ log_to_txt(Log, ?BLOCK_DEFAULT, FileName, Dir, Mibs, TextFile, Start, Stop).
+%% </BACKWARD-COMPAT>
+
+log_to_txt(Log, Block, FileName, Dir, Mibs, TextFile, Start, Stop)
+ when (((Block =:= true) orelse (Block =:= false)) andalso
+ is_list(Mibs) andalso is_list(TextFile)) ->
?vtrace("log_to_txt -> entry with"
"~n Log: ~p"
+ "~n Block: ~p"
"~n FileName: ~p"
"~n Dir: ~p"
"~n Mibs: ~p"
"~n TextFile: ~p"
"~n Start: ~p"
"~n Stop: ~p",
- [Log, FileName, Dir, Mibs, TextFile, Start, Stop]),
+ [Log, Block, FileName, Dir, Mibs, TextFile, Start, Stop]),
File = filename:join(Dir, FileName),
Converter = fun(L) ->
do_log_to_file(L, TextFile, Mibs, Start, Stop)
end,
- log_convert(Log, File, Converter).
+ log_convert(Log, Block, File, Converter).
%% -- log_to_io ---
+%% <BACKWARD-COMPAT>
log_to_io(Log, FileName, Dir, Mibs) ->
- log_to_io(Log, FileName, Dir, Mibs, null, null).
+ log_to_io(Log, ?BLOCK_DEFAULT, FileName, Dir, Mibs, null, null).
+%% </BACKWARD-COMPAT>
+log_to_io(Log, Block, FileName, Dir, Mibs)
+ when ((Block =:= true) orelse (Block =:= false)) ->
+ log_to_io(Log, Block, FileName, Dir, Mibs, null, null);
+%% <BACKWARD-COMPAT>
log_to_io(Log, FileName, Dir, Mibs, Start) ->
- log_to_io(Log, FileName, Dir, Mibs, Start, null).
-
-log_to_io(Log, FileName, Dir, Mibs, Start, Stop)
+ log_to_io(Log, ?BLOCK_DEFAULT, FileName, Dir, Mibs, Start, null).
+%% </BACKWARD-COMPAT>
+
+log_to_io(Log, Block, FileName, Dir, Mibs, Start)
+ when ((Block =:= true) orelse (Block =:= false)) ->
+ log_to_io(Log, Block, FileName, Dir, Mibs, Start, null);
+%% <BACKWARD-COMPAT>
+log_to_io(Log, FileName, Dir, Mibs, Start, Stop) ->
+ log_to_io(Log, ?BLOCK_DEFAULT, FileName, Dir, Mibs, Start, Stop).
+%% </BACKWARD-COMPAT>
+
+log_to_io(Log, Block, FileName, Dir, Mibs, Start, Stop)
when is_list(Mibs) ->
+ ?vtrace("log_to_io -> entry with"
+ "~n Log: ~p"
+ "~n Block: ~p"
+ "~n FileName: ~p"
+ "~n Dir: ~p"
+ "~n Mibs: ~p"
+ "~n Start: ~p"
+ "~n Stop: ~p",
+ [Log, Block, FileName, Dir, Mibs, Start, Stop]),
File = filename:join(Dir, FileName),
Converter = fun(L) ->
do_log_to_io(L, Mibs, Start, Stop)
end,
- log_convert(Log, File, Converter).
-
-
-%% -- log_to_plain ---
-
-%% log_to_plain(Log, FileName, Dir) ->
-%% log_to_plain(Log, FileName, Dir, null, null).
-
-%% log_to_plain(Log, FileName, Dir, Start) ->
-%% log_to_plain(Log, FileName, Dir, Start, null).
-
-%% log_to_plain(Log, FileName, Dir, Start, Stop)
-%% when is_list(Mibs) ->
-%% File = filename:join(Dir, FileName),
-%% Converter = fun(L) ->
-%% do_log_to_plain(L, Start, Stop)
-%% end,
-%% log_convert(Log, File, Converter).
+ log_convert(Log, Block, File, Converter).
%% --------------------------------------------------------------------
%% Internal functions
%% --------------------------------------------------------------------
-
%% -- log_convert ---
-log_convert(#snmp_log{id = Log}, File, Converter) ->
- do_log_convert(Log, File, Converter);
-log_convert(Log, File, Converter) ->
- do_log_convert(Log, File, Converter).
+log_convert(#snmp_log{id = Log}, Block, File, Converter) ->
+ do_log_convert(Log, Block, File, Converter);
+log_convert(Log, Block, File, Converter) ->
+ do_log_convert(Log, Block, File, Converter).
+
+do_log_convert(Log, Block, File, Converter) ->
+ %% ?vtrace("do_log_converter -> entry with"
+ %% "~n Log: ~p"
+ %% "~n Block: ~p"
+ %% "~n File: ~p"
+ %% [Log, Block, File]),
+ Verbosity = get(verbosity),
+ {Pid, Ref} =
+ erlang:spawn_monitor(
+ fun() ->
+ put(sname, lc),
+ put(verbosity, Verbosity),
+ ?vlog("begin converting", []),
+ Result = do_log_convert2(Log, Block, File, Converter),
+ ?vlog("convert result: ~p", [Result]),
+ exit(Result)
+ end),
+ receive
+ {'DOWN', Ref, process, Pid, Result} ->
+ %% ?vtrace("do_log_converter -> received result"
+ %% "~n Result: ~p", [Result]),
+ Result
+ end.
+
+do_log_convert2(Log, Block, File, Converter) ->
+
+ %% ?vtrace("do_log_converter2 -> entry with"
+ %% "~n Log: ~p"
+ %% "~n Block: ~p"
+ %% "~n File: ~p"
+ %% "~n disk_log:info(Log): ~p",
+ %% [Log, Block, File, disk_log:info(Log)]),
-do_log_convert(Log, File, Converter) ->
%% First check if the caller process has already opened the
%% log, because if we close an already open log we will cause
%% a runtime error.
+
+ ?vtrace("do_log_convert2 -> entry - check if owner", []),
case is_owner(Log) of
true ->
- Converter(Log);
+ ?vtrace("do_log_converter2 -> convert an already owned log", []),
+ maybe_block(Log, Block),
+ Res = Converter(Log),
+ maybe_unblock(Log, Block),
+ Res;
false ->
%% Not yet member of the ruling party, apply for membership...
- %% If a log is opened as read_write it is not possible to
- %% open it as read_only. So, to get around this we open
- %% it under a different name...
- Log2 = convert_name(Log),
- case log_open(Log2, File) of
+ ?vtrace("do_log_converter2 -> convert log", []),
+ case log_open(Log, File) of
{ok, _} ->
- Res = Converter(Log2),
- disk_log:close(Log2),
+ ?vdebug("do_log_convert2 -> opened - now convert", []),
+ maybe_block(Log, Block),
+ Res = Converter(Log),
+ maybe_unblock(Log, Block),
+ disk_log:close(Log),
+ ?vdebug("do_log_convert2 -> converted - done: "
+ "~n Result: ~p", [Res]),
Res;
{error, {name_already_open, _}} ->
- Converter(Log2);
+ ?vdebug("do_log_convert2 -> "
+ "already opened - now convert", []),
+ maybe_block(Log, Block),
+ Res = Converter(Log),
+ maybe_unblock(Log, Block),
+ ?vdebug("do_log_convert2 -> converted - done: "
+ "~n Result: ~p", [Res]),
+ Res;
{error, Reason} ->
+ ?vinfo("do_log_converter2 -> "
+ "failed converting log - open failed: "
+ "~n Reason: ~p", [Reason]),
{error, {Log, Reason}}
end
end.
-convert_name(Name) when is_list(Name) ->
- Name ++ "_tmp";
-convert_name(Name) when is_atom(Name) ->
- list_to_atom(atom_to_list(Name) ++ "_tmp");
-convert_name(Name) ->
- lists:flatten(io_lib:format("~w_tmp", [Name])).
+
+maybe_block(_Log, false = _Block) ->
+ %% ?vtrace("maybe_block(false) -> entry", []),
+ ok;
+maybe_block(Log, true = _Block) ->
+ %% ?vtrace("maybe_block(true) -> entry when"
+ %% "~n Log Status: ~p", [log_status(Log)]),
+ Res = disk_log:block(Log, true),
+ %% ?vtrace("maybe_block(true) -> "
+ %% "~n Log Status: ~p"
+ %% "~n Res: ~p", [log_status(Log), Res]),
+ Res.
+
+maybe_unblock(_Log, false = _Block) ->
+ %% ?vtrace("maybe_unblock(false) -> entry", []),
+ ok;
+maybe_unblock(Log, true = _Block) ->
+ %% ?vtrace("maybe_unblock(true) -> entry when"
+ %% "~n Log Status: ~p", [log_status(Log)]),
+ Res = disk_log:unblock(Log),
+ %% ?vtrace("maybe_unblock(true) -> "
+ %% "~n Log Status: ~p"
+ %% "~n Res: ~p", [log_status(Log), Res]),
+ Res.
+
+%% log_status(Log) ->
+%% Info = disk_log:info(Log),
+%% case lists:keysearch(status, 1, Info) of
+%% {value, {status, Status}} ->
+%% Status;
+%% false ->
+%% undefined
+%% end.
%% -- do_log_to_text ---
@@ -535,60 +713,68 @@ format_msg(Entry, Mib, Start, Stop) ->
end.
%% This is an old-style entry, that never had the sequence-number
-do_format_msg({Timestamp, Packet, {Addr, Port}}, Mib) ->
- do_format_msg(Timestamp, Packet, Addr, Port, Mib);
+do_format_msg({Timestamp, Packet, {Ip, Port}}, Mib) ->
+ do_format_msg(Timestamp, Packet, ipPort2Str(Ip, Port), Mib);
+%% This is the format without sequence-number
+do_format_msg({Timestamp, Packet, AddrStr}, Mib) ->
+ do_format_msg(Timestamp, Packet, AddrStr, Mib);
+%% This is the format with sequence-number
+do_format_msg({Timestamp, SeqNo, Packet, AddrStr}, Mib)
+ when is_integer(SeqNo) ->
+ do_format_msg(Timestamp, Packet, AddrStr, Mib);
%% This is the format without sequence-number
-do_format_msg({Timestamp, Packet, Addr, Port}, Mib) ->
- do_format_msg(Timestamp, Packet, Addr, Port, Mib);
+do_format_msg({Timestamp, Packet, Ip, Port}, Mib) ->
+ do_format_msg(Timestamp, Packet, ipPort2Str(Ip, Port), Mib);
%% This is the format with sequence-number
-do_format_msg({Timestamp, SeqNo, Packet, Addr, Port}, Mib) ->
- do_format_msg(Timestamp, SeqNo, Packet, Addr, Port, Mib);
+do_format_msg({Timestamp, SeqNo, Packet, Ip, Port}, Mib) ->
+ do_format_msg(Timestamp, SeqNo, Packet, ipPort2Str(Ip, Port), Mib);
%% This is crap...
do_format_msg(_, _) ->
format_tab("** unknown entry in log file\n\n", []).
-do_format_msg(TimeStamp, {V3Hdr, ScopedPdu}, Addr, Port, Mib) ->
+do_format_msg(TimeStamp, {V3Hdr, ScopedPdu}, AddrStr, Mib) ->
case (catch snmp_pdus:dec_scoped_pdu(ScopedPdu)) of
ScopedPDU when is_record(ScopedPDU, scopedPdu) ->
Msg = #message{version = 'version-3',
vsn_hdr = V3Hdr,
data = ScopedPDU},
- f(ts2str(TimeStamp), "", Msg, Addr, Port, Mib);
+ f(ts2str(TimeStamp), "", Msg, AddrStr, Mib);
{'EXIT', Reason} ->
- format_tab("** error in log file at ~s from ~p:~w ~p\n\n",
- [ts2str(TimeStamp), ip(Addr), Port, Reason])
+ format_tab(
+ "** error in log file at ~s from ~s ~p\n\n",
+ [ts2str(TimeStamp), AddrStr, Reason])
end;
-do_format_msg(TimeStamp, Packet, Addr, Port, Mib) ->
+do_format_msg(TimeStamp, Packet, AddrStr, Mib) ->
case (catch snmp_pdus:dec_message(binary_to_list(Packet))) of
Msg when is_record(Msg, message) ->
- f(ts2str(TimeStamp), "", Msg, Addr, Port, Mib);
+ f(ts2str(TimeStamp), "", Msg, AddrStr, Mib);
{'EXIT', Reason} ->
format_tab("** error in log file ~p\n\n", [Reason])
end.
-do_format_msg(TimeStamp, SeqNo, {V3Hdr, ScopedPdu}, Addr, Port, Mib) ->
+do_format_msg(TimeStamp, SeqNo, {V3Hdr, ScopedPdu}, AddrStr, Mib) ->
case (catch snmp_pdus:dec_scoped_pdu(ScopedPdu)) of
ScopedPDU when is_record(ScopedPDU, scopedPdu) ->
Msg = #message{version = 'version-3',
vsn_hdr = V3Hdr,
data = ScopedPDU},
- f(ts2str(TimeStamp), sn2str(SeqNo), Msg, Addr, Port, Mib);
+ f(ts2str(TimeStamp), sn2str(SeqNo), Msg, AddrStr, Mib);
{'EXIT', Reason} ->
- format_tab("** error in log file at ~s from ~p:~w ~p\n\n",
- [ts2str(TimeStamp), sn2str(SeqNo),
- ip(Addr), Port, Reason])
+ format_tab(
+ "** error in log file at ~s from ~s ~p\n\n",
+ [ts2str(TimeStamp), sn2str(SeqNo), AddrStr, Reason])
end;
-do_format_msg(TimeStamp, SeqNo, Packet, Addr, Port, Mib) ->
+do_format_msg(TimeStamp, SeqNo, Packet, AddrStr, Mib) ->
case (catch snmp_pdus:dec_message(binary_to_list(Packet))) of
Msg when is_record(Msg, message) ->
- f(ts2str(TimeStamp), sn2str(SeqNo), Msg, Addr, Port, Mib);
+ f(ts2str(TimeStamp), sn2str(SeqNo), Msg, AddrStr, Mib);
{'EXIT', Reason} ->
- format_tab("** error in log file ~s from ~p:~w ~p\n\n",
- [ts2str(TimeStamp), sn2str(SeqNo),
- ip(Addr), Port, Reason])
+ format_tab(
+ "** error in log file ~s from ~s ~p\n\n",
+ [ts2str(TimeStamp), sn2str(SeqNo), AddrStr, Reason])
end.
@@ -632,44 +818,71 @@ do_format_msg(TimeStamp, SeqNo, Packet, Addr, Port, Mib) ->
f(TimeStamp, SeqNo,
#message{version = Vsn, vsn_hdr = VsnHdr, data = Data},
- Addr, Port, Mib) ->
+ AddrStr, Mib) ->
Str = format_pdu(Data, Mib),
HdrStr = format_header(Vsn, VsnHdr),
- case get_type(Data) of
- trappdu ->
- f_trap(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port);
- 'snmpv2-trap' ->
- f_trap(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port);
- 'inform-request' ->
- f_inform(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port);
- 'get-response' ->
- f_response(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port);
- report ->
- f_report(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port);
- _ ->
- f_request(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port)
- end.
-
-f_request(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port) ->
- format_tab("request ~s:~w - ~s [~s]~s ~w\n~s",
- [ip(Addr), Port, HdrStr, TimeStamp, SeqNo, Vsn, Str]).
-
-f_response(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port) ->
- format_tab("response ~s:~w - ~s [~s]~s ~w\n~s",
- [ip(Addr), Port, HdrStr, TimeStamp, SeqNo, Vsn, Str]).
-
-f_report(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port) ->
- format_tab("report ~s:~w - ~s [~s]~s ~w\n~s",
- [ip(Addr), Port, HdrStr, TimeStamp, SeqNo, Vsn, Str]).
-
-f_trap(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port) ->
- format_tab("trap ~s:~w - ~s [~s]~s ~w\n~s",
- [ip(Addr), Port, HdrStr, TimeStamp, SeqNo, Vsn, Str]).
-
-f_inform(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port) ->
- format_tab("inform ~s:~w - ~s [~s]~s ~w\n~s",
- [ip(Addr), Port, HdrStr, TimeStamp, SeqNo, Vsn, Str]).
-
+ Class =
+ case get_type(Data) of
+ trappdu ->
+ trap;
+ 'snmpv2-trap' ->
+ trap;
+ 'inform-request' ->
+ inform;
+ 'get-response' ->
+ response;
+ report ->
+ report;
+ _ ->
+ request
+ end,
+ format_tab(
+ "~w ~s - ~s [~s]~s ~w\n~s",
+ [Class, AddrStr, HdrStr, TimeStamp, SeqNo, Vsn, Str]).
+
+%% f(TimeStamp, SeqNo,
+%% #message{version = Vsn, vsn_hdr = VsnHdr, data = Data},
+%% Addr, Port, Mib) ->
+%% Str = format_pdu(Data, Mib),
+%% HdrStr = format_header(Vsn, VsnHdr),
+%% case get_type(Data) of
+%% trappdu ->
+%% f_trap(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port);
+%% 'snmpv2-trap' ->
+%% f_trap(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port);
+%% 'inform-request' ->
+%% f_inform(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port);
+%% 'get-response' ->
+%% f_response(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port);
+%% report ->
+%% f_report(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port);
+%% _ ->
+%% f_request(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port)
+%% end.
+
+%% f_request(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port) ->
+%% format_tab("request ~s:~w - ~s [~s]~s ~w\n~s",
+%% [ip(Addr), Port, HdrStr, TimeStamp, SeqNo, Vsn, Str]).
+
+%% f_response(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port) ->
+%% format_tab("response ~s:~w - ~s [~s]~s ~w\n~s",
+%% [ip(Addr), Port, HdrStr, TimeStamp, SeqNo, Vsn, Str]).
+
+%% f_report(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port) ->
+%% format_tab("report ~s:~w - ~s [~s]~s ~w\n~s",
+%% [ip(Addr), Port, HdrStr, TimeStamp, SeqNo, Vsn, Str]).
+
+%% f_trap(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port) ->
+%% format_tab("trap ~s:~w - ~s [~s]~s ~w\n~s",
+%% [ip(Addr), Port, HdrStr, TimeStamp, SeqNo, Vsn, Str]).
+
+%% f_inform(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port) ->
+%% format_tab("inform ~s:~w - ~s [~s]~s ~w\n~s",
+%% [ip(Addr), Port, HdrStr, TimeStamp, SeqNo, Vsn, Str]).
+
+ipPort2Str(Ip, Port) ->
+ snmp_conf:mk_addr_string({Ip, Port}).
+ %% io_lib:format("~s:~w", [ip(Ip), Port]).
%% Convert a timestamp 2-tupple to a printable string
%%
@@ -705,21 +918,21 @@ tsf_ge(_Local,Universal,{universal_time,DateTime}) ->
tsf_ge(Local,_Universal,DateTime) ->
tsf_ge(Local,DateTime).
-tsf_ge(TimeStamp,DateTime) ->
+tsf_ge(TimeStamp, DateTime) ->
T1 = calendar:datetime_to_gregorian_seconds(TimeStamp),
T2 = calendar:datetime_to_gregorian_seconds(DateTime),
T1 >= T2.
-tsf_le(_Local,_Universal,null) ->
+tsf_le(_Local, _Universal, null) ->
true;
-tsf_le(Local,_Universal,{local_time,DateTime}) ->
- tsf_le(Local,DateTime);
-tsf_le(_Local,Universal,{universal_time,DateTime}) ->
- tsf_le(Universal,DateTime);
-tsf_le(Local,_Universal,DateTime) ->
+tsf_le(Local, _Universal, {local_time, DateTime}) ->
+ tsf_le(Local, DateTime);
+tsf_le(_Local, Universal, {universal_time, DateTime}) ->
+ tsf_le(Universal, DateTime);
+tsf_le(Local, _Universal, DateTime) ->
tsf_le(Local,DateTime).
-tsf_le(TimeStamp,DateTime) ->
+tsf_le(TimeStamp, DateTime) ->
T1 = calendar:datetime_to_gregorian_seconds(TimeStamp),
T2 = calendar:datetime_to_gregorian_seconds(DateTime),
T1 =< T2.
@@ -770,8 +983,10 @@ get_type(#pdu{type = Type}) ->
Type.
-ip({A,B,C,D}) ->
- io_lib:format("~w.~w.~w.~w", [A,B,C,D]).
+%% ip(Domain, Addr) ->
+%% snmp_conf:mk_addr_string(Domain, Addr).
+%% ip({A,B,C,D}) ->
+%% io_lib:format("~w.~w.~w.~w", [A,B,C,D]).
@@ -864,11 +1079,8 @@ do_std_log_open(Name, File, Size, Repair, Notify) ->
log_open(Name, File) ->
- Opts = [{name, Name},
- {file, File},
- {type, ?LOG_TYPE},
- {format, ?LOG_FORMAT},
- {mode, read_only}],
+ Opts = [{name, Name},
+ {file, File}],
case disk_log:open(Opts) of
{error, {badarg, size}} ->
{error, no_such_log};
diff --git a/lib/snmp/src/misc/snmp_mini_mib.erl b/lib/snmp/src/misc/snmp_mini_mib.erl
index d80270d5c2..92de339001 100644
--- a/lib/snmp/src/misc/snmp_mini_mib.erl
+++ b/lib/snmp/src/misc/snmp_mini_mib.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
diff --git a/lib/snmp/src/misc/snmp_misc.erl b/lib/snmp/src/misc/snmp_misc.erl
index a061dcd97c..1f847b7a29 100644
--- a/lib/snmp/src/misc/snmp_misc.erl
+++ b/lib/snmp/src/misc/snmp_misc.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2015. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -43,6 +44,7 @@
ip/1, ip/2,
is_auth/1,
is_BitString/1,
+ is_crypto_supported/1,
is_oid/1,
is_priv/1,
is_reportable/1,
@@ -100,30 +102,37 @@ sleep(Time) ->
%% Returns time in ms = sec/1000
% now() -> now(ms).
now(ms) ->
- Now = erlang:now(),
- element(1,Now)*1000000000+
- element(2,Now)*1000+
- (element(3,Now) div 1000);
+ erlang:monotonic_time(milli_seconds);
+
%% Returns time in cs = sec/100
now(cs) ->
- Now = erlang:now(),
- element(1,Now)*100000000+
- element(2,Now)*100+
- (element(3,Now) div 10000);
+ erlang:monotonic_time(100);
+
now(sec) ->
- Now = erlang:now(),
- element(1,Now)*1000000+
- element(2,Now)+
- (element(3,Now) div 1000000).
+ erlang:monotonic_time(seconds).
+is_crypto_supported(Alg) ->
+ %% The 'try catch' handles the case when 'crypto' is
+ %% not present in the system (or not started).
+ try
+ begin
+ Supported = crypto:supports(),
+ Hashs = proplists:get_value(hashs, Supported),
+ Ciphers = proplists:get_value(ciphers, Supported),
+ lists:member(Alg, Hashs ++ Ciphers)
+ end
+ catch
+ _:_ ->
+ false
+ end.
+
is_string([]) -> true;
is_string([Tkn | Str])
when is_integer(Tkn) andalso (Tkn >= 0) andalso (Tkn =< 255) ->
is_string(Str);
is_string(_) -> false.
-
is_oid([E1, E2| Rest])
when (length(Rest) =< 126) andalso (E1 *40 + E2 =< 255) ->
is_oid2(Rest);
@@ -464,7 +473,3 @@ format_val('OBJECT IDENTIFIER', _, Val, MiniMib) ->
io_lib:format("~w", [NVal]);
format_val(_, _, Val, _MiniMib) ->
io_lib:format("~p", [Val]).
-
-
-
-
diff --git a/lib/snmp/src/misc/snmp_note_store.erl b/lib/snmp/src/misc/snmp_note_store.erl
index 23fccf8a5f..606dd8ce4f 100644
--- a/lib/snmp/src/misc/snmp_note_store.erl
+++ b/lib/snmp/src/misc/snmp_note_store.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
diff --git a/lib/snmp/src/misc/snmp_pdus.erl b/lib/snmp/src/misc/snmp_pdus.erl
index 0788d86b2d..93f06749fd 100644
--- a/lib/snmp/src/misc/snmp_pdus.erl
+++ b/lib/snmp/src/misc/snmp_pdus.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
+%% 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
%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -174,7 +175,7 @@ dec_pdu_tag(168) ->
dec_pdu([164 | Bytes]) -> % It's a trap
Bytes2 = get_data_bytes(Bytes),
{Enterprise, Rest1} = dec_oid_tag(Bytes2),
- {{'IpAddress', AgentAddr}, Rest2} = dec_value(Rest1),
+ {{'IpAddress', [_, _, _, _] = AgentAddr}, Rest2} = dec_value(Rest1),
{GenericTrap, Rest3} = dec_int_tag(Rest2),
{SpecificTrap, Rest4} = dec_int_tag(Rest3),
{{'TimeTicks', TimeStamp}, VBBytes} = dec_value(Rest4),
@@ -254,68 +255,95 @@ strip(0, _Tail) ->
%%----------------------------------------------------------------------
%% Returns:{Type, Value}
%%----------------------------------------------------------------------
+
+%% OBJECT IDENTIFIER
dec_value([6 | Bytes]) ->
{Value, Rest} = dec_oid_notag(Bytes),
{{'OBJECT IDENTIFIER', Value}, Rest};
dec_value([5,0 | T]) ->
{{'NULL', 'NULL'}, T};
+
+%% INTEGER
dec_value([2 | Bytes]) ->
{Value, Rest} = dec_integer_notag(Bytes),
{{'INTEGER', Value}, Rest};
+
+%% OCTET STRING
dec_value([4 | Bytes]) ->
{Value, Rest} = dec_oct_str_notag(Bytes),
{{'OCTET STRING', Value}, Rest};
+
+%% IpAddress
dec_value([64 | Bytes]) ->
{Value, Rest} = dec_oct_str_notag(Bytes),
{{'IpAddress', Value}, Rest};
+
+%% Counter32
dec_value([65 | Bytes]) ->
%% Counter32 is an unsigned 32 but is actually encoded as
%% a signed integer 32 (INTEGER).
{Value, Rest} = dec_integer_notag(Bytes),
Value2 =
- if
+ if
+ (Value >= 0) andalso (Value =< 16#ffffffff) ->
+ %% We accept value above 16#7fffffff
+ %% in order to be backward bug-compatible
+ Value;
+ (Value < 0) ->
+ 16#ffffffff + Value + 1;
+ true ->
+ exit({error, {bad_counter32, Value}})
+ end,
+ {{'Counter32', Value2}, Rest};
+
+%% Unsigned32
+dec_value([66 | Bytes]) ->
+ {Value, Rest} = dec_integer_notag(Bytes),
+ Value2 =
+ if
(Value >= 0) andalso (Value =< 16#ffffffff) ->
- %% We accept value above 16#7fffffff
- %% in order to be backward bug-compatible
Value;
(Value < 0) ->
16#ffffffff + Value + 1;
true ->
- exit({error, {bad_counter32, Value}})
+ exit({error, {bad_unsigned32, Value}})
end,
- {{'Counter32', Value2}, Rest};
-dec_value([66 | Bytes]) ->
- {Value, Rest} = dec_integer_notag(Bytes),
- if
- (Value >= 0) andalso (Value =< 4294967295) ->
- {{'Unsigned32', Value}, Rest};
- true ->
- exit({error, {bad_unsigned32, Value}})
- end;
+ {{'Unsigned32', Value2}, Rest};
+
+%% TimeTicks
dec_value([67 | Bytes]) ->
{Value, Rest} = dec_integer_notag(Bytes),
- if
- (Value >= 0) andalso (Value =< 4294967295) ->
- {{'TimeTicks', Value}, Rest};
+ Value2 =
+ if
+ (Value >= 0) andalso (Value =< 16#ffffffff) ->
+ Value;
+ (Value < 0) ->
+ 16#ffffffff + Value + 1;
true ->
exit({error, {bad_timeticks, Value}})
- end;
+ end,
+ {{'TimeTicks', Value2}, Rest};
+
+%% Opaque
dec_value([68 | Bytes]) ->
{Value, Rest} = dec_oct_str_notag(Bytes),
{{'Opaque', Value}, Rest};
+
+%% Counter64
dec_value([70 | Bytes]) ->
%% Counter64 is an unsigned 64 but is actually encoded as
%% a signed integer 64.
{Value, Rest} = dec_integer_notag(Bytes),
Value2 =
- if
- (Value >= 0) andalso (Value < 16#8000000000000000) ->
- Value;
- (Value < 0) ->
- 18446744073709551615 + Value + 1;
- true ->
- exit({error, {bad_counter64, Value}}) end,
+ if
+ (Value >= 0) andalso (Value < 16#8000000000000000) ->
+ Value;
+ (Value < 0) ->
+ 16#ffffffffffffffff + Value + 1;
+ true ->
+ exit({error, {bad_counter64, Value}}) end,
{{'Counter64', Value2}, Rest};
+
dec_value([128,0|T]) ->
{{'NULL', noSuchObject}, T};
dec_value([129,0|T]) ->
@@ -629,7 +657,7 @@ enc_VarBind_attributes(#varbind{oid = Oid, variabletype = Type,value = Val}) ->
ValueBytes = enc_value(Type, Val),
lists:append(OidBytes, ValueBytes).
-enc_value('INTEGER',Val) ->
+enc_value('INTEGER', Val) ->
enc_integer_tag(Val);
enc_value('OCTET STRING', Val) ->
enc_oct_str_tag(Val);
@@ -637,7 +665,9 @@ enc_value('BITS', Val) ->
enc_oct_str_tag(bits_to_str(Val));
enc_value('OBJECT IDENTIFIER', Val) ->
enc_oid_tag(Val);
-enc_value('IpAddress',Val) ->
+enc_value('IpAddress', {A, B, C, D}) ->
+ enc_value('IpAddress', [A,B,C,D]);
+enc_value('IpAddress', Val) when is_list(Val) ->
Bytes2 = enc_oct_str_notag(Val),
Len2 = elength(length(Bytes2)),
lists:append([64 | Len2],Bytes2);
@@ -668,6 +698,24 @@ enc_value('Counter32', Val) ->
Bytes2 = enc_integer_notag(Val2),
Len2 = elength(length(Bytes2)),
lists:append([65 | Len2],Bytes2);
+enc_value('Unsigned32', Val) ->
+ if
+ (Val >= 0) andalso (Val =< 4294967295) ->
+ Bytes2 = enc_integer_notag(Val),
+ Len2 = elength(length(Bytes2)),
+ lists:append([66 | Len2], Bytes2);
+ true ->
+ exit({error, {bad_counter32, Val}})
+ end;
+enc_value('TimeTicks', Val) ->
+ if
+ (Val >= 0) andalso (Val =< 4294967295) ->
+ Bytes2 = enc_integer_notag(Val),
+ Len2 = elength(length(Bytes2)),
+ lists:append([67 | Len2], Bytes2);
+ true ->
+ exit({error, {bad_timeticks, Val}})
+ end;
enc_value('Counter64', Val) ->
Val2 =
if
@@ -682,18 +730,7 @@ enc_value('Counter64', Val) ->
end,
Bytes2 = enc_integer_notag(Val2),
Len2 = elength(length(Bytes2)),
- lists:append([70 | Len2],Bytes2);
-enc_value(Type, Val) ->
- Bytes2 = enc_integer_notag(Val),
- Len2 = elength(length(Bytes2)),
- lists:append([enc_val_tag(Type,Val) | Len2],Bytes2).
-
-enc_val_tag('Counter32',Val) when (Val >= 0) andalso (Val =< 4294967295) ->
- 65;
-enc_val_tag('Unsigned32', Val) when (Val >= 0) andalso (Val =< 4294967295) ->
- 66;
-enc_val_tag('TimeTicks', Val) when (Val >= 0) andalso (Val =< 4294967295) ->
- 67.
+ lists:append([70 | Len2],Bytes2).
%%----------------------------------------------------------------------
diff --git a/lib/snmp/src/misc/snmp_usm.erl b/lib/snmp/src/misc/snmp_usm.erl
index df2c1f0b18..bae6bdec72 100644
--- a/lib/snmp/src/misc/snmp_usm.erl
+++ b/lib/snmp/src/misc/snmp_usm.erl
@@ -1,21 +1,24 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
+%% 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
%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
+%% AES: RFC 3826
+%%
-module(snmp_usm).
@@ -24,7 +27,7 @@
-export([passwd2localized_key/3, localize_key/3]).
-export([auth_in/4, auth_out/4, set_msg_auth_params/3]).
-export([des_encrypt/3, des_decrypt/3]).
--export([aes_encrypt/3, aes_decrypt/5]).
+-export([aes_encrypt/5, aes_decrypt/5]).
-define(SNMP_USE_V3, true).
@@ -42,6 +45,9 @@
-define(i32(Int), (Int bsr 24) band 255, (Int bsr 16) band 255, (Int bsr 8) band 255, Int band 255).
+-define(BLOCK_CIPHER_AES, aes_cfb128).
+-define(BLOCK_CIPHER_DES, des_cbc).
+
%%-----------------------------------------------------------------
%% Func: passwd2localized_key/3
@@ -69,7 +75,7 @@ passwd2localized_key(Alg, Passwd, EngineID) when length(Passwd) > 0 ->
%%-----------------------------------------------------------------
localize_key(Alg, Key, EngineID) ->
Str = [Key, EngineID, Key],
- binary_to_list(crypto:Alg(Str)).
+ binary_to_list(crypto:hash(Alg, Str)).
mk_digest(md5, Passwd) ->
@@ -78,25 +84,25 @@ mk_digest(sha, Passwd) ->
mk_sha_digest(Passwd).
mk_md5_digest(Passwd) ->
- Ctx = crypto:md5_init(),
+ Ctx = crypto:hash_init(md5),
Ctx2 = md5_loop(0, [], Ctx, Passwd, length(Passwd)),
- crypto:md5_final(Ctx2).
+ crypto:hash_final(Ctx2).
md5_loop(Count, Buf, Ctx, Passwd, PasswdLen) when Count < 1048576 ->
{Buf64, NBuf} = mk_buf64(length(Buf), Buf, Passwd, PasswdLen),
- NCtx = crypto:md5_update(Ctx, Buf64),
+ NCtx = crypto:hash_update(Ctx, Buf64),
md5_loop(Count+64, NBuf, NCtx, Passwd, PasswdLen);
md5_loop(_Count, _Buf, Ctx, _Passwd, _PasswdLen) ->
Ctx.
mk_sha_digest(Passwd) ->
- Ctx = crypto:sha_init(),
+ Ctx = crypto:hash_init(sha),
Ctx2 = sha_loop(0, [], Ctx, Passwd, length(Passwd)),
- crypto:sha_final(Ctx2).
+ crypto:hash_final(Ctx2).
sha_loop(Count, Buf, Ctx, Passwd, PasswdLen) when Count < 1048576 ->
{Buf64, NBuf} = mk_buf64(length(Buf), Buf, Passwd, PasswdLen),
- NCtx = crypto:sha_update(Ctx, Buf64),
+ NCtx = crypto:hash_update(Ctx, Buf64),
sha_loop(Count+64, NBuf, NCtx, Passwd, PasswdLen);
sha_loop(_Count, _Buf, Ctx, _Passwd, _PasswdLen) ->
Ctx.
@@ -142,26 +148,33 @@ auth_out(?usmHMACSHAAuthProtocol, AuthKey, Message, UsmSecParams) ->
sha_auth_out(AuthKey, Message, UsmSecParams).
md5_auth_out(AuthKey, Message, UsmSecParams) ->
+ %% ?vtrace("md5_auth_out -> entry with"
+ %% "~n AuthKey: ~w"
+ %% "~n Message: ~w"
+ %% "~n UsmSecParams: ~w", [AuthKey, Message, UsmSecParams]),
%% 6.3.1.1
Message2 = set_msg_auth_params(Message, UsmSecParams, ?twelwe_zeros),
- Packet = snmp_pdus:enc_message_only(Message2),
+ Packet = snmp_pdus:enc_message_only(Message2),
%% 6.3.1.2-4 is done by the crypto function
%% 6.3.1.4
- MAC = binary_to_list(crypto:md5_mac_96(AuthKey, Packet)),
+ MAC = binary_to_list(crypto:hmac(md5, AuthKey, Packet, 12)),
+ %% ?vtrace("md5_auth_out -> crypto (md5) encoded"
+ %% "~n MAC: ~w", [MAC]),
%% 6.3.1.5
set_msg_auth_params(Message, UsmSecParams, MAC).
md5_auth_in(AuthKey, AuthParams, Packet) when length(AuthParams) == 12 ->
+ %% ?vtrace("md5_auth_in -> entry with"
+ %% "~n AuthKey: ~w"
+ %% "~n AuthParams: ~w"
+ %% "~n Packet: ~w", [AuthKey, AuthParams, Packet]),
%% 6.3.2.3
Packet2 = patch_packet(binary_to_list(Packet)),
%% 6.3.2.5
- MAC = binary_to_list(crypto:md5_mac_96(AuthKey, Packet2)),
+ MAC = binary_to_list(crypto:hmac(md5, AuthKey, Packet2, 12)),
%% 6.3.2.6
-%% ?vtrace("md5_auth_in -> entry with"
-%% "~n Packet2: ~w"
-%% "~n AuthKey: ~w"
-%% "~n AuthParams: ~w"
-%% "~n MAC: ~w", [Packet2, AuthKey, AuthParams, MAC]),
+ %% ?vtrace("md5_auth_in -> crypto (md5) encoded"
+ %% "~n MAC: ~w", [MAC]),
MAC == AuthParams;
md5_auth_in(_AuthKey, _AuthParams, _Packet) ->
%% 6.3.2.1
@@ -177,7 +190,7 @@ sha_auth_out(AuthKey, Message, UsmSecParams) ->
Packet = snmp_pdus:enc_message_only(Message2),
%% 7.3.1.2-4 is done by the crypto function
%% 7.3.1.4
- MAC = binary_to_list(crypto:sha_mac_96(AuthKey, Packet)),
+ MAC = binary_to_list(crypto:hmac(sha, AuthKey, Packet, 12)),
%% 7.3.1.5
set_msg_auth_params(Message, UsmSecParams, MAC).
@@ -185,7 +198,7 @@ sha_auth_in(AuthKey, AuthParams, Packet) when length(AuthParams) =:= 12 ->
%% 7.3.2.3
Packet2 = patch_packet(binary_to_list(Packet)),
%% 7.3.2.5
- MAC = binary_to_list(crypto:sha_mac_96(AuthKey, Packet2)),
+ MAC = binary_to_list(crypto:hmac(sha, AuthKey, Packet2, 12)),
%% 7.3.2.6
MAC == AuthParams;
sha_auth_in(_AuthKey, _AuthParams, _Packet) ->
@@ -203,7 +216,8 @@ des_encrypt(PrivKey, Data, SaltFun) ->
IV = list_to_binary(snmp_misc:str_xor(PreIV, Salt)),
TailLen = (8 - (length(Data) rem 8)) rem 8,
Tail = mk_tail(TailLen),
- EncData = crypto:des_cbc_encrypt(DesKey, IV, [Data,Tail]),
+ EncData = crypto:block_encrypt(?BLOCK_CIPHER_DES,
+ DesKey, IV, [Data,Tail]),
{ok, binary_to_list(EncData), Salt}.
des_decrypt(PrivKey, MsgPrivParams, EncData)
@@ -217,7 +231,8 @@ des_decrypt(PrivKey, MsgPrivParams, EncData)
Salt = MsgPrivParams,
IV = list_to_binary(snmp_misc:str_xor(PreIV, Salt)),
%% Whatabout errors here??? E.g. not a mulitple of 8!
- Data = binary_to_list(crypto:des_cbc_decrypt(DesKey, IV, EncData)),
+ Data = binary_to_list(crypto:block_decrypt(?BLOCK_CIPHER_DES,
+ DesKey, IV, EncData)),
Data2 = snmp_pdus:strip_encrypted_scoped_pdu_data(Data),
{ok, Data2};
des_decrypt(PrivKey, BadMsgPrivParams, EncData) ->
@@ -229,13 +244,12 @@ des_decrypt(PrivKey, BadMsgPrivParams, EncData) ->
throw({error, {bad_msgPrivParams, PrivKey, BadMsgPrivParams, EncData}}).
-aes_encrypt(PrivKey, Data, SaltFun) ->
+aes_encrypt(PrivKey, Data, SaltFun, EngineBoots, EngineTime) ->
AesKey = PrivKey,
Salt = SaltFun(),
- EngineBoots = snmp_framework_mib:get_engine_boots(),
- EngineTime = snmp_framework_mib:get_engine_time(),
IV = list_to_binary([?i32(EngineBoots), ?i32(EngineTime) | Salt]),
- EncData = crypto:aes_cfb_128_encrypt(AesKey, IV, Data),
+ EncData = crypto:block_encrypt(?BLOCK_CIPHER_AES,
+ AesKey, IV, Data),
{ok, binary_to_list(EncData), Salt}.
aes_decrypt(PrivKey, MsgPrivParams, EncData, EngineBoots, EngineTime)
@@ -244,7 +258,8 @@ aes_decrypt(PrivKey, MsgPrivParams, EncData, EngineBoots, EngineTime)
Salt = MsgPrivParams,
IV = list_to_binary([?i32(EngineBoots), ?i32(EngineTime) | Salt]),
%% Whatabout errors here??? E.g. not a mulitple of 8!
- Data = binary_to_list(crypto:aes_cfb_128_decrypt(AesKey, IV, EncData)),
+ Data = binary_to_list(crypto:block_decrypt(?BLOCK_CIPHER_AES,
+ AesKey, IV, EncData)),
Data2 = snmp_pdus:strip_encrypted_scoped_pdu_data(Data),
{ok, Data2}.
diff --git a/lib/snmp/src/misc/snmp_verbosity.erl b/lib/snmp/src/misc/snmp_verbosity.erl
index 85037ba2ae..edfb52a474 100644
--- a/lib/snmp/src/misc/snmp_verbosity.erl
+++ b/lib/snmp/src/misc/snmp_verbosity.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2015. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
@@ -69,14 +70,14 @@ print2(_Verbosity,Format,Arguments) ->
timestamp() ->
- format_timestamp(now()).
+ 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 4~w",
+ 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).
@@ -144,8 +145,12 @@ image_of_sname(mse) -> "M-SERVER";
image_of_sname(msew) -> io_lib:format("M-SERVER-worker(~p)", [self()]);
image_of_sname(mns) -> "M-NOTE-STORE";
image_of_sname(mnif) -> "M-NET-IF";
+image_of_sname(mnifl) -> "M-NET-IF-LOGGER";
+image_of_sname(mnifw) -> io_lib:format("M-NET-IF-worker(~p)", [self()]);
image_of_sname(mconf) -> "M-CONF";
+image_of_sname(lc) -> io_lib:format("LOG-CONVERTER(~p)", [self()]);
+
image_of_sname(mgr) -> "MGR";
image_of_sname(mgr_misc) -> "MGR_MISC";
@@ -158,4 +163,3 @@ validate(log) -> log;
validate(debug) -> debug;
validate(trace) -> trace;
validate(_) -> silence.
-
diff --git a/lib/snmp/src/misc/snmp_verbosity.hrl b/lib/snmp/src/misc/snmp_verbosity.hrl
index 934d32831f..c79f4c3e88 100644
--- a/lib/snmp/src/misc/snmp_verbosity.hrl
+++ b/lib/snmp/src/misc/snmp_verbosity.hrl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% 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%
%%
diff --git a/lib/snmp/src/subdirs.mk b/lib/snmp/src/subdirs.mk
index 1cbcd04b54..5f45fd2586 100644
--- a/lib/snmp/src/subdirs.mk
+++ b/lib/snmp/src/subdirs.mk
@@ -2,18 +2,19 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2003-2009. All Rights Reserved.
+# Copyright Ericsson AB 2003-2016. All Rights Reserved.
#
-# The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved online at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
+# 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%