How to create a table?

Hello!
This is my first time to use table OID for Agent++. I want to create a READONLY table with 9 columns (1 SnmpInt32+2 OctetStr rows+6 Gauge32) and 64 rows. I’m trying to follow examples in atm_mib and agent++2.pdf but still dont understand.

1- define table+entry+columns in atm_mib.h
#define oidAtmVclTable “1.3.6.1.2.1.37.1.7”
#define oidAtmVclEntry “1.3.6.1.2.1.37.1.7.1”
#define oidAtmVclVpi “1.3.6.1.2.1.37.1.7.1.1”
#define colAtmVclVpi “1”
#define oidAtmVclVci “1.3.6.1.2.1.37.1.7.1.2”
#define colAtmVclVci “2”
#define oidAtmVclAdminStatus “1.3.6.1.2.1.37.1.7.1.3”
#define colAtmVclAdminStatus “3”

#define oidAtmVclRowStatus “1.3.6.1.2.1.37.1.7.1.13”
#define colAtmVclRowStatus “13”
#define oidAtmVclCastType “1.3.6.1.2.1.37.1.7.1.14”
#define colAtmVclCastType “14”
#define oidAtmVclConnKind “1.3.6.1.2.1.37.1.7.1.15”
#define colAtmVclConnKind “15”
2- Create class for Entry and Columns. but I dont know why example did not create column #1 for AtmVclVpi and column #2 for AtmVclVci. Also, set_row function only define from p0 to p12. I think set_row does not have column #1 for AtmVclVpi and column #2 for AtmVclVci.
class atmVclRowStatus: public snmpRowStatus {
public:
atmVclRowStatus(const Oidx&);
virtual ~atmVclRowStatus();
virtual MibEntryPtr clone();
};

class atmVclConnKind: public SimMibLeaf {
public:
atmVclConnKind(const Oidx&);
virtual ~atmVclConnKind();
virtual MibEntryPtr clone();
virtual int prepare_set_request(Request*, int&);
virtual bool value_ok(const Vbx&);
};

class atmVclEntry: public MibTable {
public:
atmVclEntry();
virtual ~atmVclEntry();
static atmVclEntry* instance;
virtual void set_row(MibTableRow* r, int p0, int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8, int p9, int p10, int p11, int p12);
};
3- in atm_mib.cpp, example has index_info indAtmVclEntry[3]. Why there are 3 index (other examples use 1 or different index)? should I use 64 index for my case with 64 rows? How to select correct SYNTAX and max/min (other examples use sNMP_SYNTAX_OCTETS or something else)
const index_info indAtmVclEntry[3] = {
{ sNMP_SYNTAX_INT, FALSE, 1, 1 },
{ sNMP_SYNTAX_INT, FALSE, 1, 1 },
{ sNMP_SYNTAX_INT, FALSE, 1, 1 } };
struct index_info {
NS_SNMP SmiUINT32 type;
bool implied;
unsigned int min;
unsigned int max;
};
4- in atm_mib.cpp, example has add_row(“1.32.64”) what does it mean? how does we add new rows (since there are 64 rows) and update READONLY columns values? I saw set_row(r, 1, 2, 0, 0, 0, 0, 1500, 1500, 0, 1, 2, 0, 0) but since they are READONLY columns do we need to start_synch(); ->set_value() ->end_synch() those oidAtmVclCastType “1.3.6.1.2.1.37.1.7.1.14” or colAtmVclCastType “14”? do we have some examples or documents somewhere I can take a look?
atmVclEntry::atmVclEntry():
MibTable(oidAtmVclEntry, indAtmVclEntry, 3)
{
instance = this;
add_col(new atmVclAdminStatus(colAtmVclAdminStatus));

add_col(new atmVclConnKind(colAtmVclConnKind));
MibTableRow* r = add_row(“1.32.64”);
set_row(r, 1, 2, 0, 0, 0, 0, 1500, 1500, 0, 1, 2, 0, 0);
}
void atmVclEntry::set_row(MibTableRow* r, int p0, int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8, int p9, int p10, int p11, int p12)
{
r->get_nth(0)->replace_value(new SnmpInt32(p0));

r->get_nth(12)->replace_value(new SnmpInt32(p12));
}

