【snmp】net-snmp新增自定義MIB(表格)
安裝net-snmp見:【snmp】centos6.5安裝和配置snmp5.7.1
net-snmp新增自定義MIB(表格):【snmp】net-snmp新增自定義MIB(標量)
snmp 表格支援增刪改查操作,比標量節點多了增刪操作,那麼為了實現增刪操作,可以向表格增加一個RowStatus行狀態型別的列,通過設定狀態值對錶格進行控制。
RowStatus狀態值
狀態 | 說明 |
active(1) | 表明狀態行是可用的 |
notInService(2) | 表明行存在但不可用 |
notReady (3) | 表明行存在,但因為缺少必要的資訊而不能用 |
createAndGo (4) | 由管理者設定,表明希望建立一個行並設定該行的狀態列物件為active |
createAndWait(5) | 由管理者設定,表明希望建立一個行,但不可用,從上面的程式碼看到,是被設定為了notInService |
destroy(6) | 刪除行 |
一、編寫mib檔案
使用MIB Builder生成MIB檔案見:【snmp】使用MIB Builder生成MIB檔案
注意
1、要有一個index索引節點,但是這個索引的名稱不能為"index",為"index"會報錯,我這裡索引名稱是為"userIdx"
2、一般會設定最後一列為RowStatus列,實際使用時除了RowStatus對應的節點需要設定read-create,其他節點可以隨便設定,但是在MIB Builder工具中設定了一列為read-create,其他列(除索引列)也要設定為read-create,否則會報錯,因此請將表的各個節點均設定為read-create型別,後面我們再修改生成的MIB檔案
生成的UserTable-MIB.my檔案內容如下:
-- -- UserTable-MIB.my -- MIB generated by MG-SOFT Visual MIB Builder Version 6.0 Build 88 -- Thursday, August 06, 2020 at 14:12:31 -- UserTable-MIB DEFINITIONS ::= BEGIN IMPORTS OBJECT-GROUP FROM SNMPv2-CONF enterprises, Integer32, OBJECT-TYPE, MODULE-IDENTITY FROM SNMPv2-SMI; -- 1.3.6.1.4.1.85 myModule MODULE-IDENTITY LAST-UPDATED "202008071136Z" -- August 07, 2020 at 11:36 GMT ORGANIZATION "Organization." CONTACT-INFO "Contact-info." DESCRIPTION "Description." ::= { enterprises 85 } -- -- Node definitions -- -- 1.3.6.1.4.1.85.1 user OBJECT IDENTIFIER ::= { myModule 1 } -- 1.3.6.1.4.1.85.1.1 userTable OBJECT-TYPE SYNTAX SEQUENCE OF UserEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Description." ::= { user 1 } -- 1.3.6.1.4.1.85.1.1.1 userEntry OBJECT-TYPE SYNTAX UserEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Description." INDEX { userIdx } ::= { userTable 1 } UserEntry ::= SEQUENCE { userIdx Integer32, userName Integer32, userAge Integer32, userRowStatus Integer32 } -- 1.3.6.1.4.1.85.1.1.1.1 userIdx OBJECT-TYPE SYNTAX Integer32 (1..1000) MAX-ACCESS read-only STATUS current DESCRIPTION "Description." ::= { userEntry 1 } -- 1.3.6.1.4.1.85.1.1.1.2 userName OBJECT-TYPE SYNTAX Integer32 MAX-ACCESS read-create STATUS current DESCRIPTION "Description." ::= { userEntry 2 } -- 1.3.6.1.4.1.85.1.1.1.3 userAge OBJECT-TYPE SYNTAX Integer32 MAX-ACCESS read-create STATUS current DESCRIPTION "Description." ::= { userEntry 3 } -- 1.3.6.1.4.1.85.1.1.1.4 userRowStatus OBJECT-TYPE SYNTAX Integer32 MAX-ACCESS read-create STATUS current DESCRIPTION "Description." ::= { userEntry 4 } -- 1.3.6.1.4.1.85.1.3 userGroup OBJECT-GROUP OBJECTS { userIdx, userName, userAge, userRowStatus } STATUS current DESCRIPTION "Description." ::= { user 3 } END -- -- UserTable-MIB.my --
修改後的MIB檔案,有中文註釋是修改的地方:
-- -- UserTable-MIB.my -- MIB generated by MG-SOFT Visual MIB Builder Version 6.0 Build 88 -- Thursday, August 06, 2020 at 14:12:31 -- UserTable-MIB DEFINITIONS ::= BEGIN IMPORTS OBJECT-GROUP FROM SNMPv2-CONF enterprises, Integer32, OBJECT-TYPE, MODULE-IDENTITY FROM SNMPv2-SMI -- 去掉原來的分號 DisplayString, RowStatus -- 增加這一行 FROM SNMPv2-TC; -- 增加這一行 -- 1.3.6.1.4.1.85 myModule MODULE-IDENTITY LAST-UPDATED "202008071136Z" -- August 07, 2020 at 11:36 GMT ORGANIZATION "Organization." CONTACT-INFO "Contact-info." DESCRIPTION "Description." ::= { enterprises 85 } -- -- Node definitions -- -- 1.3.6.1.4.1.85.1 user OBJECT IDENTIFIER ::= { myModule 1 } -- 1.3.6.1.4.1.85.1.1 userTable OBJECT-TYPE SYNTAX SEQUENCE OF UserEntry MAX-ACCESS read-create -- 修改型別為read-create STATUS current DESCRIPTION "Description." ::= { user 1 } -- 1.3.6.1.4.1.85.1.1.1 userEntry OBJECT-TYPE SYNTAX UserEntry MAX-ACCESS read-create -- 修改型別為read-create STATUS current DESCRIPTION "Description." INDEX { userIdx } ::= { userTable 1 } UserEntry ::= SEQUENCE { userIdx Integer32, userName OCTET STRING, userAge Integer32, userRowStatus RowStatus -- 修改型別為RowStatus } -- 1.3.6.1.4.1.85.1.1.1.1 userIdx OBJECT-TYPE SYNTAX Integer32 (1..1000) MAX-ACCESS read-only -- 根據實際業務修改型別 STATUS current DESCRIPTION "Description." ::= { userEntry 1 } -- 1.3.6.1.4.1.85.1.1.1.2 userName OBJECT-TYPE SYNTAX OCTET STRING MAX-ACCESS read-write -- 根據實際業務修改型別 STATUS current DESCRIPTION "Description." ::= { userEntry 2 } -- 1.3.6.1.4.1.85.1.1.1.3 userAge OBJECT-TYPE SYNTAX Integer32 MAX-ACCESS read-write -- 根據實際業務修改型別 STATUS current DESCRIPTION "Description." ::= { userEntry 3 } -- 1.3.6.1.4.1.85.1.1.1.4 userRowStatus OBJECT-TYPE SYNTAX RowStatus -- 修改為RowStatus MAX-ACCESS read-create STATUS current DESCRIPTION "Description." ::= { userEntry 4 } -- OBJECT-GROUP可以不要 -- 1.3.6.1.4.1.85.1.3 -- userGroup OBJECT-GROUP -- OBJECTS { userIdx, userName, userAge, userRowStatus } -- STATUS current -- DESCRIPTION -- "Description." -- ::= { user 3 } END -- -- UserTable-MIB.my --
二、使用mib2c命令生成.c和.h檔案
上傳UserTable-MIB.my到linux機器的/usr/local/snmp/share/snmp/mibs目錄下
1、使用如下命令檢視檔案格式是否正確
/usr/local/snmp/bin/snmptranslate -Tp -IR UserTable-MIB::myModule
可以看到userRowStatus節點(也就是RowStatus列)所支援的狀態值
2、執行如下命令生成表格檔案
env MIBS="+/usr/local/snmp/share/snmp/mibs/UserTable-MIB.my" /usr/local/snmp/bin/mib2c -c mib2c.iterate.conf UserTable-MIB::myModule
以上命令執行完後會生成myModule.h和myModule.c檔案
生成的原始碼(myModule.c檔案)
/* * 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 "myModule.h" /** Initializes the myModule module */ void init_myModule(void) { /* * here we initialize all the tables we're planning on supporting */ initialize_table_userTable(); } # Determine the first/last column names /** Initialize the userTable table by defining its contents and how it's structured */ void initialize_table_userTable(void) { const oid userTable_oid[] = { 1, 3, 6, 1, 4, 1, 85, 1, 1 }; const size_t userTable_oid_len = OID_LENGTH(userTable_oid); netsnmp_handler_registration *reg; netsnmp_iterator_info *iinfo; netsnmp_table_registration_info *table_info; DEBUGMSGTL(("myModule:init", "initializing table userTable\n")); reg = netsnmp_create_handler_registration("userTable", userTable_handler, userTable_oid, userTable_oid_len, HANDLER_CAN_RWRITE); table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info); netsnmp_table_helper_add_indexes(table_info, ASN_INTEGER, /* index: userIdx */ 0); table_info->min_column = COLUMN_USERIDX; table_info->max_column = COLUMN_USERROWSTATUS; iinfo = SNMP_MALLOC_TYPEDEF(netsnmp_iterator_info); iinfo->get_first_data_point = userTable_get_first_data_point; iinfo->get_next_data_point = userTable_get_next_data_point; iinfo->table_reginfo = table_info; netsnmp_register_table_iterator(reg, iinfo); netsnmp_inject_handler_before(reg, netsnmp_get_cache_handler (USERTABLE_TIMEOUT, userTable_load, userTable_free, userTable_oid, userTable_oid_len), TABLE_ITERATOR_NAME); /* * Initialise the contents of the table here */ } /* * Typical data structure for a row entry */ struct userTable_entry { /* * Index values */ long userIdx; /* * Column values */ long userIdx; char userName[NNN]; size_t userName_len; char old_userName[NNN]; size_t old_userName_len; long userAge; long old_userAge; long userRowStatus; /* * Illustrate using a simple linked list */ int valid; struct userTable_entry *next; }; struct userTable_entry *userTable_head; /* * create a new row in the (unsorted) table */ struct userTable_entry * userTable_createEntry(long userIdx,) { struct userTable_entry *entry; entry = SNMP_MALLOC_TYPEDEF(struct userTable_entry); if (!entry) return NULL; entry->userIdx = userIdx; entry->next = userTable_head; userTable_head = entry; return entry; } /* * remove a row from the table */ void userTable_removeEntry(struct userTable_entry *entry) { struct userTable_entry *ptr, *prev; if (!entry) return; /* Nothing to remove */ for (ptr = userTable_head, prev = NULL; ptr != NULL; prev = ptr, ptr = ptr->next) { if (ptr == entry) break; } if (!ptr) return; /* Can't find it */ if (prev == NULL) userTable_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 userTable_load(netsnmp_cache * cache, void *vmagic) { FILE *fp; struct userTable_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/userTable", "r"); if (!fp) { return -1; } while (fgets(buf, STRMAX, fp)) { this = SNMP_MALLOC_TYPEDEF(struct userTable_entry); /* * XXX - Unpick 'buf' to extract the individual field values * and then populate the 'this' data structure with them */ this->next = userTable_head; userTable_head = this; /* Iterate helper is fine with unordered lists! */ } fclose(fp); return 0; /* OK */ } void userTable_free(netsnmp_cache * cache, void *vmagic) { struct userTable_entry *this, *that; for (this = userTable_head; this; this = that) { that = this->next; SNMP_FREE(this); /* XXX - release any other internal resources */ } userTable_head = NULL; } /* * Example iterator hook routines - using 'get_next' to do most of the work */ netsnmp_variable_list * userTable_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 = userTable_head; return userTable_get_next_data_point(my_loop_context, my_data_context, put_index_data, mydata); } netsnmp_variable_list * userTable_get_next_data_point(void **my_loop_context, void **my_data_context, netsnmp_variable_list * put_index_data, netsnmp_iterator_info *mydata) { struct userTable_entry *entry = (struct userTable_entry *) *my_loop_context; netsnmp_variable_list *idx = put_index_data; if (entry) { snmp_set_var_typed_integer(idx, ASN_INTEGER, entry->userIdx); 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 userTable table */ int userTable_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 userTable_entry *table_entry; DEBUGMSGTL(("myModule: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 userTable_entry *) netsnmp_extract_iterator_context(request); table_info = netsnmp_extract_table_info(request); switch (table_info->colnum) { case COLUMN_USERIDX: if (!table_entry) { netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHINSTANCE); continue; } snmp_set_var_typed_integer(request->requestvb, ASN_INTEGER, table_entry->userIdx); break; case COLUMN_USERNAME: if (!table_entry) { netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHINSTANCE); continue; } snmp_set_var_typed_value(request->requestvb, ASN_OCTET_STR, table_entry->userName, table_entry->userName_len); break; case COLUMN_USERAGE: if (!table_entry) { netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHINSTANCE); continue; } snmp_set_var_typed_integer(request->requestvb, ASN_INTEGER, table_entry->userAge); break; case COLUMN_USERROWSTATUS: if (!table_entry) { netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHINSTANCE); continue; } snmp_set_var_typed_integer(request->requestvb, ASN_INTEGER, table_entry->userRowStatus); break; default: netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHOBJECT); break; } } break; /* * Write-support */ case MODE_SET_RESERVE1: for (request = requests; request; request = request->next) { table_entry = (struct userTable_entry *) netsnmp_extract_iterator_context(request); table_info = netsnmp_extract_table_info(request); switch (table_info->colnum) { case COLUMN_USERNAME: /* * or possibly 'netsnmp_check_vb_type_and_size' */ ret = netsnmp_check_vb_type_and_max_size(request->requestvb, ASN_OCTET_STR, sizeof(table_entry-> userName)); if (ret != SNMP_ERR_NOERROR) { netsnmp_set_request_error(reqinfo, request, ret); return SNMP_ERR_NOERROR; } break; case COLUMN_USERAGE: /* * or possibly 'netsnmp_check_vb_int_range' */ ret = netsnmp_check_vb_int(request->requestvb); if (ret != SNMP_ERR_NOERROR) { netsnmp_set_request_error(reqinfo, request, ret); return SNMP_ERR_NOERROR; } break; case COLUMN_USERROWSTATUS: ret = netsnmp_check_vb_rowstatus(request->requestvb, (table_entry ? RS_ACTIVE : RS_NONEXISTENT)); if (ret != SNMP_ERR_NOERROR) { netsnmp_set_request_error(reqinfo, request, ret); return SNMP_ERR_NOERROR; } break; default: netsnmp_set_request_error(reqinfo, request, SNMP_ERR_NOTWRITABLE); return SNMP_ERR_NOERROR; } } break; case MODE_SET_RESERVE2: for (request = requests; request; request = request->next) { table_entry = (struct userTable_entry *) netsnmp_extract_iterator_context(request); table_info = netsnmp_extract_table_info(request); switch (table_info->colnum) { case COLUMN_USERROWSTATUS: switch (*request->requestvb->val.integer) { case RS_CREATEANDGO: case RS_CREATEANDWAIT: table_row = userTable_createEntry(, *table_info->indexes->val. integer); if (table_row) { netsnmp_insert_iterator_context(request, table_row); } else { netsnmp_set_request_error(reqinfo, request, SNMP_ERR_RESOURCEUNAVAILABLE); return SNMP_ERR_NOERROR; } } } } break; case MODE_SET_FREE: for (request = requests; request; request = request->next) { table_entry = (struct userTable_entry *) netsnmp_extract_iterator_context(request); table_info = netsnmp_extract_table_info(request); switch (table_info->colnum) { case COLUMN_USERROWSTATUS: switch (*request->requestvb->val.integer) { case RS_CREATEANDGO: case RS_CREATEANDWAIT: if (table_entry && !table_entry->valid) { userTable_removeEntry(table_data, table_row); } } } } break; case MODE_SET_ACTION: for (request = requests; request; request = request->next) { table_entry = (struct userTable_entry *) netsnmp_extract_iterator_context(request); table_info = netsnmp_extract_table_info(request); switch (table_info->colnum) { case COLUMN_USERNAME: memcpy(table_entry->old_userName, table_entry->userName, sizeof(table_entry->userName)); table_entry->old_userName_len = table_entry->userName_len; memset(table_entry->userName, 0, sizeof(table_entry->userName)); memcpy(table_entry->userName, request->requestvb->val.string, request->requestvb->val_len); table_entry->userName_len = request->requestvb->val_len; break; case COLUMN_USERAGE: table_entry->old_userAge = table_entry->userAge; table_entry->userAge = *request->requestvb->val.integer; break; } } /* * Check the internal consistency of an active row */ for (request = requests; request; request = request->next) { table_entry = (struct userTable_entry *) netsnmp_extract_iterator_context(request); table_info = netsnmp_extract_table_info(request); switch (table_info->colnum) { case COLUMN_USERROWSTATUS: switch (*request->requestvb->val.integer) { case RS_ACTIVE: case RS_CREATEANDGO: if ( /* XXX */ ) { netsnmp_set_request_error(reqinfo, request, SNMP_ERR_INCONSISTENTVALUE); return SNMP_ERR_NOERROR; } } } } break; case MODE_SET_UNDO: for (request = requests; request; request = request->next) { table_entry = (struct userTable_entry *) netsnmp_extract_iterator_context(request); table_info = netsnmp_extract_table_info(request); switch (table_info->colnum) { case COLUMN_USERNAME: memcpy(table_entry->userName, table_entry->old_userName, sizeof(table_entry->userName)); memset(table_entry->old_userName, 0, sizeof(table_entry->userName)); table_entry->userName_len = table_entry->old_userName_len; break; case COLUMN_USERAGE: table_entry->userAge = table_entry->old_userAge; table_entry->old_userAge = 0; break; case COLUMN_USERROWSTATUS: switch (*request->requestvb->val.integer) { case RS_CREATEANDGO: case RS_CREATEANDWAIT: if (table_entry && !table_entry->valid) { userTable_removeEntry(table_data, table_row); } } break; } } break; case MODE_SET_COMMIT: for (request = requests; request; request = request->next) { table_entry = (struct userTable_entry *) netsnmp_extract_iterator_context(request); table_info = netsnmp_extract_table_info(request); switch (table_info->colnum) { case COLUMN_USERROWSTATUS: switch (*request->requestvb->val.integer) { case RS_CREATEANDGO: table_entry->valid = 1; /* * Fall-through */ case RS_ACTIVE: table_entry->userRowStatus = RS_ACTIVE; break; case RS_CREATEANDWAIT: table_entry->valid = 1; /* * Fall-through */ case RS_NOTINSERVICE: table_entry->userRowStatus = RS_NOTINSERVICE; break; case RS_DESTROY: userTable_removeEntry(table_data, table_row); } } } break; } return SNMP_ERR_NOERROR; }View Code
需要對myModule.c檔案進行修改,修改後的檔案如下(有中文註釋的地方就是修改的地方)
/* * 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 "myModule.h" /** Initializes the myModule module */ void init_myModule(void) { /* * here we initialize all the tables we're planning on supporting */ initialize_table_userTable(); } // 註釋下面這行 // # Determine the first/last column names /** Initialize the userTable table by defining its contents and how it's structured */ void initialize_table_userTable(void) { const oid userTable_oid[] = { 1, 3, 6, 1, 4, 1, 85, 1, 1 }; const size_t userTable_oid_len = OID_LENGTH(userTable_oid); netsnmp_handler_registration *reg; netsnmp_iterator_info *iinfo; netsnmp_table_registration_info *table_info; DEBUGMSGTL(("myModule:init", "initializing table userTable\n")); reg = netsnmp_create_handler_registration("userTable", userTable_handler, userTable_oid, userTable_oid_len, HANDLER_CAN_RWRITE); table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info); netsnmp_table_helper_add_indexes(table_info, ASN_INTEGER, /* index: userIdx */ 0); table_info->min_column = COLUMN_USERIDX; table_info->max_column = COLUMN_USERROWSTATUS; iinfo = SNMP_MALLOC_TYPEDEF(netsnmp_iterator_info); iinfo->get_first_data_point = userTable_get_first_data_point; iinfo->get_next_data_point = userTable_get_next_data_point; iinfo->table_reginfo = table_info; netsnmp_register_table_iterator(reg, iinfo); netsnmp_inject_handler_before(reg, netsnmp_get_cache_handler (USERTABLE_TIMEOUT, userTable_load, userTable_free, userTable_oid, userTable_oid_len), TABLE_ITERATOR_NAME); /* * Initialise the contents of the table here */ } #define NNN 256 //定義這個巨集,下面這個結構體用到 /* * Typical data structure for a row entry */ struct userTable_entry { /* * Index values */ long userIdx; /* * Column values */ // long userIdx; //註釋掉,上面已經定義了 char userName[NNN]; size_t userName_len; char old_userName[NNN]; size_t old_userName_len; long userAge; long old_userAge; long userRowStatus; /* * Illustrate using a simple linked list */ int valid; struct userTable_entry *next; }; struct userTable_entry *userTable_head; /* * create a new row in the (unsorted) table */ //補全這個函式的引數,其實就是表格中那四列的內容 //這個函式就是新增一行資料的函式,RowStatus列不傳也可以,程式內部會自動處理 struct userTable_entry * userTable_createEntry(long userIdx,char *userName ,size_t userName_len,long userAge) { struct userTable_entry *entry; entry = SNMP_MALLOC_TYPEDEF(struct userTable_entry); if (!entry) return NULL; entry->userIdx = userIdx; snprintf(entry->userName, sizeof(entry->userName), "%s", userName); //將userName資料賦給結構體 entry->userName_len = userName_len; //將userName_len資料賦給結構體 entry->userAge = userAge; //將userAge資料賦值給結構體 entry->next = userTable_head; userTable_head = entry; return entry; } /* * remove a row from the table */ void userTable_removeEntry(struct userTable_entry *entry) { struct userTable_entry *ptr, *prev; if (!entry) return; /* Nothing to remove */ for (ptr = userTable_head, prev = NULL; ptr != NULL; prev = ptr, ptr = ptr->next) { if (ptr == entry) break; } if (!ptr) return; /* Can't find it */ if (prev == NULL) userTable_head = ptr->next; else prev->next = ptr->next; SNMP_FREE(entry); /* XXX - release any other internal resources */ } #define STRMAX 1024 //定義巨集 /* * Example cache handling - set up linked list from a suitable file */ int userTable_load(netsnmp_cache * cache, void *vmagic) { FILE *fp; struct userTable_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/userTable", "r"); if (!fp) { return -1; } while (fgets(buf, STRMAX, fp)) { this = SNMP_MALLOC_TYPEDEF(struct userTable_entry); /* * XXX - Unpick 'buf' to extract the individual field values * and then populate the 'this' data structure with them */ this->next = userTable_head; userTable_head = this; /* Iterate helper is fine with unordered lists! */ } fclose(fp); return 0; /* OK */ } void userTable_free(netsnmp_cache * cache, void *vmagic) { struct userTable_entry *this, *that; for (this = userTable_head; this; this = that) { that = this->next; SNMP_FREE(this); /* XXX - release any other internal resources */ } userTable_head = NULL; } /* * Example iterator hook routines - using 'get_next' to do most of the work */ netsnmp_variable_list * userTable_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 = userTable_head; return userTable_get_next_data_point(my_loop_context, my_data_context, put_index_data, mydata); } netsnmp_variable_list * userTable_get_next_data_point(void **my_loop_context, void **my_data_context, netsnmp_variable_list * put_index_data, netsnmp_iterator_info *mydata) { struct userTable_entry *entry = (struct userTable_entry *) *my_loop_context; netsnmp_variable_list *idx = put_index_data; if (entry) { snmp_set_var_typed_integer(idx, ASN_INTEGER, entry->userIdx); 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 userTable table */ int userTable_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 userTable_entry *table_entry; struct userTable_entry *table_row; //這個變數未定義 int ret; //變數未定義 DEBUGMSGTL(("myModule: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 userTable_entry *) netsnmp_extract_iterator_context(request); table_info = netsnmp_extract_table_info(request); switch (table_info->colnum) { case COLUMN_USERIDX: if (!table_entry) { netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHINSTANCE); continue; } snmp_set_var_typed_integer(request->requestvb, ASN_INTEGER, table_entry->userIdx); break; case COLUMN_USERNAME: if (!table_entry) { netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHINSTANCE); continue; } snmp_set_var_typed_value(request->requestvb, ASN_OCTET_STR, table_entry->userName, table_entry->userName_len); break; case COLUMN_USERAGE: if (!table_entry) { netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHINSTANCE); continue; } snmp_set_var_typed_integer(request->requestvb, ASN_INTEGER, table_entry->userAge); break; case COLUMN_USERROWSTATUS: if (!table_entry) { netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHINSTANCE); continue; } snmp_set_var_typed_integer(request->requestvb, ASN_INTEGER, table_entry->userRowStatus); break; default: netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHOBJECT); break; } } break; /* * Write-support */ case MODE_SET_RESERVE1: for (request = requests; request; request = request->next) { table_entry = (struct userTable_entry *) netsnmp_extract_iterator_context(request); table_info = netsnmp_extract_table_info(request); switch (table_info->colnum) { case COLUMN_USERNAME: /* * or possibly 'netsnmp_check_vb_type_and_size' */ ret = netsnmp_check_vb_type_and_max_size(request->requestvb, ASN_OCTET_STR, sizeof(table_entry-> userName)); if (ret != SNMP_ERR_NOERROR) { netsnmp_set_request_error(reqinfo, request, ret); return SNMP_ERR_NOERROR; } break; case COLUMN_USERAGE: /* * or possibly 'netsnmp_check_vb_int_range' */ ret = netsnmp_check_vb_int(request->requestvb); if (ret != SNMP_ERR_NOERROR) { netsnmp_set_request_error(reqinfo, request, ret); return SNMP_ERR_NOERROR; } break; case COLUMN_USERROWSTATUS: ret = netsnmp_check_vb_rowstatus(request->requestvb, (table_entry ? RS_ACTIVE : RS_NONEXISTENT)); if (ret != SNMP_ERR_NOERROR) { netsnmp_set_request_error(reqinfo, request, ret); return SNMP_ERR_NOERROR; } break; default: netsnmp_set_request_error(reqinfo, request, SNMP_ERR_NOTWRITABLE); return SNMP_ERR_NOERROR; } } break; case MODE_SET_RESERVE2: for (request = requests; request; request = request->next) { table_entry = (struct userTable_entry *) netsnmp_extract_iterator_context(request); table_info = netsnmp_extract_table_info(request); switch (table_info->colnum) { case COLUMN_USERROWSTATUS: switch (*request->requestvb->val.integer) { case RS_CREATEANDGO: case RS_CREATEANDWAIT: table_row = userTable_createEntry(*table_info->indexes->val.integer,"",0,0); //補全,這裡是建立一個新的行 if (table_row) { netsnmp_insert_iterator_context(request, table_row); } else { netsnmp_set_request_error(reqinfo, request, SNMP_ERR_RESOURCEUNAVAILABLE); return SNMP_ERR_NOERROR; } } } } break; case MODE_SET_FREE: for (request = requests; request; request = request->next) { table_entry = (struct userTable_entry *) netsnmp_extract_iterator_context(request); table_info = netsnmp_extract_table_info(request); switch (table_info->colnum) { case COLUMN_USERROWSTATUS: switch (*request->requestvb->val.integer) { case RS_CREATEANDGO: case RS_CREATEANDWAIT: if (table_entry && !table_entry->valid) { userTable_removeEntry(table_row); //多傳了table_data引數,刪除 } } } } break; case MODE_SET_ACTION: for (request = requests; request; request = request->next) { table_entry = (struct userTable_entry *) netsnmp_extract_iterator_context(request); table_info = netsnmp_extract_table_info(request); switch (table_info->colnum) { case COLUMN_USERNAME: memcpy(table_entry->old_userName, table_entry->userName, sizeof(table_entry->userName)); table_entry->old_userName_len = table_entry->userName_len; memset(table_entry->userName, 0, sizeof(table_entry->userName)); memcpy(table_entry->userName, request->requestvb->val.string, request->requestvb->val_len); table_entry->userName_len = request->requestvb->val_len; break; case COLUMN_USERAGE: table_entry->old_userAge = table_entry->userAge; table_entry->userAge = *request->requestvb->val.integer; break; } } /* * Check the internal consistency of an active row */ for (request = requests; request; request = request->next) { table_entry = (struct userTable_entry *) netsnmp_extract_iterator_context(request); table_info = netsnmp_extract_table_info(request); switch (table_info->colnum) { case COLUMN_USERROWSTATUS: switch (*request->requestvb->val.integer) { case RS_ACTIVE: case RS_CREATEANDGO: if ( 0/* 出錯條件 */ ) { netsnmp_set_request_error(reqinfo, request, SNMP_ERR_INCONSISTENTVALUE); return SNMP_ERR_NOERROR; } } } } break; case MODE_SET_UNDO: for (request = requests; request; request = request->next) { table_entry = (struct userTable_entry *) netsnmp_extract_iterator_context(request); table_info = netsnmp_extract_table_info(request); switch (table_info->colnum) { case COLUMN_USERNAME: memcpy(table_entry->userName, table_entry->old_userName, sizeof(table_entry->userName)); memset(table_entry->old_userName, 0, sizeof(table_entry->userName)); table_entry->userName_len = table_entry->old_userName_len; break; case COLUMN_USERAGE: table_entry->userAge = table_entry->old_userAge; table_entry->old_userAge = 0; break; case COLUMN_USERROWSTATUS: switch (*request->requestvb->val.integer) { case RS_CREATEANDGO: case RS_CREATEANDWAIT: if (table_entry && !table_entry->valid) { userTable_removeEntry(table_row); //多傳了table_data引數,刪除 } } break; } } break; case MODE_SET_COMMIT: for (request = requests; request; request = request->next) { table_entry = (struct userTable_entry *) netsnmp_extract_iterator_context(request); table_info = netsnmp_extract_table_info(request); switch (table_info->colnum) { case COLUMN_USERROWSTATUS: switch (*request->requestvb->val.integer) { case RS_CREATEANDGO: table_entry->valid = 1; /* * Fall-through */ case RS_ACTIVE: table_entry->userRowStatus = RS_ACTIVE; break; case RS_CREATEANDWAIT: table_entry->valid = 1; /* * Fall-through */ case RS_NOTINSERVICE: table_entry->userRowStatus = RS_NOTINSERVICE; break; case RS_DESTROY: userTable_removeEntry(table_entry); //修改table_row為table_entry,否則刪除行不成功, 多傳了table_data引數,刪除 } } } break; } return SNMP_ERR_NOERROR; }
三、載入自定義的MIB庫
1、將myModule.h 和修改後的myModule.c檔案複製到linux機器的net-snmp-5.7.1/agent/mibgroup/目錄下
2、如果snmp服務在執行,停止snmp服務
3、在/root/net-snmp-5.7.1目錄下依次執行下面3個命令編譯安裝
./configure --prefix=/usr/local/snmp --with-mib-modules="myModule"
make
make install
四、測試
1、執行/usr/local/snmp/sbin/snmpd -c /usr/local/snmp/etc/snmpd.conf 命令啟動snmp服務
2、執行/usr/local/snmp/bin/snmpwalk -v 2c -c public localhost 1.3.6.1.4.1.85.1.1查看錶格內容,可以看到表裡什麼都沒有
3、新增第一行資料:/usr/local/snmp/bin/snmpset -v 2c -c public localhost 1.3.6.1.4.1.85.1.1.1.4.1 i 4
這個命令表示對錶的第一行的第三列設定值為4,因為第三列為RowStatus型別,所以系統會建立這一行
(表中原本是沒有第一行的,只要對第一行的RowStatus列寫入4就可以建立這一行)
4、修改第一行資料中的userName欄位:/usr/local/snmp/bin/snmpset -v 2c -c public localhost 1.3.6.1.4.1.85.1.1.1.2.1 s harara
5、修改第一行資料中的userAge欄位:/usr/local/snmp/bin/snmpset -v 2c -c public localhost 1.3.6.1.4.1.85.1.1.1.3.1 i 24
6、刪除第1行,對第1行的第4列寫入6即可:/usr/local/snmp/bin/snmpset -v 2c -c public localhost 1.3.6.1.4.1.85.1.1.1.4.1 i 6