#2414 row merge results in wrong handler being called

open
nobody
agent (1103)
5
2014-08-08
2012-10-04
Joan Landry
No

SW version 5.7.1
OS: Linux
CMD: snmpgetnext with multiple oid's for a one row table.

If you place two requests in one packet for the same oid on a table that has only one row you get two different responses. Where the table is initialized for row_merge.
The expected result is that the handler for the specific oid will be called once with two column requests. This works if there is more than one row in the table.
Also, if I add netsnmp_inject_handler(reg, netsnmp_get_serialize_handler()); to the initialization of the table, the problem goes away.
However this is not an acceptable solution from a speed perspective, as each row request goes out to a database to retreive the data.

Test Results:
snmpgetnext -c public -v 2c a.b.c.d
1.3.6.1.4.1.4444.2.11.2.7.1.1.3.5
1.3.6.1.4.1.4444.2.11.2.7.1.1.3.5
SNMPv2-SMI::enterprises.4444.2.11.2.7.1.1.4.5 = "" <--this is valid result - next column in the table
SNMPv2-SMI::enterprises.4444.2.11.2.7.2.1.1.5.0.4 = INTEGER: 0 <-- this is not valid as it is the next table in the tree

Init function:

oid ovnNGAggrTable_oid[] = { 1, 3, 6, 1, 4, 1,4444, 2, 11, 2, 7, 1 };
size_t ovnNGAggrTable_oid_len = OID_LENGTH(ovnNGAggrTable_oid);
handler_ptr = netsnmp_create_handler("ovnNGAggrTable", ovnNGAggrTable_handler);
if(!handler_ptr)
{
TRACE_LOG( TRACE_SNMP, TRACE_INFO, "Memory allocation failed for snmp mib init.");
return;
}
reg = netsnmp_handler_registration_create("ovnNGAggrTableChain",
handler_ptr,
ovnNGAggrTable_oid,
ovnNGAggrTable_oid_len,
HANDLER_CAN_RWRITE);
if(reg == NULL)
{
netsnmp_handler_free(handler_ptr);
return;
}
table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info);
if(!verifyTableInfo(table_info))
{
netsnmp_handler_free(handler_ptr);
netsnmp_handler_registration_free(reg);
return;
}
netsnmp_table_helper_add_indexes(table_info, ASN_INTEGER,
/* index: ovnNGAggrId */ 0);
table_info->min_column = COLUMN_OVNNGAGGRID;
table_info->max_column = COLUMN_OVNNGAGGRROWSTATUS;
netsnmp_register_table(reg, table_info);
handler_ptr2 = netsnmp_get_row_merge_handler(reg->rootoid_len + 2);
if(!handler_ptr2)
{
SNMP_FREE(table_info);
netsnmp_handler_registration_free(reg);
return;
}
netsnmp_inject_handler(reg, handler_ptr2);