I think your main misunderstanding I about how INDEX columns are stored in a AGENT++ table. INDEX cols are always stored within the index OID of a row. Therefore those INDEX columns are not part of the table’s columns.

Hope this helps.

Hi Frank,
I tried single-integer index
// The table class: single-integer index (1..1 in sub-id count); we will create 64 rows with indices 1..64
const index_info indEntry[1] = {
// type, implied, minSubids, maxSubids
{ sNMP_SYNTAX_INT, FALSE, 1, 1 } // single INTEGER subidentifier index (not implied)
};

I could modify atm_mib.cpp to dump all rows and columns info.
debug_dump_rows: row_map size=64
Row index (map info=1): 01 .
col[0]: Gauge=7777
col[1]: OctetStr=‘T1’
col[2]: OctetStr=‘E1’
col[3]: Gauge=10
col[4]: Gauge=11
col[5]: Gauge=12
col[6]: Gauge=13
col[7]: Int=-5
col[8]: OctetStr=‘N1’
Row index (map info=2): 02 .
col[0]: Gauge=8888
col[1]: OctetStr=‘S1’
col[2]: OctetStr=‘D1’
col[3]: Gauge=1
col[4]: Gauge=2
col[5]: Gauge=3
col[6]: Gauge=4
col[7]: Int=-1
col[8]: OctetStr=‘R1’

However for snmpWalk, I received below with bad (oid)=1.3.6.1.4.1.8419.210.2.1.12.1.1.1.3.6.1.4.1.8419.210.2.1.12.1.1.1.4. I dont understand why oids are bad and objects=1
End of MIB Reached
Total # of Requests = 1
Total # of Objects = 1
(2)EVENT : Mib: process request: getbulk request, oid: (0), (1.3.6.1.4.1.8419.210.2.1.12.1.1)
(3)EVENT : RequestList: finished subrequest (ind): (0)
(3)EVENT : RequestList: finished subrequest (ind)(oid)(val)(syn): (0), (1.3.6.1.4.1.8419.210.2.1.12.1.1), (), (130)
(3)EVENT : RequestList: finished subrequest (ind): (1)
(3)EVENT : RequestList: finished subrequest (ind)(oid)(val)(syn): (1), (1.3.6.1.4.1.8419.210.2.1.12.1.1.1.3.6.1.4.1.8419.210.2.1.12.1.1.1.1), (), (130)
(3)EVENT : RequestList: finished subrequest (ind): (2)
(3)EVENT : RequestList: finished subrequest (ind)(oid)(val)(syn): (2), (1.3.6.1.4.1.8419.210.2.1.12.1.1.1.3.6.1.4.1.8419.210.2.1.12.1.1.1.2), (), (130)
(3)EVENT : RequestList: finished subrequest (ind): (3)
(3)EVENT : RequestList: finished subrequest (ind)(oid)(val)(syn): (3), (1.3.6.1.4.1.8419.210.2.1.12.1.1.1.3.6.1.4.1.8419.210.2.1.12.1.1.1.3), (), (130)
(3)EVENT : RequestList: finished subrequest (ind): (4)
(3)EVENT : RequestList: finished subrequest (ind)(oid)(val)(syn): (4), (1.3.6.1.4.1.8419.210.2.1.12.1.1.1.3.6.1.4.1.8419.210.2.1.12.1.1.1.4), (), (130)
(3)EVENT : RequestList: finished subrequest (ind): (5)
(3)EVENT : RequestList: finished subrequest (ind)(oid)(val)(syn): (5), (1.3.6.1.4.1.8419.210.2.1.12.1.1.1.3.6.1.4.1.8419.210.2.1.12.1.1.2.1), (), (130)
(3)EVENT : RequestList: finished subrequest (ind): (6)
(3)EVENT : RequestList: finished subrequest (ind)(oid)(val)(syn): (6), (1.3.6.1.4.1.8419.210.2.1.12.1.1.1.3.6.1.4.1.8419.210.2.1.12.1.1.2.2), (), (130)
(3)EVENT : RequestList: finished subrequest (ind): (7)
(3)EVENT : RequestList: finished subrequest (ind)(oid)(val)(syn): (7), (1.3.6.1.4.1.8419.210.2.1.12.1.1.1.3.6.1.4.1.8419.210.2.1.12.1.1.2.3), (), (130)
(3)EVENT : RequestList: finished subrequest (ind): (8)
(3)EVENT : RequestList: finished subrequest (ind)(oid)(val)(syn): (8), (1.3.6.1.4.1.8419.210.2.1.12.1.1.1.3.6.1.4.1.8419.210.2.1.12.1.1.2.4), (), (130)
(3)EVENT : RequestList: finished subrequest (ind): (9)
(3)EVENT : RequestList: finished subrequest (ind)(oid)(val)(syn): (9), (1.3.6.1.4.1.8419.210.2.1.12.1.1.1.3.6.1.4.1.8419.210.2.1.12.1.1.3.1), (), (130)
(1)DEBUG : Snmpx::send called with UTarget

