我如何使用netsnmp_query_walk()或netsnmp_query_get()?

时间:2012-04-03 22:53:50

标签: c linux net-snmp

我已成功使用以下内容从本地snmpd读取一些简单的SNMP值:

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
}

虽然这适用于一些简单的整数标量,但我也有一些我需要阅读的表。我已经尝试了表的OID和snmp_add_null_var()中表条目的oid,但是snmp_sync_response()返回错误代码,表明找不到OID。

因此浏览头文件时遇到了这些调用。我怀疑其中一个可能就是我想要使用的东西:

  1. netsnmp_query_walk()
  2. netsnmp_query_get()
  3. 但是,我无法弄清楚如何使用它们。这就是我尝试过的:

    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 );
    

    ...但是在这一点上,rc总是== -1,我猜这意味着有一个错误。我如何使用这些,或者,我应该使用更好的API吗?

4 个答案:

答案 0 :(得分:2)

我怀疑有几个问题。第一个是这一行:

snmp_pdu_create( SNMP_MSG_GET );

如果我考虑使用SNMP_MSG_GETBULK,它可能会有所帮助,而不是调用MSG_GET。但事实证明我所连接的SNMP服务器只支持SNMPv1,而GETBULK特定于SNMPv2 +,所以我没有费心去挖掘。

我发现的是如何使用GETNEXT,它可以用来一次遍历一个变量表。以下是代码的工作原理:

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 );
}

答案 1 :(得分:0)

for snmpget使用此行=&gt; pdu = snmp_pdu_create(SNMP_MSG_GET); 对于snmpwalk使用此行=&gt; pdu = snmp_pdu_create(SNMP_MSG_GETNEXT); 其余代码相同

答案 2 :(得分:0)

在查看snmpwalk的代码后,我得到了一个如何在代码中执行此操作的简单示例。

#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()

答案 3 :(得分:0)

我花了一些时间来解决这个问题,因为该功能的文档很少。无论你是对的,它都比使用低级函数更优雅。

您只需打开会话,初始化NULL varlist,然后使用snmp_varlist_add_variable填写oid和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);
}

现在您可以使用varlist,因为它已填充查询结果。比乱搞PDU更清洁。