snmp user wrote:

> I'm trying to generate code for an SNMP implementation on vxWorks
> using mibcomp, and my MIB structure requires me to have tables with
> holes in them - i.e. some of the rows of the table (inlcuding the
> first) might not have any valid data in them. The code i have so far,
> does not deal with this appropriately. The SNMP agent sends out a

^^^^^
you mean "manager" I assume...

> series of [next] requests through TableEntry_nexts. On getting these
> requests, the generated code seems to go through a loop where it check
> the first row of the table each time, before returning subsequent
> rows. However, the functions to return rows return NULL if there is no
> valid data in the row.


The MIBcomp generated code (-stub output) does not assume that
the Entry_firstrow() and Entry_nextrow() functions are returning
the Entries in the table in lexicographical order. So, it
iterates across ALL the table row structures returned from
Entry_nextrow, and determines the "next" one, based on what the
previous one was (which is what the compl/compc arguments are).

Note that the mibcomp generated code is incorrect and inconsistent
in a number of ways and won't compile. You'll need to augment it
quite a bit and fix the errors and inconsistencies.

> When that happens, the TableEntry_next function returns
> nextproc_no_next to the agent trying to get the table, and that in
> turn, stops asking for more rows.
> The whole procedure is complicated by the values of the parameters to
> the TableEntry_next function: OIDC_T lastmatch, int compc, OIDC_T
> *compl.
> I am not sure what these parameters are supposed to mean. The values
> of these parameters affect how the rows returned are interpreted. The
> values of these parameters do not seem to follow a pattern that is
> easily discernible. If anyone has an idea about how to deal with these
> tables, please let me know.


lastmatch is which COLUMN in the row is being requested. That's
really only releavant in the Entry_get_value function, which should
have been generated for you.

compl/compc are the *remaining* OID components that have not
been "consumed". In the case of a table, this is your index
information. If your index is a single integer, then for a
normal table walk, compc will be 1 and compl[0] will contain
the index the manager sent in it's request. In the case of
a next operation, the manager wants the NEXT valid entry
larger than compl[0].

As noted above, the code in TableEntry_next is trying to find
the "next" best entry, and iterates across all the rows returned
from Entry_nextrow(), comparing each entry to the compc/compl.

In the code you sent, if compc == 0, meaning that the agent did
not provide any indexing information at all and wants the very
frist row in the table, then the code selects that entry and
breaks.

Else, the ID (I presume this is the index field) is compared to
compl[0], and if ID is greater, then that is the "best next"
entry, and the code selects that and breaks.

It appears you've deleted the code that mibcomp -stub generated
for dealing with out-of-order entries from Entry_nextrow()? So
if Entry_nextrow() returns entires out of order, this won't be
caught, and you may end up returning entries out-of-order to the
manager, which could have unexpected results.

> I've pasted some of the relevant code below:
> STRUCT_TableEntry *Entry_firstrow()
> {
> int indx = 0;
>
> if (getRowValid(indx))
> {
> getRow(indx, &Row);
> return &Row;
> }
> else
> {
> return 0;
> }
> }


This is a function that was NOT generated by mibcomp (I don't think
anyway). This function should always simply return the first row in
the table, regardless of index.

> STRUCT_BoardTableEntry *BoardEntry_nextrow()
> {
> int indx = -1;
>
> if (Row.rowValid)
> {
> indx = Row.ID;
> indx++;
> }
> else
> {
> return 0;
> }
>
> /* check if next row is valid */
> if ((indx >= 0) && (indx < MAX_ROWS) && getRowValid(indx))
> {
> getRow(indx, &Row);
> return &Row;
> }
> else
> {
> return 0;
> }
> }


As above, you must have provided this implementation.

This function should take the data ptr passed in (it is below,
but you seem to be ignoring that in this function?) and return
the next valid row. So this code really should iterate the indx
value until it finds a valid row. It should only fail the request
if there are no more entries in the table at all.

> void BoardEntry_next(OIDC_T lastmatch,
> int compc,
> OIDC_T *compl,
> SNMP_PKT_T *pktp,
> VB_T *vbp)
> {
> #define Entry_INSTANCE_LEN 1 /* !!! */
> STRUCT_TableEntry *data; /* !!! */
> STRUCT_TableEntry *best; /* !!! */
> OIDC_T best_inst[Entry_INSTANCE_LEN];
> int i;
> int error;
> unsigned best_inst_len;
>
> /* find all the varbinds that share the same getproc and instance */
> snmpdGroupByGetprocAndInstance(pktp, vbp, compc, compl);
>
> /* generate the instance of each table entry and find the
> * smallest instance that's larger than compc/compl */
> best = 0;


> /* This loop needs to iterate over each entry in your table */
> for (data = Entry_firstrow(); data; /* !!! */
> data = Entry_nextrow(data)) { /* !!! */
> if (compc == 0)
> {
> best = data;
> best_inst_len = Entry_INSTANCE_LEN;
> best_inst[0] = compc;
> break;
> }
> else
> {
> if (data->ID > *compl)
> {
> best = data;
> best_inst_len = Entry_INSTANCE_LEN;
> best_inst[0] = data->ID;
> break;
> }
> }
> }


You seem to have removed some code here, but what it's trying to
do is compare the compc[0] to every table row returned from
Entry_nextrow(data), and determine which is the "next" one.
As you've changed, it, it assumes that Entry_nextrow(data) will
return them correct lexicographical order.

You could potentially eliminate this code, and pass compl[0] in
as the current index, and have your code return the next valid
index. This would probably be more efficient.

> /* if we found good row */
> if (best)
> {
> /* we found a next so get the values and set the instance for all
> * the varbinds for this row of this table.
> * NOTE: if you allow holes in the table then this code will have
> to
> * change significantly to accomodate that. */
> for ( ; vbp ; vbp = vbp->vb_link)
> {
> if ((error = Entry_get_value(vbp->vb_ml.ml_last_match, pktp,
> vbp, best)) == NO_ERROR)
> {
> nextproc_next_instance(pktp, vbp, best_inst_len,
> best_inst);
> }
> else
> {
> nextproc_error(pktp, vbp, error);
> }
> }
> }
> else /* there's no more in this table */
> for ( ; vbp ; vbp = vbp->vb_link )
> nextproc_no_next(pktp, vbp);
> }


If a "best" row is found, this code iterates across all the related
var bind in the packet (i.e. the ones in the same table row), and calls
Entry_get_value (which should have been generated for you by mibcomp)
to extract the correct column from the row (the best ptr) and fill in
the var bind (it calls one of the vb_got_ macros, based on the
variable type).

Hope this helps,
Pete
--
Pete Flugstad
Remove NO.SPAM to reply directly
Icon Labs (http://www.icon-labs.com)