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資料變量的結構體,了解它更有助于編寫代理的實作:
後記
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;