File 3733-snmp-manager-Add-active-supervision-of-NetIF.patch of Package erlang

From e07bd386c429cda10df4c6e2673c11e9a095eeea Mon Sep 17 00:00:00 2001
From: Micael Karlberg <bmk@erlang.org>
Date: Wed, 26 Feb 2020 14:08:45 +0100
Subject: [PATCH 3/5] [snmp|manager] Add active supervision of NetIF

Add an active NetIF process supervision.
Basically this mean create a process (if configured
to use this) that actively supervises the NetIF
process. This done by simply sending a 'ping'
message to NetIF, which it has to answer with a pong
message.

OTP-16447
---
 lib/snmp/src/manager/snmpm.erl        |   5 +-
 lib/snmp/src/manager/snmpm_config.erl |  21 ++-
 lib/snmp/src/manager/snmpm_net_if.erl |  40 +++-
 lib/snmp/src/manager/snmpm_server.erl | 339 ++++++++++++++++++++++++++++++++--
 lib/snmp/src/manager/snmpm_user.erl   |   4 +-
 lib/snmp/src/misc/snmp_verbosity.erl  |   1 +
 lib/snmp/src/misc/snmp_verbosity.hrl  |  34 +++-
 7 files changed, 419 insertions(+), 25 deletions(-)

diff --git a/lib/snmp/src/manager/snmpm.erl b/lib/snmp/src/manager/snmpm.erl
index fe30dbbdff..c0859f6fd8 100644
--- a/lib/snmp/src/manager/snmpm.erl
+++ b/lib/snmp/src/manager/snmpm.erl
@@ -89,7 +89,7 @@
 	 system_start_time/0,
 	 sys_up_time/0,
 
-	 info/0, 
+	 info/0, info/1,
 	 verbosity/2,
          restart/1
 	]).
@@ -298,6 +298,9 @@ oid_to_type(Oid) ->
 info() ->
     snmpm_server:info().
 
+info(Key) ->
+    proplists:get_value(Key, info(), {error, not_found}).
+
 
 %% -- Verbosity -- 
 
diff --git a/lib/snmp/src/manager/snmpm_config.erl b/lib/snmp/src/manager/snmpm_config.erl
index fc6ddc5738..decda09022 100644
--- a/lib/snmp/src/manager/snmpm_config.erl
+++ b/lib/snmp/src/manager/snmpm_config.erl
@@ -151,6 +151,7 @@
 -define(SERVER_OPT_GCT_DEFAULT,  30000).
 -define(SERVER_OPT_MT_DEFAULT,   true).
 -define(SERVER_OPT_CBP_DEFAULT,  temporary). % permanent
+-define(SERVER_OPT_NIS_DEFAULT,  none).
 
 %% -define(DEF_ADDR_TAG,       default_addr_tag).
 -define(DEFAULT_TARGETNAME, default_agent).
@@ -1115,15 +1116,17 @@ do_init(Opts) ->
     end,
 
     %% -- Server (optional) --
-    ServerOpts = get_opt(server,         Opts,      []),
+    ServerOpts = get_opt(server,         Opts,       []),
     ServerVerb = get_opt(verbosity,      ServerOpts, ?SERVER_OPT_VERB_DEFAULT),
     ServerGct  = get_opt(timeout,        ServerOpts, ?SERVER_OPT_GCT_DEFAULT),
     ServerMt   = get_opt(multi_threaded, ServerOpts, ?SERVER_OPT_MT_DEFAULT),
     ServerCBP  = get_opt(cbproxy,        ServerOpts, ?SERVER_OPT_CBP_DEFAULT),
+    ServerNIS  = get_opt(netif_sup,      ServerOpts, ?SERVER_OPT_NIS_DEFAULT),
     ets:insert(snmpm_config_table, {server_verbosity,      ServerVerb}),
     ets:insert(snmpm_config_table, {server_timeout,        ServerGct}),
     ets:insert(snmpm_config_table, {server_multi_threaded, ServerMt}),
     ets:insert(snmpm_config_table, {server_cbproxy,        ServerCBP}),
