From 622952a654c2c8dd6ada8e0001343dfe2bce72e2 Mon Sep 17 00:00:00 2001
From: Micael Karlberg <bmk@erlang.org>
Date: Fri, 2 Aug 2013 15:35:54 +0200
Subject: [snmp/agent] Improved loading and unload of MIBs

Improved the documentation of the loading and unloading
of MIBs (plural). also added functions for loading and
unloading a single mib.

OTP-11216
---
 lib/snmp/src/agent/snmpa.erl       | 70 ++++++++++++++++++++++++++++++++++----
 lib/snmp/src/agent/snmpa_agent.erl | 32 ++++++++++++++---
 lib/snmp/src/agent/snmpa_mib.erl   | 49 +++++++++++++++++++-------
 lib/snmp/src/app/snmp.appup.src    | 24 +++++++++++--
 4 files changed, 150 insertions(+), 25 deletions(-)

(limited to 'lib/snmp/src')

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_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}}};
diff --git a/lib/snmp/src/app/snmp.appup.src b/lib/snmp/src/app/snmp.appup.src
index 16b626111b..6edcf7e833 100644
--- a/lib/snmp/src/app/snmp.appup.src
+++ b/lib/snmp/src/app/snmp.appup.src
@@ -29,12 +29,22 @@
 %% {add_module,  snmpm_net_if_mt}
 
  [
+  {"4.24.1", 
+   [
+    {load_module, snmpa, soft_purge, soft_purge, [snmpa_agent]}, 
+    {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_agent]}, 
+    {update, snmpa_mib,   soft, soft_purge, soft_purge, []}
+   ]
+  }, 
   {"4.24", 
    [
     {load_module, snmp_conf,               soft_purge, soft_purge, []}, 
     {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, 
      [snmp_conf]}, 
-    {update, snmpa_local_db, soft, soft_purge, soft_purge, []}
+    {load_module, snmpa, soft_purge, soft_purge, [snmpa_agent]}, 
+    {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, 
+    {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_agent]}, 
+    {update, snmpa_mib,   soft, soft_purge, soft_purge, []}
    ]
   }, 
   {"4.23.1", [{restart_application, snmp}]}, 
@@ -47,12 +57,22 @@
 %% {remove, {snmpm_net_if_mt, soft_purge, soft_purge}}
 
  [
+  {"4.24.1", 
+   [
+    {load_module, snmpa, soft_purge, soft_purge, [snmpa_agent]}, 
+    {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_agent]}, 
+    {update, snmpa_mib,   soft, soft_purge, soft_purge, []}
+   ]
+  }, 
   {"4.24", 
    [
     {load_module, snmp_conf,               soft_purge, soft_purge, []}, 
     {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, 
      [snmp_conf]}, 
-    {update, snmpa_local_db, soft, soft_purge, soft_purge, []}
+    {load_module, snmpa, soft_purge, soft_purge, [snmpa_agent]}, 
+    {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, 
+    {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_agent]}, 
+    {update, snmpa_mib,   soft, soft_purge, soft_purge, []}
    ]
   }, 
   {"4.23.1", [{restart_application, snmp}]}, 
-- 
cgit v1.2.3