aboutsummaryrefslogtreecommitdiffstats
path: root/lib/snmp/src/agent
diff options
context:
space:
mode:
Diffstat (limited to 'lib/snmp/src/agent')
-rw-r--r--lib/snmp/src/agent/snmp_view_based_acm_mib.erl133
-rw-r--r--lib/snmp/src/agent/snmpa.erl70
-rw-r--r--lib/snmp/src/agent/snmpa_agent.erl32
-rw-r--r--lib/snmp/src/agent/snmpa_local_db.erl2
-rw-r--r--lib/snmp/src/agent/snmpa_mib.erl49
5 files changed, 243 insertions, 43 deletions
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 ad9540e886..c0177b1cea 100644
--- a/lib/snmp/src/agent/snmp_view_based_acm_mib.erl
+++ b/lib/snmp/src/agent/snmp_view_based_acm_mib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -49,6 +49,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.
@@ -160,14 +168,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 +195,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],
@@ -953,13 +954,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
@@ -977,6 +988,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).
@@ -1014,11 +1079,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}).
diff --git a/lib/snmp/src/agent/snmpa.erl b/lib/snmp/src/agent/snmpa.erl
index 14b93439df..a95e41ea42 100644
--- a/lib/snmp/src/agent/snmpa.erl
+++ b/lib/snmp/src/agent/snmpa.erl
@@ -39,8 +39,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,
@@ -300,19 +302,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) ->
diff --git a/lib/snmp/src/agent/snmpa_agent.erl b/lib/snmp/src/agent/snmpa_agent.erl
index c267ce5a70..9bed6e554e 100644
--- a/lib/snmp/src/agent/snmpa_agent.erl
+++ b/lib/snmp/src/agent/snmpa_agent.erl
@@ -28,7 +28,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 +72,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").
@@ -528,12 +530,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).
@@ -1216,13 +1228,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", []),
diff --git a/lib/snmp/src/agent/snmpa_local_db.erl b/lib/snmp/src/agent/snmpa_local_db.erl
index 2c0cad807a..5198c6ec4e 100644
--- a/lib/snmp/src/agent/snmpa_local_db.erl
+++ b/lib/snmp/src/agent/snmpa_local_db.erl
@@ -583,7 +583,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) ->
diff --git a/lib/snmp/src/agent/snmpa_mib.erl b/lib/snmp/src/agent/snmpa_mib.erl
index 031309b990..5b523447c5 100644
--- a/lib/snmp/src/agent/snmpa_mib.erl
+++ b/lib/snmp/src/agent/snmpa_mib.erl
@@ -26,7 +26,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,
@@ -39,6 +39,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]).
@@ -182,19 +186,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}).
%%----------------------------------------------------------------------
@@ -323,10 +340,6 @@ do_init(Prio, Mibs, Opts) ->
%% Returns: {ok, NewMibData} | {'aborted at', Mib, NewData, Reason}
%% Args: Operation is load_mib | unload_mib.
%%----------------------------------------------------------------------
-mib_operations(Mod, Operation, Mibs, Data, MeOverride, TeOverride) ->
- mib_operations(Mod, Operation, Mibs, Data, MeOverride, TeOverride, false).
-
-
mib_operations(_Mod, _Operation, [], Data, _MeOverride, _TeOverride, _Force) ->
{ok, Data};
mib_operations(Mod, Operation, [Mib|Mibs], Data0, MeOverride, TeOverride, Force) ->
@@ -451,18 +464,23 @@ handle_call({next, Oid, MibView}, _From,
?vdebug("next -> Reply: ~p", [Reply]),
{reply, Reply, NewState};
-handle_call({load_mibs, Mibs}, _From,
+%% <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("load mibs ~p",[Mibs]),
+ ?vlog("[~w] load mibs ~p", [Force, Mibs]),
%% Invalidate cache
NewCache = maybe_invalidate_cache(Cache),
{NData, Reply} =
case (catch mib_operations(Mod, load_mib, Mibs, Data,
- MeOverride, TeOverride)) of
+ 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}}};
@@ -472,19 +490,24 @@ handle_call({load_mibs, Mibs}, _From,
Mod:sync(NData),
{reply, Reply, State#state{data = NData, cache = NewCache}};
-handle_call({unload_mibs, Mibs}, _From,
+%% <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("unload mibs ~p",[Mibs]),
+ ?vlog("[~w] unload mibs ~p", [Force, Mibs]),
%% Invalidate cache
NewCache = maybe_invalidate_cache(Cache),
%% Unload mib(s)
{NData, Reply} =
case (catch mib_operations(Mod, unload_mib, Mibs, Data,
- MeOverride, TeOverride)) of
+ MeOverride, TeOverride, Force)) of
{'aborted at', Mib, NewData, Reason} ->
?vlog("aborted at ~p for reason ~p", [Mib,Reason]),
{NewData, {error, {'unload aborted at', Mib, Reason}}};