2012-03-23 11 views
7

Ho scritto un'app AgentX (Linux, gcc, g ++) che funziona bene con l'invio di scaler. Ecco quello che sto facendo ora:In cerca di codice di esempio per l'implementazione di una tabella SNMP tramite AgentX

init_agent("blah"); 
netsnmp_register_read_only_scalar(netsnmp_create_handler_registration("foo1", handle_foo1, oid, oid.size(), HANDLER_CAN_RONLY)); 
init_snmp("blah"); 
while (true) 
{ 
    // internal stuff 
    agent_check_and_process(1); // where 1==block 
} 

LE funzioni come chiamata handle_foo1(...)snmp_set_var_typed_value(...) per restituire i valori che sono memorizzate nella cache in una struttura globale C all'interno dell'applicazione.

Quello che sto cercando di fare ora è modificare questo codice per supportare anche una tabella SNMP. Il contenuto della tabella viene memorizzato/memorizzato nella cache come un contenitore STL all'interno dell'applicazione. Questa è una tabella SNMP relativamente semplice, con righe consecutive e tutte le colonne sono composte da tipi come Integer32, Gauge32, InetAddress e TruthValue. Il problema è che non vedo grandi esempi di codice sul sito web net-snmp, solo un sacco di pagine doxygen.

La mia domanda:

Cosa API dovrei essere guardando? Sono queste le chiamate giuste:

netsnmp_register_read_only_table_data(); 
netsnmp_create_table_data(); 
netsnmp_create_table_data_row(); 
netsnmp_table_data_add_row(); 

... o c'è qualcosa di più semplice che dovrei usare?

+0

Stai scrivendo il tuo agente da zero o usando 'mib2c'? 'mib2c' può generare l'intero scheletro per te. Dopo di che, convertirlo in un sub-agente è facile. Hai già letto "http://net-snmp.sourceforge.net/wiki/index.php/TUT:Writing_a_Subagent"? – j4x

risposta

15

Penso che il più grande dolore quando si tratta di net-snmp sono tutte quelle pagine Doxygen degli indici di Google ma che forniscono contenuti utilizzabili quasi zero. Leggere i file .h è probabilmente già ovvio per la maggior parte degli sviluppatori, e la verità è che net-snmp fornisce molti livelli diversi di API con pochissima documentazione che ho trovato utile. Ciò di cui abbiamo bisogno non sono alcune decine di copie identiche di siti Web che ospitano Doxygen, ma invece alcuni buoni esempi.

Alla fine, lo strumento mib2c è come ho ottenuto abbastanza codice di esempio per far funzionare tutto. Penso di aver provato a eseguire mib2c con ogni singolo file net-snmp .conf e ho trascorso molto tempo a leggere il codice generato per ottenere una migliore comprensione. Qui sono quelli che ho trovato mi hanno dato i migliori suggerimenti:

  • mib2c -c mib2c.create-dataset.conf MyMib
  • mib2c -c mib2c.table_data.conf MyMib

I file .conf sono qui: /etc/snmp/mib2c.*

utili sono stati anche le seguenti pagine:

Da quello che ho capito, ci sono molti aiutanti/livelli disponibili nell'API net-SNMP. Quindi questo esempio pseudocodice potrebbe non funzionare per tutti, ma questo è come io personalmente ho le mie tabelle di lavorare utilizzando net-snmp v5.4:

variabile necessaria tra diverse funzioni (renderlo globale, o un membro di un struct?)

netsnmp_tdata *table = NULL; 

Struttura per rappresentare una riga della tabella (deve corrispondere alla definizione MIB)

struct MyTable_entry 
{ 
    long myTableIndex; 
    ...insert one line here for each column of the table... 
    int valid; // add this one to the end 
} 

inizializzare la tabella con snmpd

std::string name("name_of_the_table_from_mib"); 
table = netsnmp_tdata_create_table(name.c_str(), 0); 
netsnmp_table_registration_info *table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info); 
netsnmp_table_helper_add_indexes(table_info, ASN_INTEGER, 0); // index: myTableIndex 
// specify the number of columns in the table (exclude the index which was already added) 
table_info->min_column = COLUMN_BLAH; 
table_info->max_column = MAX_COLUMN_INDEX; 
netsnmp_handler_registration *reg = netsnmp_create_handler_registration(name.c_str(), MyTable_handler, oid, oid.size(), HANDLER_CAN_RONLY); 
netsnmp_tdata_register(reg, table, table_info); 

Handler per elaborare le richieste

int myTable_handler(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) 
{ 
    if (reqInfo->mode != MODE_GET) return SNMP_ERR_NOERROR; 
    for (netsnmp_request_info *request = requests; request; request = request->next) 
    { 
     MyTable_entry *table_entry = (MyTable_entry*)netsnmp_tdata_extract_entry(request); 
     netsnmp_table_request_info *table_info = netsnmp_extract_table_info(request); 

     if (table_entry == NULL) { netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHINSTANCE); continue; } 

     switch (table_info->colnum) 
     { 
      // ...this is similar to non-table situations, eg: 
      case COLUMN_BLAH: 
       snmp_set_var_typed_integer(request->requestvb, ASN_INTEGER, table_entry->blah); break; 
      // ... 
      default: netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHOBJECT); 
     } 
    } 
    return SNMP_ERR_NOERROR; 
} 

Costruire/aggiunta di righe alla tabella

if (table == NULL) return; // remember our "global" variable named "table"? 

// start by deleting all of the existing rows 
while (netsnmp_tdata_row_count(table) > 0) 
{ 
    netsnmp_tdata_row *row = netsnmp_tdata_row_first(table); 
    netsnmp_tdata_remove_and_delete_row(table, row); 
} 

for (...loop through all the data you want to add as rows into the table...) 
{ 
    MyTable_entry *entry = SNMP_MALLOC_TYPEDEF(MyTable_entry); 
    if (entry == NULL) ... return; 
    netsnmp_tdata_row *row = netsnmp_tdata_create_row(); 
    if (row == NULL) SNMP_FREE(entry); .... return; 

    entry->myTableIndex = 123; // the row index number 
    // populate the table the way you need 
    entry->blah = 456; 
    // ... 

    // add the data into the row, then add the row to the table 
    entry->valid = 1; 
    row->data = entry; 
    netsnmp_tdata_row_add_index(row, ASN_INTEGER, &(entry->myTableIndex), sizeof(entry->myTableIndex)); 
    netsnmp_tdata_add_row(table, row); 
} 

Mettere insieme

Nel mio caso, quell'ultima funzione che crea le righe viene attivata periodicamente da alcuni altri eventi nel sistema. Quindi ogni tanto quando sono disponibili nuove statistiche, la tabella viene ricostruita, tutte le vecchie file vengono rimosse e quelle nuove vengono inserite. Non mi sono preoccupato di provare a modificare le righe esistenti. Invece, ho trovato che era più facile ricostruire il tavolo da zero.