net-snmp代理开发之表格开发入门

Net-SNMP代理开发之表格开发入门

net-snmp开发比较难以理解的是表格的实现方式,本文,笔者尝试一个人的理解,用简单的方式解释net-snmp的开发。并通过示例来说明如何开发表格。

Net-SNMP表格的理解

现实中的表格如下图所示,有多行,多列,有唯一确定某一行的索引列,可以是固定的一列,也可以是多列共同决定某行。

在Net-SNMP中,表格的标识方法如下图所示:


上图定义了表的类型,每一个表有个Entry标识,表示行,通过MIB定了了表头的结构。其中XXXTable和XXXEntry是MIB的规范,其中ColumnN为列名称,可以像标量定义。如果按MIB的OID编码方法,表格的数据可以解释为下图:


比如需要访问第一行,第一列的数据,需要通过XXXTable.XXXEntry.XXXColumn1.1来访问,绿色的数字表示那一列,红色的数字表示哪一行。比如要访问第二行,第五列,通过XXXTable.XXXEntry.XXXColumn5.2来访问。

Net-SNMP表格数据的迭代器访问方式

通过mib2c命令可以生成表格访问的代码模板,本文讲述mib2c.iterator_access.conf配置文件生成的模板。该模板生成表格访问代码除需要实现get/set函数外,还需要实现表格行的迭代。

在讲述之前,请读者想一下:如果我需要按表格的方式访问时,我应该如何实现代码?首先,我需要知道用户请求的行索引,让后通过索引定位到行,再依据访问的列调用特定的get/set方法。通过索引找到对应的行就需要对表格所有行上索引列进行遍历,定位特定的行。SNMP协议支持遍历(snmpwalk),从第一行开始,遍历到最后一行。所以表格的迭代需要实现一个遍历表格的方法。

net-snmp库需要使用一个迭代(循环)上下文,来保存当前的迭代位置,还有一个内容上下文,保存一行数据的上下文,net-snmp库需要获得索引数据的指针和数据的长度,用于比较。迭代上下文在迭代时作为迭代的参数,内容上下文会作为get/set的参数。

对于iterator.conf或iterator_access.conf的配置文件生成的文件需要实现xxx_get_first_data_point和xxx_get_next_data_point函数。xxx_get_first_data_point和xxx_get_next_data_point两个函数取得表格的第一行,以及下一行。这两个函数前两个参数为用户自定义指针,my_loop_context由xxxx_get_first_data_point创建,XXX_get_next_data_point和xxx_context_convert_function函数中作为参数中传入。
xxx_get_first_data_point返回第一行索引对象指针,并初始化迭代器上下文和数据上下文。
xxx_get_next_data_point返回后续行索引对象指针,并修改迭代器上下文和数据上下文。

一般,在C语言中,我们通过链表实现一个表格的模型,如下图所示。标识索引可以单独定义,也可以定义在数据中,数据可以是一个结构体,标识表格的一行数据。


netsnmp_variable_list *
controllerTable_get_first_data_point(void **my_loop_context, void **my_data_context,
                          netsnmp_variable_list *put_index_data,
                          netsnmp_iterator_info *mydata)
{

    netsnmp_variable_list *vptr;
    lampctrl_row_t* prow = get_first_lampctrl_row();
    if (prow == NULL){
        *my_loop_context = NULL;
        *my_data_context = NULL;
        return NULL;
    }
    *my_loop_context = prow;
    *my_data_context = prow->data;

    vptr = put_index_data;
    
    snmp_set_var_value(vptr, prow->index, strlen(prow->index));
    vptr = vptr->next_variable;

    return put_index_data;
}
上述代码通过方法get_first_lampctrl_row()取得表格的第一行对象,让后把行对象写入迭代上下文(my_loop_context),把数据对象写入数据上下文(my_data_context),接着,通过snmp_set_var_value把索引写入put_index_data结构体(一个snmp的变量结构,可以存SNMP定义的所有数据类型),本示例代码使用的字符串的索引,最后返回索引的变量对象指针。

netsnmp_variable_list *
controllerTable_get_next_data_point(void **my_loop_context, void **my_data_context,
                         netsnmp_variable_list *put_index_data,
                         netsnmp_iterator_info *mydata)
{

    netsnmp_variable_list *vptr;
    lampctrl_row_t* pcurrow = *my_loop_context;
    lampctrl_row_t* prow = get_next_lampctrl_row(pcurrow);
    if (prow == NULL){
        *my_loop_context = NULL;
        *my_data_context = NULL;
        return NULL;
    }
    *my_loop_context = prow;
    *my_data_context = prow->data;

    vptr = put_index_data;
    
    snmp_set_var_value(vptr, prow->index, strlen(prow->index));
    vptr = vptr->next_variable;

    return put_index_data;
}
在xxx_get_next_data_point实现是,迭代器上下文和数据上下文都通过参数传递过来了,迭代器指向了当前行的位置,而数据上下文指向了当前行的数据。该行数需要通过上下文获得下一行的迭代器上下文和数据上下文,并更新上下文参数的数据。最后,把新行的索引写入索引数据。

