aboutsummaryrefslogtreecommitdiffstats
path: root/lib/snmp/src/agent/snmp_notification_mib.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/snmp/src/agent/snmp_notification_mib.erl')
-rw-r--r--lib/snmp/src/agent/snmp_notification_mib.erl457
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).