snmp_generic(3)

πŸ“¦
version 29.0.6 Β· 3 versions
, in ubuntu stonking

okay so bestie, this is the manual page for snmp_generic(3) β€” the Erlang module that's basically the backstage crew for your SNMP objects. It's giving "generic functions for implementing SNMP objects in a database" energy, and we're about to break it all the way down. πŸ’…βœ¨

✨ NAME ✨

snmp_generic β€” Generic Functions for Implementing SNMP Objects in a Database

πŸ’– DESCRIPTION πŸ’–

So the module snmp_generic is packed with generic functions that let you implement tables (and variables, bestie, don't forget those) using the SNMP built-in database or Mnesia. These default functions get used when no instrumentation function is provided for a managed object in a MIB. But sometimes you gotta customize the default behavior, you know? Like when a trap should be sent if a row is deleted or modified, or when some hardware needs to be informed that information changed. It's giving "main character needs a custom touch" energy. πŸ¦‹

The overall structure is shown in the following figure:

                       +---------------+
                       |   SNMP Agent  |
                       +- - - - - - - -+
                       |      MIB      |
                       +---------------+
                               |
                       Association file       (associates a MIB object with
                               |               snmp_generic:table_funct
                               |               snmp_generic:variable_func)
              +--------------------------------------+
              |           snmp_generic               |  Support for get-next,
              |                                      |  RowStatus operations
              +----------------------+---------------+
              |    snmpa_local_db    |    Mnesia     |  Database
              +--------------+-------+---------------+
              |     dets     |  ets  |
              | (persistent) |       |
              +--------------+-------+

Each function takes the argument NameDb, which is a tuple {Name, Db}, to identify which database the functions should use. Name is the symbolic name of the managed object as defined in the MIB, and Db is either volatile, persistent, or mnesia. If it is mnesia, all variables are stored in the Mnesia table snmp_variables which must be a table with two attributes (not a Mnesia SNMP table). The SNMP tables are stored in Mnesia tables with the same names as the SNMP tables. All functions assume that a Mnesia table exists with the correct name and attributes. It is the programmer's responsibility to ensure this. Specifically, if variables are stored in Mnesia, the table snmp_variables must be created by the programmer. The record definition for this table is defined in the file snmp/include/snmp_types.hrl. No cap, that's just how it is. 🌸

If an instrumentation function in the association file for a variable myVar does not have a name when compiling an MIB, the compiler generates an entry.

              {myVar, {snmp_generic, variable_func, [{myVar, Db]}}.

And for a table:

              {myTable, {snmp_generic, table_func, [{myTable, Db]}}.

πŸŽ€ Example πŸŽ€

The following example shows an implementation of a table which is stored in Mnesia, but with some checks performed at set-request operations. It's giving "custom logic but make it cute" vibes. ✨

              myTable_func(new, NameDb) ->   % pass unchanged
                snmp_generic:table_func(new, NameDb).

              myTable_func(delete, NameDb) ->   % pass unchanged
                snmp_generic:table_func(delete, NameDb).

              %% change row
              myTable_func(is_set_ok, RowIndex, Cols, NameDb) ->
                case snmp_generic:table_func(is_set_ok, RowIndex,
                                             Cols, NameDb) of
                  {noError, 0} ->
                    myApplication:is_set_ok(RowIndex, Cols);
                  Err ->
                    Err
                end;

              myTable_func(set, RowIndex, Cols, NameDb) ->
                case snmp_generic:table_func(set, RowIndex, Cols,
                                             NameDb),
                  {noError, 0} ->
                    % Now the row is updated, tell the application
                    myApplication:update(RowIndex, Cols);
                  Err ->
                    Err
                end;

              myTable_func(Op, RowIndex, Cols, NameDb) ->   % pass unchanged
                snmp_generic:table_func(Op, RowIndex, Cols, NameDb).

The .funcs file would look like:

              {myTable, {myModule, myTable_func, [{myTable, mnesia}]}}.

🌈 DATA TYPES 🌈

  • column() :: pos_integer(). β€” a column, bestie. It's a positive integer, periodt.
  • columns() :: [column()] | [{column(), Value :: term()}]. β€” Is a list of column numbers in the case of a get operation, and a list of column numbers and values in the case of a set operation. So either just the column numbers, or the column numbers and their values. Slay. πŸ’…
  • table_info_item() ::
nbr_of_cols | defvals | status_col | not_accessible |
index_types | first_accessible | first_own_index.

For an ordinary table, the types will be the following:

  • nbr_of_cols β€” Number of columns. Value type: pos_integer()
  • defvals β€” A list of default values, ordered by column. Value type: {Col :: [pos_integer(), DefVal :: term()]}
  • status_col β€” Column number of the status column. Value type: pos_integer()
  • not_accessible β€” A sorted list of columns (> first_accessible) that are 'not-accessible'. Value type: [pos_integer()]
  • index_types β€” A list of asn1_type() for the index columns, ordered by column number or an "augment"-tuple (see below). Value type: [asn1_type()]
  • first_accessible β€” The first accessible column. Value type: pos_integer()
  • first_own_index β€” Column number of the first own index. Will be 0 if there is no such index for this table. Value type: non_neg_integer()

For a augmented table, it will instead look like this:

  • index_types β€” Value type: {augments, {atom(), asn1_type()}}
  • nbr_of_cols β€” Value type: pos_integer()
  • not_accessible β€” Value type: [pos_integer()]
  • first_accessible β€” Value type: pos_integer()

🫢 FUNCTIONS 🫢

Okay bestie, this is the part where the good stuff lives β€” all the actual functions you can call. Buckle up. πŸ’–


🌸 get_index_types(Name) -> IndexTypes

get_index_types(Name) -> IndexTypes
                        when
                            Name :: snmpa:name() | snmpa:name_db(),
                            IndexTypes :: [snmp:asn1_type()].

Gets the index types of Name. ✨

You'd use this inside instrumentation functions when you need to pull out the index types part of the table info. That's it, that's the whole vibe. 😌


🌸 get_status_col(Name, Cols) -> false | {value, StatusCol}

get_status_col(Name, Cols) -> false | {value, StatusCol}
                        when
                            Name :: snmpa:name() | snmpa:name_db(),
                            Cols :: columns(),
                            StatusCol :: term().

Gets the value of the status column straight out of Cols. πŸ’…

Instrumentation functions love this one for is_set_ok, undo or set β€” it's how you check whether the status column of a table has been modified. Sneaky little status check, iconic honestly.


🌸 get_table_info(Name, Item) -> Result

get_table_info(Name, Item :: nbr_of_cols) -> Result
                        when
                            Name :: snmpa:name() | snmpa:name_db(),
                            Result :: pos_integer();
                    (Name, Item :: defvals) -> Result
                        when
                            Name :: snmpa:name() | snmpa:name_db(),
                            Result :: [{Col, DefVal}],
                            Col :: pos_integer(),
                            DefVal :: term();
                    (Name, Item :: status_col) -> Result
                        when
                            Name :: snmpa:name() | snmpa:name_db(),
                            Result :: pos_integer();
                    (Name, Item :: not_accessible) -> Result
                        when
                            Name :: snmpa:name() | snmpa:name_db(),
                            Result :: [pos_integer()];
                    (Name, Item :: index_types) -> Result
                        when
                            Name :: snmpa:name() | snmpa:name_db(),
                            Result :: [snmp:asn1_type()];
                    (Name, Item :: first_accessible) -> Result
                        when
                            Name :: snmpa:name() | snmpa:name_db(),
                            Result :: pos_integer();
                    (Name, Item :: first_own_index) -> Result
                        when
                            Name :: snmpa:name() | snmpa:name_db(),
                            Result :: non_neg_integer();
                    (Name, Item :: all) -> Result
                        when
                            Name :: snmpa:name() | snmpa:name_db(),
                            Result :: [{table_info_item(), term()}].

Grabs one specific table info item for you. πŸŽ€

But bestie β€” if Item is all? Then instead of one lil item you get back a two tuple list (a property list, iykyk) containing every item and its respective value for that table. The whole menu. 🌈

Use this in instrumentation functions whenever you need to retrieve a given part of the table info.


🌸 table_func(Op, NameDb) -> Return

table_func(Op, NameDb) -> Return
                    when
                        Op :: new | delete,
                        NameDb :: snmpa:name_db(),
                        Return :: term().

This is the default instrumentation function for tables. 🫢

  • The new operation creates the table if it does not exist β€” but only if the database is the SNMP internal db. No cap.
  • The delete operation does not delete the table from the database, since unloading an MIB does not necessarily mean that the table should be destroyed. Let that table live, honestly. 😌
If it's possible for a manager to create or delete rows in the table, there must be a RowStatus column for is_set_ok, set and undo to work properly. Mandatory. Periodt.

The function returns according to the specification of an instrumentation function.


🌸 table_func(Op, RowIndex, Cols, NameDb) -> Return

table_func(Op, RowIndex, Cols, NameDb) -> Return
                    when
                        Op :: get | get_next | is_set_ok | set | undo,
                        RowIndex :: snmp:row_index(),
                        Cols :: columns(),
                        NameDb :: snmpa:name_db(),
                        Return :: term().

Still the default instrumentation function for tables, just the four-arg flavour. ✨

  • The is_set_ok operation checks that a row which is to be modified or deleted exists, and that a row which is to be created does not exist. Vibe check on the whole row situation. πŸ”₯
  • The undo operation does nothing. Truly the chillest operation.
  • The set operation checks if it has enough information to make the row change its status from notReady to notInService (when a row has been set to createAndWait). If a row is set to createAndWait, columns without a value are set to noinit. And if Mnesia is used, the set functionality is handled within a transaction. πŸ‘‘
Same warning, same energy: if a manager can create or delete rows in the table, there must be a RowStatus column for is_set_ok, set and undo to work properly. 🚨

The function returns according to the specification of an instrumentation function.


🌸 table_get_elements(NameDb, RowIndex, Cols) -> Values

table_get_elements(NameDb, RowIndex, Cols) -> Values
                            when
                                NameDb :: snmpa:name_db(),
                                RowIndex :: snmp:row_index(),
                                Cols :: columns(),
                                Values :: [noinit | Value],
                                Value :: term().

Returns a list with values for all the columns in Cols. πŸ’–

If a column is undefined, its value is noinit. Simple as.


🌸 table_next(NameDb, RestOid) -> Result

table_next(NameDb, RestOid) -> Result
                    when
                        NameDb :: snmpa:name_db(),
                        RestOid :: [integer()],
                        Result :: RowIndex | endOfTable,
                        RowIndex :: snmp:row_index().

Finds the indices of the next row in the table. πŸ”

Cute detail: RestOid does not have to specify an existing row. It's giving "just point me somewhere, I'll figure it out". πŸ¦‹


🌸 table_row_exists(NameDb, RowIndex) -> Result

table_row_exists(NameDb, RowIndex) -> Result
                            when
                                NameDb :: snmpa:name_db(),
                                RowIndex :: snmp:row_index(),
                                Result :: boolean().

Checks if a row in a table exists. That's it. Tiny function, huge main character energy. πŸ‘‘


🌸 table_set_elements(NameDb, RowIndex, Columns) -> Result

table_set_elements(NameDb, RowIndex, Columns) -> Result
                            when
                                NameDb :: snmpa:name_db(),
                                RowIndex :: snmp:row_index(),
                                Columns :: [{Column, Value}],
                                Column :: column(),
                                Value :: term(),
                                Result :: boolean().

Sets the elements in Cols to the row specified by RowIndex. ⚑

Ngl bestie: no checks are performed on the new values. It just does it. Live your truth, but know the risk. πŸ’€

If the Mnesia database is used, this function calls mnesia:write to store the values. Which means this function must be called from within a transaction (mnesia:transaction/1). Don't forget, or it's not gonna slay. 😭


🌸 variable_func(Op, Name) -> Result

variable_func(Op :: new, Name) -> Result
                        when
                            Name :: snmpa:name() | snmpa:name_db(),
                            Result :: ok | boolean();
                    (Op :: delete, Name) -> Result
                        when
                            Name :: snmpa:name() | snmpa:name_db(),
                            Result :: ok;
                    (Op :: get, Name) -> Result
                        when
                            Name :: snmpa:name() | snmpa:name_db(),
                            Result :: {value, Value} | genErr,
                            Value :: term().

This is the default instrumentation function for variables. 🌸

  • The new operation creates a new variable in the database with a default value as defined in the MIB, or a zero value (depending on the type).
  • The delete function does not delete the variable from the database. Leaving it exactly where it is, respectfully. πŸ™ˆ

The function returns according to the specification of an instrumentation function.


🌸 variable_func(Op, Value, Name) -> Result

variable_func(Op :: is_set_ok, Value, Name) -> Result
                        when
                            Value :: term(),
                            Name :: snmpa:name() | snmpa:name_db(),
                            Result :: noError;
                    (Op :: set, Value, Name) -> Result
                        when
                            Value :: term(),
                            Name :: snmpa:name() | snmpa:name_db(),
                            Result :: noError | commitFailed;
                    (Op :: undo, Value, Name) -> Result
                        when
                            Value :: term(),
                            Name :: snmpa:name() | snmpa:name_db(),
                            Result :: noError.

Also the default instrumentation function for variables β€” but this is the one with operations: is_set_ok | set | undo. ✨

  • The is_set_ok operation does nothing. A legend of doing the absolute least.
  • The set operation returns noError if successful or commitFailed otherwise.
  • The undo operation does nothing. Again. Consistent queen. πŸ’…

The function returns according to the specification of an instrumentation function.


🌸 variable_get(Name) -> {value, Value} | undefined

variable_get(Name) -> {value, Value} | undefined
                        when
                            Name :: snmpa:name() | snmpa:name_db(),
                            Value :: term().

Gets the value of a variable. Short, sweet, gets the job done. 🫢


🌸 variable_set(Name, Value) -> boolean()

variable_set(Name, Value) -> boolean()
                        when
                            Name :: snmpa:name() | snmpa:name_db(),
                            Value :: term().

Sets a new value to a variable. πŸ’œ

The variable is created if it does not exist β€” no need to set up in advance, it'll show up. But ngl: no checks are made on the type of the new value. 😳

Returns false if the NameDb argument is incorrectly specified, otherwise true.


πŸŽ€ That's the whole page, bestie! Every single function, every arg, every noinit and every commitFailed, present and accounted for. You ate. πŸ’…

✨ Sign-off time ✨ β€” this page came from Ericsson AB, sitting pretty at snmp 5.20.5, and it's page snmp_generic(3). Go forth and instrument, my love. πŸ¦‹πŸ’–πŸŒΈ

πŸ“¦ where this page comes from