How do I use netsnmp_query_walk() or netsnmp_query_get()?

Go To StackoverFlow.com

2

I've successfully used the following to read some simple SNMP values from a local snmpd:

snmp_open( &session )
snmp_pdu_create( SNMP_MSG_GET );
snmp_add_null_var( pdu, oid, len ); // multiple lines like this
snmp_sync_response( ss, pdu, &response );
for ( netsnmp_variable_list *vars = response->variables; vars; vars = vars->next_variable )
{
    // look at vars->name, vars->name_length, and vars->val.integer
}

While this works for a few simple integer scalars, I also have some tables I need to read. I've tried both the OID of the table and the oid of the table entry in snmp_add_null_var(), but snmp_sync_response() returns with an error code indicating that OID cannot be found.

So browsing the header files I came across these calls. I suspect one of these is likely to be what I want to be using:

  1. netsnmp_query_walk()
  2. netsnmp_query_get()

However, I cannot figure out how to use them. This is what I've tried:

netsnmp_variable_list *vb = (netsnmp_variable_list*)SNMP_MALLOC_TYPEDEF( netsnmp_variable_list );
if ( vb == NULL ) ...
snmp_set_var_objid( vb, oid, len );
int rc = netsnmp_query_walk( vb, ss );
//int rc = netsnmp_query_get( vb, ss );

...but at this point, rc is always == -1 which I'm guessing means there was an error. How do I use these, or, is there a better API I should be using?

2012-04-03 22:53
by Stéphane


2

I suspect there were several problems. The first is this line:

snmp_pdu_create( SNMP_MSG_GET );

Instead of calling MSG_GET, it would probably have helped if I'd looked into using SNMP_MSG_GETBULK. But it turns out the SNMP server against which I'm connecting only supports SNMPv1, and GETBULK is specific to SNMPv2+, so I didn't bother digging.

What I found instead is how to use GETNEXT, which can be used to traverse the table one variable at a time. Here is how the code works:

oid = ....; // start with a known OID, like the table you want to read
while ( true )
{
    pdu = snmp_pdu_create( SNMP_MSG_GETNEXT );
    snmp_add_null_var( pdu, oid, len );
    status = snmp_synch_response( ss, pdu, reply );
    if ( status != STAT_SUCCESS )
    {
        // either an error, or there is nothing left to read
        snmp_free_pdu( reply );
        break;
    }
    for ( netsnmp_variable_list *vars=reply->variables; vars; vars=vars->next_variable )
    {
        // make sure you remember this OID so you know what to use
        // when you get back to the top of the while() loop
        oid = ...vars->name[], vars->name_length...;

        // do something with this snmp value, such as:
        std::cout << oid << ": " << *vars->val.integer << std::endl;
    }
    snmp_free_pdu( reply );
}
2012-04-06 01:15
by Stéphane


0

for snmpget use this line => pdu = snmp_pdu_create( SNMP_MSG_GET ); for snmpwalk use this line => pdu = snmp_pdu_create( SNMP_MSG_GETNEXT ); rest of code is same

2012-07-16 12:19
by sam


0

After looking at the code for snmpwalk I got a simple example of how to do it in code.

#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <string.h>

void
snmp_get_and_print(netsnmp_session * ss, oid * theoid, size_t theoid_len)
{
    netsnmp_pdu    *pdu, *response;
    netsnmp_variable_list *vars;
    int             status;

    pdu = snmp_pdu_create(SNMP_MSG_GET);
    snmp_add_null_var(pdu, theoid, theoid_len);

    status = snmp_synch_response(ss, pdu, &response);
    if (status == STAT_SUCCESS && response->errstat == SNMP_ERR_NOERROR) {
        for (vars = response->variables; vars; vars = vars->next_variable) {
            print_variable(vars->name, vars->name_length, vars);
        }
    }
    if (response) {
        snmp_free_pdu(response);
    }
}

int main(int argc, char ** argv)
{
    netsnmp_session session, *ss;
    netsnmp_pdu *pdu, *response;
    netsnmp_variable_list *vars;

    oid             name[MAX_OID_LEN];
    size_t          name_length;
    oid             root[MAX_OID_LEN];
    size_t          rootlen;
    oid             end_oid[MAX_OID_LEN];
    size_t          end_len = 0;
    int             count;
    int             running;

    int status = STAT_ERROR;;

    init_snmp("snmpwalk");

    snmp_sess_init( &session );
    session.peername = strdup("SNMP.device.domain");


    //session.version = SNMP_VERSION_1;
    session.version = SNMP_VERSION_2c;

    session.community = "public";
    session.community_len = strlen(session.community);

    SOCK_STARTUP;
    ss = snmp_open(&session);

    if (!ss) {
      snmp_sess_perror("ack", &session);
      SOCK_CLEANUP;
      exit(1);
    }

    rootlen = MAX_OID_LEN;
    if (snmp_parse_oid("RFC1213-MIB::ifIndex", root, &rootlen) == NULL) {
        snmp_perror("RFC1213-MIB::ifIndex");
        exit(1);
    }

    memmove(end_oid, root, rootlen*sizeof(oid));
    end_len = rootlen;
    end_oid[end_len-1]++;

    memmove(name, root, rootlen * sizeof(oid));
    name_length = rootlen;

    running = 1;

    while (running) {
        // create PDU for GETNEXT request and add object name to request
        pdu = snmp_pdu_create(SNMP_MSG_GETNEXT);
        snmp_add_null_var(pdu, name, name_length);

        status = snmp_synch_response(ss, pdu, &response);

        if (status == STAT_SUCCESS) {
            if (response->errstat == SNMP_ERR_NOERROR) {
                // check resulting variables
                for (vars = response->variables; vars;
                     vars = vars->next_variable) {
                    if (snmp_oid_compare(end_oid, end_len,
                        vars->name, vars->name_length) <= 0) {
                        //not part of this subtree
                        running = 0;
                        continue;
                    }
                    print_variable(vars->name, vars->name_length, vars);
                    memmove((char *) name, (char *) vars->name,
                       vars->name_length * sizeof(oid));
                    name_length = vars->name_length;
                }
            }
        }
        if (response)
            snmp_free_pdu(response);
    }

    snmp_close(ss);

    SOCK_CLEANUP;
    return (0);

} // main()
2016-05-23 21:30
by Sam Sanders


0

Took me a while to figure this out, as that function has very little documentation. However you are correct, it is far more elegant than using the lower level functions.

You simply open the session, initialize a NULL varlist, and then use snmp_varlist_add_variable to fill in the oid and oid_len.

ss = snmp_open(&session);
if (!ss) {
    snmp_sess_perror("snmp_open", &session);
    exit(STATUS_UNKNOWN);
}

/* Walk Indexes */
snmp_varlist_add_variable(&hrprload_var, hrprload_oid, hrprload_len, ASN_NULL, NULL, 0);

query_status = netsnmp_query_walk(hrprload_var, ss);
if (query_status != SNMP_ERR_NOERROR) {
    if (query_status == STAT_TIMEOUT) {
        fprintf(stderr, "Timeout: No Response from %s\n", ss->peername);
    } else {
        fprintf(stderr, "Error in packet: %s\n", snmp_api_errstring(ss->s_snmp_errno));
    }
    exit(STATUS_UNKNOWN);
}

Now you can use the varlist as it has been populated with the query results. Much cleaner than messing around with PDUs.

2017-08-29 14:44
by J. M. Becker