From b528d830a741f6611b704ddcce1e702b41757c36 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 27 Mar 2019 11:00:53 +0100 Subject: [snmp|agent] Add the net-if data (Extra) argument to get-callbacks Added the Extra (net-if data) argument to all the get- mechanism callback functions. OTP-15691 --- lib/snmp/src/agent/snmpa_agent.erl | 41 +- lib/snmp/src/agent/snmpa_get.erl | 31 +- lib/snmp/src/agent/snmpa_get_mechanism.erl | 12 +- lib/snmp/src/agent/snmpa_set_lib.erl | 2 +- lib/snmp/src/agent/tmp/snmpa_get.erl | 859 ----------------------------- lib/snmp/src/agent/tmp/snmpa_get_lib.erl | 507 ----------------- lib/snmp/test/snmp_agent_test_get.erl | 25 +- 7 files changed, 50 insertions(+), 1427 deletions(-) delete mode 100644 lib/snmp/src/agent/tmp/snmpa_get.erl delete mode 100644 lib/snmp/src/agent/tmp/snmpa_get_lib.erl diff --git a/lib/snmp/src/agent/snmpa_agent.erl b/lib/snmp/src/agent/snmpa_agent.erl index f75c4cfee0..a521b3773b 100644 --- a/lib/snmp/src/agent/snmpa_agent.erl +++ b/lib/snmp/src/agent/snmpa_agent.erl @@ -2708,8 +2708,9 @@ mk_next_oid(Vb) -> %%----------------------------------------------------------------- do_get(UnsortedVarbinds, IsNotification) -> + Extra = get(net_if_data), GetModule = get(get_module), - GetModule:do_get(UnsortedVarbinds, IsNotification). + GetModule:do_get(UnsortedVarbinds, IsNotification, Extra). %%----------------------------------------------------------------- @@ -2724,8 +2725,9 @@ do_get(UnsortedVarbinds, IsNotification) -> %% we *may* need to tunnel into the master-agent and let it do the work. do_get(MibView, UnsortedVarbinds, IsNotification) -> + Extra = get(net_if_data), GetModule = get(get_module), - GetModule:do_get(MibView, UnsortedVarbinds, IsNotification). + GetModule:do_get(MibView, UnsortedVarbinds, IsNotification, Extra). do_get(MibView, UnsortedVarbinds, IsNotification, ForceMaster) -> case (whereis(snmp_master_agent) =:= self()) of @@ -2780,8 +2782,9 @@ do_get(MibView, UnsortedVarbinds, IsNotification, ForceMaster) -> do_get_next(MibView, UnsortedVarbinds) -> + Extra = get(net_if_data), GetModule = get(get_module), - GetModule:do_get_next(MibView, UnsortedVarbinds). + GetModule:do_get_next(MibView, UnsortedVarbinds, Extra). @@ -2796,9 +2799,11 @@ do_get_next(MibView, UnsortedVarbinds) -> %%%----------------------------------------------------------------- do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds, GbMaxVBs) -> + Extra = get(net_if_data), GetModule = get(get_module), GetModule:do_get_bulk(MibView, NonRepeaters, MaxRepetitions, - PduMS, Varbinds, GbMaxVBs). + PduMS, Varbinds, GbMaxVBs, + Extra). @@ -3119,6 +3124,7 @@ report_err(Val, Mfa, Err) -> user_err("Got ~p from ~w. Using ~w", [Val, Mfa, Err]), {error, Err}. + is_valid_pdu_type('get-request') -> true; is_valid_pdu_type('get-next-request') -> true; is_valid_pdu_type('get-bulk-request') -> true; @@ -3156,33 +3162,8 @@ mapfoldl(F, Eas, Accu0, [Hd|Tail]) -> mapfoldl(_F, _Eas, Accu, []) -> {Accu,[]}. -%%----------------------------------------------------------------- -%% Runtime debugging of the agent. -%%----------------------------------------------------------------- - -%% dbg_apply(M,F,A) -> -%% case get(verbosity) of -%% silence -> -%% apply(M,F,A); -%% _ -> -%% ?vlog("~n apply: ~w,~w,~p~n", [M,F,A]), -%% Res = (catch apply(M,F,A)), -%% case Res of -%% {'EXIT', Reason} -> -%% ?vinfo("Call to: " -%% "~n Module: ~p" -%% "~n Function: ~p" -%% "~n Args: ~p" -%% "~n" -%% "~nresulted in an exit" -%% "~n" -%% "~n ~p", [M, F, A, Reason]); -%% _ -> -%% ?vlog("~n returned: ~p", [Res]) -%% end, -%% Res -%% end. +%% --------------------------------------------------------------------- short_name(none) -> ma; short_name(_Pid) -> sa. diff --git a/lib/snmp/src/agent/snmpa_get.erl b/lib/snmp/src/agent/snmpa_get.erl index be4ecd9a71..50aab6b487 100644 --- a/lib/snmp/src/agent/snmpa_get.erl +++ b/lib/snmp/src/agent/snmpa_get.erl @@ -28,9 +28,9 @@ %%%----------------------------------------------------------------- -export([ - do_get/2, do_get/3, - do_get_next/2, - do_get_bulk/6 + do_get/3, do_get/4, + do_get_next/3, + do_get_bulk/7 ]). -include("snmpa_internal.hrl"). @@ -74,7 +74,7 @@ %% {ErrorStatus, ErrorIndex, []} %%----------------------------------------------------------------- -do_get(UnsortedVarbinds, IsNotification) -> +do_get(UnsortedVarbinds, IsNotification, _Extra) -> {MyVarbinds, SubagentVarbinds} = ?LIB:agent_sort_vbs(UnsortedVarbinds), case do_get_local(MyVarbinds, IsNotification) of {noError, 0, NewMyVarbinds} -> @@ -97,7 +97,7 @@ do_get(UnsortedVarbinds, IsNotification) -> %% {ErrorStatus, ErrorIndex, []} %%----------------------------------------------------------------- -do_get(MibView, UnsortedVarbinds, IsNotification) -> +do_get(MibView, UnsortedVarbinds, IsNotification, Extra) -> ?vtrace("do_get -> entry with" "~n MibView: ~p" "~n UnsortedVarbinds: ~p" @@ -105,7 +105,7 @@ do_get(MibView, UnsortedVarbinds, IsNotification) -> [MibView, UnsortedVarbinds, IsNotification]), %% This is me, the master, so go ahead {OutSideView, InSideView} = ?LIB:split_vbs_view(UnsortedVarbinds, MibView), - {Error, Index, NewVbs} = do_get(InSideView, IsNotification), + {Error, Index, NewVbs} = do_get(InSideView, IsNotification, Extra), {Error, Index, NewVbs ++ OutSideView}. @@ -437,7 +437,7 @@ validate_tab_res(_TooMany, [], Mfa, _Res, I) -> %%% According to RFC1157, section 4.1.3 and RFC1905, section 4.2.2. %%%----------------------------------------------------------------- %%----------------------------------------------------------------- -%% Func: do_get_next/2 +%% Func: do_get_next/3 %% Purpose: do_get_next handles "getNextRequests". %% Note: Even if it is SNMPv1, a varbind's value can be %% endOfMibView. This is converted to noSuchName in process_pdu. @@ -470,16 +470,16 @@ validate_tab_res(_TooMany, [], Mfa, _Res, I) -> %% subagent must be considered to be very rare. %%----------------------------------------------------------------- -do_get_next(MibView, UnsortedVBs) -> - do_get_next(MibView, UnsortedVBs, infinity). +do_get_next(MibView, UnsortedVBs, _Extra) -> + do_get_next2(MibView, UnsortedVBs, infinity). %% The third argument is only used if we are called as result %% of a get-bulk request. -do_get_next(_MibView, UnsortedVarbinds, GbMaxVBs) +do_get_next2(_MibView, UnsortedVarbinds, GbMaxVBs) when (is_integer(GbMaxVBs) andalso (length(UnsortedVarbinds) > GbMaxVBs)) -> {tooBig, 0, []}; % What is the correct index in this case? -do_get_next(MibView, UnsortedVBs, GbMaxVBs) -> - ?vt("do_get_next -> entry when" +do_get_next2(MibView, UnsortedVBs, GbMaxVBs) -> + ?vt("do_get_next2 -> entry when" "~n MibView: ~p" "~n UnsortedVBs: ~p", [MibView, UnsortedVBs]), SortedVBs = ?LIB:oid_sort_vbs(UnsortedVBs), @@ -959,7 +959,8 @@ next_oid(Oid) -> %%% resulting response cannot contain more then this number of VBs. %%%----------------------------------------------------------------- -do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds, GbMaxVBs) -> +do_get_bulk(MibView, NonRepeaters, MaxRepetitions, + PduMS, Varbinds, GbMaxVBs, _Extra) -> ?vtrace("do_get_bulk -> entry with" "~n MibView: ~p" "~n NonRepeaters: ~p" @@ -972,7 +973,7 @@ do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds, GbMaxVBs) -> ?vt("do_get_bulk -> split: " "~n NonRepVbs: ~p" "~n RestVbs: ~p", [NonRepVbs, RestVbs]), - case do_get_next(MibView, NonRepVbs, GbMaxVBs) of + case do_get_next2(MibView, NonRepVbs, GbMaxVBs) of {noError, 0, UResNonRepVbs} -> ?vt("do_get_bulk -> next noError: " "~n UResNonRepVbs: ~p", [UResNonRepVbs]), @@ -1106,7 +1107,7 @@ try_get_bulk(Sz, MibView, Varbinds, GbMaxVBs) -> "~n Sz: ~w" "~n MibView: ~w" "~n Varbinds: ~w", [Sz, MibView, Varbinds]), - case do_get_next(MibView, Varbinds, GbMaxVBs) of + case do_get_next2(MibView, Varbinds, GbMaxVBs) of {noError, 0, UNextVarbinds} -> ?vt("try_get_bulk -> noError: " "~n UNextVarbinds: ~p", [UNextVarbinds]), diff --git a/lib/snmp/src/agent/snmpa_get_mechanism.erl b/lib/snmp/src/agent/snmpa_get_mechanism.erl index 7be4ae79a2..744a6529e1 100644 --- a/lib/snmp/src/agent/snmpa_get_mechanism.erl +++ b/lib/snmp/src/agent/snmpa_get_mechanism.erl @@ -35,7 +35,8 @@ %% mibview (local). -callback do_get(UnsortedVBs :: [snmp:varbind()], - IsNotification :: boolean()) -> + IsNotification :: boolean(), + Extra :: term()) -> {noError, 0, ResVBs :: [snmp:varbind()]} | {ErrStatus :: snmp:error_status(), ErrIndex :: snmp:error_index(), []}. @@ -44,7 +45,8 @@ -callback do_get(MibView :: snmp_view_based_acm_mib:mibview(), UnsortedVBs :: [snmp:varbind()], - IsNotification :: boolean()) -> + IsNotification :: boolean(), + Extra :: term()) -> {noError, 0, ResVBs :: [snmp:varbind()]} | {ErrStatus :: snmp:error_status(), ErrIndex :: snmp:error_index(), []}. @@ -56,7 +58,8 @@ %% Purpose: Handles "get-next-requests". -callback do_get_next(MibView :: snmp_view_based_acm_mib:mibview(), - UnsortedVBs :: [snmp:varbind()]) -> + UnsortedVBs :: [snmp:varbind()], + Extra :: term()) -> {noError, 0, ResVBs :: [snmp:varbind()]} | {ErrStatus :: snmp:error_status(), ErrIndex :: snmp:error_index(), []}. @@ -70,6 +73,7 @@ MaxRepetitions :: non_neg_integer(), PduMS :: pos_integer(), VBs :: [snmp:varbind()], - MaxVBs :: pos_integer()) -> + MaxVBs :: pos_integer(), + Extra :: term()) -> {noError, 0, ResVBs :: [snmp:varbind()]} | {ErrStatus :: snmp:error_status(), ErrIndex :: snmp:error_index(), []}. diff --git a/lib/snmp/src/agent/snmpa_set_lib.erl b/lib/snmp/src/agent/snmpa_set_lib.erl index 57507a36e8..3dcf49cbe6 100644 --- a/lib/snmp/src/agent/snmpa_set_lib.erl +++ b/lib/snmp/src/agent/snmpa_set_lib.erl @@ -390,7 +390,7 @@ dbg_apply(M,F,A) -> {'EXIT', {function_clause, [{M, F, A} | _]}} -> {'EXIT', {hook_function_clause, {M, F, A}}}; - % XYZ: Older format for compatibility + %% XYZ: Older format for compatibility {'EXIT', {undef, {M, F, A}}} -> {'EXIT', {hook_undef, {M, F, A}}}; {'EXIT', {function_clause, {M, F, A}}} -> diff --git a/lib/snmp/src/agent/tmp/snmpa_get.erl b/lib/snmp/src/agent/tmp/snmpa_get.erl deleted file mode 100644 index d1710f673c..0000000000 --- a/lib/snmp/src/agent/tmp/snmpa_get.erl +++ /dev/null @@ -1,859 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2019-2019. All Rights Reserved. -%% -%% Licensed under the Apache License, Version 2.0 (the "License"); -%% you may not use this file except in compliance with the License. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%% -%% %CopyrightEnd% -%% - --module(snmpa_get). - --behaviour(snmpa_get_mechanism). - -%%%----------------------------------------------------------------- -%%% snmpa_get_mechanism exports -%%%----------------------------------------------------------------- - --export([ - do_get/2, do_get/3, - do_get_next/2, - do_get_bulk/6 - ]). - -%% Internal exports --export([do_get_next/3]). - --include("snmpa_internal.hrl"). --include("snmp_types.hrl"). --include("snmp_debug.hrl"). --include("snmp_verbosity.hrl"). - --ifndef(default_verbosity). --define(default_verbosity,silence). --endif. - --define(empty_pdu_size, 21). - --ifdef(snmp_extended_verbosity). --define(vt(F,A), ?vtrace(F, A)). --else. --define(vt(_F, _A), ok). --endif. - - --define(AGENT, snmpa_agent). --define(LIB, snmpa_get_lib). - - - -%%% ================ GET ========================================== - -%%----------------------------------------------------------------- -%% Func: do_get/2 -%% Purpose: Handles all VBs in a request that is inside the -%% mibview (local). -%% Returns: {noError, 0, ListOfNewVarbinds} | -%% {ErrorStatus, ErrorIndex, []} -%%----------------------------------------------------------------- - -do_get(UnsortedVBs, IsNotification) -> - {MyIVBs, SubagentVBs} = ?LIB:sort_vbs(UnsortedVBs), - case do_get_local(MyIVBs, IsNotification) of - {noError, 0, NewMyVBs} -> - case do_get_subagents(SubagentVBs, IsNotification) of - {noError, 0, NewSubagentVBs} -> - {noError, 0, NewMyVBs ++ NewSubagentVBs}; - {ErrorStatus, ErrorIndex, _} -> - {ErrorStatus, ErrorIndex, []} - end; - {ErrorStatus, ErrorIndex, _} -> - {ErrorStatus, ErrorIndex, []} - end. - - -%%----------------------------------------------------------------- -%% Func: do_get/3 -%% Purpose: do_get handles "getRequests". -%% Pre: incoming varbinds have type == 'NULL', value == unSpecified -%% Returns: {noError, 0, ListOfNewVarbinds} | -%% {ErrorStatus, ErrorIndex, []} -%%----------------------------------------------------------------- - -do_get(MibView, UnsortedVBs, IsNotification) -> - {OutSideView, InSideView} = ?LIB:split_vbs_view(UnsortedVBs, MibView), - {Error, Index, NewVbs} = do_get(InSideView, IsNotification), - {Error, Index, NewVbs ++ OutSideView}. - - - - -%%% ================ GET-NEXT ===================================== - -%%----------------------------------------------------------------- -%% Func: do_get_next/2 -%% Purpose: do_get_next handles "getNextRequests". -%% Note: Even if it is SNMPv1, a varbind's value can be -%% endOfMibView. This is later converted to noSuchName. -%% Returns: {noError, 0, ListOfNewVarbinds} | -%% {ErrorStatus, ErrorIndex, []} -%% Note2: ListOfNewVarbinds is not sorted in any order!!! -%% Alg: First, the variables are sorted in OID order. -%% -%% Second, next in the MIB is performed for each OID, and -%% the result is collected as: if next oid is a variable, -%% perform a get to retrieve its value; if next oid is in a -%% table, save this value and continue until we get an oid -%% outside this table. Then perform get_next on the table, -%% and continue with all endOfTables and the oid outside the -%% table; if next oid is an subagent, save this value and -%% continue as in the table case. -%% -%% Third, each response is checked for endOfMibView, or (for -%% subagents) that the Oid returned has the correct prefix. -%% (This is necessary since an SA can be registered under many -%% separated subtrees, and if the last variable in the first -%% subtree is requested in a next, the SA will return the first -%% variable in the second subtree. This might be working, since -%% there may be a variable in between these subtrees.) For each -%% of these, a new get-next is performed, one at a time. -%% This alg. might be optimised in several ways. The most -%% striking one is that the same SA might be called several -%% times, when one time should be enough. But it isn't clear -%% that this really matters, since many nexts across the same -%% subagent must be considered to be very rare. -%%----------------------------------------------------------------- - -do_get_next(MibView, UnsortedVBs) -> - do_get_next(MibView, UnsortedVBs, infinity). - -%% The third argument is only used if we are called as result -%% of a get-buld request. -do_get_next(_MibView, UnsortedVBs, MaxVBs) - when (is_list(UnsortedVBs) andalso - is_integer(MaxVBs) andalso - (length(UnsortedVBs) > MaxVBs)) -> - {tooBig, 0, []}; -do_get_next(MibView, UnsortedVBs, MaxVBs) -> - ?vt("do_get_next -> entry when" - "~n MibView: ~p" - "~n UnsortedVBs: ~p", [MibView, UnsortedVBs]), - SortedVBs = ?LIB:oid_sort_vbs(UnsortedVBs), - ?vt("do_get_next -> " - "~n SortedVBs: ~p", [SortedVBs]), - next_varbinds_loop([], SortedVBs, MibView, MaxVBs, [], []). - - - -next_varbinds_loop(_, Vbs, _MibView, MaxVBs, Res, _LAVb) - when (is_integer(MaxVBs) andalso - ((length(Vbs) + length(Res)) > MaxVBs)) -> - {tooBig, 0, []}; - -%% LAVb is Last Accessible Vb -next_varbinds_loop([], [Vb | Vbs], MibView, MaxVBs, Res, LAVb) -> - ?vt("next_loop_varbinds -> entry when" - "~n Vb: ~p" - "~n MibView: ~p", [Vb, MibView]), - case varbind_next(Vb, MibView) of - endOfMibView -> - ?vt("next_varbinds_loop -> endOfMibView", []), - RVb = if LAVb =:= [] -> Vb; - true -> LAVb - end, - NewVb = RVb#varbind{variabletype = 'NULL', value = endOfMibView}, - next_varbinds_loop([], Vbs, MibView, MaxVBs, [NewVb | Res], []); - - {variable, ME, VarOid} when ((ME#me.access =/= 'not-accessible') andalso - (ME#me.access =/= 'write-only') andalso - (ME#me.access =/= 'accessible-for-notify')) -> - ?vt("next_varbinds_loop -> variable: " - "~n ME: ~p" - "~n VarOid: ~p", [ME, VarOid]), - case ?LIB:try_get_instance(Vb, ME) of - {value, noValue, _NoSuchSomething} -> - ?vt("next_varbinds_loop -> noValue", []), - %% Try next one - NewVb = Vb#varbind{oid = VarOid, - value = 'NULL'}, - next_varbinds_loop([], [NewVb | Vbs], MibView, MaxVBs, Res, []); - {value, Type, Value} -> - ?vt("next_varbinds_loop -> value" - "~n Type: ~p" - "~n Value: ~p", [Type, Value]), - NewVb = Vb#varbind{oid = VarOid, - variabletype = Type, - value = Value}, - next_varbinds_loop([], Vbs, MibView, MaxVBs, - [NewVb | Res], []); - {error, ErrorStatus} -> - ?vdebug("next varbinds loop:" - "~n ErrorStatus: ~p",[ErrorStatus]), - {ErrorStatus, Vb#varbind.org_index, []} - end; - {variable, _ME, VarOid} -> - ?vt("next_varbinds_loop -> variable: " - "~n VarOid: ~p", [VarOid]), - RVb = if LAVb =:= [] -> Vb; - true -> LAVb - end, - NewVb = Vb#varbind{oid = VarOid, value = 'NULL'}, - next_varbinds_loop([], [NewVb | Vbs], MibView, MaxVBs, Res, RVb); - {table, TableOid, TableRestOid, ME} -> - ?vt("next_varbinds_loop -> table: " - "~n TableOid: ~p" - "~n TableRestOid: ~p" - "~n ME: ~p", [TableOid, TableRestOid, ME]), - next_varbinds_loop({table, TableOid, ME, - [{?LIB:tab_oid(TableRestOid), Vb}]}, - Vbs, MibView, MaxVBs, Res, []); - {subagent, SubAgentPid, SAOid} -> - ?vt("next_varbinds_loop -> subagent: " - "~n SubAgentPid: ~p" - "~n SAOid: ~p", [SubAgentPid, SAOid]), - NewVb = Vb#varbind{variabletype = 'NULL', value = 'NULL'}, - next_varbinds_loop({subagent, SubAgentPid, SAOid, [NewVb]}, - Vbs, MibView, MaxVBs, Res, []) - end; - -next_varbinds_loop({table, TableOid, ME, TabOids}, - [Vb | Vbs], MibView, MaxVBs, Res, _LAVb) -> - ?vt("next_varbinds_loop(table) -> entry with" - "~n TableOid: ~p" - "~n Vb: ~p", [TableOid, Vb]), - case varbind_next(Vb, MibView) of - {table, TableOid, TableRestOid, _ME} -> - next_varbinds_loop({table, TableOid, ME, - [{?LIB:tab_oid(TableRestOid), Vb} | TabOids]}, - Vbs, MibView, MaxVBs, Res, []); - _ -> - case get_next_table(ME, TableOid, TabOids, MibView) of - {ok, TabRes, TabEndOfTabVbs} -> - NewVbs = lists:append(TabEndOfTabVbs, [Vb | Vbs]), - NewRes = lists:append(TabRes, Res), - next_varbinds_loop([], NewVbs, MibView, MaxVBs, NewRes, []); - {ErrorStatus, OrgIndex} -> - ?vdebug("next varbinds loop: next varbind" - "~n ErrorStatus: ~p" - "~n OrgIndex: ~p", - [ErrorStatus,OrgIndex]), - {ErrorStatus, OrgIndex, []} - end - end; -next_varbinds_loop({table, TableOid, ME, TabOids}, - [], MibView, MaxVBs, Res, _LAVb) -> - ?vt("next_varbinds_loop(table) -> entry with" - "~n TableOid: ~p", [TableOid]), - case get_next_table(ME, TableOid, TabOids, MibView) of - {ok, TabRes, TabEndOfTabVbs} -> - ?vt("next_varbinds_loop(table) -> get_next_table result:" - "~n TabRes: ~p" - "~n TabEndOfTabVbs: ~p", [TabRes, TabEndOfTabVbs]), - NewRes = lists:append(TabRes, Res), - next_varbinds_loop([], TabEndOfTabVbs, MibView, MaxVBs, NewRes, []); - {ErrorStatus, OrgIndex} -> - ?vdebug("next varbinds loop: next table" - "~n ErrorStatus: ~p" - "~n OrgIndex: ~p", - [ErrorStatus,OrgIndex]), - {ErrorStatus, OrgIndex, []} - end; - -next_varbinds_loop({subagent, SAPid, SAOid, SAVbs}, - [Vb | Vbs], MibView, MaxVBs, Res, _LAVb) -> - ?vt("next_varbinds_loop(subagent) -> entry with" - "~n SAPid: ~p" - "~n SAOid: ~p" - "~n Vb: ~p", [SAPid, SAOid, Vb]), - case varbind_next(Vb, MibView) of - {subagent, _SubAgentPid, SAOid} -> - next_varbinds_loop({subagent, SAPid, SAOid, - [Vb | SAVbs]}, - Vbs, MibView, MaxVBs, Res, []); - _ -> - case get_next_sa(SAPid, SAOid, SAVbs, MibView) of - {ok, SARes, SAEndOfMibViewVbs} -> - NewVbs = lists:append(SAEndOfMibViewVbs, [Vb | Vbs]), - NewRes = lists:append(SARes, Res), - next_varbinds_loop([], NewVbs, MibView, MaxVBs, NewRes, []); - {noSuchName, OrgIndex} -> - %% v1 reply, treat this Vb as endOfMibView, and try again - %% for the others. - case lists:keysearch(OrgIndex, #varbind.org_index, SAVbs) of - {value, EVb} -> - NextOid = ?LIB:next_oid(SAOid), - EndOfVb = - EVb#varbind{oid = NextOid, - value = {endOfMibView, NextOid}}, - case lists:delete(EVb, SAVbs) of - [] -> - next_varbinds_loop([], [EndOfVb, Vb | Vbs], - MibView, Res, [], - MaxVBs); - TryAgainVbs -> - next_varbinds_loop({subagent, SAPid, SAOid, - TryAgainVbs}, - [EndOfVb, Vb | Vbs], - MibView, Res, [], - MaxVBs) - end; - false -> - %% bad index from subagent - {genErr, (hd(SAVbs))#varbind.org_index, []} - end; - {ErrorStatus, OrgIndex} -> - ?vdebug("next varbinds loop: next subagent" - "~n Vb: ~p" - "~n ErrorStatus: ~p" - "~n OrgIndex: ~p", - [Vb,ErrorStatus,OrgIndex]), - {ErrorStatus, OrgIndex, []} - end - end; -next_varbinds_loop({subagent, SAPid, SAOid, SAVbs}, - [], MibView, GbMaxVBs, Res, _LAVb) -> - ?vt("next_varbinds_loop(subagent) -> entry with" - "~n SAPid: ~p" - "~n SAOid: ~p", [SAPid, SAOid]), - case get_next_sa(SAPid, SAOid, SAVbs, MibView) of - {ok, SARes, SAEndOfMibViewVbs} -> - NewRes = lists:append(SARes, Res), - next_varbinds_loop([], SAEndOfMibViewVbs, MibView, GbMaxVBs, - NewRes, []); - {noSuchName, OrgIndex} -> - %% v1 reply, treat this Vb as endOfMibView, and try again for - %% the others. - case lists:keysearch(OrgIndex, #varbind.org_index, SAVbs) of - {value, EVb} -> - NextOid = ?LIB:next_oid(SAOid), - EndOfVb = EVb#varbind{oid = NextOid, - value = {endOfMibView, NextOid}}, - case lists:delete(EVb, SAVbs) of - [] -> - next_varbinds_loop([], [EndOfVb], MibView, - GbMaxVBs, Res, []); - TryAgainVbs -> - next_varbinds_loop({subagent, SAPid, SAOid, - TryAgainVbs}, - [EndOfVb], MibView, GbMaxVBs, - Res, []) - end; - false -> - %% bad index from subagent - {genErr, (hd(SAVbs))#varbind.org_index, []} - end; - {ErrorStatus, OrgIndex} -> - ?vdebug("next varbinds loop: next subagent" - "~n ErrorStatus: ~p" - "~n OrgIndex: ~p", - [ErrorStatus,OrgIndex]), - {ErrorStatus, OrgIndex, []} - end; - -next_varbinds_loop([], [], _MibView, _GbMaxVBs, Res, _LAVb) -> - ?vt("next_varbinds_loop -> entry when done", []), - {noError, 0, Res}. - - -%%----------------------------------------------------------------- -%% Perform a next, using the varbinds Oid if value is simple -%% value. If value is {endOf, NextOid}, use NextOid. -%% This case happens when a table has returned endOfTable, or -%% a subagent has returned endOfMibView. -%%----------------------------------------------------------------- -varbind_next(#varbind{value = Value, oid = Oid}, MibView) -> - ?vt("varbind_next -> entry with" - "~n Value: ~p" - "~n Oid: ~p" - "~n MibView: ~p", [Value, Oid, MibView]), - case Value of - {endOfTable, NextOid} -> - snmpa_mib:next(get(mibserver), NextOid, MibView); - {endOfMibView, NextOid} -> - snmpa_mib:next(get(mibserver), NextOid, MibView); - _ -> - snmpa_mib:next(get(mibserver), Oid, MibView) - end. - - -get_next_table(#me{mfa = {M, F, A}}, TableOid, TableOids, MibView) -> - % We know that all TableOids have at least a column number as oid - ?vt("get_next_table -> entry with" - "~n M: ~p" - "~n F: ~p" - "~n A: ~p" - "~n TableOid: ~p" - "~n TableOids: ~p" - "~n MibView: ~p", [M, F, A, TableOid, TableOids, MibView]), - Sorted = snmpa_svbl:sort_varbinds_rows(TableOids), - case get_next_values_all_rows(Sorted, M,F,A, [], TableOid) of - NewVbs when is_list(NewVbs) -> - ?vt("get_next_table -> " - "~n NewVbs: ~p", [NewVbs]), - % We must now check each Vb for endOfTable and that it is - % in the MibView. If not, it becomes a endOfTable. We - % collect all of these together. - transform_tab_next_result(NewVbs, {[], []}, MibView); - {ErrorStatus, OrgIndex} -> - {ErrorStatus, OrgIndex} - end. - - -get_next_values_all_rows([], _M, _F, _A, Res, _TabOid) -> - Res; -get_next_values_all_rows([Row | Rows], M, F, A, Res, TabOid) -> - {RowIndex, TableOids} = Row, - Cols = ?LIB:delete_index(TableOids), - ?vt("get_next_values_all_rows -> " - "~n Cols: ~p", [Cols]), - Result = (catch ?LIB:dbg_apply(M, F, [get_next, RowIndex, Cols | A])), - ?vt("get_next_values_all_rows -> " - "~n Result: ~p", [Result]), - case validate_tab_next_res(Result, TableOids, {M, F, A}, TabOid) of - Values when is_list(Values) -> - ?vt("get_next_values_all_rows -> " - "~n Values: ~p", [Values]), - NewRes = lists:append(Values, Res), - get_next_values_all_rows(Rows, M, F, A, NewRes, TabOid); - {ErrorStatus, OrgIndex} -> - {ErrorStatus, OrgIndex} - end. - -transform_tab_next_result([Vb | Vbs], {Res, EndOfs}, MibView) -> - case Vb#varbind.value of - {endOfTable, _} -> - ?LIB:split_vbs(Vbs, Res, [Vb | EndOfs]); - _ -> - case snmpa_acm:validate_mib_view(Vb#varbind.oid, MibView) of - true -> - transform_tab_next_result(Vbs, {[Vb|Res], EndOfs},MibView); - _ -> - Oid = Vb#varbind.oid, - NewEndOf = Vb#varbind{value = {endOfTable, Oid}}, - transform_tab_next_result(Vbs, {Res, [NewEndOf | EndOfs]}, - MibView) - end - end; -transform_tab_next_result([], {Res, EndOfs}, _MibView) -> - ?vt("transform_tab_next_result -> entry with: " - "~n Res: ~p" - "~n EndIfs: ~p",[Res, EndOfs]), - {ok, Res, EndOfs}. - - -%%----------------------------------------------------------------- -%% Three cases: -%% 1) All values ok -%% 2) table_func returned {Error, ...} -%% 3) Some value in Values list is erroneous. -%% Args: Value is a list of values from table_func(get_next, ...) -%% TableOids is a list of {TabRestOid, OrgVb} -%% each element in Values and TableOids correspond to each -%% other. -%% Returns: List of NewVarbinds | -%% {ErrorStatus, OrgIndex} -%% (In the NewVarbinds list, the value may be endOfTable) -%%----------------------------------------------------------------- -validate_tab_next_res(Values, TableOids, Mfa, TabOid) -> - ?vt("validate_tab_next_res -> entry with: " - "~n Values: ~p" - "~n TableOids: ~p" - "~n Mfa: ~p" - "~n TabOid: ~p", [Values, TableOids, Mfa, TabOid]), - {_Col, _ASN1Type, OneIdx} = hd(TableOids), - validate_tab_next_res(Values, TableOids, Mfa, [], TabOid, - ?LIB:next_oid(TabOid), OneIdx). -validate_tab_next_res([{NextOid, Value} | Values], - [{_ColNo, OrgVb, _Index} | TableOids], - Mfa, Res, TabOid, TabNextOid, I) -> - ?vt("validate_tab_next_res -> entry with: " - "~n NextOid: ~p" - "~n Value: ~p" - "~n Values: ~p" - "~n TableOids: ~p" - "~n Mfa: ~p" - "~n TabOid: ~p", - [NextOid, Value, Values, TableOids, Mfa, TabOid]), - #varbind{org_index = OrgIndex} = OrgVb, - ?vt("validate_tab_next_res -> OrgIndex: ~p", [OrgIndex]), - NextCompleteOid = lists:append(TabOid, NextOid), - case snmpa_mib:lookup(get(mibserver), NextCompleteOid) of - {table_column, #me{asn1_type = ASN1Type}, _TableEntryOid} -> - ?vt("validate_tab_next_res -> ASN1Type: ~p", [ASN1Type]), - case ?LIB:make_value_a_correct_value({value, Value}, ASN1Type, Mfa) of - {error, ErrorStatus} -> - ?vt("validate_tab_next_res -> " - "~n ErrorStatus: ~p", [ErrorStatus]), - {ErrorStatus, OrgIndex}; - {value, Type, NValue} -> - ?vt("validate_tab_next_res -> " - "~n Type: ~p" - "~n NValue: ~p", [Type, NValue]), - NewVb = OrgVb#varbind{oid = NextCompleteOid, - variabletype = Type, value = NValue}, - validate_tab_next_res(Values, TableOids, Mfa, - [NewVb | Res], TabOid, TabNextOid, I) - end; - Error -> - ?LIB:user_err("Invalid oid ~w from ~w (get_next). Using genErr => ~p", - [NextOid, Mfa, Error]), - {genErr, OrgIndex} - end; -validate_tab_next_res([endOfTable | Values], - [{_ColNo, OrgVb, _Index} | TableOids], - Mfa, Res, TabOid, TabNextOid, I) -> - ?vt("validate_tab_next_res(endOfTable) -> entry with: " - "~n Values: ~p" - "~n OrgVb: ~p" - "~n TableOids: ~p" - "~n Mfa: ~p" - "~n Res: ~p" - "~n TabOid: ~p" - "~n TabNextOid: ~p" - "~n I: ~p", - [Values, OrgVb, TableOids, Mfa, Res, TabOid, TabNextOid, I]), - NewVb = OrgVb#varbind{value = {endOfTable, TabNextOid}}, - validate_tab_next_res(Values, TableOids, Mfa, [NewVb | Res], - TabOid, TabNextOid, I); -validate_tab_next_res([], [], _Mfa, Res, _TabOid, _TabNextOid, _I) -> - Res; -validate_tab_next_res([], [{_Col, _OrgVb, Index}|_], Mfa, _Res, _, _, _I) -> - ?LIB:user_err("Too few values returned from ~w (get_next)", [Mfa]), - {genErr, Index}; -validate_tab_next_res({genErr, ColNumber}, OrgCols, - Mfa, _Res, _TabOid, _TabNextOid, _I) -> - OrgIndex = snmpa_svbl:col_to_orgindex(ColNumber, OrgCols), - ?AGENT:validate_err(table_next, {genErr, OrgIndex}, Mfa); -validate_tab_next_res({error, Reason}, [{_ColNo, OrgVb, _Index} | _TableOids], - Mfa, _Res, _TabOid, _TabNextOid, _I) -> - #varbind{org_index = OrgIndex} = OrgVb, - ?LIB:user_err("Erroneous return value ~w from ~w (get_next)", - [Reason, Mfa]), - {genErr, OrgIndex}; -validate_tab_next_res(Error, [{_ColNo, OrgVb, _Index} | _TableOids], - Mfa, _Res, _TabOid, _TabNextOid, _I) -> - #varbind{org_index = OrgIndex} = OrgVb, - ?LIB:user_err("Invalid return value ~w from ~w (get_next)", - [Error, Mfa]), - {genErr, OrgIndex}; -validate_tab_next_res(TooMany, [], Mfa, _Res, _, _, I) -> - ?LIB:user_err("Too many values ~w returned from ~w (get_next)", - [TooMany, Mfa]), - {genErr, I}. - - -%%----------------------------------------------------------------- -%% Func: get_next_sa/4 -%% Purpose: Loop the list of varbinds for the subagent. -%% Call subagent_get_next to retreive -%% the next varbinds. -%% Returns: {ok, ListOfNewVbs, ListOfEndOfMibViewsVbs} | -%% {ErrorStatus, ErrorIndex} -%%----------------------------------------------------------------- -get_next_sa(SAPid, SAOid, SAVbs, MibView) -> - case catch subagent_get_next(SAPid, MibView, SAVbs) of - {noError, 0, NewVbs} -> - NewerVbs = transform_sa_next_result(NewVbs, SAOid, - ?LIB:next_oid(SAOid)), - ?LIB:split_vbs(NewerVbs); - {ErrorStatus, ErrorIndex, _} -> - {ErrorStatus, ErrorIndex}; - {'EXIT', Reason} -> - ?LIB:user_err("Lost contact with subagent (next) ~w. Using genErr", - [Reason]), - {genErr, 0} - end. - - -%%----------------------------------------------------------------- -%% Check for wrong prefix returned or endOfMibView, and convert -%% into {endOfMibView, SANextOid}. -%%----------------------------------------------------------------- -transform_sa_next_result([Vb | Vbs], SAOid, SANextOid) - when Vb#varbind.value =:= endOfMibView -> - [Vb#varbind{value = {endOfMibView, SANextOid}} | - transform_sa_next_result(Vbs, SAOid, SANextOid)]; -transform_sa_next_result([Vb | Vbs], SAOid, SANextOid) -> - case lists:prefix(SAOid, Vb#varbind.oid) of - true -> - [Vb | transform_sa_next_result(Vbs, SAOid, SANextOid)]; - _ -> - [Vb#varbind{oid = SANextOid, value = {endOfMibView, SANextOid}} | - transform_sa_next_result(Vbs, SAOid, SANextOid)] - end; -transform_sa_next_result([], _SAOid, _SANextOid) -> - []. - - - -%%% ================ GET-BULK ===================================== -%%% -%%% In order to prevent excesses in reply sizes there are two -%%% preventive methods in place. One is to check that the encode -%%% size does not exceed Max PDU size (this is mentioned in the -%%% standard). The other is a simple VBs limit. That is, the -%%% resulting response cannot contain more then this number of VBs. -%%% - -do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds, GbMaxVBs) -> - ?vtrace("do_get_bulk -> entry with" - "~n MibView: ~p" - "~n NonRepeaters: ~p" - "~n MaxRepetitions: ~p" - "~n PduMS: ~p" - "~n Varbinds: ~p" - "~n GbMaxVBs: ~p", - [MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds, GbMaxVBs]), - {NonRepVbs, RestVbs} = ?LIB:split_gb_vbs(NonRepeaters, Varbinds), - ?vt("do_get_bulk -> split: " - "~n NonRepVbs: ~p" - "~n RestVbs: ~p", [NonRepVbs, RestVbs]), - case do_get_next(MibView, NonRepVbs, GbMaxVBs) of - {noError, 0, UResNonRepVbs} -> - ?vt("do_get_bulk -> next noError: " - "~n UResNonRepVbs: ~p", [UResNonRepVbs]), - ResNonRepVbs = lists:keysort(#varbind.org_index, UResNonRepVbs), - %% Decode the first varbinds, produce a reversed list of - %% listOfBytes. - case (catch enc_vbs(PduMS - ?empty_pdu_size, ResNonRepVbs)) of - {error, Idx, Reason} -> - ?LIB:user_err("failed encoding varbind ~w:~n~p", [Idx, Reason]), - {genErr, Idx, []}; - {SizeLeft, Res} when is_integer(SizeLeft) and is_list(Res) -> - ?vtrace("do_get_bulk -> encoded: " - "~n SizeLeft: ~p" - "~n Res: ~w", [SizeLeft, Res]), - case (catch do_get_rep(SizeLeft, MibView, MaxRepetitions, - RestVbs, Res, - length(UResNonRepVbs), GbMaxVBs)) of - {error, Idx, Reason} -> - ?LIB:user_err("failed encoding varbind ~w:~n~p", - [Idx, Reason]), - {genErr, Idx, []}; - Res when is_list(Res) -> - ?vtrace("do get bulk -> Res: " - "~n ~w", [Res]), - {noError, 0, conv_res(Res)}; - {noError, 0, Data} = OK -> - ?vtrace("do get bulk -> OK: " - "~n length(Data): ~w", [length(Data)]), - OK; - Else -> - ?vtrace("do get bulk -> Else: " - "~n ~w", [Else]), - Else - end; - Res when is_list(Res) -> - {noError, 0, conv_res(Res)} - end; - - {ErrorStatus, Index, _} -> - ?vdebug("do get bulk: " - "~n ErrorStatus: ~p" - "~n Index: ~p",[ErrorStatus, Index]), - {ErrorStatus, Index, []} - end. - - -enc_vbs(SizeLeft, Vbs) -> - ?vt("enc_vbs -> entry with" - "~n SizeLeft: ~w", [SizeLeft]), - Fun = fun(Vb, {Sz, Res}) when Sz > 0 -> - ?vt("enc_vbs -> (fun) entry with" - "~n Vb: ~p" - "~n Sz: ~p" - "~n Res: ~w", [Vb, Sz, Res]), - case (catch snmp_pdus:enc_varbind(Vb)) of - {'EXIT', Reason} -> - ?vtrace("enc_vbs -> encode failed: " - "~n Reason: ~p", [Reason]), - throw({error, Vb#varbind.org_index, Reason}); - X -> - ?vt("enc_vbs -> X: ~w", [X]), - Lx = length(X), - ?vt("enc_vbs -> Lx: ~w", [Lx]), - if - Lx < Sz -> - {Sz - length(X), [X | Res]}; - true -> - throw(Res) - end - end; - (_Vb, {_Sz, [_H | T]}) -> - ?vt("enc_vbs -> (fun) entry with" - "~n T: ~p", [T]), - throw(T); - (_Vb, {_Sz, []}) -> - ?vt("enc_vbs -> (fun) entry", []), - throw([]) - end, - lists:foldl(Fun, {SizeLeft, []}, Vbs). - -do_get_rep(Sz, MibView, MaxRepetitions, Varbinds, Res, GbNumVBs, GbMaxVBs) - when MaxRepetitions >= 0 -> - do_get_rep(Sz, MibView, 0, MaxRepetitions, Varbinds, Res, - GbNumVBs, GbMaxVBs); -do_get_rep(Sz, MibView, _MaxRepetitions, Varbinds, Res, GbNumVBs, GbMaxVBs) -> - do_get_rep(Sz, MibView, 0, 0, Varbinds, Res, GbNumVBs, GbMaxVBs). - -conv_res(ResVarbinds) -> - conv_res(ResVarbinds, []). -conv_res([VbListOfBytes | T], Bytes) -> - conv_res(T, VbListOfBytes ++ Bytes); -conv_res([], Bytes) -> - Bytes. - -%% The only other value, then a positive integer, is infinity. -do_get_rep(_Sz, _MibView, Count, Max, _, _Res, GbNumVBs, GbMaxVBs) - when (is_integer(GbMaxVBs) andalso (GbNumVBs > GbMaxVBs)) -> - ?vinfo("Max Get-BULK VBs limit (~w) exceeded (~w) when:" - "~n Count: ~p" - "~n Max: ~p", [GbMaxVBs, GbNumVBs, Count, Max]), - {tooBig, 0, []}; -do_get_rep(_Sz, _MibView, Max, Max, _, Res, _GbNumVBs, _GbMaxVBs) -> - ?vt("do_get_rep -> done when: " - "~n Res: ~p", [Res]), - {noError, 0, conv_res(Res)}; -do_get_rep(Sz, MibView, Count, Max, Varbinds, Res, GbNumVBs, GbMaxVBs) -> - ?vt("do_get_rep -> entry when: " - "~n Sz: ~p" - "~n Count: ~p" - "~n Res: ~w", [Sz, Count, Res]), - case try_get_bulk(Sz, MibView, Varbinds, GbMaxVBs) of - {noError, NextVarbinds, SizeLeft, Res2} -> - ?vt("do_get_rep -> noError: " - "~n SizeLeft: ~p" - "~n Res2: ~p", [SizeLeft, Res2]), - do_get_rep(SizeLeft, MibView, Count+1, Max, NextVarbinds, - Res2 ++ Res, - GbNumVBs + length(Varbinds), GbMaxVBs); - {endOfMibView, _NextVarbinds, _SizeLeft, Res2} -> - ?vt("do_get_rep -> endOfMibView: " - "~n Res2: ~p", [Res2]), - {noError, 0, conv_res(Res2 ++ Res)}; - {ErrorStatus, Index} -> - ?vtrace("do_get_rep -> done when error: " - "~n ErrorStatus: ~p" - "~n Index: ~p", [ErrorStatus, Index]), - {ErrorStatus, Index, []} - end. - -org_index_sort_vbs(Vbs) -> - lists:keysort(#varbind.org_index, Vbs). - -try_get_bulk(Sz, MibView, Varbinds, GbMaxVBs) -> - ?vt("try_get_bulk -> entry with" - "~n Sz: ~w" - "~n MibView: ~w" - "~n Varbinds: ~w", [Sz, MibView, Varbinds]), - case do_get_next(MibView, Varbinds, GbMaxVBs) of - {noError, 0, UNextVarbinds} -> - ?vt("try_get_bulk -> noError: " - "~n UNextVarbinds: ~p", [UNextVarbinds]), - NextVarbinds = org_index_sort_vbs(UNextVarbinds), - case (catch enc_vbs(Sz, NextVarbinds)) of - {error, Idx, Reason} -> - ?LIB:user_err("failed encoding varbind ~w:~n~p", [Idx, Reason]), - ?vtrace("try_get_bulk -> encode error: " - "~n Idx: ~p" - "~n Reason: ~p", [Idx, Reason]), - {genErr, Idx}; - {SizeLeft, Res} when is_integer(SizeLeft) andalso - is_list(Res) -> - ?vt("try get bulk -> encode ok: " - "~n SizeLeft: ~w" - "~n Res: ~w", [SizeLeft, Res]), - {check_end_of_mibview(NextVarbinds), - NextVarbinds, SizeLeft, Res}; - Res when is_list(Res) -> - ?vt("try get bulk -> Res: " - "~n ~w", [Res]), - {endOfMibView, [], 0, Res} - end; - {ErrorStatus, Index, _} -> - ?vt("try_get_bulk -> error: " - "~n ErrorStatus: ~p" - "~n Index: ~p", [ErrorStatus, Index]), - {ErrorStatus, Index} - end. - -%% If all variables in this pass are endOfMibView, -%% there is no reason to continue. -check_end_of_mibview([#varbind{value = endOfMibView} | T]) -> - check_end_of_mibview(T); -check_end_of_mibview([]) -> - endOfMibView; -check_end_of_mibview(_) -> - noError. - - - -%%----------------------------------------------------------------- -%% Internal -%%----------------------------------------------------------------- - -%%----------------------------------------------------------------- -%% Func: do_get_local/2 -%% Purpose: Loop the variablebindings list. We know that each varbind -%% in that list belongs to us. -%% Returns: {noError, 0, ListOfNewVarbinds} | -%% {ErrorStatus, ErrorIndex, []} -%%----------------------------------------------------------------- - -do_get_local(IVBs, IsNotification) -> - do_get_local(IVBs, IsNotification, []). - -do_get_local([], _IsNotification, Res) -> - {noError, 0, Res}; -do_get_local([IVB | IVBs], IsNotification, Res) -> - case ?LIB:try_get(IVB, IsNotification) of - NewVB when is_record(NewVB, varbind) -> - do_get_local(IVBs, IsNotification, [NewVB | Res]); - NewVBs when is_list(NewVBs) -> - do_get_local(IVBs, IsNotification, lists:append(NewVBs, Res)); - {error, Error, OrgIndex} -> - {Error, OrgIndex, []} - end. - - -%%----------------------------------------------------------------- -%% Func: do_get_subagents/2 -%% Purpose: Loop the list of varbinds for different subagents. -%% For each of them, call subagent_get to retreive -%% the values for them. -%% Returns: {noError, 0, ListOfNewVarbinds} | -%% {ErrorStatus, ErrorIndex, []} -%%----------------------------------------------------------------- - -do_get_subagents(SubagentVarbinds, IsNotification) -> - do_get_subagents(SubagentVarbinds, IsNotification, []). - -do_get_subagents([], _IsNotification, Res) -> - {noError, 0, Res}; -do_get_subagents([{SAPid, SAVBs} | Tail], IsNotification, Res) -> - {_SAOids, VBs} = ?LIB:sa_split(SAVBs), - case (catch subagent_get(SAPid, IsNotification, VBs)) of - {noError, 0, NewVBs} -> - do_get_subagents(Tail, IsNotification, lists:append(NewVBs, Res)); - {ErrorStatus, ErrorIndex, _} -> - {ErrorStatus, ErrorIndex, []}; - {'EXIT', Reason} -> - ?LIB:user_err("Lost contact with subagent (get) ~w. Using genErr", - [Reason]), - {genErr, 0, []} - end. - - - - diff --git a/lib/snmp/src/agent/tmp/snmpa_get_lib.erl b/lib/snmp/src/agent/tmp/snmpa_get_lib.erl deleted file mode 100644 index 2bd7e4a1d2..0000000000 --- a/lib/snmp/src/agent/tmp/snmpa_get_lib.erl +++ /dev/null @@ -1,507 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2019-2019. All Rights Reserved. -%% -%% Licensed under the Apache License, Version 2.0 (the "License"); -%% you may not use this file except in compliance with the License. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%% -%% %CopyrightEnd% -%% - --module(snmpa_get_lib). - --export([ - try_get/2, - try_get_instance/1, - - delete_prefixes/2, - delete_index/1, - - sort_vbs/1, - split_gb_vbs/2, - split_vbs/1, split_vbs/3, - split_vbs_view/2, - - make_value_a_correct_value/3, - - dbg_apply/3, - - user_err/2 - ]). - - - -%% *** sort_vbs *** - --spec sort_vbs(VBs :: [snmp:varbind()]) -> [snmp:ivarbind()]. - -sort_vbs(VBs) -> - snmpa_svbl:sort_varbindlist(get(mibserver), VBs). - - -%% *** split_vbs *** - --spec split_gb_vbs(NonRepeaters :: integer(), - VBs :: [varbind()]) -> - {NonRepVBs :: [varbind()], RestVBs :: [varbind()]}. - -split_gb_vbs(N, VBs) -> - split_gb_vbs(N, VBs, []). - -split_gb_vbs(N, Varbinds, Res) when N =< 0 -> - {Res, Varbinds}; -split_gb_vbs(N, [H | T], Res) -> - split_gb_vbs(N-1, T, [H | Res]); -split_gb_vbs(_N, [], Res) -> - {Res, []}. - - - -%% *** split_vbs_view *** - --spec split_vbs_view(VBs :: [varbind()], - MibView :: snmp_view_based_acm_mib:mibview()) -> - {OutSideView :: [varbind()], - InSideView :: [varbind()]}. - -split_vbs_view(VBs, MibView) -> - ?vtrace("split the varbinds view", []), - split_vbs_view(VBs, MibView, [], []). - -split_vbs_view([], _MibView, Out, In) -> - {Out, In}; -split_vbs_view([Vb | Vbs], MibView, Out, In) -> - case snmpa_acm:validate_mib_view(Vb#varbind.oid, MibView) of - true -> split_vbs_view(Vbs, MibView, Out, [Vb | In]); - false -> split_vbs_view(Vbs, MibView, - [Vb#varbind{value = noSuchObject} | Out], In) - end. - - - -%% *** split_vbs/1,3 *** -%% -%% Sort out the 'end of' things (mib view of tables). -%% - --spec split_vbs(VBs :: [varbind()]) -> - {ok, Res :: [varbind()], EndOfs :: [varbond()]}. - -split_vbs(VBs) -> - split_vbs(VBs, [], []). - --spec split_vbs(VBs :: [varbind()], - Res :: [varbind()], - EndOfs :: [varbond()]) -> - {ok, Res :: [varbind()], EndOfs :: [varbond()]}. - -split_vbs([], Res, EndOfs) -> - {ok, Res, EndOfs}; -split_vbs([Vb | Vbs], Res, EndOfs) -> - case Vb#varbind.value of - {endOfMibView, _} -> split_varbinds(Vbs, Res, [Vb | EndOfs]); - {endOfTable, _} -> split_varbinds(Vbs, Res, [Vb | EndOfs]); - _ -> split_varbinds(Vbs, [Vb | Res], EndOfs) - end. - - -next_oid(Oid) -> - case lists:reverse(Oid) of - [H | T] -> lists:reverse([H+1 | T]); - [] -> [] - end. - - - -%% *** delete_prefixes *** - --spec delete_prefixes(Prefix :: oid(), - IVBs :: [ivarbind()]) -> - [{ShortOID :: snmp:oid(), - ASN1Type :: snmp:asn1_type()}]. - -delete_prefixes(Prefix, IVBs) -> - [{snmp_misc:diff(Oid, Prefix), ME#me.asn1_type} || - #ivarbind{varbind = #varbind{oid = Oid}, mibentry = ME} <- IVBs]. - - - -%% *** delete_index *** - --spec delete_index(TableOids :: [{Col :: integer(), - Val :: term(), - OrgIndex :: integer()}]) -> - [Col :: integer()]. - -delete_index(TableOids) -> - [Col || {Col, _Val, _OrgIndex} <- TableOids]. - - - -%%----------------------------------------------------------------- -%% transforms a (hopefully correct) return value ((perhaps) from a -%% mib-function) to a typed and guaranteed correct return value. -%% An incorrect return value is transformed to {error, genErr}. -%% A correct return value is on the form: -%% {error, } | {value, , } -%%----------------------------------------------------------------- - --spec make_value_a_correct_value(Value :: term(), - ASN1 :: snmp:asn1_type(), - MFA :: term()) -> - {error, Error :: atom()} | - {value, ValueType :: atom(), - Value :: term()}. - -make_value_a_correct_value({value, Val}, Asn1, Mfa) - when Asn1#asn1_type.bertype =:= 'INTEGER' -> - check_integer(Val, Asn1, Mfa); - -make_value_a_correct_value({value, Val}, Asn1, Mfa) - when Asn1#asn1_type.bertype =:= 'Counter32' -> - check_integer(Val, Asn1, Mfa); - -make_value_a_correct_value({value, Val}, Asn1, Mfa) - when Asn1#asn1_type.bertype =:= 'Unsigned32' -> - check_integer(Val, Asn1, Mfa); - -make_value_a_correct_value({value, Val}, Asn1, Mfa) - when Asn1#asn1_type.bertype =:= 'TimeTicks' -> - check_integer(Val, Asn1, Mfa); - -make_value_a_correct_value({value, Val}, Asn1, Mfa) - when Asn1#asn1_type.bertype =:= 'Counter64' -> - check_integer(Val, Asn1, Mfa); - -make_value_a_correct_value({value, Val}, Asn1, Mfa) - when (Asn1#asn1_type.bertype =:= 'BITS') andalso is_list(Val) -> - {value,Kibbles} = snmp_misc:assq(kibbles,Asn1#asn1_type.assocList), - case snmp_misc:bits_to_int(Val,Kibbles) of - error -> - wrongValue(Val, Mfa); - Int -> - make_value_a_correct_value({value,Int},Asn1,Mfa) - end; - -make_value_a_correct_value({value, Val}, Asn1, Mfa) - when (Asn1#asn1_type.bertype =:= 'BITS') andalso is_integer(Val) -> - {value,Kibbles} = snmp_misc:assq(kibbles,Asn1#asn1_type.assocList), - {_Kibble,BitNo} = lists:last(Kibbles), - case (1 bsl (BitNo+1)) of - X when Val < X -> - {value,'BITS',Val}; - _Big -> - wrongValue(Val, Mfa) - end; - -make_value_a_correct_value({value, String}, - #asn1_type{bertype = 'OCTET STRING', - hi = Hi, lo = Lo}, Mfa) -> - check_octet_string(String, Hi, Lo, Mfa, 'OCTET STRING'); - -make_value_a_correct_value({value, String}, - #asn1_type{bertype = 'IpAddress', - hi = Hi, lo = Lo}, Mfa) -> - check_octet_string(String, Hi, Lo, Mfa, 'IpAddress'); - -make_value_a_correct_value({value, Oid}, - #asn1_type{bertype = 'OBJECT IDENTIFIER'}, - _Mfa) -> - case snmp_misc:is_oid(Oid) of - true -> {value, 'OBJECT IDENTIFIER', Oid}; - _Else -> {error, wrongType} - end; - -make_value_a_correct_value({value, Val}, Asn1, _Mfa) - when Asn1#asn1_type.bertype =:= 'Opaque' -> - if is_list(Val) -> {value, 'Opaque', Val}; - true -> {error, wrongType} - end; - -make_value_a_correct_value({noValue, noSuchObject}, _ASN1Type, _Mfa) -> - {value, noValue, noSuchObject}; -make_value_a_correct_value({noValue, noSuchInstance}, _ASN1Type, _Mfa) -> - {value, noValue, noSuchInstance}; -make_value_a_correct_value({noValue, noSuchName}, _ASN1Type, _Mfa) -> - %% Transform this into a v2 value. It is converted to noSuchName - %% later if it was v1. If it was v2, we use noSuchInstance. - {value, noValue, noSuchInstance}; -%% For backwards compatibility only - we really shouldn't allow this; -%% it makes no sense to return unSpecified for a variable! But we did -%% allow it previously. -- We transform unSpecified to noSuchInstance -%% (OTP-3303). -make_value_a_correct_value({noValue, unSpecified}, _ASN1Type, _Mfa) -> - {value, noValue, noSuchInstance}; -make_value_a_correct_value(genErr, _ASN1Type, _MFA) -> - {error, genErr}; - -make_value_a_correct_value(_WrongVal, _ASN1Type, undef) -> - {error, genErr}; - -make_value_a_correct_value(WrongVal, ASN1Type, Mfa) -> - user_err("Got ~w from ~w. (~w) Using genErr", - [WrongVal, Mfa, ASN1Type]), - {error, genErr}. - -check_integer(Val, Asn1, Mfa) -> - case Asn1#asn1_type.assocList of - undefined -> check_size(Val, Asn1, Mfa); - Alist -> - case snmp_misc:assq(enums, Alist) of - {value, Enums} -> check_enums(Val, Asn1, Enums, Mfa); - false -> check_size(Val, Asn1, Mfa) - end - end. - -check_octet_string(String, Hi, Lo, Mfa, Type) -> - Len = (catch length(String)), % it might not be a list - case snmp_misc:is_string(String) of - true when Lo =:= undefined -> {value, Type, String}; - true when Len =< Hi, Len >= Lo -> - {value, Type, String}; - true -> - wrongLength(String, Mfa); - _Else -> - wrongType(String, Mfa) - end. - -check_size(Val, #asn1_type{lo = Lo, hi = Hi, bertype = Type}, Mfa) - when is_integer(Val) -> - ?vtrace("check size of integer: " - "~n Value: ~p" - "~n Upper limit: ~p" - "~n Lower limit: ~p" - "~n BER-type: ~p", - [Val,Hi,Lo,Type]), - if - (Lo =:= undefined) andalso (Hi =:= undefined) -> {value, Type, Val}; - (Lo =:= undefined) andalso is_integer(Hi) andalso (Val =< Hi) -> - {value, Type, Val}; - is_integer(Lo) andalso (Val >= Lo) andalso (Hi =:= undefined) -> - {value, Type, Val}; - is_integer(Lo) andalso is_integer(Hi) andalso (Val >= Lo) andalso (Val =< Hi) -> - {value, Type, Val}; - true -> - wrongValue(Val, Mfa) - end; -check_size(Val, _, Mfa) -> - wrongType(Val, Mfa). - -check_enums(Val, Asn1, Enums, Mfa) -> - Association = - if - is_integer(Val) -> lists:keysearch(Val, 2, Enums); - is_atom(Val) -> lists:keysearch(Val, 1, Enums); - true -> {error, wrongType} - end, - case Association of - {value, {_AliasIntName, Val2}} -> - {value, Asn1#asn1_type.bertype, Val2}; - false -> - wrongValue(Val, Mfa); - {error, wrongType} -> - wrongType(Val, Mfa) - end. - -wrongLength(Val, Mfa) -> - report_err(Val, Mfa, wrongLength). - -wrongValue(Val, Mfa) -> - report_err(Val, Mfa, wrongValue). - -wrongType(Val, Mfa) -> - report_err(Val, Mfa, wrongType). - -report_err(_Val, undef, Err) -> - {error, Err}; -report_err(Val, Mfa, Err) -> - user_err("Got ~p from ~w. Using ~w", [Val, Mfa, Err]), - {error, Err}. - - - - -is_valid_pdu_type('get-request') -> true; -is_valid_pdu_type('get-next-request') -> true; -is_valid_pdu_type('get-bulk-request') -> true; -is_valid_pdu_type('set-request') -> true; -is_valid_pdu_type(_) -> false. - - - -%%----------------------------------------------------------------- -%% Func: try_get/2 -%% Returns: {error, ErrorStatus, OrgIndex} | -%% #varbind | -%% List of #varbind -%%----------------------------------------------------------------- - --spec try_get(IVB :: ivarbind(), - IsNotification :: boolean()) -> - {error, ErrorStatus, OrgIndex} | varbind() | [varbind()]. - -try_get(IVb, IsNotification) when is_record(IVb, ivarbind) -> - ?vtrace("try_get(ivarbind) -> entry with" - "~n IVb: ~p", [IVb]), - get_var_value_from_ivb(IVb, IsNotification); -try_get({TableOid, TableVbs}, IsNotification) -> - ?vtrace("try_get(table) -> entry with" - "~n TableOid: ~p" - "~n TableVbs: ~p", [TableOid, TableVbs]), - [#ivarbind{mibentry = MibEntry}|_] = TableVbs, - {NoAccessVbs, AccessVbs} = - check_all_table_vbs(TableVbs, IsNotification, [], []), - case get_tab_value_from_mib(MibEntry, TableOid, AccessVbs) of - {error, ErrorStatus, OrgIndex} -> - {error, ErrorStatus, OrgIndex}; - NVbs -> - NVbs ++ NoAccessVbs - end. - - -%%----------------------------------------------------------------- -%% Func: try_get_instance/1 -%% Returns: {value, noValue, term()} | -%% {value, Type, Value} | -%% {error, ErrorStatus} -%%----------------------------------------------------------------- - --spec try_get_instance(ME :: snmp:me()) -> - {value, noValue, term()} | - {value, Type :: asn1_type(), Value :: term()} | - {error, error_status()}. - -try_get_instance(#me{mfa = {M, F, A}, asn1_type = ASN1Type}) -> - ?vtrace("try_get_instance -> entry with" - "~n M: ~p" - "~n F: ~p" - "~n A: ~p", [M,F,A]), - Result = (catch dbg_apply(M, F, [get | A])), - % mib shall return {value, } | - % {noValue, noSuchName} (v1) | - % {noValue, noSuchObject | noSuchInstance} (v2, v1) - % everything else (including 'genErr') will generate 'genErr'. - make_value_a_correct_value(Result, ASN1Type, {M, F, A}). - - - -%%----------------------------------------------------------------- -%% Returns: {error, ErrorStatus, OrgIndex} | -%% #varbind -%%----------------------------------------------------------------- - -get_var_value_from_ivb(#ivarbind{status = noError, - mibentry = ME, - varbind = VB} = IVb, IsNotification) -> - ?vtrace("get_var_value_from_ivb(noError) -> entry", []), - #varbind{org_index = OrgIndex, oid = Oid} = Vb, - case ME#me.access of - 'not-accessible' -> - Vb#varbind{value = noSuchInstance}; - 'accessible-for-notify' when (IsNotification =:= false) -> - Vb#varbind{value = noSuchInstance}; - 'write-only' -> - Vb#varbind{value = noSuchInstance}; - _ -> - case get_var_value_from_mib(Me, Oid) of - {value, Type, Value} -> - Vb#varbind{variabletype = Type, value = Value}; - {error, ErrorStatus} -> - {error, ErrorStatus, OrgIndex} - end - end; -get_var_value_from_ivb(#ivarbind{status = Status, varbind = VB}, _) -> - ?vtrace("get_var_value_from_ivb(~p) -> entry", [Status]), - VB#varbind{value = Status}. - - - -%%----------------------------------------------------------------- -%% Func: get_var_value_from_mib/1 -%% Purpose: -%% Pre: Oid is a correct instance Oid (lookup checked that). -%% Returns: {error, ErrorStatus} | -%% {value, Type, Value} -%% Returns: A correct return value (see make_value_a_correct_value) -%%----------------------------------------------------------------- -get_var_value_from_mib(#me{entrytype = variable, - asn1_type = ASN1Type, - mfa = {Mod, Func, Args}}, - _Oid) -> - ?vtrace("get_var_value_from_mib(variable) -> entry when" - "~n Mod: ~p" - "~n Func: ~p" - "~n Args: ~p", [Mod, Func, Args]), - Result = (catch dbg_apply(Mod, Func, [get | Args])), - % mib shall return {value, } | - % {noValue, noSuchName} (v1) | - % {noValue, noSuchObject | noSuchInstance} (v2, v1) - % everything else (including 'genErr') will generate 'genErr'. - make_value_a_correct_value(Result, ASN1Type, {Mod, Func, Args}); - -get_var_value_from_mib(#me{entrytype = table_column, - oid = MeOid, - asn1_type = ASN1Type, - mfa = {Mod, Func, Args}}, - Oid) -> - ?vtrace("get_var_value_from_mib(table_column) -> entry when" - "~n MeOid: ~p" - "~n Mod: ~p" - "~n Func: ~p" - "~n Args: ~p" - "~n Oid: ~p", [MeOid, Mod, Func, Args, Oid]), - Col = lists:last(MeOid), - Indexes = snmp_misc:diff(Oid, MeOid), - [Result] = (catch dbg_apply(Mod, Func, [get, Indexes, [Col] | Args])), - make_value_a_correct_value(Result, ASN1Type, - {Mod, Func, Args, Indexes, Col}). - - - -%%----------------------------------------------------------------- -%% Runtime debugging of the agent. -%%----------------------------------------------------------------- - --spec dbg_apply(M :: atom(), F :: atom(), A :: list()) -> - any(). - -dbg_apply(M, F, A) -> - case get(verbosity) of - silence -> - apply(M,F,A); - _ -> - ?vlog("~n apply: ~w,~w,~p~n", [M,F,A]), - Res = (catch apply(M,F,A)), - case Res of - {'EXIT', Reason} -> - ?vinfo("Call to: " - "~n Module: ~p" - "~n Function: ~p" - "~n Args: ~p" - "~n" - "~nresulted in an exit" - "~n" - "~n ~p", [M, F, A, Reason]); - _ -> - ?vlog("~n returned: ~p", [Res]) - end, - Res - end. - - -%% --------------------------------------------------------------------- - -user_err(F, A) -> - snmpa_error:user_err(F, A). - - diff --git a/lib/snmp/test/snmp_agent_test_get.erl b/lib/snmp/test/snmp_agent_test_get.erl index 46436044f5..517c71507a 100644 --- a/lib/snmp/test/snmp_agent_test_get.erl +++ b/lib/snmp/test/snmp_agent_test_get.erl @@ -28,28 +28,31 @@ %%%----------------------------------------------------------------- -export([ - do_get/2, do_get/3, - do_get_next/2, - do_get_bulk/6 + do_get/3, do_get/4, + do_get_next/3, + do_get_bulk/7 ]). -do_get(UnsortedVarbinds, IsNotification) -> - snmpa_get:do_get(UnsortedVarbinds, IsNotification). +do_get(UnsortedVarbinds, IsNotification, Extra) -> + snmpa_get:do_get(UnsortedVarbinds, IsNotification, Extra). -do_get(MibView, UnsortedVarbinds, IsNotification) -> - snmpa_get:do_get(MibView, UnsortedVarbinds, IsNotification). +do_get(MibView, UnsortedVarbinds, IsNotification, Extra) -> + snmpa_get:do_get(MibView, UnsortedVarbinds, IsNotification, Extra). -do_get_next(MibView, UnsortedVBs) -> - snmpa_get:do_get_next(MibView, UnsortedVBs). +do_get_next(MibView, UnsortedVBs, Extra) -> + snmpa_get:do_get_next(MibView, UnsortedVBs, Extra). -do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds, GbMaxVBs) -> + +do_get_bulk(MibView, NonRepeaters, MaxRepetitions, + PduMS, Varbinds, GbMaxVBs, Extra) -> snmpa_get:do_get_bulk(MibView, NonRepeaters, MaxRepetitions, - PduMS, Varbinds, GbMaxVBs). + PduMS, Varbinds, GbMaxVBs, + Extra). -- cgit v1.2.3