for snmpGet of column 8 row 1, I received Syntax = 128 and Exception: 128 occured
VB nr: 0
Oid = 1.3.6.1.4.1.8419.210.2.1.12.1.1.8.1
Value =
Syntax = 128
Exception: 128 occured.
(2)EVENT : Agent: starting thread execution (pduType)(subrequests): (160), (1)
(2)EVENT : Mib: process request: get request, oid: (1), (1.3.6.1.4.1.8419.210.2.1.12.1.1.8.1)
(3)EVENT : Mib: process subrequest: get request, oid: (1), (1.3.6.1.4.1.8419.210.2.1.12.1.1.8.1)
(3)EVENT : RequestList: finished subrequest (ind)(oid)(val)(syn): (0), (1.3.6.1.4.1.8419.210.2.1.12.1.1.8.1), (), (128)
(1)DEBUG : Snmpx::send called with UTarget

Do you have any ideas I can try?

Hi,

After I tried single-integer index
{ sNMP_SYNTAX_INT, FALSE, 1, 1 } // single INTEGER subidentifier index (not implied)

And add column LEAVES using the column number (relative column OID), not by constructing independent MibLeafs with the full absolute OID.

for snmpWalk, I could do just fine.

for snmpGet of column 8 row 1, I received Value = -1 and Syntax = 2
(2)EVENT : Agent: starting thread execution (pduType)(subrequests): (160), (1)
(2)EVENT : Mib: process request: get request, oid: (11), (1.3.6.1.4.1.8419.210.2.1.12.1.1.8.1)
(3)EVENT : Mib: process subrequest: get request, oid: (11), (1.3.6.1.4.1.8419.210.2.1.12.1.1.8.1)
(7)DEBUG : Vacm: Access requested for: (viewName) (oid): (v1ReadView), (1.3.6.1.4.1.8419.210.2.1.12.1.1.8.1)
(7)DEBUG : Vacm: isInMibView: (viewName) (subtree): (v1ReadView), (1.3.6.1.4.1.8419.210.2.1.12.1.1.8.1)
(3)EVENT : RequestList: finished subrequest (ind)(oid)(val)(syn): (0), (1.3.6.1.4.1.8419.210.2.1.12.1.1.8.1), (-1), (2)
VB nr: 0
Oid = 1.3.6.1.4.1.8419.210.2.1.12.1.1.8.1
Value = -1
Syntax = 2

when I tried to update rows, I could dump all rows and columns info correct but snmpGet keeps getting the all initialize values when add_row
debug_dump_rows: row_map size=64
Row index (map info=1): 01
col[0]: Gauge=1
col[1]: OctetStr=‘TTT’
col[2]: OctetStr=‘EEE’
col[3]: Gauge=10
col[4]: Gauge=11
col[5]: Gauge=12
col[6]: Gauge=13
col[7]: Int=39
col[8]: OctetStr=‘NNN’