char *get_controllerId(void *data_context, size_t *ret_len) {
	lampctrl_data_t* pdata = (lampctrl_data_t*)data_context;
	DEBUGMSGTL(("lampController:get", "controller Id:%s\n", pdata->controllerId));
	*ret_len = strlen(pdata->controllerId);
	return pdata->controllerId; /** XXX: replace this with a pointer to a real value */
}
get方法有一个数据上下文(data_context),还有一个放回值长度的参数,需要设置为返回数据的长度。通过数据上下文,可以很容易的取得对应列(每一个列都实现了一个get/set方法)。数据返回的是数据的地址,本例为字符串,直接使用了字符串地址,并通过strlen计算了数据的长度。


(高级)迭代器上下文和snmp变量结构体

需要完全理解表格的操作,需要理解结构体:netsnmp_iterator_info_s的定义。

迭代器的定义如下:

/** @struct netsnmp_iterator_info_s

     * Holds iterator information containing functions which should be
       called by the iterator_handler to loop over your data set and
       sort it in a SNMP specific manner.
       
       The netsnmp_iterator_info typedef can be used instead of directly calling this struct if you would prefer.
     */
    typedef struct netsnmp_iterator_info_s {
       /** Number of handlers that own this data structure. */
       int refcnt;

       /** Responsible for: returning the first set of "index" data, a
           loop-context pointer, and optionally a data context
           pointer */
        Netsnmp_First_Data_Point *get_first_data_point;

       /** Given the previous loop context, this should return the
           next loop context, associated index set and optionally a
           data context */
        Netsnmp_Next_Data_Point *get_next_data_point;

       /** If a data context wasn't supplied by the
           get_first_data_point or get_next_data_point functions and
           the make_data_context pointer is defined, it will be called
           to convert a loop context into a data context. */
        Netsnmp_Make_Data_Context *make_data_context;

       /** A function which should free the loop context.  This
           function is called at *each* iteration step, which is
           not-optimal for speed purposes.  The use of
           free_loop_context_at_end instead is strongly
           encouraged. This can be set to NULL to avoid its usage. */
        Netsnmp_Free_Loop_Context *free_loop_context;

       /** Frees a data context.  This will be called at any time a
           data context needs to be freed.  This may be at the same
           time as a correspondng loop context is freed, or much much
           later.  Multiple data contexts may be kept in existence at
           any time. */
       Netsnmp_Free_Data_Context *free_data_context;

       /** Frees a loop context at the end of the entire iteration
           sequence.  Generally, this would free the loop context
           allocated by the get_first_data_point function (which would
           then be updated by each call to the get_next_data_point
           function).  It is not called until the get_next_data_point
           function returns a NULL */
        Netsnmp_Free_Loop_Context *free_loop_context_at_end;

       /** This can be used by client handlers to store any
           information they need */
        void           *myvoid;
        int             flags;
#define NETSNMP_ITERATOR_FLAG_SORTED	0x01
#define NETSNMP_HANDLER_OWNS_IINFO	0x02

       /** A pointer to the netsnmp_table_registration_info object
           this iterator is registered along with. */
        netsnmp_table_registration_info *table_reginfo;

        /* Experimental extension - Use At Your Own Risk
           (these two fields may change/disappear without warning) */
        Netsnmp_First_Data_Point *get_row_indexes;
        netsnmp_variable_list *indexes;
    } netsnmp_iterator_info;

下面简要说明一下主要参数的作用(笔者是理解力该结构体才理解表格迭代的方法的):

get_first_data_point 函数返回第一行记录的索引变量列表,一个记录行迭代器上下文指针和数据上下文指针(可选)需要设置。

get_next_data_point 函数返回后续行记录的索引,提供了迭代器和数据上下文指针,同时需要修改迭代器和数据上下文指针指向下一记录。

make_data_context函数在数据上下文没有在get_first_data_point和get_next_data_point函数中设置数据上下文变量时,这个函数会调用。

free_data_context函数释放数据上下文。

free_loop_context_at_end 释放迭代器上下文。


netsnmp_variable_list定义了SNMP数据变量的结构体,理解它更有助于编写代理的实现:

netsnmp_variable_list


后记

net-snmp表格的实现,主要在于理解,理解了,设计数据结构,和实现代码就很简单。由于参考资料中使用的方法都有点复杂,所以理解就存在困难。本文使用的数据结构简单,定义一个行数据结构,在定义一个链表结构,就可以实现表格的访问了。

typedef struct _lampctrl_data_t{
    char controllerId[MAX_CONTROLLER_ID_LEN];
    unsigned int sysUpTime;
    //...
    unsigned int batChargeMode;
}lampctrl_data_t;

typedef struct _lampctrl_node_t{
    lampctrl_data_t data;
    struct _lampctrl_node_t* next;
}lampctrl_node_t;


  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值