updating dynamic tables in an agent

Robert Premuz (rpremuz@srce.hr)
Fri, 29 Mar 1996 11:31:40 +0100 (MET)

Hello,

In this message, I'm going to address a problem in implementing SNMP
agents. (I'm new to the SNMP and implementation of agents and I hope
I'm not discovering the hot water :)

The problem occurs in agents which are not integrated in the useful
processes of managed elements but are separated from them. Note that
the whole consideration refers to this kind of agents. You may wish to
build such an agent if you do not have access to the internal data of
the useful processes (simply, the source codes of them are not
accessible to you :). I've tried to do such a thing using the Scotty,
an extension of Tcl/Tk scripting language suitable for writing SNMP
agents and managers.

Before explaining the details, I'll make an introduction. (If you are
inpatient, go to the place marked with ** the point **).

I hope we all agree that:

(*) SNMP is used to convey management information between the agents
and management stations in a management system.

(*) Management stations execute management applications (also termed
managers) which monitor and control managed elements on managed nodes
according to particular management policy defined by a human.

(*) Managed elements are devices such as hosts, routers, terminal
servers, etc., which are monitored and controlled via access to their
management information.

(*) The management information is viewed as a collection of managed
objects, residing in a virtual information store, termed the
Management Information Base (MIB).

(*) An agent is a processing entity which manipulates the data
structures in useful processes of managed elements at the request of a
management station. By reading or writing these data structures in the
useful processes, the state of the processes is retrieved or changed
and, in this way, the managed elements are actually managed.

I think that, from an agent implementor's point of view, it is
important to note that the above definitions mention two collections
of data objects held in a managed node:

(a) the MIB held in the agent executing on the managed node,

(b) the data structures in the useful processes of managed elements.

If the useful processes share their data structures with the agent,
then the two collections of data overlap. In this trivial case, the
information in the MIB held in the agent is always consistent with the
data structures in useful processes. But, this is not the case in the
agents I am writing about.

As an example of the trivial case, I would imagine how an agent for a
laser printer works.

But also, the MIB held in the agent may be separated from the data
structures in the useful processes. In this non-trivial case, when the
state of useful processes changes, it does not mean that the relevant
information in the MIB changes accordingly, and vice versa. To make
the two collections of data consistent, they have to be updated by
exchanging the information about the changes in the collections.

As an example of the non-trivial case, I would imagine how an agent
for monitoring the Unix file system works in case the agent is not
integrated into the Unix kernel.

First, let's consider set requests. When an agent receives a set
request, it interacts with the useful processes in some way and ask
them to change the content of their data structures according to the
values in the set request. The outcome of the set request depends on
the outcome of the interaction. All this is well defined by the
current SNMPv2 standards.

On the other hand, for an agent to be able to respond to get, get-next
and get-bulk requests with the current values of MIB variables, the
variables must be updated by retrieving the relevant information from
useful processes. I can see three possible methods for updating MIB
variables in this case:

(1) The useful processes inform the agent about every change of their
data as they happen by some kind of set requests or notification
messages. This assumes that the useful processes run in close
cooperation with the agent, which is not true in the agents I am
writing about.

(2) The agent polls the useful processes periodically to get the
current values of the relevant data. If the frequency of polling is
low, the spending of the resources is low too, but the achieved
consistency may also be low.

(3) The agent asks the useful processes for the data relevant for
responding to a get, get-next or get-bulk request after receiving such
a request. This method seems very efficient but there is a big problem
with it.

The problem results from the fact that there may be some conceptual
tables within the MIB held in an agent. The number of rows in a
conceptual table may be constant during the execution of the agent,
but it may also change. Such a conceptual table with variable number
of rows can be termed a dynamic conceptual table.

The number of rows of a dynamic conceptual table may be changed by set
requests from a manager or, on the other hand, it may change because
the number of entities in useful processes represented by rows of the
table changes during the execution of the agent. The frequency of this
later kind of changes may vary a lot in real situations (for example,
from one change in a month to thousands of changes in a second).

** the point **

Now, imagine the following situation. You have decided to implement an
agent for monitoring and controlling processes on a Unix host, but you
cannot integrate the agent into the kernel because you do not have the
source of it. The MIB module for the agent has a conceptual table with
the information about the current processes. The table is inherently a
dynamic conceptual table as the processes are created and destroyed
all the time.

My question is: which of the above methods would you use for updating
the table in the agent? The second and third method are suitable, but
which one is more efficient?

If the agent polls the kernel periodically to get the current process
table, what is the right period of this polling? Updating the table in
the agent once a second could be enough, but this may be wasting of
the CPU time. As we know, the useful processes do something useful on
the managed node, so the impact of adding the agent process to the
resources needed by the useful processes should be minimal.

