1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 1996-2020. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20-module(snmpa_set). 21 22-behaviour(snmpa_set_mechanism). 23 24-define(VMODULE,"SET"). 25-include("snmp_verbosity.hrl"). 26 27 28%%%----------------------------------------------------------------- 29%%% This module implements a simple, basic atomic set mechanism. 30%%%----------------------------------------------------------------- 31%%% Table of contents 32%%% ================= 33%%% 1. SET REQUEST 34%%% 1.1 SET phase one 35%%% 1.2 SET phase two 36%%% 2. Misc functions 37%%%----------------------------------------------------------------- 38 39%% External exports 40-export([do_set/2, do_subagent_set/1]). 41 42%%%----------------------------------------------------------------- 43%%% 1. SET REQUEST 44%%% 45%%% 1) Perform set_phase_one for all own vars 46%%% 2) Perform set_phase_one for all SAs 47%%% IF nok THEN 2.1 ELSE 3 48%%% 2.1) Perform set_phase_two(undo) for all SAs that have performed 49%%% set_phase_one. 50%%% 3) Perform set_phase_two for all own vars 51%%% 4) Perform set_phase_two(set) for all SAs 52%%% IF nok THEN 4.1 ELSE 5 53%%% 4.1) Perform set_phase_two(undo) for all SAs that have performed 54%%% set_phase_one but not set_phase_two(set). 55%%% 5) noError 56%%%----------------------------------------------------------------- 57%%----------------------------------------------------------------- 58%% First of all - validate MibView for all varbinds. In this way 59%% we don't have to send the MibView to all SAs for validation. 60%%----------------------------------------------------------------- 61do_set(MibView, UnsortedVarbinds) -> 62 ?vtrace("do set with" 63 "~n MibView: ~p",[MibView]), 64 case snmpa_acm:validate_all_mib_view(UnsortedVarbinds, MibView) of 65 true -> 66 {MyVarbinds , SubagentVarbinds} = 67 sort_varbindlist(UnsortedVarbinds), 68 case set_phase_one(MyVarbinds, SubagentVarbinds) of 69 {noError, 0} -> set_phase_two(MyVarbinds, SubagentVarbinds); 70 {Reason, Index} -> {Reason, Index} 71 end; 72 {false, Index} -> 73 {noAccess, Index} 74 end. 75 76%%----------------------------------------------------------------- 77%% This function is called when a subagents receives a message 78%% concerning some set_phase. 79%% Mandatory messages for all subagents: 80%% [phase_one, UnsortedVarbinds] 81%% [phase_two, set, UnsortedVarbinds] 82%% [phase_two, undo, UnsortedVarbinds] 83%%----------------------------------------------------------------- 84do_subagent_set([phase_one, UnsortedVarbinds]) -> 85 ?vtrace("do subagent set, phase one",[]), 86 {MyVarbinds, SubagentVarbinds} = sort_varbindlist(UnsortedVarbinds), 87 set_phase_one(MyVarbinds, SubagentVarbinds); 88do_subagent_set([phase_two, State, UnsortedVarbinds]) -> 89 ?vtrace("do subagent set, phase two",[]), 90 {MyVarbinds, SubagentVarbinds} = sort_varbindlist(UnsortedVarbinds), 91 set_phase_two(State, MyVarbinds, SubagentVarbinds). 92 93%%%----------------------------------------------------------------- 94%%% 1.1 SET phase one 95%%%----------------------------------------------------------------- 96%%----------------------------------------------------------------- 97%% Func: set_phase_one/3 98%% Purpose: First, do set_phase_one for my own variables (i.e. 99%% variables handled by this agent). Then, do set_phase_one 100%% for all subagents. If any SA failed, do set_phase_two 101%% (undo) for all SA that have done set_phase_one. 102%% Returns: {noError, 0} | {ErrorStatus, Index} 103%%----------------------------------------------------------------- 104set_phase_one(MyVarbinds, SubagentVarbinds) -> 105 ?vtrace("set phase one: " 106 "~n MyVarbinds: ~p" 107 "~n SubagentVarbinds: ~p", 108 [MyVarbinds, SubagentVarbinds]), 109 case set_phase_one_my_variables(MyVarbinds) of 110 {noError, 0} -> 111 case set_phase_one_subagents(SubagentVarbinds, []) of 112 {noError, 0} -> 113 {noError, 0}; 114 {{ErrorStatus, Index}, PerformedSubagents} -> 115 case set_phase_two_undo(MyVarbinds, PerformedSubagents) of 116 {noError, 0} -> 117 {ErrorStatus, Index}; 118 {WorseErrorStatus, WorseIndex} -> 119 {WorseErrorStatus, WorseIndex} 120 end 121 end; 122 {ErrorStatus, Index} -> 123 {ErrorStatus, Index} 124 end. 125 126set_phase_one_my_variables(MyVarbinds) -> 127 ?vtrace("my variables set, phase one:" 128 "~n ~p",[MyVarbinds]), 129 case snmpa_set_lib:is_varbinds_ok(MyVarbinds) of 130 {noError, 0} -> 131 snmpa_set_lib:consistency_check(MyVarbinds); 132 {ErrorStatus, Index} -> 133 {ErrorStatus, Index} 134 end. 135 136%%----------------------------------------------------------------- 137%% Loop all subagents, and perform set_phase_one for them. 138%%----------------------------------------------------------------- 139set_phase_one_subagents([{SubAgentPid, SAVbs}|SubagentVarbinds], Done) -> 140 {_SAOids, Vbs} = sa_split(SAVbs), 141 case (catch snmpa_agent:subagent_set(SubAgentPid, [phase_one, Vbs])) of 142 {noError, 0} -> 143 set_phase_one_subagents(SubagentVarbinds, 144 [{SubAgentPid, SAVbs} | Done]); 145 {'EXIT', Reason} -> 146 user_err("Lost contact with subagent (set phase_one)" 147 "~n~w. Using genErr", [Reason]), 148 {{genErr, 0}, Done}; 149 {ErrorStatus, ErrorIndex} -> 150 {{ErrorStatus, ErrorIndex}, Done} 151 end; 152set_phase_one_subagents([], _Done) -> 153 {noError, 0}. 154 155%%%----------------------------------------------------------------- 156%%% 1.2 SET phase two 157%%%----------------------------------------------------------------- 158%% returns: {ErrStatus, ErrIndex} 159set_phase_two(MyVarbinds, SubagentVarbinds) -> 160 ?vtrace("set phase two: " 161 "~n MyVarbinds: ~p" 162 "~n SubagentVarbinds: ~p", 163 [MyVarbinds, SubagentVarbinds]), 164 case snmpa_set_lib:try_set(MyVarbinds) of 165 {noError, 0} -> 166 ?vtrace("set phase two: (local) varbinds set ok", []), 167 set_phase_two_subagents(SubagentVarbinds); 168 {ErrorStatus, ErrorIndex} -> 169 ?vlog("set phase two: (local) varbinds set failed" 170 "~n ErrorStatus: ~p" 171 "~n ErrorIndex: ~p", [ErrorStatus, ErrorIndex]), 172 set_phase_two_undo_subagents(SubagentVarbinds), 173 {ErrorStatus, ErrorIndex} 174 end. 175 176%%----------------------------------------------------------------- 177%% This function is called for each phase_two state in the 178%% subagents. The undo state just pass undo along to each of its 179%% subagents. 180%%----------------------------------------------------------------- 181set_phase_two(set, MyVarbinds, SubagentVarbinds) -> 182 set_phase_two(MyVarbinds, SubagentVarbinds); 183set_phase_two(undo, MyVarbinds, SubagentVarbinds) -> 184 set_phase_two_undo(MyVarbinds, SubagentVarbinds). 185 186%%----------------------------------------------------------------- 187%% Loop all subagents, and perform set_phase_two(set) for them. 188%% If any fails, perform set_phase_two(undo) for the not yet 189%% called SAs. 190%%----------------------------------------------------------------- 191set_phase_two_subagents([{SubAgentPid, SAVbs} | SubagentVarbinds]) -> 192 {_SAOids, Vbs} = sa_split(SAVbs), 193 case catch snmpa_agent:subagent_set(SubAgentPid, [phase_two, set, Vbs]) of 194 {noError, 0} -> 195 ?vtrace("set phase two: subagent ~p varbinds set ok", [SubAgentPid]), 196 set_phase_two_subagents(SubagentVarbinds); 197 {'EXIT', Reason} -> 198 user_err("Lost contact with subagent (set)~n~w. Using genErr", 199 [Reason]), 200 set_phase_two_undo_subagents(SubagentVarbinds), 201 {genErr, 0}; 202 {ErrorStatus, ErrorIndex} -> 203 ?vlog("set phase two: subagent ~p varbinds set failed" 204 "~n ErrorStatus: ~p" 205 "~n ErrorIndex: ~p", [SubAgentPid, ErrorStatus, ErrorIndex]), 206 set_phase_two_undo_subagents(SubagentVarbinds), 207 {ErrorStatus, ErrorIndex} 208 end; 209set_phase_two_subagents([]) -> 210 ?vtrace("set phase two: subagent(s) set ok", []), 211 {noError, 0}. 212 213%%----------------------------------------------------------------- 214%% This function undos phase_one, own and subagent. 215%%----------------------------------------------------------------- 216set_phase_two_undo(MyVarbinds, SubagentVarbinds) -> 217 case set_phase_two_undo_my_variables(MyVarbinds) of 218 {noError, 0} -> 219 set_phase_two_undo_subagents(SubagentVarbinds); 220 {ErrorStatus, Index} -> 221 set_phase_two_undo_subagents(SubagentVarbinds), 222 {ErrorStatus, Index} 223 end. 224 225set_phase_two_undo_my_variables(MyVarbinds) -> 226 snmpa_set_lib:undo_varbinds(MyVarbinds). 227 228set_phase_two_undo_subagents([{SubAgentPid, SAVbs} | SubagentVarbinds]) -> 229 {_SAOids, Vbs} = sa_split(SAVbs), 230 case catch snmpa_agent:subagent_set(SubAgentPid, [phase_two, undo, Vbs]) of 231 {noError, 0} -> 232 set_phase_two_undo_subagents(SubagentVarbinds); 233 {'EXIT', Reason} -> 234 user_err("Lost contact with subagent (undo)~n~w. Using genErr", 235 [Reason]), 236 {genErr, 0}; 237 {ErrorStatus, ErrorIndex} -> 238 {ErrorStatus, ErrorIndex} 239 end; 240set_phase_two_undo_subagents([]) -> 241 {noError, 0}. 242 243%%%----------------------------------------------------------------- 244%%% 2. Misc functions 245%%%----------------------------------------------------------------- 246sort_varbindlist(Varbinds) -> 247 snmpa_svbl:sort_varbindlist(get(mibserver), Varbinds). 248 249sa_split(SubagentVarbinds) -> 250 snmpa_svbl:sa_split(SubagentVarbinds). 251 252 253user_err(F, A) -> 254 snmpa_error:user_err(F, A). 255