查找使用AgentX实现SNMP表的示例代码

Looking for example code to implement a SNMP table using AgentX

本文关键字:代码 SNMP AgentX 实现 查找      更新时间:2023-10-16

我已经编写了一个AgentX应用程序(Linux、gcc、g++),它可以很好地发送回缩放器。以下是我现在正在做的事情:

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
}

handle_foo1(...)这样的函数调用snmp_set_var_typed_value(...)来返回缓存在应用程序中的全局C结构中的值。

我现在要做的是修改此代码,使其也支持SNMP表。表的内容作为STL容器存储/缓存在应用程序中。这是一个相对简单的SNMP表,具有连续的行,所有列都由Integer32、Gauge32、InetAddress和TruthValue等类型组成。问题是,我在net-snmp网站上没有看到很棒的代码示例,只有很多doxygen页面。

我的问题:

我应该看什么API?这是正确的选择吗:

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

或者有什么更简单的东西我应该使用吗?

我认为当涉及到net-snmp时,最大的痛苦是谷歌索引的所有Doxygen页面,但它提供的可用内容几乎为零。阅读.h文件对大多数开发人员来说可能已经很明显了,事实是net-snmp提供了许多不同的API层,而我发现有用的文档很少。我们需要的不是几十个相同的Doxygen网站副本,而是一些好的例子。

最后,mib2c工具是我如何获得足够的示例代码来使整个工作正常进行的。我想我试着用每一个net-snmp .conf文件运行mib2c,并花了很多时间阅读它生成的代码以更好地理解它。以下是我发现的给我最好的提示:

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

.conf文件在这里:/etc/snmp/mib2c.*

以下页面也很有用:

  • 常见问题:http://www.net-snmp.org/FAQ.html
  • 表格的示例代码:http://www.net-snmp.org/dev/agent/data__set_8c-example.html
  • Doxygen页面:http://www.net-snmp.org/dev/agent/group__library.html

据我所知,在net-snmp API中有许多助手/层可用。因此,这个示例伪代码可能不适用于所有人,但这就是我个人使用net-snmp v5.4:使表工作的方式

多个函数所需的变量(使其成为全局变量或结构的成员?)

netsnmp_tdata *table = NULL;

表示表中一行的结构(必须与MIB定义匹配)

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

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

处理请求的处理程序

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

构建/向表添加行

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

组合

在我的例子中,构建行的最后一个函数是由系统中的一些其他事件定期触发的。因此,每隔一段时间,当新的统计数据可用时,就会重建表,删除所有旧的行,并插入新的行。我没有费心修改现有的行。相反,我发现从头开始重建表更容易。