+    ets:insert(snmpm_config_table, {server_nis,            ServerNIS}),
    
     %% -- Mibs (optional) --
     ?vdebug("initiate mini mib", []),
@@ -1132,7 +1135,7 @@ do_init(Opts) ->
     init_mini_mib(Mibs),
 
     %% -- Net-if (optional) --
-    ?vdebug("net_if options", []),
+    ?vdebug("net-if options", []),
     NetIfIrb     = 
 	case get_opt(inform_request_behaviour, Opts, ?IRB_DEFAULT) of
 	    user ->
@@ -1421,6 +1424,9 @@ verify_server_opts([{multi_threaded, MT}|Opts]) when is_boolean(MT) ->
 verify_server_opts([{cbproxy, CBP}|Opts]) ->
     verify_server_cbproxy(CBP),
     verify_server_opts(Opts);
+verify_server_opts([{netif_sup, NIS}|Opts]) ->
+    verify_server_nis(NIS),
+    verify_server_opts(Opts);
 verify_server_opts([Opt|_]) ->
     error({invalid_server_option, Opt}).
 
@@ -1436,6 +1442,17 @@ verify_server_cbproxy(permanent) ->
 verify_server_cbproxy(CBP) ->
     error({invalid_server_cbproxy, CBP}).
 
+verify_server_nis(none) ->
+    ok;
+verify_server_nis({PingTo, PongTo} = V) when is_integer(PingTo) andalso
+                                             (PingTo > 0) andalso
+                                             is_integer(PongTo) andalso
+                                             (PongTo > 0) ->
+    ok;
+verify_server_nis(NIS) ->
+    error({invalid_server_netif_sup, NIS}).
+
+
 verify_net_if_opts([]) ->
     ok;
 verify_net_if_opts([{module, Mod}|Opts]) ->
diff --git a/lib/snmp/src/manager/snmpm_net_if.erl b/lib/snmp/src/manager/snmpm_net_if.erl
index c2e5c6d2f0..0d57bc944a 100644
--- a/lib/snmp/src/manager/snmpm_net_if.erl
+++ b/lib/snmp/src/manager/snmpm_net_if.erl
@@ -58,6 +58,14 @@
 %% -define(VMODULE,"NET_IF").
 -include("snmp_verbosity.hrl").
 
