SNMP Table是对象的有序集合,包含若干行。为什么SNMP中需要用表格呢,原因是有些数据的组织用表格来表达更方便,多个对象的组合才能完整描述一条信息。
表格代码框架概述:
表格框架的配置文件根据表格数据是否存在于Net-SNMP的内核中分为两大类:
-
一类是表格数据存放于其内部。这类框架代码中将所有的表格信息和数据都注册到系统中,同时生成单个处理句柄,在代理内核完成数据的GET/SET等操作。当对表格中某列有特殊的处理需求时,才自定义额外的处理句柄。这类框架配置文件有,mib2c.table_data.conf, mib2c.create_dataset.conf,mib2c.array-user.conf等,后者还具有根据表格索引排序的功能。
-
另一类时表格数据存在于其外部。这类代码框架中,表格数据由外部程序定义和维护。这些数据可以存在于代理中,也可以存在于另外的系统中,一般的项目中就属于这种数据模型。表格数据的查询通过迭代器的方式来实现,这些迭代器的功能是实现表格行和列数据的获取。使用迭代器一般要求表格数据定义为链表结构,每个链表节点代表一行数据。框架一般会提供get_first_data和get——next-data方法来实现迭代的功能,这类框架配置文件有mib2c.iterate.conf和mib2c.iterate_access.conf等。
这些框架代码也有其共同之处,如模块注册等机制。
我们使用的是代码框架配置文件:mib2c.iterate.conf,该代码框架既可以用于简单表也适用于通用表。
Iterate 系列框架
Iterate 框架中,表格模块的注册与标量模块注册方式是一样的:注册OID的回调函数(XXX_handler)。这些注册由接口init_XXX()和initialize_table_XXX()实现。不过在表格框架的代码中还需要注册查询表格的迭代器,即表格中还需要具有查询表格行的方法。它们由XXX_get_first_data_point()和XXX_get_next_data_point()实现。另外,该代码框架还提供了定义表格的链表结构体(XXX_Table_entry)和操作链表的两个函数XXXTable_createEntry()和XXXTable_remove Entry()。
MIB文件:
TEST-TABLE-MIB DEFINITIONS ::= BEGIN
IMPORTS
MODULE-IDENTITY, OBJECT-TYPE, TimeTicks FROM SNMPv2-SMI
DisplayString, FROM SNMPv2-TC
jsHostInfo
FROM JS-MAIN-MIB ;
testTable OBJECT IDENTIFIER ::= { jsHostInfo 20 }
boardSlotTable OBJECT-TYPE
SYNTAX SEQUENCE OF BoardSlotEntry
MAX-ACCESS not-accessible
STATUS current
DESCRIPTION " Fan status description table "
::= { testTable 2 }
boardSlotEntry OBJECT-TYPE
SYNTAX BoardSlotEntry
MAX-ACCESS not-accessible
STATUS current
DESCRIPTION " Boad status description table entry "
INDEX { boardSlotID }
::= { boardSlotTable 1}
BoardSlotEntry::=
SEQUENCE {
boardSlotID INTEGER,
boardType INTEGER,
boardSeriesNumber DisplayString,
}
boardSlotID OBJECT-TYPE
SYNTAX INTEGER
MAX-ACCESS read-only
STATUS current
DESCRIPTION " Slot ID "
::= { boardSlotEntry 1 }
--add enum value
boardType OBJECT-TYPE
SYNTAX INTEGER
MAX-ACCESS read-only
STATUS current
DESCRIPTION " Slot Number "
::= { boardSlotEntry 2 }
boardSeriesNumber OBJECT-TYPE
SYNTAX DisplayString (SIZE (0..128))
MAX-ACCESS read-only
STATUS current
DESCRIPTION " Slot Series Number "
::= { boardSlotEntry 3 }
boardWorkMode OBJECT-TYPE
SYNTAX INTEGER
{
normal (1),
abnormal (2),
offline (3)
}
MAX-ACCESS read-only
STATUS current
DESCRIPTION " Board Status: normal (1), abnormal (2) and offline (3)"
::= { boardSlotEntry 4 }
END
使用
mib2c mib2c.iterate.conf TEST-TABLE-MIB::testTable 将MIB文件编译成C模块代码
选择2,回车
选择2,回车
选择1,回车
选择1 回车
最后生成我们想要的.c .h文件
源码没有修改前的文件:
/*
* Note: this file originally auto-generated by mib2c using
* $
*/
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include "boardSlotTable.h"
/** Initializes the boardSlotTable module */
void
init_boardSlotTable(void)
{
/*
* here we initialize all the tables we're planning on supporting
*/
initialize_table_boardSlotTable();
}
#Determine the first/last column names
/** Initialize the boardSlotTable table by defining its contents and how it's structured */
void
initialize_table_boardSlotTable(void)
{
const oid boardSlotTable_oid[] =
{ 1, 3, 6, 1, 4, 1, 88888, 1, 1, 20, 2 };
const size_t boardSlotTable_oid_len =
OID_LENGTH(boardSlotTable_oid);
netsnmp_handler_registration *reg;
netsnmp_iterator_info *iinfo;
netsnmp_table_registration_info *table_info;
DEBUGMSGTL(("boardSlotTable:init",
"initializing table boardSlotTable\n"));
reg =
netsnmp_create_handler_registration("boardSlotTable",
boardSlotTable_handler,
boardSlotTable_oid,
boardSlotTable_oid_len,
HANDLER_CAN_RONLY);
table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info);
netsnmp_table_helper_add_indexes(table_info, ASN_INTEGER, /* index: boardSlotID */
0);
table_info->min_column = COLUMN_BOARDSLOTID;
table_info->max_column = COLUMN_BOARDWORKMODE;
iinfo = SNMP_MALLOC_TYPEDEF(netsnmp_iterator_info);
iinfo->get_first_data_point = boardSlotTable_get_first_data_point;
iinfo->get_next_data_point = boardSlotTable_get_next_data_point;
iinfo->table_reginfo = table_info;
netsnmp_register_table_iterator(reg, iinfo);
netsnmp_inject_handler_before(reg,
netsnmp_get_cache_handler
(BOARDSLOTTABLE_TIMEOUT,
boardSlotTable_load,
boardSlotTable_free, boardSlotTable_oid,
boardSlotTable_oid_len),
TABLE_ITERATOR_NAME);
/*
* Initialise the contents of the table here
*/
}
/*
* Typical data structure for a row entry
*/
struct boardSlotTable_entry {
/*
* Index values
*/
long boardSlotID;
/*
* Column values
*/
long boardSlotID;
long boardType;
char boardSeriesNumber[NNN];
size_t boardSeriesNumber_len;
long boardWorkMode;
/*
* Illustrate using a simple linked list
*/
int valid;
struct boardSlotTable_entry *next;
};
struct boardSlotTable_entry *boardSlotTable_head;
/*
* create a new row in the (unsorted) table
*/
struct boardSlotTable_entry *
boardSlotTable_createEntry(long boardSlotID,)
{
struct boardSlotTable_entry *entry;
entry = SNMP_MALLOC_TYPEDEF(struct boardSlotTable_entry);
if (!entry)
return NULL;
entry->boardSlotID = boardSlotID;
entry->next = boardSlotTable_head;
boardSlotTable_head = entry;
return entry;
}
/*
* remove a row from the table
*/
void
boardSlotTable_removeEntry(struct boardSlotTable_entry *entry)
{
struct boardSlotTable_entry *ptr, *prev;
if (!entry)
return; /* Nothing to remove */
for (ptr = boardSlotTable_head, prev = NULL;
ptr != NULL; prev = ptr, ptr = ptr->next) {
if (ptr == entry)
break;
}
if (!ptr)
return; /* Can't find it */
if (prev == NULL)
boardSlotTable_head = ptr->next;
else
prev->next = ptr->next;
SNMP_FREE(entry); /* XXX - release any other internal resources */
}
/*
* Example cache handling - set up linked list from a suitable file
*/
int
boardSlotTable_load(netsnmp_cache * cache, void *vmagic)
{
FILE *fp;
struct boardSlotTable_entry *this;
char buf[STRMAX];
/*
* The basic load routine template assumes that the data to
* be reported is held in a file - with one row of the file
* for each row of the table.
* If your data is available via a different API, you
* should amend this initial block (and the control of the
* 'while' loop) accordingly.
* 'XXX' marks where the template is incomplete and
* code will definitely need to be added.
*/
fp = fopen("/data/for/boardSlotTable", "r");
if (!fp) {
return -1;
}
while (fgets(buf, STRMAX, fp)) {
this = SNMP_MALLOC_TYPEDEF(struct boardSlotTable_entry);
/*
* XXX - Unpick 'buf' to extract the individual field values
* and then populate the 'this' data structure with them
*/
this->next = boardSlotTable_head;
boardSlotTable_head = this; /* Iterate helper is fine with unordered lists! */
}
fclose(fp);
return 0; /* OK */
}
void
boardSlotTable_free(netsnmp_cache * cache, void *vmagic)
{
struct boardSlotTable_entry *this, *that;
for (this = boardSlotTable_head; this; this = that) {
that = this->next;
SNMP_FREE(this); /* XXX - release any other internal resources */
}
boardSlotTable_head = NULL;
}
/*
* Example iterator hook routines - using 'get_next' to do most of the work
*/
netsnmp_variable_list *
boardSlotTable_get_first_data_point(void **my_loop_context,
void **my_data_context,
netsnmp_variable_list * put_index_data,
netsnmp_iterator_info *mydata)
{
*my_loop_context = boardSlotTable_head;
return boardSlotTable_get_next_data_point(my_loop_context,
my_data_context,
put_index_data, mydata);
}
netsnmp_variable_list *
boardSlotTable_get_next_data_point(void **my_loop_context,
void **my_data_context,
netsnmp_variable_list * put_index_data,
netsnmp_iterator_info *mydata)
{
struct boardSlotTable_entry *entry =
(struct boardSlotTable_entry *) *my_loop_context;
netsnmp_variable_list *idx = put_index_data;
if (entry) {
snmp_set_var_typed_integer(idx, ASN_INTEGER, entry->boardSlotID);
idx = idx->next_variable;
*my_data_context = (void *) entry;
*my_loop_context = (void *) entry->next;
return put_index_data;
} else {
return NULL;
}
}
/** handles requests for the boardSlotTable table */
int
boardSlotTable_handler(netsnmp_mib_handler *handler,
netsnmp_handler_registration *reginfo,
netsnmp_agent_request_info *reqinfo,
netsnmp_request_info *requests)
{
netsnmp_request_info *request;
netsnmp_table_request_info *table_info;
struct boardSlotTable_entry *table_entry;
DEBUGMSGTL(("boardSlotTable:handler", "Processing request (%d)\n",
reqinfo->mode));
switch (reqinfo->mode) {
/*
* Read-support (also covers GetNext requests)
*/
case MODE_GET:
for (request = requests; request; request = request->next) {
table_entry = (struct boardSlotTable_entry *)
netsnmp_extract_iterator_context(request);
table_info = netsnmp_extract_table_info(request);
switch (table_info->colnum) {
case COLUMN_BOARDSLOTID:
if (!table_entry) {
netsnmp_set_request_error(reqinfo, request,
SNMP_NOSUCHINSTANCE);
continue;
}
snmp_set_var_typed_integer(request->requestvb, ASN_INTEGER,
table_entry->boardSlotID);
break;
case COLUMN_BOARDTYPE:
if (!table_entry) {
netsnmp_set_request_error(reqinfo, request,
SNMP_NOSUCHINSTANCE);
continue;
}
snmp_set_var_typed_integer(request->requestvb, ASN_INTEGER,
table_entry->boardType);
break;
case COLUMN_BOARDSERIESNUMBER:
if (!table_entry) {
netsnmp_set_request_error(reqinfo, request,
SNMP_NOSUCHINSTANCE);
continue;
}
snmp_set_var_typed_value(request->requestvb, ASN_OCTET_STR,
table_entry->boardSeriesNumber,
table_entry->
boardSeriesNumber_len);
break;
case COLUMN_BOARDWORKMODE:
if (!table_entry) {
netsnmp_set_request_error(reqinfo, request,
SNMP_NOSUCHINSTANCE);
continue;
}
snmp_set_var_typed_integer(request->requestvb, ASN_INTEGER,
table_entry->boardWorkMode);
break;
default:
netsnmp_set_request_error(reqinfo, request,
SNMP_NOSUCHOBJECT);
break;
}
}
break;
}
return SNMP_ERR_NOERROR;
}
修改后的文件:
/*
* Note: this file originally auto-generated by mib2c using
* $
*/
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include "boardSlotTable.h"
#define SN_SIZE 64
#define STRMAX 128
/*
* Typical data structure for a row entry
*/
struct boardSlotTable_entry {
/*
* Index values
*/
//long boardSlotID;
/*
* Column values
*/
long boardSlotID;
long boardType;
char boardSeriesNumber[SN_SIZE];
size_t boardSeriesNumber_len;
long boardWorkMode;
/*
* Illustrate using a simple linked list
*/
int valid;
struct boardSlotTable_entry *next;
};
struct boardSlotTable_entry *boardSlotTable_head;
/*
* create a new row in the (unsorted) table
*/
//参数是可变的,自定义
struct boardSlotTable_entry *
boardSlotTable_createEntry(long boardSlotID,long boardtype,char *boardSeriesNumber,size_t boardSeriesNumber_len)
{
struct boardSlotTable_entry *entry;
entry = SNMP_MALLOC_TYPEDEF(struct boardSlotTable_entry);
if (!entry)
return NULL;
entry->boardSlotID = boardSlotID;
memcpy(entry->boardSeriesNumber,boardSeriesNumber,strlen(boardSeriesNumber));
entry->boardSeriesNumber_len = boardSeriesNumber_len;
entry->boardType = boardtype;
entry->next = boardSlotTable_head;
boardSlotTable_head = entry;
return entry;
}
/*
* remove a row from the table
*/
void
boardSlotTable_removeEntry(struct boardSlotTable_entry *entry)
{
struct boardSlotTable_entry *ptr, *prev;
if (!entry)
return; /* Nothing to remove */
for (ptr = boardSlotTable_head, prev = NULL;
ptr != NULL; prev = ptr, ptr = ptr->next) {
if (ptr == entry)
break;
}
if (!ptr)
return; /* Can't find it */
if (prev == NULL)
boardSlotTable_head = ptr->next;
else
prev->next = ptr->next;
SNMP_FREE(entry); /* XXX - release any other internal resources */
}
/** 初始化testTable模块 */
void
init_boardSlotTable(void)
{
/*
* here we initialize all the tables we're planning on supporting
*/
initialize_table_boardSlotTable();
}
//#Determine the first/last column names
/** Initialize the boardSlotTable table by defining its contents and how it's structured */
/**注册表格信息 */
void
initialize_table_boardSlotTable(void)
{
const oid boardSlotTable_oid[] =
{ 1, 3, 6, 1, 4, 1, 88888, 1, 1, 20, 2 };
const size_t boardSlotTable_oid_len =
OID_LENGTH(boardSlotTable_oid);
netsnmp_handler_registration *reg;
netsnmp_iterator_info *iinfo;
netsnmp_table_registration_info *table_info;
DEBUGMSGTL(("boardSlotTable:init",
"initializing table boardSlotTable\n"));
//注册OID的响应句柄
reg =
netsnmp_create_handler_registration("boardSlotTable",
boardSlotTable_handler,
boardSlotTable_oid,
boardSlotTable_oid_len,
HANDLER_CAN_RONLY);
table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info);
//注册表格的索引信息
netsnmp_table_helper_add_indexes(table_info, ASN_INTEGER, /* index: boardSlotID */
0);
//定义表格第一列和最后一列
table_info->min_column = COLUMN_BOARDSLOTID;
table_info->max_column = COLUMN_BOARDWORKMODE;
//注册迭代器
iinfo = SNMP_MALLOC_TYPEDEF(netsnmp_iterator_info);
iinfo->get_first_data_point = boardSlotTable_get_first_data_point;
iinfo->get_next_data_point = boardSlotTable_get_next_data_point;
iinfo->table_reginfo = table_info;
netsnmp_register_table_iterator(reg, iinfo);
//下面是针对OID实现缓存。当不提供缓存机制时可不实现
//testTable_load 为钩子函数 testTable_free 为相应资源释放函数
netsnmp_inject_handler_before(reg,
netsnmp_get_cache_handler
(BOARDSLOTTABLE_TIMEOUT,
boardSlotTable_load,
boardSlotTable_free, boardSlotTable_oid,
boardSlotTable_oid_len),
TABLE_ITERATOR_NAME);
/*
* Initialise the contents of the table here
*/
boardSlotTable_createEntry(1,0,"TRY-621-0",strlen("TRY-621-0"));
boardSlotTable_createEntry(2,1,"TRY-621-1",strlen("TRY-621-1"));
boardSlotTable_createEntry(3,2,"TRY-621-2",strlen("TRY-621-2"));
boardSlotTable_createEntry(4,3,"TRY-621-3",strlen("TRY-621-3"));
}
/*
* Example cache handling - set up linked list from a suitable file
*/
int
boardSlotTable_load(netsnmp_cache * cache, void *vmagic)
{
FILE *fp;
struct boardSlotTable_entry *this;
char buf[STRMAX];
/*
* The basic load routine template assumes that the data to
* be reported is held in a file - with one row of the file
* for each row of the table.
* If your data is available via a different API, you
* should amend this initial block (and the control of the
* 'while' loop) accordingly.
* 'XXX' marks where the template is incomplete and
* code will definitely need to be added.
*/
fp = fopen("/data/for/boardSlotTable", "r");
if (!fp) {
return -1;
}
while (fgets(buf, STRMAX, fp)) {
this = SNMP_MALLOC_TYPEDEF(struct boardSlotTable_entry);
/*
* XXX - Unpick 'buf' to extract the individual field values
* and then populate the 'this' data structure with them
*/
this->next = boardSlotTable_head;
boardSlotTable_head = this; /* Iterate helper is fine with unordered lists! */
}
fclose(fp);
return 0; /* OK */
}
void
boardSlotTable_free(netsnmp_cache * cache, void *vmagic)
{
struct boardSlotTable_entry *this, *that;
for (this = boardSlotTable_head; this; this = that) {
that = this->next;
SNMP_FREE(this); /* XXX - release any other internal resources */
}
boardSlotTable_head = NULL;
}
/*
* Example iterator hook routines - using 'get_next' to do most of the work
*/
//获取第一行:表结构链表
netsnmp_variable_list *
boardSlotTable_get_first_data_point(void **my_loop_context,
void **my_data_context,
netsnmp_variable_list * put_index_data,
netsnmp_iterator_info *mydata)
{
//只需要赋值表结构链表变量 boardSlotTable_head
*my_loop_context = boardSlotTable_head;
return boardSlotTable_get_next_data_point(my_loop_context,
my_data_context,
put_index_data, mydata);
}
//迭代器 获取下一行数据
netsnmp_variable_list *
boardSlotTable_get_next_data_point(void **my_loop_context,
void **my_data_context,
netsnmp_variable_list * put_index_data,
netsnmp_iterator_info *mydata)
{
struct boardSlotTable_entry *entry =
(struct boardSlotTable_entry *) *my_loop_context;
netsnmp_variable_list *idx = put_index_data;
if (entry) {
snmp_set_var_typed_integer(idx, ASN_INTEGER, entry->boardSlotID);
idx = idx->next_variable;
*my_data_context = (void *) entry;
*my_loop_context = (void *) entry->next;
return put_index_data;
} else {
return NULL;
}
}
//处理请求的回调函数都类型:根据请求类型和列号进行查询
/** handles requests for the boardSlotTable table */
int
boardSlotTable_handler(netsnmp_mib_handler *handler,
netsnmp_handler_registration *reginfo,
netsnmp_agent_request_info *reqinfo,
netsnmp_request_info *requests)
{
netsnmp_request_info *request;
netsnmp_table_request_info *table_info;
struct boardSlotTable_entry *table_entry;
DEBUGMSGTL(("boardSlotTable:handler", "Processing request (%d)\n",
reqinfo->mode));
switch (reqinfo->mode) {
/*
* Read-support (also covers GetNext requests)
*/
case MODE_GET:
for (request = requests; request; request = request->next) {
table_entry = (struct boardSlotTable_entry *)
netsnmp_extract_iterator_context(request);
table_info = netsnmp_extract_table_info(request);
switch (table_info->colnum) {
case COLUMN_BOARDSLOTID:
if (!table_entry) {
netsnmp_set_request_error(reqinfo, request,
SNMP_NOSUCHINSTANCE);
continue;
}
snmp_set_var_typed_integer(request->requestvb, ASN_INTEGER,
table_entry->boardSlotID);
break;
case COLUMN_BOARDTYPE:
if (!table_entry) {
netsnmp_set_request_error(reqinfo, request,
SNMP_NOSUCHINSTANCE);
continue;
}
snmp_set_var_typed_integer(request->requestvb, ASN_INTEGER,
table_entry->boardType);
break;
case COLUMN_BOARDSERIESNUMBER:
if (!table_entry) {
netsnmp_set_request_error(reqinfo, request,
SNMP_NOSUCHINSTANCE);
continue;
}
snmp_set_var_typed_value(request->requestvb, ASN_OCTET_STR,
table_entry->boardSeriesNumber,
table_entry->
boardSeriesNumber_len);
break;
case COLUMN_BOARDWORKMODE:
if (!table_entry) {
netsnmp_set_request_error(reqinfo, request,
SNMP_NOSUCHINSTANCE);
continue;
}
snmp_set_var_typed_integer(request->requestvb, ASN_INTEGER,
table_entry->boardWorkMode);
break;
default:
netsnmp_set_request_error(reqinfo, request,
SNMP_NOSUCHOBJECT);
break;
}
}
break;
}
return SNMP_ERR_NOERROR;
}
运行测试:
./snmpwalk -v2c -c public localhost 1.3.6.1.4.1.88888.1.1.20.2
./snmpget -v2c -c public localhost 1.3.6.1.4.1.88888.1.1.20.2.1.1.1