mib2c
will assume the simple table case,
and this will need to be corrected.
Perform any necessary initialization, then walk through the underlying instances, retrieving the data for each one, until the desired instance is found. If no valid entry is found, return failure.For an exact match (
GET
and similar), identifying the desired
instance is trivial - construct the OID (from the 'vp' variable
parameter and the index value or values), and see whether it matches
the requested OID.
GETNEXT
, the situation is not quite so simple. Depending on the
underlying representation of the data, the entries may be returned in
the same order as they should appear in the table (i.e. lexically
increasing by index). However, this is not guaranteed, and the
natural way of retrieving the data may be in some "random" order.
In this case, then the whole table needs to be traversed for each request.
in order to determine the appropriate successor.
The algorithm outlined above can now be expanded into the following pseudo-code:
Init_{Name}_Entry(); // Perform any necessary initialisation while (( index = Get_Next_{Name}_Entry() ) != EndMarker ) { // This steps through the underlying table, // returning the current index, // or some suitable end-marker when all // the entries have been examined. // Note that this routine should also return the // data for this entry, either via a parameter, // or some external location construct OID from vp->name and index compare new OID and request if valid { save current data if finished // exact match, or ordered table break; // so don't look at any more entries } // Otherwise, we need to loop round, and examine // the next entry in the table. Either because // the entry wasn't valid for this request, // or the entry was a possible "next" candidate, // but we don't know that there isn't there's a // better one later in the table. } if no saved data // Nothing matched return failure // Otherwise, go on to the switch handling // we've already covered in the earlier styles.This is now very close to the actual code used in many current implementations (such as the the routine
header_ifEntry
in
mibII/interfaces.c
). Notice that the pseudo-code fragment
if valid
expands in practise to
if ((exact && (result == 0)) || //This is a very common expression, that can be seen in most of the table implementations.GET
request, and identical OIDs (!exact && (result < 0)) ) //GETNEXT
, and candidate OID is later // than requested OID.
Notice also that the interfaces table returns immediately
the first valid entry is found, even for GETNEXT
requests.
This is because entries are returned in lexical order, so
the first succeeding entry will be the one that's required.
(As an aside, this also means that the underlying data can
be saved implicitly within the 'next entry' routine - not very
clean, but it saves some unnecessary copying).
The more general case can be seen in the TCP and UDP tables
(see mibII/tcp.c
and mibII/udp.c
).
Here, the if valid
fragment expands to:
if ( exact && (result == 0)) { // save results break; } else if (!exact && (result < 0)) { if ( .... ) { // no saved OID, or this OID // precedes the saved OID // save this OID into 'lowest' // save the results into Lowinpcb // don't break, since we still need to look // at the rest of the table } }The
GET
match handling is just as we've already seen - is this the
requested OID or not.
If so, save the results and move on to the switch statement.
The GETNEXT
case is more complicated. As well as considering whether
this is a possible match (using the same test we've already seen), we
also have to check whether this is a better match than anything we've
already seen. This is done by comparing the current candidate (newname
)
with the best match found so far (lowest
).
inpcb
block, and state flag). But having found one
better match, we don't know that there isn't an even better one later
on. So we can't break out of the enclosing loop - we need to keep going
and examine all the remaining entries of the table.
These two cases (the TCP and UDP tables) also show a more general style
of indexing. Rather than simply appending a single index value to the
OID prefix, these routines have to add the local four-octet IP address
plus port (and the same for the remote end in the case of the TCP table).
This is the purpose of the op
and cp
section of code that precedes
the comparison.
These two are probably among the most complex cases you are likely to encounter. If you can follow the code here, then you've probably cracked the problem of understanding how the agent works.
Finally, the next part discusses
how to implement a writable (or SET
able) object in a MIB module.
Last modified: Wednesday, 01-Aug-2018 04:41:28 UTC
For questions regarding web content and site functionality, please write to the net-snmp-users mail list.