1. 程式人生 > 實用技巧 >【snmp】net-snmp新增自定義MIB(表格)

【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
--
View Code

修改後的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