handler:
--
int ovnNGAggrTable_handler(netsnmp_mib_handler *handler,
netsnmp_handler_registration *reginfo,
netsnmp_agent_request_info *reqinfo,
netsnmp_request_info *requests)
{
netsnmp_request_info *request;
netsnmp_table_request_info *table_info;
struct ovnNGAggrTable_entry *table_entry = NULL;
struct ovnNGAggrTable_entry entry;
int ret;
size_t len;
uint32 snmpValue;
struct ovnNGAggrTable_entry *setptr;
int createFlag = 0;
UiApi & uiApi = UiApi::getInstance();
setReturnCode code = ERR_NOTWRITABLE;
STRUCT_aggr_table aggr_table;
#ifdef ISG_FEATURE_LOOP_DETECT
STRUCT_loop_detect_if_table ifLoopDetect_table;
#endif
netsnmp_variable_list * ptr;
printf("aggr tabe top\n");

setInfoPtr->action = ACTIVATE\_SET;
setptr = &ovnNGAggrTableSetEntry;
setptr->ifPtr = &ifDbSetEntry;

switch \(reqinfo->mode\) \{
case MODE\_GET:
case MODE\_GETNEXT: 
    for \(request = requests; request; request = request->next\) \{
        table\_info = netsnmp\_extract\_table\_info\(request\);
        if\(reqinfo->mode == MODE\_GET\)
            ret = SNMP\_NOSUCHINSTANCE;
        else
            ret = SNMP\_ENDOFMIBVIEW;
       if\(\!table\_info\)
        \{
printf\("aggr tabe no info\n"\);
            netsnmp\_set\_request\_error\(reqinfo, request, ret\);
            return SNMP\_ERR\_NOERROR;
        \}
        if \(\!table\_entry\)
        \{
          if\(reqinfo->mode == MODE\_GET\)
          \{
            table\_entry = ovnNGAggrTable\_get\_entry\(table\_info->indexes, &entry\);
            if\(\!table\_entry\)
            \{
               netsnmp\_set\_request\_error\(reqinfo, request,  ret\);
               return SNMP\_ERR\_NOERROR;
            \}
          \}
          else
          \{
            table\_entry = ovnNGAggrTable\_get\_next\_entry\(reginfo, request, table\_info->colnum, table\_info->indexes,  &entry\);
            if\(\!table\_entry\)
            \{
printf\("aggr tabe no entry\n"\);
               netsnmp\_set\_request\_error\(reqinfo, request, ret\);
               return SNMP\_ERR\_NOERROR;
            \}
          \}
        \}
        if\(reqinfo->mode == MODE\_GETNEXT\)
        \{
          ptr = table\_info->indexes;
          \*\(ptr->val.integer\) = table\_entry->ovnNGAggrId;
          buildNextOid\(reginfo, request, table\_info->colnum, table\_info->indexes\);
        \}
        printf\("aggr tabe table\_info->colnum %d\n", table\_info->colnum\);
        switch \(table\_info->colnum\) \{
        case COLUMN\_OVNNGAGGRID:
            snmp\_set\_var\_typed\_integer\(request->requestvb, ASN\_INTEGER,
                                       table\_entry->ovnNGAggrId\);
            break;
        case COLUMN\_OVNNGAGGRIFINDEX:
            snmp\_set\_var\_typed\_integer\(request->requestvb, ASN\_INTEGER,
                                       table\_entry->ovnNGAggrIfIndex\);
            break;
        case COLUMN\_OVNNGAGGRNAME:
            len = strlen\(table\_entry->ifPtr->ovnNGIfName\);
            snmp\_set\_var\_typed\_value\(request->requestvb, ASN\_OCTET\_STR,
               \(u\_char \*\) table\_entry->ifPtr->ovnNGIfName, len\);
            break;
        case COLUMN\_OVNNGAGGRSERVICENAME:
            len = strlen\(table\_entry->ifPtr->ovnNGServiceName\);
            snmp\_set\_var\_typed\_value\(request->requestvb, ASN\_OCTET\_STR,
               \(u\_char \*\)table\_entry->ifPtr->ovnNGServiceName,len\);
            break;
        case COLUMN\_OVNNGAGGRLOADBALANCE:
            snmp\_set\_var\_typed\_integer\(request->requestvb, ASN\_INTEGER,
                                       table\_entry->
                                       ovnNGAggrLoadBalance\);
            break;
        case COLUMN\_OVNNGAGGRFASTSW:
            snmp\_set\_var\_typed\_integer\(request->requestvb, ASN\_INTEGER,
                                       table\_entry->ovnNGAggrFastSw\);
            break;
        case COLUMN\_OVNNGAGGRLAGSIZE:
            snmp\_set\_var\_typed\_integer\(request->requestvb, ASN\_INTEGER,
                                       table\_entry->ovnNGAggrLagSize\);
            break;
        case COLUMN\_OVNNGAGGRSYSPRIORITY:
            snmp\_set\_var\_typed\_integer\(request->requestvb, ASN\_INTEGER,
                                       table\_entry->
                                       ovnNGAggrSysPriority\);
            break;
        case COLUMN\_OVNNGAGGRADMINSTATE:
            snmp\_set\_var\_typed\_integer\(request->requestvb, ASN\_INTEGER,
                             table\_entry->ifPtr->ifAdminStatus\);
            break;
        case COLUMN\_ovnNGAggrLoopDetect:
            snmp\_set\_var\_typed\_integer\(request->requestvb, ASN\_INTEGER,
                                       table\_entry->ovnNGAggrLoopDetect\);
            break;
        case COLUMN\_ovnNGAggrLoopDetectVlan:
            snmp\_set\_var\_typed\_integer\(request->requestvb, ASN\_INTEGER,
                                       table\_entry->ovnNGAggrLoopDetectVlan\);
            break;
        case COLUMN\_ovnNGAggrLoopDetectPbit:
            snmp\_set\_var\_typed\_integer\(request->requestvb, ASN\_INTEGER,
                        table\_entry->ovnNGAggrLoopDetectPbit\);
            break;

        case COLUMN\_OVNNGAGGRROWSTATUS:
            snmp\_set\_var\_typed\_integer\(request->requestvb, ASN\_INTEGER,
                      VAL\_active\);
            break;
        default:
            netsnmp\_set\_request\_error\(reqinfo, request,
                                      SNMP\_NOSUCHOBJECT\);
            break;
        \}
    \}
    break;

Discussion

  • Bill Fenner
    Bill Fenner
    2012-10-05

    We had a similar experience with the table_iterator:

    $ snmpget -v 2c -c public blue ifInOctets.43 ifInOctets.44
    IF-MIB::ifInOctets.43 = Counter32: 483792666
    IF-MIB::ifInOctets.44 = Counter32: 1470706044

    vs.

    $ snmpget -v 2c -c public blue ifInOctets.44 ifInOctets.43
    IF-MIB::ifInOctets.44 = Counter32: 1474004919
    IF-MIB::ifInOctets.43 = No Such Instance currently exists at this OID

    (It is hard to publish our agent code, since it is tightly integrated with our system. We use table_iterator along with NETSNMP_ITERATOR_FLAG_SORTED. I see that NETSNMP_ITERATOR_FLAG_SORTED is only used by the old mibII/udpTable and mibII/tcpTable implementations.)

    The solution of injecting the serialize handler works in our environment.

     
  • Joan Landry
    Joan Landry
    2012-10-05

    issue is not restricted to having the colum be the same
    example:
    indeivdual getnext request get valid response:
    snmpgetnext -c public -v 2c xxx 1.3.6.1.4.1.4444.2.11.1.2.1.1.4.1
    SNMPv2-SMI::enterprises.4444.2.11.1.2.1.1.5.1 = STRING: "#142 SMP PREEMPT Mon Jun 27 13:27:06 EDT 2011"
    snmpgetnext -c public -v 2c xxxx 1.3.6.1.4.1.4444.2.11.1.2.1.1.7.1
    SNMPv2-SMI::enterprises.4444.2.11.1.2.1.1.8.1 = STRING: "00:07:C1:50:06:20"

    put together you get different results:
    snmpgetnext -c public -v 2c xxx 1.3.6.1.4.1.4444.2.11.1.2.1.1.4.1 1.3.6.1.4.1.4444.2.11.1.2.1.1.4.1
    SNMPv2-SMI::enterprises.4444.2.11.1.2.1.1.5.1 = STRING: "#142 SMP PREEMPT Mon Jun 27 13:27:06 EDT 2011"
    SNMPv2-SMI::enterprises.4444.2.11.1.2.3.1.2.1 = STRING: "System Chassis"

    where the 2nd response is for the next table not the next column

     
  • Joan Landry
    Joan Landry
    2012-11-13

    I think it is possible this issue is the result of the following:
    if(!table_entry)
    {
    netsnmp_set_request_error(reqinfo, request, ret);
    return SNMP_ERR_NOERROR;
    }

    should be
    if(!table_entry)
    {
    netsnmp_set_request_error(reqinfo, request, ret);
    continue;
    }