+%% This is for debugging!!
+-ifdef(snmp_debug).
+-define(allow_exec, true).
+-else.
+-define(allow_exec, false).
+-endif.
+
+
 -record(state,
 	{
 	  server,
@@ -67,7 +75,8 @@
 	  log,
 	  irb = auto, % auto | {user, integer()}
 	  irgc,
-	  filter
+          filter,
+          allow_exec = ?allow_exec
 	 }).
 
 -record(transport,
@@ -92,6 +101,7 @@
 -define(ATL_SEQNO_MAX,     2147483647).
 
 
+
 %%%-------------------------------------------------------------------
 %%% API
 %%%-------------------------------------------------------------------
@@ -520,6 +530,13 @@ handle_call(info, _From, State) ->
     Reply = get_info(State),
     {reply, Reply, State};
 
+%% This is for debugging!!
+handle_call({exec, F}, _From, #state{allow_exec = true} = State)
+  when is_function(F, 0) ->
+    ?vlog("[call] exec", []),
+    {reply, F(), State};
+
+
 handle_call(Req, From, State) ->
     warning_msg("received unknown request (from ~p): ~n~p", [Req, From]),
     {reply, {error, {invalid_request, Req}}, State}.
@@ -556,6 +573,13 @@ handle_cast(filter_reset, State) ->
     reset_counters(),
     {noreply, State};
 
+%% This is for debugging!!
+handle_cast({exec, F}, #state{allow_exec = true} = State) when is_function(F, 0) ->
+    ?vlog("[cast] exec", []),
+    F(),
+    {noreply, State};
+
+
 handle_cast(Msg, State) ->
     warning_msg("received unknown message: ~n~p", [Msg]),
     {noreply, State}.
@@ -597,6 +621,20 @@ handle_info({disk_log, _Node, Log, Info}, State) ->
 handle_info({'DOWN', _, _, _, _} = Info, State) ->
     handle_info_down(Info, State);
 
+
+handle_info({ping, Pid}, State) ->
+    ?vdebug("received ping message from ~p", [Pid]),
+    Pid ! {pong, self()},
+    {noreply, State};
+
+
+%% This is for debugging!!
+handle_info({exec, F}, #state{allow_exec = true} = State) when is_function(F, 0) ->
+    ?vlog("[info] exec", []),
+    F(),
+    {noreply, State};
+
+
 handle_info(Info, State) ->
     handle_info_unknown(Info, State).
 
diff --git a/lib/snmp/src/manager/snmpm_server.erl b/lib/snmp/src/manager/snmpm_server.erl
index b3740b4d83..1a8d09ab9b 100644
--- a/lib/snmp/src/manager/snmpm_server.erl
+++ b/lib/snmp/src/manager/snmpm_server.erl
@@ -77,6 +77,9 @@
 %% GCT exports
 -export([gct_init/1, gct/2]).
 
+%% NIS exports
+-export([nis_init/2, nis_loop/1]).
+
 %% CallBack Proxy exports
 -export([cbproxy_loop/1,
 	 do_handle_error/4,
@@ -157,6 +160,24 @@
 	 net_if,
 	 net_if_mod,
 	 net_if_ref,
+
+         %% NetIF supervision
+         %% This (config) option defines if/how the "server"
+         %% shall supervise the net-if process.
+         %% And by "supervise" we don't meant in the way a
+         %% *supervisor" supervisor. This is "active" supervision
+         %% (basically, send ping and expect pong back).
+         %% There are two alternatives:
+         %%      none - No supervision (default)
+         %%      {PingInterval, PongTimeout}
+         %%         PingInterval :: pos_integer()
+         %%            Time between a successful test and the next.
+         %%         PongInterval :: pos_integer()
+         %%            Time the NetIF process has to answer a ping
+         %%      
+	 nis     :: none | {pos_integer(), pos_integer()},
+         nis_pid :: undefined | pid(), % Pid of the process doing the actual sup
+
 	 req,  %%  ???? Last request id in outgoing message
 	 oid,  %%  ???? Last oid in request outgoing message
 	 mini_mib,
@@ -591,6 +612,15 @@ do_init() ->
     {NoteStore, NoteStoreRef}      = do_init_note_store(Prio),
     {NetIf, NetIfModule, NetIfRef} = do_init_net_if(NoteStore),
 
+    %% -- (maybe) Start the NetIF "supervisor" --
+    {NIS, NISPid} =
+        case snmpm_config:system_info(server_nis) of
+            {ok, none = V} ->
+                {V, undefined};
+            {ok, {PingTO, PongTO} = V} ->
+                {V, nis_start(NetIf, PingTO, PongTO)}
+        end,
+
     MiniMIB = snmpm_config:make_mini_mib(),
     State = #state{mini_mib       = MiniMIB,
 		   gct            = GCT,
@@ -599,6 +629,8 @@ do_init() ->
 		   net_if         = NetIf,
 		   net_if_mod     = NetIfModule,
 		   net_if_ref     = NetIfRef,
+                   nis            = NIS,
+                   nis_pid        = NISPid,
                    cbproxy        = CBProxy,
 		   cbproxy_pid    = CBPPid},
     ?vlog("started", []),
@@ -1086,12 +1118,11 @@ handle_info(gc_timeout, #state{gct = GCT} = State) ->
     {noreply, State};
 
 
-handle_info({'DOWN', _MonRef, process, Pid, _Reason}, 
-	    #state{note_store = NoteStore, 
-		   net_if     = Pid} = State) ->
+handle_info({'DOWN', _MonRef, process, Pid, Reason}, 
+	    #state{net_if = Pid} = State) ->
     ?vlog("received 'DOWN' message regarding net_if (~p)", [Pid]),
-    {NetIf, _, Ref} = do_init_net_if(NoteStore),
-    {noreply, State#state{net_if = NetIf, net_if_ref = Ref}};
+    NewState = handle_netif_down(State, Reason),
+    {noreply, NewState};
 
 
 handle_info({'DOWN', _MonRef, process, Pid, _Reason}, 
@@ -1127,8 +1158,17 @@ handle_info({'EXIT', Pid, Reason}, #state{cbproxy_pid = Pid} = State) ->
     {noreply, State#state{cbproxy_pid = NewCBP}};
 
 
+handle_info({'EXIT', Pid, Reason}, #state{net_if  = NetIF,
+                                          nis     = {PingTO, PongTO},
+                                          nis_pid = Pid} = State) ->
+    warning_msg("NetIF (active) supervisor (~w) process crashed: "
+		"~n   ~p", [Pid, Reason]),
+    NewNIS = nis_start(NetIF, PingTO, PongTO),
+    {noreply, State#state{nis_pid = NewNIS}};
+
+
 handle_info(Info, State) ->
-    warning_msg("received unknown info: ~n~p", [Info]),
+    warning_msg("received unknown info: ~n   ~p", [Info]),
     {noreply, State}.
 
 
@@ -1155,8 +1195,9 @@ code_change(_Vsn, #state{gct = Pid} = State0, _Extra) ->
 %% Terminate
 %%----------------------------------------------------------
                                                                               
-terminate(Reason, #state{gct = GCT, cbproxy = CBP}) ->
+terminate(Reason, #state{nis_pid = NIS, gct = GCT, cbproxy = CBP}) ->
     ?vdebug("terminate: ~p",[Reason]),
+    nis_stop(NIS),
     cbproxy_stop(CBP),
     gct_stop(GCT),
     snmpm_misc_sup:stop_note_store(),
@@ -3128,7 +3169,17 @@ handle_invalid_result(Func, Args, InvalidResult) ->
 	      "~n   Invalid result: ~p", 
 	      [Func, Args, InvalidResult]).
 
-	    
+
+handle_netif_down(#state{note_store = NoteStore, 
+                         nis_pid    = NIS} = State,
+                  Reason) ->
+    %% Srart a new NetIF
+    {NetIF, _, Ref} = do_init_net_if(NoteStore),
+    %% Inform the (active) supervisor
+    nis_netif(NIS, NetIF),
+    netif_down_inform_users(Reason),
+    State#state{net_if = NetIF, net_if_ref = Ref}.
+
 handle_down(MonRef) ->
     (catch do_handle_down(MonRef)).
 
@@ -3616,6 +3667,258 @@ new_timeout(T1, T2) ->
     end.
 
 
+%%----------------------------------------------------------------------
+%% NetIF Supervisor
+%%
+%% The NIS process "supervises" the NetIF process. That does *not* mean
+%% that it takes on the role of a standard erlang 'supervisor' process.
+%% The NIS is instead a process that "actively" supervises by means
+%% of "ping" messages, which the supervised process must respond to
+%% (with a pong message) *in time*.
+%% If it does not, NIS assumes that it has hung, and kills it.
+%% The server process then restarts the NetIF process and informs NIS.
+%%----------------------------------------------------------------------
+
+nis_start(NetIF, PingTO, PongTO) ->
+    ?vdebug("start nis process (~w, ~w)", [PingTO, PongTO]),
+    State = #{parent     => self(),
+              netif_pid  => NetIF,
+              ping_to    => PingTO,
+              ping_tref  => undefined,
+              ping_start => undefined, % Time when ping sent
+              ping_max   => undefined, % Max roundtrip time
+              pong_to    => PongTO,
+              pong_tref  => undefined,
+              kill_cnt   => 0},
+    proc_lib:start_link(?MODULE, nis_init, [State, get(verbosity)]).
+
+nis_stop(NIS) when is_pid(NIS) ->
+    NIS ! {?MODULE, self(), stop};
+nis_stop(_) ->
+    ok.
+
+
+nis_info(NIS) when is_pid(NIS) ->
+    NIS ! {?MODULE, self(), info},
+    receive
+        {?MODULE, NIS, {info, Info}} ->
+            Info
+    after 1000 ->
+            []
+    end;
+nis_info(_) ->
+    [].
+
+
+nis_netif(NIS, NetIF) when is_pid(NIS) andalso is_pid(NetIF) ->
+    NIS ! {?MODULE, self(), {netif, NetIF}};
+nis_netif(_, _) ->
+    ok.
+
+
+nis_init(#{parent    := Parent,
+           netif_pid := NetIF,
+           ping_to   := PingTO} = State,
+         Verbosity) ->
+    put(verbosity, Verbosity),
+    put(sname, mnis),
+    ?vlog("starting"),
+    MRef = erlang:monitor(process, NetIF),
+    TRef = erlang:start_timer(PingTO, self(), ping_timeout),
+    erlang:register(snmpm_server_nis, self()),
+    proc_lib:init_ack(Parent, self()),
+    ?vlog("started"),
+    nis_loop(State#{netif_mref => MRef,
+                    ping_tref  => TRef}).
+
+%% The NetIF is dead. Its up to the server to restart it and inform us
+nis_loop(#{parent    := Parent,
+           netif_pid := undefined,
+           ping_tref := undefined,
+           pong_tref := undefined} = State) ->
+    receive
+        {?MODULE, Parent, stop} ->
+            ?vlog("[idle] stop received"),
+            nis_handle_stop(State),
+            exit(normal);
+
+        {?MODULE, Pid, info} ->
+            ?vtrace("[idle] info received"),
+	    Info = nis_handle_info(State),
+	    Pid ! {?MODULE, self(), {info, Info}},
+            ?MODULE:nis_loop(State);
+
+        {?MODULE, Parent, {netif, NetIF}} ->
+            ?vlog("[idle] (new) netif started: ~p => start ping timer", [NetIF]),
+            MRef   = erlang:monitor(process, NetIF),
+            PingTO = maps:get(ping_to, State),
+            TRef   = erlang:start_timer(PingTO, self(), ping_timeout),
+            ?MODULE:nis_loop(State#{netif_pid  => NetIF,
+                                    netif_mref => MRef,
+                                    ping_max   => undefined,
+                                    ping_tref  => TRef});
+
+        _Any ->
+            ?MODULE:nis_loop(State)
+
+    after 5000 ->
+            %% This is for code upgrade
+            ?MODULE:nis_loop(State)
+    end;
+
+%% PING timer running (waiting for ping-timeout)
+nis_loop(#{parent     := Parent,
+           netif_pid  := NetIF,
+           netif_mref := MRef,
+           ping_tref  := PingTRef,
+           pong_tref  := undefined} = State) when is_pid(NetIF) andalso
+                                                 (PingTRef =/= undefined) ->
+    receive
+        {'DOWN', MRef, process, NetIF, _} ->
+            ?vlog("[ping] netif died => cancel ping timer"),
+            erlang:cancel_timer(PingTRef),            
+            ?MODULE:nis_loop(State#{netif_pid  => undefined,
+                                    netif_mref => undefined,
+                                    ping_tref  => undefined});
+
+        {?MODULE, Parent, stop} ->
+            ?vlog("[ping] stop received"),
+            nis_handle_stop(State),
+            exit(normal);
+
+        {?MODULE, Pid, info} ->
+            ?vtrace("[ping] info received"),
+	    Info = nis_handle_info(State),
+	    Pid ! {?MODULE, self(), {info, Info}},
+            ?MODULE:nis_loop(State);
+
+        %% Time to ping NetIF
+        {timeout, PingTRef, ping_timeout} ->
+            ?vlog("[ping] (ping-) timer timeout => send ping and start pong timer"),
+            NetIF ! {ping, self()},
+            PongTO = maps:get(pong_to, State),
+            TRef   = erlang:start_timer(PongTO, self(), pong_timeout),
+            ?MODULE:nis_loop(State#{ping_tref  => undefined,
+                                    ping_start => us(),
+                                    pong_tref  => TRef});
+
+        _Any ->
+            ?MODULE:nis_loop(State)
+
+    after 5000 ->
+            %% This is for code upgrade
+            ?MODULE:nis_loop(State)
+    end;
+
+%% PONG timer running (waiting for pong message)
+nis_loop(#{parent     := Parent,
+           netif_pid  := NetIF,
+           netif_mref := MRef,
+           ping_tref  := undefined,
+           pong_tref  := PongTRef} = State) when is_pid(NetIF) andalso
+                                                 (PongTRef =/= undefined) ->
+    receive
+        {'DOWN', MRef, process, NetIF, _} ->
+            ?vlog("[pong] netif died => cancel pong timer"),
+            erlang:cancel_timer(PongTRef),            
+            ?MODULE:nis_loop(State#{netif_pid  => undefined,
+                                    netif_mref => undefined,
+                                    pong_tref  => undefined});
+
+        {?MODULE, Parent, stop} ->
+            ?vlog("[pong] stop received"),
+            nis_handle_stop(State),
+            exit(normal);
+
+        {?MODULE, Pid, info} ->
+            ?vlog("[pong] info received"),
+	    Info = nis_handle_info(State),
+	    Pid ! {?MODULE, self(), {info, Info}},
+            ?MODULE:nis_loop(State);
+
+        {pong, NetIF} ->
+            ?vlog("[pong] received pong => cancel pong timer, start ping timer"),
+            T = us(),
+            erlang:cancel_timer(PongTRef),
+            Start    = maps:get(ping_start, State),
+            Max      = maps:get(ping_max, State),
+            RT       = T - Start,
+            NewMax   =
+                if
+                    (Max =:= undefined) ->
+                        ?vtrace("[pong] Max: ~w", [RT]),
+                        RT;
+                    (RT > Max) ->
+                        ?vtrace("[pong] New Max: ~w", [RT]),
+                        RT;
+                   true ->
+                        Max
+                end,
+            PingTO   = maps:get(ping_to, State),
+            PingTRef = erlang:start_timer(PingTO, self(), ping_timeout),
+            ?MODULE:nis_loop(State#{ping_tref  => PingTRef,
+                                    ping_start => undefined,
+                                    ping_max   => NewMax,
+                                    pong_tref  => undefined});
+
+        %% Time to kill NetIF
+        {timeout, PongTRef, pong_timeout} ->
+            ?vinfo("[pong] (pong-) timer timeout => kill NetIF (~p)", [NetIF]),
+            nis_handle_pong_timeout(NetIF, MRef),
+            KCnt = maps:get(kill_cnt, State),
+            ?MODULE:nis_loop(State#{netif_pid  => undefined,
+                                    netif_mref => undefined,
+                                    pong_tref  => undefined,
+                                    kill_cnt   => KCnt + 1});
+
+        _Any ->
+            ?MODULE:nis_loop(State)
+
+    after 5000 ->
+            %% This is for code upgrade
+            ?MODULE:nis_loop(State)
+    end.
+
+
+nis_handle_info(#{ping_max := undefined, kill_cnt := KCnt}) ->
+    [{kcnt, KCnt}];
+nis_handle_info(#{ping_max := Max, kill_cnt := KCnt}) ->
+    [{max, Max}, {kcnt, KCnt}].
+
+
+nis_handle_stop(#{pong_tref := PongTRef,
+                  ping_tref := PingTRef}) ->
+    cancel_timer(PongTRef),
+    cancel_timer(PingTRef).
+            
+%% Inform all users that the netif process has been killed
+nis_handle_pong_timeout(NetIF, MRef) ->
+    erlang:demonitor(MRef, [flush]),
+    exit(NetIF, kill),
+    netif_down_inform_users({pong, killed}),
+    ok.
+
+
+%%----------------------------------------------------------------------
+
+%% Inform all users that "something" fatal happened to the NetIF process.
+netif_down_inform_users(Reason) ->
+    InformUser = fun(UserId) ->
+                         spawn(fun() ->
+                                       case snmpm_config:user_info(UserId) of
+                                           {ok, UserMod, UserData} ->
+                                               UserMod:handle_error(netif,
+                                                                    Reason,
+                                                                    UserData);
+                                           {error, _} ->
+                                               ok
+                                       end,
+                                       exit(normal)
+                               end)
+                 end,
+    lists:foreach(InformUser, snmpm_config:which_users()).
+    
+
 %%----------------------------------------------------------------------
 
 maybe_delete(false, ReqId) ->
@@ -3684,15 +3987,16 @@ get_info(#state{gct        = GCT,
 		net_if     = NI,
                 net_if_mod = NIMod, 
 		note_store = NS,
+                nis_pid    = NIS,
 		cbproxy    = CBP}) ->
