1
<?xml version="1.0" encoding="latin1" ?>
2
<!DOCTYPE chapter SYSTEM "chapter.dtd">
7
<year>1997</year><year>2009</year>
8
<holder>Ericsson AB. All Rights Reserved.</holder>
11
The contents of this file are subject to the Erlang Public License,
12
Version 1.1, (the "License"); you may not use this file except in
13
compliance with the License. You should have received a copy of the
14
Erlang Public License along with this software. If not, it can be
15
retrieved online at http://www.erlang.org/.
17
Software distributed under the License is distributed on an "AS IS"
18
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
19
the License for the specific language governing rights and limitations
24
<title>Advanced Agent Topics</title>
26
<responsible></responsible>
32
<file>snmp_advanced_agent.xml</file>
34
<p>The chapter <em>Advanced Agent Topics</em> describes the more advanced
35
agent related features of the SNMP development tool. The following topics
38
<list type="bulleted">
39
<item>When to use a Sub-agent</item>
40
<item>Agent semantics</item>
41
<item>Sub-agents and dependencies</item>
42
<item>Distributed tables</item>
43
<item>Fault tolerance</item>
44
<item>Using Mnesia tables as SNMP tables</item>
45
<item>Audit Trail Logging</item>
46
<item>Deviations from the standard
51
<title>When to use a Sub-agent</title>
52
<p>The section <em>When to use a Sub-agent</em> describes situations
53
where the mechanism of loading and unloading MIBs is insufficient.
54
In these cases a sub-agent is needed.
58
<title>Special Set Transaction Mechanism</title>
59
<p>Each sub-agent can implement its own mechanisms for
60
<c>set</c>, <c>get</c> and <c>get-next</c>. For example, if the
61
application requires the <c>get</c> mechanism to be
62
asynchronous, or needs a N-phase <c>set</c> mechanism, a
63
specialized sub-agent should be used.
65
<p>The toolkit allows different kinds of sub-agents at the same
66
time. Accordingly, different MIBs can have different <c>set</c>
67
or <c>get</c> mechanisms.
72
<title>Process Communication</title>
73
<p>A simple distributed agent can be managed without sub-agents.
74
The instrumentation functions can use distributed Erlang to
75
communicate with other parts of the application. However, a
76
sub-agent can be used on each node if this generates too much
77
unnecessary traffic. A sub-agent processes requests per
78
incoming SNMP request, not per variable. Therefore the network
81
<p>If the instrumentation functions communicate with UNIX
82
processes, it might be a good idea to use a special
83
sub-agent. This sub-agent sends the SNMP request to the other
84
process in one packet in order to minimize context switches. For
85
example, if a whole MIB is implemented on the C level in UNIX,
86
but you still want to use the Erlang SNMP tool, then you may
87
have one special sub-agent, which sends the variables in the
88
request as a single operation down to C.
93
<title>Frequent Loading of MIBs</title>
94
<p>Loading and unloading of MIBs are quite cheap
95
operations. However, if the application does this very often,
96
perhaps several times per minute, it should load the MIBs once
97
and for all in a sub-agent. This sub-agent only registers and
98
unregisters itself under another agent instead of loading the
99
MIBs each time. This is cheaper than loading an MIB.
104
<title>Interaction With Other SNMP Agent Toolkits</title>
105
<p>If the SNMP agent needs to interact with sub-agents
106
constructed in another package, a special sub-agent should be
107
used, which communicates through a protocol specified by the
114
<title>Agent Semantics</title>
115
<p>The agent can be configured to be multi-threaded, to process
116
one incoming request at a time, or to have a request limit
117
enabled (this can be used for load control or to limit the effect
118
of DoS attacks). If it is multi-threaded, read requests (<c>get</c>,
119
<c>get-next</c> and <c>get-bulk</c>) and traps are processed in
120
parallel with each other and <c>set</c> requests. However, all
121
<c>set</c> requests are serialized, which means that if the agent
122
is waiting for the application to complete a complicated write
123
operation, it will not process any new write requests until this
124
operation is finished. It processes read requests and sends traps,
125
concurrently. The reason for not handle write requests in parallel is
126
that a complex locking mechanism would be needed even in the simplest
127
cases. Even with the scheme described above, the user must be
128
careful not to violate that the <c>set</c> requests are atoms.
129
If this is hard to do, do not use the multi-threaded feature.
131
<p>The order within an request is undefined and variables are not
132
processed in a defined order. Do not assume that the first
133
variable in the PDU will be processed before the second, even if
134
the agent processes variables in this order. It
135
cannot even be assumed that requests belonging to different
136
sub-agents have any order.
138
<p>If the manager tries to set the same variable many times in the
139
same PDU, the agent is free to improvise. There is no definition
140
which determines if the instrumentation will be called once or
141
twice. If called once only, there is no definition that determines
142
which of the new values is going to be supplied.
144
<p>When the agent receives a request, it keeps the request ID for
145
one second after the response is sent. If the agent receives
146
another request with the same request ID during this time, from
147
the same IP address and UDP port, that request will be
148
discarded. This mechanism has nothing to do with the function
149
<c>snmpa:current_request_id/0</c>.</p>
153
<title>Sub-agents and Dependencies </title>
154
<p>The toolkit supports the use of different types of sub-agents,
155
but not the construction of sub-agents.
157
<p>Also, the toolkit does not support dependencies between
158
sub-agents. A sub-agent should by definition be stand alone and it is
159
therefore not good design to create dependencies between them.
164
<title>Distributed Tables</title>
165
<p>A common situation in more complex systems is that the data in
166
a table is distributed. Different table rows are implemented in
167
different places. Some SNMP tool-kits dedicate an SNMP sub-agent for
168
each part of the table and load the corresponding MIB into all
169
sub-agents. The Master Agent is responsible for presenting the
170
distributed table as a single table to the manager. The toolkit
171
supplied uses a different method.
173
<p>The method used to implement distributed tables with this SNMP
174
tool is to implement a table coordinator process responsible for
175
coordinating the processes, which hold the table data and they
176
are called table holders. All table holders must in some way be
177
known by the coordinator; the structure of the table data
178
determines how this is achieved. The coordinator may require
179
that the table holders explicitly register themselves and specify
180
their information. In other cases, the table holders can be
181
determined once at compile time.
183
<p>When the instrumentation function for the distributed table is
184
called, the request should be forwarded to the table
185
coordinator. The coordinator finds the requested information among
186
the table holders and then returns the answer to the
187
instrumentation function. The SNMP toolkit contains no support for
188
coordination of tables since this must be independent of the
191
<p>The advantages of separating the table coordinator from the
194
<list type="bulleted">
195
<item>We do not need a sub-agent for each table holder. Normally,
196
the sub-agent is needed to take care of communication, but in
197
Distributed Erlang we use ordinary message passing.
199
<item>Most likely, some type of table coordinator already
200
exists. This process should take care of the instrumentation for
203
<item>The method used to present a distributed table is strongly
204
application dependent. The use of different masking techniques
205
is only valid for a small subset of problems and registering
206
every row in a distributed table makes it non-distributed.
212
<title>Fault Tolerance</title>
213
<p>The SNMP agent toolkit gets input from three different sources:
215
<list type="bulleted">
216
<item>UDP packets from the network</item>
217
<item>return values from the user defined instrumentation functions</item>
218
<item>return values from the MIB.
221
<p>The agent is highly fault tolerant. If the manager gets an
222
unexpected response from the agent, it is possible that some
223
instrumentation function has returned an erroneous value. The
224
agent will not crash even if the instrumentation does. It should
225
be noted that if an instrumentation function enters an infinite
226
loop, the agent will also be blocked forever. The supervisor ,or
227
the application, specifies how to restart the agent.
231
<title>Using the SNMP Agent in a Distributed Environment</title>
232
<p>The normal way to use the agent in a distributed
233
environment is to use one master agent located at one node,
234
and zero or more sub-agents located on other nodes. However,
235
this configuration makes the master agent node a single point
236
of failure. If that node goes down, the agent will not work.
238
<p>One solution to this problem is to make the snmp application
239
a distributed Erlang application, and that means, the agent
240
may be configured to run on one of several nodes. If the node
241
where it runs goes down, another node restarts the agent.
242
This is called <em>failover</em>. When the node starts again,
243
it may <em>takeover</em> the application. This solution to
244
the problem adds another problem. Generally, the new node has
245
another IP address than the first one, which may cause
246
problems in the communication between the SNMP managers and
249
<p>If the snmp agent is configured as a distributed Erlang
250
application, it will during takeover try to load the same MIBs
251
that were loaded at the old node. It uses the same filenames
252
as the old node. If the MIBs are not located in the same
253
paths at the different nodes, the MIBs must be loaded
254
explicitly after takeover.
260
<title>Using Mnesia Tables as SNMP Tables</title>
261
<p>The Mnesia DBMS can be used for storing data of SNMP
262
tables. This means that an SNMP table can be implemented as a
263
Mnesia table, and that a Mnesia table can be made visible via
264
SNMP. This mapping is largely automated.
266
<p>There are three main reasons for using this mapping:
268
<list type="bulleted">
269
<item>We get all features of Mnesia, such as fault tolerance,
270
persistent data storage, replication, and so on.
272
<item>Much of the work involved is automated. This includes
273
<c>get-next</c> processing and <c>RowStatus</c> handling.
275
<item>The table may be used as an ordinary Mnesia table, using
276
the Mnesia API internally in the application at the same time as
277
it is visible through SNMP.
280
<p>When this mapping is used, insertion and deletion in the
281
original Mnesia table is slower, with a factor O(log n). The read
282
access is not affected.
284
<p>A drawback with implementing an SNMP table as a Mnesia table is
285
that the internal resource is forced to use the table definition
286
from the MIB, which means that the external data model must be
287
used internally. Actually, this is only partially true. The Mnesia
288
table may extend the SNMP table, which means that the Mnesia table
289
may have columns which are use internally and are not seen by
290
SNMP. Still, the data model from SNMP must be maintained. Although
291
this is undesirable, it is a pragmatic compromise in many
292
situations where simple and efficient implementation is preferable
297
<title>Creating the Mnesia Table</title>
298
<p>The table must be created in Mnesia before the manager can
299
use it. The table must be declared as type <c>snmp</c>. This
300
makes the table ordered in accordance with the lexicographical
301
ordering rules of SNMP. The name of the Mnesia table must be
302
identical to the SNMP table name. The types of the INDEX fields
303
in the corresponding SNMP table must be specified.
305
<p>If the SNMP table has more than one INDEX column, the
306
corresponding Mnesia row is a tuple, where the first element
307
is a tuple with the INDEX columns. Generally, if the SNMP table
308
has <em>N</em> INDEX columns and <em>C</em> data columns, the
309
Mnesia table is of arity <em>(C-N)+1</em>, where the key is a
310
tuple of arity <em>N</em> if <em>N > 1</em>, or a single term
313
<p>Refer to the Mnesia User's Guide for information on how to
314
declare a Mnesia table as an SNMP table.
316
<p>The following example illustrates a situation in which we
317
have an SNMP table that we wish to implement as a Mnesia
318
table. The table stores information about employees at a
319
company. Each employee is indexed with the department number and
324
SYNTAX SEQUENCE OF EmpEntry
325
ACCESS not-accessible
328
"A table with information about employees."
332
ACCESS not-accessible
336
INDEX { empDepNo, empName }
341
empName DisplayString,
342
empTelNo DisplayString
346
<p>The corresponding Mnesia table is specified as follows:
349
mnesia:create_table([{name, employees},
350
{snmp, [{key, {integer, string}}]},
351
{attributes, [key, telno, row_status]}]).
354
<p>In the Mnesia tables, the two key columns are stored as a
355
tuple with two elements. Therefore, the arity of the table is
361
<title>Instrumentation Functions</title>
362
<p>The MIB table shown in the previous section can be compiled
366
1> <input>snmpc:compile("EmpMIB", [{db, mnesia}]).</input>
368
<p>This is all that has to be done! Now the manager can read,
369
add, and modify rows. Also, you can use the ordinary Mnesia API
370
to access the table from your programs. The only explicit action
371
is to create the Mnesia table, an action the user has to perform
372
in order to create the required table schemas.</p>
376
<title>Adding Own Actions</title>
377
<p>It is often necessary to take some specific action when a
378
table is modified. This is accomplished with an instrumentation
379
function. It executes some specific code when the table is set,
380
and passes all other requests down to the pre-defined function.
382
<p>The following example illustrates this idea:
385
emp_table(set, RowIndex, Cols) ->
386
notify_internal_resources(RowIndex, Cols),
387
snmp_generic:table_func(set, RowIndex, Cols, {empTable, mnesia});
388
emp_table(Op, RowIndex, Cols) ->
389
snmp_generic:table_func(Op, RowIndex, Cols, {empTable, mnesia}).
391
<p>The default instrumentation functions are defined in the
392
module <c>snmp_generic</c>. Refer to the Reference Manual,
393
section SNMP, module <c>snmp_generic</c> for details.</p>
397
<title>Extending the Mnesia Table</title>
398
<p>A table may contain columns that are used internally, but
399
should not be visible to a manager. These internal columns must
400
be the last columns in the table. The <c>set</c> operation will
401
not work with this arrangement, because there are columns that
402
the agent does not know about. This situation is handled by
403
adding values for the internal columns in the <c>set</c>
406
<p>To illustrate this, suppose we extend our Mnesia
407
<c>empTable</c> with one internal column. We create it as
408
before, but with an arity of 4, by adding another attribute.
411
mnesia:create_table([{name, employees},
412
{snmp, [{key, {integer, string}}]},
413
{attributes, {key, telno, row_status, internal_col}}]).
415
<p>The last column is the internal column. When performing a
416
<c>set</c> operation, which creates a row, we must give a
417
value to the internal column. The instrumentation functions will now
421
-define(createAndGo, 4).
422
-define(createAndWait, 5).
424
emp_table(set, RowIndex, Cols) ->
425
notify_internal_resources(RowIndex, Cols),
427
case is_row_created(empTable, Cols) of
428
true -> Cols ++ [{4, "internal"}]; % add internal column
429
false -> Cols % keep original cols
431
snmp_generic:table_func(set, RowIndex, NewCols, {empTable, mnesia});
432
emp_table(Op, RowIndex, Cols) ->
433
snmp_generic:table_func(Op, RowIndex, Cols, {empTable, mnesia}).
435
is_row_created(Name, Cols) ->
436
case snmp_generic:get_status_col(Name, Cols) of
437
{ok, ?createAndGo} -> true;
438
{ok, ?createAndWait} -> true;
442
<p>If a row is created, we always set the internal column to
449
<title>Deviations from the Standard</title>
450
<p>In some aspects the agent does not implement SNMP fully. Here
453
<list type="bulleted">
454
<item>The default functions and <c>snmp_generic</c> cannot
455
handle an object of type <c>NetworkAddress</c> as INDEX
456
(SNMPv1 only!). Use <c>IpAddress</c> instead.
458
<item>The agent does not check complex ranges specified for
459
INTEGER objects. In these cases it just checks that the value
460
lies within the minimum and maximum values specified. For
461
example, if the range is specified as <c>1..10 | 12..20</c>
462
the agent would let 11 through, but not 0 or 21. The
463
instrumentation functions must check the complex ranges
466
<item>The agent will never generate the <c>wrongEncoding</c>
467
error. If a variable binding is erroneous encoded, the
468
<c>asn1ParseError</c> counter will be incremented.
470
<item>A <c>tooBig</c> error in an SNMPv1 packet will always use
471
the <c>'NULL'</c> value in all variable bindings.
473
<item>The default functions and <c>snmp_generic</c> do not check
474
the range of each OCTET in textual conventions derived from
475
OCTET STRING, e.g. <c>DisplayString</c> and
476
<c>DateAndTime</c>. This must be checked in an overloaded
477
<c>is_set_ok</c> function.