diff options
Diffstat (limited to 'lib/snmp/src/agent/snmpa_set.erl')
-rw-r--r-- | lib/snmp/src/agent/snmpa_set.erl | 244 |
1 files changed, 244 insertions, 0 deletions
diff --git a/lib/snmp/src/agent/snmpa_set.erl b/lib/snmp/src/agent/snmpa_set.erl new file mode 100644 index 0000000000..0f85d0aaa0 --- /dev/null +++ b/lib/snmp/src/agent/snmpa_set.erl @@ -0,0 +1,244 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +-module(snmpa_set). + +-behaviour(snmpa_set_mechanism). + +-define(VMODULE,"SET"). +-include("snmp_verbosity.hrl"). + + +%%%----------------------------------------------------------------- +%%% This module implements a simple, basic atomic set mechanism. +%%%----------------------------------------------------------------- +%%% Table of contents +%%% ================= +%%% 1. SET REQUEST +%%% 1.1 SET phase one +%%% 1.2 SET phase two +%%% 2. Misc functions +%%%----------------------------------------------------------------- + +%% External exports +-export([do_set/2, do_subagent_set/1]). + +%%%----------------------------------------------------------------- +%%% 1. SET REQUEST +%%% +%%% 1) Perform set_phase_one for all own vars +%%% 2) Perform set_phase_one for all SAs +%%% IF nok THEN 2.1 ELSE 3 +%%% 2.1) Perform set_phase_two(undo) for all SAs that have performed +%%% set_phase_one. +%%% 3) Perform set_phase_two for all own vars +%%% 4) Perform set_phase_two(set) for all SAs +%%% IF nok THEN 4.1 ELSE 5 +%%% 4.1) Perform set_phase_two(undo) for all SAs that have performed +%%% set_phase_one but not set_phase_two(set). +%%% 5) noError +%%%----------------------------------------------------------------- +%%----------------------------------------------------------------- +%% First of all - validate MibView for all varbinds. In this way +%% we don't have to send the MibView to all SAs for validation. +%%----------------------------------------------------------------- +do_set(MibView, UnsortedVarbinds) -> + ?vtrace("do set with" + "~n MibView: ~p",[MibView]), + case snmpa_acm:validate_all_mib_view(UnsortedVarbinds, MibView) of + true -> + {MyVarbinds , SubagentVarbinds} = + sort_varbindlist(UnsortedVarbinds), + case set_phase_one(MyVarbinds, SubagentVarbinds) of + {noError, 0} -> set_phase_two(MyVarbinds, SubagentVarbinds); + {Reason, Index} -> {Reason, Index} + end; + {false, Index} -> + {noAccess, Index} + end. + +%%----------------------------------------------------------------- +%% This function is called when a subagents receives a message +%% concerning some set_phase. +%% Mandatory messages for all subagents: +%% [phase_one, UnsortedVarbinds] +%% [phase_two, set, UnsortedVarbinds] +%% [phase_two, undo, UnsortedVarbinds] +%%----------------------------------------------------------------- +do_subagent_set([phase_one, UnsortedVarbinds]) -> + ?vtrace("do subagent set, phase one",[]), + {MyVarbinds, SubagentVarbinds} = sort_varbindlist(UnsortedVarbinds), + set_phase_one(MyVarbinds, SubagentVarbinds); +do_subagent_set([phase_two, State, UnsortedVarbinds]) -> + ?vtrace("do subagent set, phase two",[]), + {MyVarbinds, SubagentVarbinds} = sort_varbindlist(UnsortedVarbinds), + set_phase_two(State, MyVarbinds, SubagentVarbinds). + +%%%----------------------------------------------------------------- +%%% 1.1 SET phase one +%%%----------------------------------------------------------------- +%%----------------------------------------------------------------- +%% Func: set_phase_one/3 +%% Purpose: First, do set_phase_one for my own variables (i.e. +%% variables handled by this agent). Then, do set_phase_one +%% for all subagents. If any SA failed, do set_phase_two +%% (undo) for all SA that have done set_phase_one. +%% Returns: {noError, 0} | {ErrorStatus, Index} +%%----------------------------------------------------------------- +set_phase_one(MyVarbinds, SubagentVarbinds) -> + ?vtrace("set phase one: " + "~n MyVarbinds: ~p" + "~n SubagentVarbinds: ~p", + [MyVarbinds, SubagentVarbinds]), + case set_phase_one_my_variables(MyVarbinds) of + {noError, 0} -> + case set_phase_one_subagents(SubagentVarbinds, []) of + {noError, 0} -> + {noError, 0}; + {{ErrorStatus, Index}, PerformedSubagents} -> + case set_phase_two_undo(MyVarbinds, PerformedSubagents) of + {noError, 0} -> + {ErrorStatus, Index}; + {WorseErrorStatus, WorseIndex} -> + {WorseErrorStatus, WorseIndex} + end + end; + {ErrorStatus, Index} -> + {ErrorStatus, Index} + end. + +set_phase_one_my_variables(MyVarbinds) -> + ?vtrace("my variables set, phase one:" + "~n ~p",[MyVarbinds]), + case snmpa_set_lib:is_varbinds_ok(MyVarbinds) of + {noError, 0} -> + snmpa_set_lib:consistency_check(MyVarbinds); + {ErrorStatus, Index} -> + {ErrorStatus, Index} + end. + +%%----------------------------------------------------------------- +%% Loop all subagents, and perform set_phase_one for them. +%%----------------------------------------------------------------- +set_phase_one_subagents([{SubAgentPid, SAVbs}|SubagentVarbinds], Done) -> + {_SAOids, Vbs} = sa_split(SAVbs), + case (catch snmpa_agent:subagent_set(SubAgentPid, [phase_one, Vbs])) of + {noError, 0} -> + set_phase_one_subagents(SubagentVarbinds, + [{SubAgentPid, SAVbs} | Done]); + {'EXIT', Reason} -> + user_err("Lost contact with subagent (set phase_one)" + "~n~w. Using genErr", [Reason]), + {{genErr, 0}, Done}; + {ErrorStatus, ErrorIndex} -> + {{ErrorStatus, ErrorIndex}, Done} + end; +set_phase_one_subagents([], _Done) -> + {noError, 0}. + +%%%----------------------------------------------------------------- +%%% 1.2 SET phase two +%%%----------------------------------------------------------------- +%% returns: {ErrStatus, ErrIndex} +set_phase_two(MyVarbinds, SubagentVarbinds) -> + ?vtrace("set phase two: " + "~n MyVarbinds: ~p" + "~n SubagentVarbinds: ~p", + [MyVarbinds, SubagentVarbinds]), + case snmpa_set_lib:try_set(MyVarbinds) of + {noError, 0} -> + set_phase_two_subagents(SubagentVarbinds); + {ErrorStatus, Index} -> + set_phase_two_undo_subagents(SubagentVarbinds), + {ErrorStatus, Index} + end. + +%%----------------------------------------------------------------- +%% This function is called for each phase_two state in the +%% subagents. The undo state just pass undo along to each of its +%% subagents. +%%----------------------------------------------------------------- +set_phase_two(set, MyVarbinds, SubagentVarbinds) -> + set_phase_two(MyVarbinds, SubagentVarbinds); +set_phase_two(undo, MyVarbinds, SubagentVarbinds) -> + set_phase_two_undo(MyVarbinds, SubagentVarbinds). + +%%----------------------------------------------------------------- +%% Loop all subagents, and perform set_phase_two(set) for them. +%% If any fails, perform set_phase_two(undo) for the not yet +%% called SAs. +%%----------------------------------------------------------------- +set_phase_two_subagents([{SubAgentPid, SAVbs} | SubagentVarbinds]) -> + {_SAOids, Vbs} = sa_split(SAVbs), + case catch snmpa_agent:subagent_set(SubAgentPid, [phase_two, set, Vbs]) of + {noError, 0} -> + set_phase_two_subagents(SubagentVarbinds); + {'EXIT', Reason} -> + user_err("Lost contact with subagent (set)~n~w. Using genErr", + [Reason]), + set_phase_two_undo_subagents(SubagentVarbinds), + {genErr, 0}; + {ErrorStatus, ErrorIndex} -> + set_phase_two_undo_subagents(SubagentVarbinds), + {ErrorStatus, ErrorIndex} + end; +set_phase_two_subagents([]) -> + {noError, 0}. + +%%----------------------------------------------------------------- +%% This function undos phase_one, own and subagent. +%%----------------------------------------------------------------- +set_phase_two_undo(MyVarbinds, SubagentVarbinds) -> + case set_phase_two_undo_my_variables(MyVarbinds) of + {noError, 0} -> + set_phase_two_undo_subagents(SubagentVarbinds); + {ErrorStatus, Index} -> + set_phase_two_undo_subagents(SubagentVarbinds), + {ErrorStatus, Index} + end. + +set_phase_two_undo_my_variables(MyVarbinds) -> + snmpa_set_lib:undo_varbinds(MyVarbinds). + +set_phase_two_undo_subagents([{SubAgentPid, SAVbs} | SubagentVarbinds]) -> + {_SAOids, Vbs} = sa_split(SAVbs), + case catch snmpa_agent:subagent_set(SubAgentPid, [phase_two, undo, Vbs]) of + {noError, 0} -> + set_phase_two_undo_subagents(SubagentVarbinds); + {'EXIT', Reason} -> + user_err("Lost contact with subagent (undo)~n~w. Using genErr", + [Reason]), + {genErr, 0}; + {ErrorStatus, ErrorIndex} -> + {ErrorStatus, ErrorIndex} + end; +set_phase_two_undo_subagents([]) -> + {noError, 0}. + +%%%----------------------------------------------------------------- +%%% 2. Misc functions +%%%----------------------------------------------------------------- +sort_varbindlist(Varbinds) -> + snmpa_svbl:sort_varbindlist(get(mibserver), Varbinds). + +sa_split(SubagentVarbinds) -> + snmpa_svbl:sa_split(SubagentVarbinds). + + +user_err(F, A) -> + snmpa_error:user_err(F, A). |