-    Info = [{server,         server_info(GCT, CBP)},
+    Info = [{server,         server_info(GCT, CBP, NIS)},
 	    {config,         config_info()},
 	    {net_if,         net_if_info(NI, NIMod)},
 	    {note_store,     note_store_info(NS)},
 	    {stats_counters, get_stats_counters()}],
     Info.
 
-server_info(GCT, CBP) ->
+server_info(GCT, CBP, NIS) ->
     {CBPInfo, CBPSz} =
 	if
 	    (CBP =:= permanent) ->
@@ -3701,12 +4005,20 @@ server_info(GCT, CBP) ->
 	    true ->
 		{[], []}
 	end,
+    {NISInfo, NISSz} =
+        case NIS of
+            undefined ->
+                {[], []};
+            _ ->
+                {[{nis, nis_info(NIS)}],
+                 [{nis, proc_mem(NIS)}]}
+        end,
     ProcSize = proc_mem(self()),
     GCTSz    = proc_mem(GCT),
     RTSz     = tab_size(snmpm_request_table),
     MTSz     = tab_size(snmpm_monitor_table),
-    [{process_memory, [{server, ProcSize}, {gct, GCTSz}] ++ CBPSz},
-     {db_memory, [{request, RTSz}, {monitor, MTSz}]}] ++ CBPInfo.
+    [{process_memory, [{server, ProcSize}, {gct, GCTSz}] ++ CBPSz ++ NISSz},
+     {db_memory, [{request, RTSz}, {monitor, MTSz}]}] ++ CBPInfo ++ NISInfo.
 
 proc_mem(P) when is_pid(P) ->
     case (catch erlang:process_info(P, memory)) of
@@ -3756,3 +4068,6 @@ note_store_info(Pid) ->
 
 
 %%----------------------------------------------------------------------
+
+us() ->
+    erlang:monotonic_time(micro_seconds).
diff --git a/lib/snmp/src/manager/snmpm_user.erl b/lib/snmp/src/manager/snmpm_user.erl
index c0100d372f..9d0077449a 100644
--- a/lib/snmp/src/manager/snmpm_user.erl
+++ b/lib/snmp/src/manager/snmpm_user.erl
@@ -1,7 +1,7 @@
 %% 
 %% %CopyrightBegin%
 %% 
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2020. 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.
@@ -41,7 +41,7 @@
 %% An "asynchronous" error has been detected 
 
 -callback handle_error(
-	    ReqId :: integer(), 
+	    ReqId :: netif | integer(), 
 	    Reason :: {unexpected_pdu, SnmpInfo :: snmp_gen_info()} |
 		      {invalid_sec_info,
 		       SecInfo :: term(),
diff --git a/lib/snmp/src/misc/snmp_verbosity.erl b/lib/snmp/src/misc/snmp_verbosity.erl
index 9b2676d048..a42a1acb3a 100644
--- a/lib/snmp/src/misc/snmp_verbosity.erl
+++ b/lib/snmp/src/misc/snmp_verbosity.erl
@@ -138,6 +138,7 @@ 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(mnis)      -> "M-NIS";
 image_of_sname(mconf)     -> "M-CONF";
 
 image_of_sname(lc)        -> io_lib:format("LOG-CONVERTER(~p)", [self()]);
diff --git a/lib/snmp/src/misc/snmp_verbosity.hrl b/lib/snmp/src/misc/snmp_verbosity.hrl
index c79f4c3e88..6aef28a854 100644
--- a/lib/snmp/src/misc/snmp_verbosity.hrl
+++ b/lib/snmp/src/misc/snmp_verbosity.hrl
@@ -24,39 +24,59 @@
 
 -ifdef(VMODULE).
 
+-define(vinfo(F),   ?vinfo(F, [])).
 -define(vinfo(F,A), snmp_verbosity:print(get(verbosity),info, ?VMODULE,F,A)).
+-define(vlog(F),    ?vlog(F, [])).
 -define(vlog(F,A),  snmp_verbosity:print(get(verbosity),log,  ?VMODULE,F,A)).
+-define(vdebug(F),  ?vdebug(F, [])).
 -define(vdebug(F,A),snmp_verbosity:print(get(verbosity),debug,?VMODULE,F,A)).
+-define(vtrace(F),  ?vtrace(F, [])).
 -define(vtrace(F,A),snmp_verbosity:print(get(verbosity),trace,?VMODULE,F,A)).
 
 -else.
 
+-define(vinfo(F),   ?vinfo(F, [])).
 -define(vinfo(F,A), snmp_verbosity:print(get(verbosity),info, F,A)).
+-define(vlog(F),    ?vlog(F, [])).
 -define(vlog(F,A),  snmp_verbosity:print(get(verbosity),log,  F,A)).
+-define(vdebug(F),  ?vdebug(F, [])).
 -define(vdebug(F,A),snmp_verbosity:print(get(verbosity),debug,F,A)).
+-define(vtrace(F),  ?vtrace(F, [])).
 -define(vtrace(F,A),snmp_verbosity:print(get(verbosity),trace,F,A)).
 
 -endif.
 
 -define(vvalidate(V), snmp_verbosity:validate(V)).
 
+-define(vinfoc(F),   ?vinfoc(F, [])).
 -define(vinfoc(F,A), snmp_verbosity:printc(get(verbosity),info, F,A)).
+-define(vlogc(F),    ?vlogc(F, [])).
 -define(vlogc(F,A),  snmp_verbosity:printc(get(verbosity),log,  F,A)).
+-define(vdebugc(F),  ?vdebug(F, [])).
 -define(vdebugc(F,A),snmp_verbosity:printc(get(verbosity),debug,F,A)).
+-define(vtracec(F),  ?vtracec(F, [])).
 -define(vtracec(F,A),snmp_verbosity:printc(get(verbosity),trace,F,A)).
 
 -else.
 
 -define(vvalidate(V),ok).
 
--define(vinfo(F,A),ok).
--define(vlog(F,A),ok).
--define(vdebug(F,A),ok).
--define(vtrace(F,A),ok).
-
--define(vinfoc(F,A),ok).
--define(vlogc(F,A),ok).
+-define(vinfo(F),    ok).
+-define(vinfo(F,A),  ok).
+-define(vlog(F),     ok).
+-define(vlog(F,A),   ok).
+-define(vdebug(F),   ok).
+-define(vdebug(F,A), ok).
+-define(vtrace(F),   ok).
+-define(vtrace(F,A), ok).
+
+-define(vinfoc(F),   ok).
+-define(vinfoc(F,A), ok).
+-define(vlogc(F),    ok).
+-define(vlogc(F,A),  ok).
+-define(vdebugc(F),  ok).
 -define(vdebugc(F,A),ok).
+-define(vtracec(F),  ok).
 -define(vtracec(F,A),ok).
 
 -endif.
-- 
2.16.4

openSUSE Build Service is sponsored by