Actually, the agent exists because of a manager willing to retrieve
its MIB variables. So, the third method where the manager initiates
updating of a table when it wants to retrieve the table, seems more
appropriate. In that way, the manager determines the frequency of
updating by the frequency of its retrieval requests.

More precisely, a manager is able to retrieve a dynamic conceptual
table from an agent only by the get-next or get-bulk requests starting
from a MIB object lexicographically previous to the first variable in
the table. Typically, the manager starts traversing a dynamic table by
using the OID of one of the following MIB objects:

(*) the object representing the conceptual table,
(*) the object representing the conceptual row (entry) of the table,
(*) one or more objects representing one or more columns of the table.

So, for updating a dynamic conceptual table by the third method, the
agent must be able to recognise the existence of every of the above
objects in a get-next or get-bulk request so that it is able to do the
update before responding to such a request.

But things may be more complicated as a manager may wish to start
traversing MIB variables from a MIB node high above the node
representing a dynamic table in the MIB tree (for example, form the
object representing a MIB module, or even from the root). There may
also be many dynamic conceptual tables held in an agent.

All this shows that deciding whether a dynamic conceptual table should
be updated after receiving a get-next or get-bulk request is not an
easy job for an agent. Even if this job is done, you can imagine the
case when the agent must update all its dynamic conceptual tables
after receiving a single get-next request, which may be very time
consuming, and hence, the manager may give up waiting for the reply
from the agent (trust me, I know what I am writing about!).

So, for the above method to work, the manager must start traversing a
dynamic table by using the OIDs of the objects mentioned above. But, I
do not know how a common manager may be made aware of that because
there is no clause in OBJECT-IDENTITY macro which would note that an
MIB object is a dynamic conceptual table which must be explicitly
requested in get-next or get-bulk requests for the table to be updated
in the agent.

Hopefully, there is one more method for updating the dynamic
conceptual tables. An auxiliary MIB variable may be introduced for
every dynamic conceptual table implemented in an agent. When the agent
executes the get operation on such an auxiliary variable, then the
associated table is updated. (Shortly said, the auxiliary variable
works as an update button). Note that the agent may execute the get
operation on a variable after receiving either an get, get-next or
get-bulk request.

And where to put such an auxiliary variable in the MIB tree? I suggest
the possibility shown in the following example:

unixPsTable OBJECT-TYPE
SYNTAX SEQUENCE OF UnixPsEntry
MAX-ACCESS not-accessible
STATUS mandatory
DESCRIPTION
"The table of the Unix processes currently in execution."
::= { unixProcesses 1 }

unixPsTableLastUpdate OBJECT-TYPE
SYNTAX TimeStamp
MAX-ACCESS read-only
STATUS mandatory
DESCRIPTION
"The value of sysUpTime at the time of the most recent
successful update of the MIB variables subordinate to the
unixPsTable. The get operation executed in the agent on this
variable updates the said MIB variables."
::= { unixPsTable 1 }

unixPsTableEntry OBJECT-TYPE
SYNTAX UnixPsEntry
MAX-ACCESS not-accessible
STATUS mandatory
DESCRIPTION
"An entry (row) in the unixPsTable."
INDEX { unixPsProcessID }
::= { unixPsTable 2 }

As you can see, the unixPsTable has two child objects: the
unixPsTableLastUpdate, which is the update button, and the
unixPsTableEntry. (The columnar objects of the table not shown above
are subordinate to the unixPsTableEntry object as usually.)

Because the update button is lexicographically previous to each of the
instances of the columnar objects, when the agent receives an get-next
or get-bulk request, which would start walking through the variables
in the table, the agent first step on the update button, i.e. executes
the get operation on it invoking the update of the table. Retrieving
of the updated variables will begin in the response to the current
get-bulk request or to the subsequent get-next requests.

I have seen something similar in some enterprise MIB modules. They
introduce set requests on an auxiliary MIB variable for invoking the
update of a table. Also, they put the variable outside of the table.

What do you think about it all? Is my suggestion the right way to
solve the problem of updating dynamic conceptual tables in an agent?
Would you suggest something better? Would it cooperate well with
common managers? Have I overlooked something important, or suggested
something forbidden in SNMPv1/v2 ?

Until now, I've read 'The Simple Book', issues of 'The Simple Times',
had a look at some SNMP RFCs and F.A.Q.s, but haven't seen any
discussion on the issue explained in this message.

Thank you for your time and your replies.

v
-- rpr. : Robert B. Premuz
Internet: rpremuz@malik.srce.hr * Voice at home: +385 (0)1 687564