diff options
Diffstat (limited to 'lib/snmp/src/agent/snmp_notification_mib.erl')
-rw-r--r-- | lib/snmp/src/agent/snmp_notification_mib.erl | 457 |
1 files changed, 457 insertions, 0 deletions
diff --git a/lib/snmp/src/agent/snmp_notification_mib.erl b/lib/snmp/src/agent/snmp_notification_mib.erl new file mode 100644 index 0000000000..16e43f05d7 --- /dev/null +++ b/lib/snmp/src/agent/snmp_notification_mib.erl @@ -0,0 +1,457 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-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(snmp_notification_mib). + +-export([configure/1, reconfigure/1, invalidate_cache/0, + snmpNotifyTable/1, snmpNotifyTable/3, + snmpNotifyFilterTable/3, snmpNotifyFilterProfileTable/3, + get_targets/0, get_targets/1]). +-export([add_notify/3, delete_notify/1]). +-export([check_notify/1]). + +-include("SNMP-NOTIFICATION-MIB.hrl"). +-include("SNMPv2-TC.hrl"). +-include("snmp_tables.hrl"). + +-define(VMODULE,"NOTIFICATION-MIB"). +-include("snmp_verbosity.hrl"). + +-ifndef(default_verbosity). +-define(default_verbosity,silence). +-endif. + + +%%----------------------------------------------------------------- +%% Func: configure/1 +%% Args: Dir is the directory where the configuration files are found. +%% Purpose: If the tables doesn't exist, this function reads +%% the config-files for the notify tables, and +%% inserts the data. This means that the data in the tables +%% survive a reboot. However, the StorageType column is +%% checked for each row. If volatile, the row is deleted. +%% Returns: ok +%% Fails: exit(configuration_error) +%%----------------------------------------------------------------- +configure(Dir) -> + set_sname(), + case db(snmpNotifyTable) of + {_, mnesia} -> + ?vlog("notification table in mnesia: cleanup",[]), + gc_tabs(); + TabDb -> + case snmpa_local_db:table_exists(TabDb) of + true -> + ?vlog("notification table exist: cleanup",[]), + gc_tabs(); + false -> + ?vlog("notification table does not exist: reconfigure",[]), + reconfigure(Dir) + end + end. + +%%----------------------------------------------------------------- +%% Func: reconfigure/1 +%% Args: Dir is the directory where the configuration files are found. +%% Purpose: Reads the config-files for the notify tables, and +%% inserts the data. Makes sure that all old data in +%% the tables are deleted, and the new data inserted. +%% This function makes sure that all (and only) +%% config-file-data are in the tables. +%% Returns: ok +%% Fails: exit(configuration_error) +%%----------------------------------------------------------------- +reconfigure(Dir) -> + set_sname(), + case (catch do_reconfigure(Dir)) of + ok -> + ok; + {error, Reason} -> + ?vinfo("reconfigure error: ~p", [Reason]), + config_err("reconfigure failed: ~p", [Reason]), + exit(configuration_error); + Error -> + ?vinfo("reconfigure failed: ~p", [Error]), + config_err("reconfigure failed: ~p", [Error]), + exit(configuration_error) + end. + +do_reconfigure(Dir) -> + ?vdebug("read notify config files",[]), + Notifs = read_notify_config_files(Dir), + init_tabs(Notifs), + ?vdebug("invalidate cache",[]), + invalidate_cache(), + ok. + + +read_notify_config_files(Dir) -> + ?vdebug("read notify config file",[]), + Gen = fun(_) -> ok end, + Filter = fun(Notifs) -> Notifs end, + Check = fun(Entry) -> check_notify(Entry) end, + [Notifs] = + snmp_conf:read_files(Dir, [{Gen, Filter, Check, "notify.conf"}]), + Notifs. + +check_notify({Name, Tag, Type}) -> + snmp_conf:check_string(Name,{gt,0}), + snmp_conf:check_string(Tag), + {ok, Val} = snmp_conf:check_atom(Type, [{trap, 1}, {inform, 2}]), + Notify = {Name, Tag, Val, + ?'StorageType_nonVolatile', ?'RowStatus_active'}, + {ok, Notify}; +check_notify(X) -> + error({invalid_notify, X}). + + +init_tabs(Notifs) -> + ?vdebug("create notify table",[]), + snmpa_local_db:table_delete(db(snmpNotifyTable)), + snmpa_local_db:table_create(db(snmpNotifyTable)), + ?vdebug("initiate notify table",[]), + init_notify_table(Notifs). + +init_notify_table([Row | T]) -> + Key = element(1, Row), + snmpa_local_db:table_create_row(db(snmpNotifyTable), Key, Row), + init_notify_table(T); +init_notify_table([]) -> true. + +table_cre_row(Tab, Key, Row) -> + snmpa_mib_lib:table_cre_row(db(Tab), Key, Row). + +table_del_row(Tab, Key) -> + snmpa_mib_lib:table_del_row(db(Tab), Key). + + +%% FIXME: does not work with mnesia +add_notify(Name, Tag, Type) -> + Notif = {Name, Tag, Type}, + case (catch check_notify(Notif)) of + {ok, Row} -> + Key = element(1, Row), + case table_cre_row(snmpNotifyTable, Key, Row) of + true -> + {ok, Key}; + false -> + {error, create_failed} + end; + {error, Reason} -> + {error, Reason}; + Error -> + {error, Error} + end. + +%% FIXME: does not work with mnesia +delete_notify(Key) -> + case table_del_row(snmpNotifyTable, Key) of + true -> + ok; + false -> + {error, delete_failed} + end. + +gc_tabs() -> + DB = db(snmpNotifyTable), + STC = stc(snmpNotifyTable), + FOI = foi(snmpNotifyTable), + snmpa_mib_lib:gc_tab(DB, STC, FOI), + ok. + + +%%----------------------------------------------------------------- +%% Func: get_targets() +%% get_targets(NotifyName) -> [Target] +%% Types: Target = {DestAddr, TargetName, TargetParams, NotifyType} +%% NotifyName = string() - the INDEX +%% DestAddr = {TDomain, TAddr} +%% TagrgetName = string() +%% TargetParams = {MpModel, SecModel, SecName, SecLevel} +%% NotifyType = trap | {inform, Timeout, Retry} +%% Purpose: Returns a list of all targets. Called by snmpa_trap +%% when a trap should be sent. +%% If a NotifyName is specified, the targets for that +%% name is returned. +%%----------------------------------------------------------------- +get_targets() -> + TargetsFun = fun find_targets/0, + snmpa_target_cache:targets(TargetsFun). + +get_targets(NotifyName) -> + TargetsFun = fun find_targets/0, + snmpa_target_cache:targets(TargetsFun, NotifyName). + + +%%----------------------------------------------------------------- +%% We use a cache of targets to avoid searching the tables each +%% time a trap is sent. When some of the 3 tables (notify, +%% targetAddr, targetParams) is modified, the cache is invalidated. +%%----------------------------------------------------------------- + +invalidate_cache() -> + snmpa_target_cache:invalidate(). + + +%% Ret: [{NotifyName, {DestAddr, TargetName, TargetParams, NotifyType}}] +%% NotifyType = trap | {inform, Timeout. Retry} +%% DestAddr = {Domain, Addr} ; e.g. {snmpUDPDomain, {IPasList, UdpPort}} + +find_targets() -> + TargAddrs = snmp_target_mib:get_target_addrs(), + %% TargAddrs = [{TagList,DestAddr,TargetName,TargetParams,Timeout,Retry}] + {_, Db} = db(snmpNotifyTable), + find_targets([], TargAddrs, Db, []). +find_targets(Key, TargAddrs, Db, Res) -> + case table_next(snmpNotifyTable, Key) of + endOfTable -> + Res; + NextKey when Db == mnesia -> + case mnesia:snmp_get_row(snmpNotifyTable, NextKey) of + {ok, #snmpNotifyTable{ + snmpNotifyTag = Tag, + snmpNotifyType = Type, + snmpNotifyRowStatus = ?'RowStatus_active'}} -> + ?vtrace("found notify entry for ~w" + "~n Tag: ~w" + "~n Type: ~w", [NextKey, Tag, Type]), + Targs = get_targets(TargAddrs, Tag, Type, NextKey), + find_targets(NextKey, TargAddrs, Db, Targs ++ Res); + {ok, #snmpNotifyTable{ + snmpNotifyTag = Tag, + snmpNotifyType = Type, + snmpNotifyRowStatus = RowStatus}} -> + ?vtrace("found invalid notify entry for ~w" + "~n Tag: ~w" + "~n Type: ~w" + "~n RowStatus: ~p", + [NextKey, Tag, Type, RowStatus]), + find_targets(NextKey, TargAddrs, Db, Res); + _ -> + ?vtrace("notify entry not found for ~w", [NextKey]), + find_targets(NextKey, TargAddrs, Db, Res) + end; + NextKey -> + Elements = [?snmpNotifyTag, ?snmpNotifyType, ?snmpNotifyRowStatus], + case snmpNotifyTable(get, NextKey, Elements) of + [{value, Tag}, {value, Type}, {value, ?'RowStatus_active'}] -> + ?vtrace("found notify entry for ~w" + "~n Tag: ~w" + "~n Type: ~w", [NextKey, Tag, Type]), + Targs = get_targets(TargAddrs, Tag, Type, NextKey), + find_targets(NextKey, TargAddrs, Db, Targs ++ Res); + [{value, Tag1}, {value, Type1}, {value, RowStatus}] -> + ?vtrace("found invalid notify entry for ~w" + "~n Tag: ~w" + "~n Type: ~w" + "~n RowStatus: ~w", + [NextKey, Tag1, Type1, RowStatus]), + find_targets(NextKey, TargAddrs, Db, Res); + _ -> + ?vtrace("notify entry not found for ~w", [NextKey]), + find_targets(NextKey, TargAddrs, Db, Res) + end + end. + +get_targets([{TagList, Addr, TargetName, Params, Timeout, Retry}|T], + Tag, Type, Name) -> + case snmp_misc:is_tag_member(Tag, TagList) of + true -> [{Name, {Addr, TargetName, Params, type(Type, Timeout, Retry)}}| + get_targets(T, Tag, Type, Name)]; + false -> + get_targets(T, Tag, Type, Name) + end; +get_targets([], _Tag, _Type, _Name) -> + []. + +type(trap, _, _) -> trap; +type(1, _, _) -> trap; %% OTP-4329 +type(inform, Timeout, Retry) -> {inform, Timeout, Retry}; +type(2, Timeout, Retry) -> {inform, Timeout, Retry}. %% OTP-4329 + + +%%----------------------------------------------------------------- +%% Instrumentation Functions +%%----------------------------------------------------------------- +%% Op = print - Used for debugging purposes +snmpNotifyTable(print) -> + Table = snmpNotifyTable, + DB = db(Table), + FOI = foi(Table), + PrintRow = + fun(Prefix, Row) -> + lists:flatten( + io_lib:format("~sName: ~p" + "~n~sTag: ~p" + "~n~sType: ~p (~w)" + "~n~sStorageType: ~p (~w)" + "~n~sStatus: ~p (~w)", + [Prefix, element(?snmpNotifyName, Row), + Prefix, element(?snmpNotifyTag, Row), + Prefix, element(?snmpNotifyType, Row), + case element(?snmpNotifyType, Row) of + ?snmpNotifyType_inform -> inform; + ?snmpNotifyType_trap -> trap; + _ -> undefined + end, + Prefix, element(?snmpNotifyStorageType, Row), + case element(?snmpNotifyStorageType, Row) of + ?'snmpNotifyStorageType_readOnly' -> readOnly; + ?'snmpNotifyStorageType_permanent' -> permanent; + ?'snmpNotifyStorageType_nonVolatile' -> nonVolatile; + ?'snmpNotifyStorageType_volatile' -> volatile; + ?'snmpNotifyStorageType_other' -> other; + _ -> undefined + end, + Prefix, element(?snmpNotifyRowStatus, Row), + case element(?snmpNotifyRowStatus, Row) of + ?'snmpNotifyRowStatus_destroy' -> destroy; + ?'snmpNotifyRowStatus_createAndWait' -> createAndWait; + ?'snmpNotifyRowStatus_createAndGo' -> createAndGo; + ?'snmpNotifyRowStatus_notReady' -> notReady; + ?'snmpNotifyRowStatus_notInService' -> notInService; + ?'snmpNotifyRowStatus_active' -> active; + _ -> undefined + end])) + end, + snmpa_mib_lib:print_table(Table, DB, FOI, PrintRow); +%% Op == new | delete +snmpNotifyTable(Op) -> + snmp_generic:table_func(Op, db(snmpNotifyTable)). + +%% Op == get | is_set_ok | set | get_next +snmpNotifyTable(get, RowIndex, Cols) -> + %% BMK BMK BMK BMK + get(snmpNotifyTable, RowIndex, Cols); +snmpNotifyTable(get_next, RowIndex, Cols) -> + %% BMK BMK BMK BMK + next(snmpNotifyTable, RowIndex, Cols); +snmpNotifyTable(set, RowIndex, Cols0) -> + %% BMK BMK BMK BMK + case (catch verify_snmpNotifyTable_cols(Cols0, [])) of + {ok, Cols} -> + invalidate_cache(), + %% invalidate_cache(RowIndex), + Db = db(snmpNotifyTable), + snmp_generic:table_func(set, RowIndex, Cols, Db); + Error -> + Error + end; +snmpNotifyTable(is_set_ok, RowIndex, Cols0) -> + case (catch verify_snmpNotifyTable_cols(Cols0, [])) of + {ok, Cols} -> + Db = db(snmpNotifyTable), + snmp_generic:table_func(is_set_ok, RowIndex, Cols, Db); + Error -> + Error + end; +snmpNotifyTable(Op, Arg1, Arg2) -> + snmp_generic:table_func(Op, Arg1, Arg2, db(snmpNotifyTable)). + + +verify_snmpNotifyTable_cols([], Cols) -> + {ok, lists:reverse(Cols)}; +verify_snmpNotifyTable_cols([{Col, Val0}|Cols], Acc) -> + Val = verify_snmpNotifyTable_col(Col, Val0), + verify_snmpNotifyTable_cols(Cols, [{Col, Val}|Acc]). + +verify_snmpNotifyTable_col(?snmpNotifyName, Name) -> + case (catch snmp_conf:check_string(Name, {gt, 0})) of + ok -> + Name; + _ -> + wrongValue(?snmpNotifyName) + end; +verify_snmpNotifyTable_col(?snmpNotifyTag, Tag) -> + case (catch snmp_conf:check_string(Tag)) of + ok -> + Tag; + _ -> + wrongValue(?snmpNotifyTag) + end; +verify_snmpNotifyTable_col(?snmpNotifyType, Type) -> + case Type of + trap -> 1; + inform -> 2; + 1 -> 1; + 2 -> 2; + _ -> wrongValue(?snmpNotifyType) + end; +verify_snmpNotifyTable_col(_, Val) -> + Val. + + +%%----------------------------------------------------------------- +%% In this version of the agent, we don't support notification +%% filters. +%%----------------------------------------------------------------- +snmpNotifyFilterTable(get, _RowIndex, Cols) -> + lists:map(fun(_Col) -> {noValue, noSuchObject} end, Cols); +snmpNotifyFilterTable(get_next, _RowIndex, Cols) -> + lists:map(fun(_Col) -> endOfTable end, Cols); +snmpNotifyFilterTable(is_set_ok, _RowIndex, Cols) -> + {notWritable, element(1, hd(Cols))}. + +snmpNotifyFilterProfileTable(get, _RowIndex, Cols) -> + lists:map(fun(_Col) -> {noValue, noSuchObject} end, Cols); +snmpNotifyFilterProfileTable(get_next, _RowIndex, Cols) -> + lists:map(fun(_Col) -> endOfTable end, Cols); +snmpNotifyFilterProfileTable(is_set_ok, _RowIndex, Cols) -> + {notWritable, element(1, hd(Cols))}. + + +db(X) -> snmpa_agent:db(X). + +fa(snmpNotifyTable) -> ?snmpNotifyTag. + +foi(snmpNotifyTable) -> ?snmpNotifyName. + +noc(snmpNotifyTable) -> 5. + +stc(snmpNotifyTable) -> ?snmpNotifyStorageType. + +next(Name, RowIndex, Cols) -> + snmp_generic:handle_table_next(db(Name), RowIndex, Cols, + fa(Name), foi(Name), noc(Name)). + +table_next(Name, RestOid) -> + snmp_generic:table_next(db(Name), RestOid). + + +get(Name, RowIndex, Cols) -> + snmp_generic:handle_table_get(db(Name), RowIndex, Cols, foi(Name)). + + +wrongValue(V) -> throw({wrongValue, V}). + + +%% ----- + +set_sname() -> + set_sname(get(sname)). + +set_sname(undefined) -> + put(sname,conf); +set_sname(_) -> %% Keep it, if already set. + ok. + +error(Reason) -> + throw({error, Reason}). + +config_err(F, A) -> + snmpa_error:config_err("[NOTIFICATION-MIB]: " ++ F, A). |