void update_row_by_index(unsigned int index, unsigned long p0, const OctetStr& p1,
const OctetStr& p2, unsigned long p3, unsigned long p4,
unsigned long p5, unsigned long p6, long p7, const OctetStr& p8) {
auto *table = InfoEntry::instance;
if (!table) return;
// 1) find existing row pointer in row_map
auto it = table->row_map.find(index);
MibTableRow *r = (it != table->row_map.end()) ? it->second : nullptr;
// 2) create-if-missing ONLY if you truly need a new row
if (!r) {
char idxStr[16];
snprintf(idxStr, sizeof(idxStr), “%d”, index);
r = table->add_row(idxStr); // create new row intentionally
if (!r) return;
table->row_map[index] = r;
}
// 3) atomic update of cells
table->start_synch();
table->set_row(r, p0, p1, p2, p3, p4, p5, p6, p7, p8);
table->end_synch();
}

void set_row(MibTableRow* r, unsigned int p0, const OctetStr& p1, const OctetStr& p2,
unsigned int p3, unsigned int p4, unsigned int p5, unsigned int p6, int p7, const OctetStr& p8)
{
if (!r) return;
r->get_nth(0)->replace_value(new Gauge32(p0));
r->get_nth(1)->replace_value(new OctetStr(p1));
r->get_nth(2)->replace_value(new OctetStr(p2));
r->get_nth(3)->replace_value(new Gauge32(p3));
r->get_nth(4)->replace_value(new Gauge32(p4));
r->get_nth(5)->replace_value(new Gauge32(p5));
r->get_nth(6)->replace_value(new Gauge32(p6));
r->get_nth(7)->replace_value(new SnmpInt32(p7));
r->get_nth(8)->replace_value(new OctetStr(p8));
}

Do you have any ideas I can try?

Hi,

dump_row_ptrs printed nth(7) leafptr = 0x7f2068078730 (the leaf object I updated).
SlotNumber::get_request logged leafptr = 0x7f2074017730 when the snmpGet arrived.
Those pointer values are different. That means the SNMP engine invoked a different leaf object than the one you updated in row_map.
Somehow the agent is serving a different table/row leaf (a stale/deserialized clone or another table instance).
That explains why external GET returned -1 while my internal_get saw 39.
I tried lock_mib()->start_synch()->unlock_mib()->update table->end_synch() but it did not help.
I also tried to use only 1 agent instead multi-threaded agent but I still saw the same issue.
Do you have any ideas?

(1)EVENT : UPDATE_CALLED idx=: (1), (UPDATE_CALLED slot=), (39)
safe_update_row_by_index UPDATE_CALLED index=1 slot=39
Before update:
SlotNumber (before) - index: 01
nth=7 ptr=0x7f2068078730 : Int=-1
RegisterNumber (before) - index: 01
nth=8 ptr=0x7f2068078880 : OctetStr=‘RegisterNumber0’

After update (still under table lock, before end_synch):
SlotNumber (after) - index: 01
nth=7 ptr=0x7f2068078730 : Int=39
RegisterNumber (after) - index: 01
nth=8 ptr=0x7f2068078880 : OctetStr=‘RN0’

(3)EVENT : Mib: process subrequest: get request, oid: (0), (1.3.6.1.4.1.8419.210.2.1.12.1.1.8.1)
(7)DEBUG : Vacm: Access requested for: (viewName) (oid): (testView), (1.3.6.1.4.1.8419.210.2.1.12.1.1.8.1)
(7)DEBUG : Vacm: isInMibView: (viewName) (subtree): (testView), (1.3.6.1.4.1.8419.210.2.1.12.1.1.8.1)
(1)EVENT : SlotNumber::get_request called: leafptr=0x7f2074017730
(3)EVENT : RequestList: finished subrequest (ind)(oid)(val)(syn): (8), (1.3.6.1.4.1.8419.210.2.1.12.1.1.8.1), (-1), (2)

What purpose has this code?

I think you have some misunderstanding how a row is being updated. Again, the code snippets are hard to read, important stuff seems to be missing. We cannot do debugging here in the forum based on code fragments.

Maybe we should rather talk about the concept?