2

私は、ローカル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
}

これはいくつかの単純な整数スカラーで機能しますが、読み取る必要のあるテーブルもいくつかあります。snmp_add_null_var()でテーブルのOIDとテーブルエントリのOIDの両方を試しましたが、snmp_sync_response()は、OIDが見つからないことを示すエラーコードを返します。

だから私はこれらの呼び出しに出くわしたヘッダーファイルを閲覧しました。これらの1つが、私が使用したいものである可能性が高いと思われます。

  1. netsnmp_query_walk()
  2. netsnmp_query_get()

しかし、使い方がわかりません。これは私が試したことです:

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

4 に答える 4

3

いくつか問題があったのではないかと思います。最初はこの行です:

snmp_pdu_create( SNMP_MSG_GET );

MSG_GETを呼び出す代わりに、を使用することを検討した場合はおそらく役に立ちましたSNMP_MSG_GETBULK。しかし、接続先のSNMPサーバーはSNMPv1のみをサポートしており、GETBULKはSNMPv2 +に固有であることが判明したため、わざわざ掘り下げることはしませんでした。

代わりに私が見つけたのは、一度に1つの変数でテーブルをトラバースするために使用できる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 );
}
于 2012-04-06T01:15:01.253 に答える
0

snmpgetの場合、この行を使用します=> pdu = snmp_pdu_create(SNMP_MSG_GET); snmpwalkの場合、この行を使用します=> pdu = snmp_pdu_create(SNMP_MSG_GETNEXT); 残りのコードは同じです

于 2012-07-16T12:19:39.327 に答える
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()
于 2016-05-23T21:30:03.127 に答える
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をいじるよりもはるかにクリーンです。

于 2017-08-29T14:44:28.983 に答える