0.环境
 0.1 编译net-snmp
      cd net-snmp-5.7.2
      ./configure --prefix=/usr/local/snmp
BEGIN failed--compilation aborted at Makefile.PL line 1.
        make: *** [perlmakefiles] Error 2      
         
     yum install cpan -y
     make && make install
     /usr/local/snmp/sbin/snmpd  启动
     
 0.2 直接安装(本文采用直接安装的方式)
     yum install -y net-snmp, net-snmp-devel,net-snmp-perl,net-snmp-utils
    vim /etc/snmp/snmpd.conf    
         master agentx  
         rocommunity public  
         rwcommunity public
     service snmpd restart
     
     service snmpd restart
    
 1.验证
 1.1 snmpd服务
     vim /etc/snmp/snmpd.conf    
         master agentx  
         rocommunity public  
         rwcommunity public
     service snmpd restart   
     
 1.2 启动编写的子代理程序:
   ./snmp_agent_mib &
   提示NET-SNMP version 5.9.3 AgentX subagent connected
   
 1.3 mib查询  
   1.3.1  验证方式1:
   
       验证mib文件是否有错(LINUO-ATCA-BOARD-STATUS-MIB.txt):
        snmptranslate -Tp -IR LINUO-ATCA-BOARD-STATUS-MIB::atcaModule  //解析出来说明mib文件没有语法错误之类的
         
         snmpget -v2c -c public localhost 1.3.6.1.4.1.12001.5.1.0
                   SNMPv2-SMI::enterprises.12001.5.1.0 = Gauge32: 2
         
         snmpget -v2c -c public localhost 1.3.6.1.4.1.12001.5.5.1.0
                   SNMPv2-SMI::enterprises.12001.5.5.1.0 = Gauge32: 3
  
   1.3.2 验证方式2:
        安装mib-browse 加载LINUO-ATCA-BOARD-STATUS-MIB.txt后进行查询
 2.mib文件
-- LINUO-ATCA-BOARD-STATUS-MIB.my
 LINUO-ATCA-BOARD-STATUS-MIB DEFINITIONS ::= BEGIN
    IMPORTS
         OBJECT-GROUP, MODULE-COMPLIANCE, NOTIFICATION-GROUP
             FROM SNMPv2-CONF
         enterprises, OBJECT-TYPE, MODULE-IDENTITY, Unsigned32
             FROM SNMPv2-SMI
         DisplayString
             FROM SNMPv2-TC;
-- Module Identity
 -- OID: 1.3.6.1.4.1.12001
     atcaModule MODULE-IDENTITY
         LAST-UPDATED "202310010000Z"  -- Update with actual timestamp
         ORGANIZATION
             "LINUO Corporation"
         CONTACT-INFO
             "Postal: LINUO Corp\nEmail: support@linuo.com"
         DESCRIPTION
             "MIB for ATCA Board Status Monitoring."
         ::= { enterprises 12001 }  -- 1.3.6.1.4.1.12001
-- Top-level OID structure
     linuoAtca OBJECT IDENTIFIER ::= { atcaModule 5 }  -- 1.3.6.1.4.1.12001.5
-- Node 1: atcaCollectionStatus (Unsigned32)
 -- OID: 1.3.6.1.4.1.12001.5.1
     atcaCollectionStatus OBJECT-TYPE
         SYNTAX      Unsigned32
         MAX-ACCESS  read-only
         STATUS      current
         DESCRIPTION
             "Status of ATCA board collection."
         ::= { linuoAtca 1 }
-- Subtree for chassis info
     atcaChassis OBJECT IDENTIFIER ::= { linuoAtca 5 }  -- 1.3.6.1.4.1.12001.5.5
-- Node 2: atcaBoardInfoIndex (Unsigned32)
 -- OID: 1.3.6.1.4.1.12001.5.5.1
     atcaBoardInfoIndex OBJECT-TYPE
         SYNTAX      Unsigned32
         MAX-ACCESS  read-only
         STATUS      current
         DESCRIPTION
             "Index identifier for ATCA board chassis information."
         ::= { atcaChassis 1 }
END
3.代码(为了方便贴上来集中在一个文件中)
/* add by zhuwei 2025/3/18
  *
  * 安装依赖库(如 Net-SNMP):yum install net-snmp net-snmp-utils
  *                            yum install net-snmp-devel  //相关头文件
  * 编译:gcc -o snmp_agent snmp_agent.c -lnetsnmpagent -lnetsnmphelpers -lnetsnmpmibs -lnetsnmp   //相关库在/usr/lib64
  * 配置文件(/etc/snmp/snmpd.conf):
 * 启动 Agent:./snmp_agent_mib
  * 客户端测试:snmpget -v2c -c public localhost 1.3.6.1.4.1.12001.5.1.0
  * 查看调试日志:net-snmp-config --log-file   
  *               tail -f /var/log/snmpd.log
  * 
  */
#include <stdio.h>
 #include <stdlib.h>
 #include <net-snmp/net-snmp-config.h>  // 必须首先包含
 #include <net-snmp/types.h>            // 定义 oid、netsnmp_container 等
 #include <net-snmp/library/tools.h>    // 提供基础工具函数
 #include <net-snmp/library/container.h>
 #include <net-snmp/agent/net-snmp-agent-includes.h>
 #include <net-snmp/net-snmp-includes.h>
extern int netsnmp_running;
const char *app_name = "snmp_agent_mib";
 static int reconfig = 0;
 // 定义 atcaCollectionStatus 的 OID
  const oid atcaCollectionStatus_oid[] = { 1, 3, 6, 1, 4, 1, 12001, 5, 1 };
// 定义 atcaBoardInfoIndex 的 OID
 const oid atcaBoardInfoIndex_oid[] = { 1, 3, 6, 1, 4, 1, 12001, 5, 5, 1 };
#ifdef __GNUC__
     #define UNUSED __attribute__((unused))
 #else
     #define UNUSED
 #endif
 RETSIGTYPE stop_server(UNUSED int a) 
 {
     puts("捕捉到信号 SIGTERM/SIGINT");
     netsnmp_running = 0;
 }
#ifdef SIGHUP
 RETSIGTYPE hup_handler(int sig)
 {
     puts("捕捉到信号 SIGHUP");
     reconfig = 1;
     signal(SIGHUP, hup_handler);
 }
 #endif
 void reg_sig()
 {
 #ifdef SIGTERM
     signal(SIGTERM, stop_server);
 #endif
 #ifdef SIGINT
     signal(SIGINT, stop_server);
 #endif
 #ifdef SIGHUP
     signal(SIGHUP, hup_handler);
 #endif
 }
int handle_atcaCollectionStatus(
     netsnmp_mib_handler *handler,
     netsnmp_handler_registration *reginfo,
     netsnmp_agent_request_info *reqinfo,
     netsnmp_request_info *requests
 );
 int handle_atcaBoardInfoIndex(
     netsnmp_mib_handler *handler,
     netsnmp_handler_registration *reginfo,
     netsnmp_agent_request_info *reqinfo,
     netsnmp_request_info *requests
 );
 void register_oids() 
 {
     netsnmp_handler_registration *reg;
    // 注册 atcaCollectionStatus
     reg = netsnmp_create_handler_registration(
         "atcaCollectionStatus",
         handle_atcaCollectionStatus, // 回调函数
         atcaCollectionStatus_oid,
         OID_LENGTH(atcaCollectionStatus_oid),
         HANDLER_CAN_RONLY
     );
     
     if(MIB_REGISTERED_OK != netsnmp_register_scalar(reg))
     {
         printf("atcaCollectionStatus register fail \n");
     }
    // 注册 atcaBoardInfoIndex(类似逻辑)
     reg = netsnmp_create_handler_registration(
         "atcaBoardInfoIndex",
         handle_atcaBoardInfoIndex, // 回调函数
         atcaBoardInfoIndex_oid,
         OID_LENGTH(atcaBoardInfoIndex_oid),
         HANDLER_CAN_RONLY
     );
    if(MIB_REGISTERED_OK != netsnmp_register_scalar(reg))
     {
         printf("atcaBoardInfoIndex register fail \n");
     }
 }
 unsigned int read_hardware_status() {
     // 通过 ioctl 或内存映射读取硬件寄存器
    // int fd = open("/dev/atca_device", O_RDONLY);
     unsigned int status = 2;
     //ioctl(fd, ATCA_GET_STATUS, &status);
    // close(fd);
     return status;
 }
int handle_atcaCollectionStatus(
     netsnmp_mib_handler *handler,
     netsnmp_handler_registration *reginfo,
     netsnmp_agent_request_info *reqinfo,
     netsnmp_request_info *requests
 ) {
     unsigned int status = 0;
     switch (reqinfo->mode) {
         case MODE_GET:
             // 从设备读取数据(示例值)
             status = read_hardware_status(); // 自定义数据采集函数
             snmp_set_var_typed_value(
                 requests->requestvb,
                 ASN_UNSIGNED, // 数据类型与 MIB 一致
                 &status,
                 sizeof(status)
             );
             break;
         default:
             // 不支持的操作(如 SET)
             return SNMP_ERR_GENERR;
     }
     return SNMP_ERR_NOERROR;
 }
 unsigned int read_hardware_index() {
     // 通过 ioctl 或内存映射读取硬件寄存器
     //int fd = open("/dev/atca_device", O_RDONLY);
     unsigned int status = 3;
     //ioctl(fd, ATCA_GET_STATUS, &status);
     //close(fd);
     return status;
 }
 int handle_atcaBoardInfoIndex(
     netsnmp_mib_handler *handler,
     netsnmp_handler_registration *reginfo,
     netsnmp_agent_request_info *reqinfo,
     netsnmp_request_info *requests
 ) {
     unsigned int status = 0;
     switch (reqinfo->mode) {
         case MODE_GET:
             // 从设备读取数据(示例值)
             status = read_hardware_index(); // 自定义数据采集函数
             snmp_set_var_typed_value(
                 requests->requestvb,
                 ASN_UNSIGNED, // 数据类型与 MIB 一致
                 &status,
                 sizeof(status)
             );
             break;
         default:
             // 不支持的操作(如 SET)
             return SNMP_ERR_GENERR;
     }
     return SNMP_ERR_NOERROR;
 }
static void usage(const char *prog)
 {
     fprintf(stderr,
             "USAGE: %s [OPTIONS]\n"
             "\n"
             "OPTIONS:\n", prog);
    fprintf(stderr,
             "  -d\t\t\tdump all traffic\n"
             "  -D TOKEN[,...]\tturn on debugging output for the specified "
             "TOKENs\n"
             "\t\t\t   (ALL gives extremely verbose debugging output)\n"
             "  -f\t\t\tDo not fork() from the calling shell.\n"
             "  -h\t\t\tdisplay this help message\n"
             "  -H\t\t\tdisplay a list of configuration file directives\n"
             "  -L LOGOPTS\t\tToggle various defaults controlling logging:\n");
     snmp_log_options_usage("\t\t\t  ", stderr);
 #ifndef DISABLE_MIB_LOADING
     fprintf(stderr,
             "  -m MIB[:...]\t\tload given list of MIBs (ALL loads "
             "everything)\n"
             "  -M DIR[:...]\t\tlook in given list of directories for MIBs\n");
 #endif /* DISABLE_MIB_LOADING */
 #ifndef DISABLE_MIB_LOADING
     fprintf(stderr,
             "  -P MIBOPTS\t\tToggle various defaults controlling mib "
             "parsing:\n");
     snmp_mib_toggle_options_usage("\t\t\t  ", stderr);
 #endif /* DISABLE_MIB_LOADING */
     fprintf(stderr,
             "  -v\t\t\tdisplay package version number\n"
             "  -x TRANSPORT\tconnect to master agent using TRANSPORT\n");
     exit(1);
 }
static void version(void)
 {
     fprintf(stderr, "NET-SNMP version: %s\n", netsnmp_get_version());
     exit(0);
 }
 int main (int argc, char **argv)
 {
     int arg;
     char* cp = NULL;
     int dont_fork = 0, do_help = 0;
    while ((arg = getopt(argc, argv, "dD:fhHL:"
     #ifndef DISABLE_MIB_LOADING
                        "m:M:"
     #endif /* DISABLE_MIB_LOADING */
                        "n:"
     #ifndef DISABLE_MIB_LOADING
                        "P:"
     #endif /* DISABLE_MIB_LOADING */
                        "vx:")) != EOF) 
     {
         switch (arg) {
         case 'd':
           
           //netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_LOG_FILE, "/var/log/snmpd.log");
           //netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_DEBUG_LEVEL, 3);
           netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,NETSNMP_DS_LIB_DUMP_PACKET, 1);
           
           break;
        case 'D':
           debug_register_tokens(optarg);
           snmp_set_do_debugging(1);
           break;
        case 'f':
           dont_fork = 1;
           break;
        case 'h':
           usage(argv[0]);
           break;
        case 'H':
           do_help = 1;
           break;
        case 'L':
           if (snmp_log_options(optarg, argc, argv) < 0) {
             exit(1);
           }
           break;
    #ifndef DISABLE_MIB_LOADING
         case 'm':
           if (optarg != NULL) {
             setenv("MIBS", optarg, 1);
           } else {
             usage(argv[0]);
           }
           break;
        case 'M':
           if (optarg != NULL) {
             setenv("MIBDIRS", optarg, 1);
           } else {
             usage(argv[0]);
           }
           break;
     #endif /* DISABLE_MIB_LOADING */
        case 'n':
           if (optarg != NULL) {
             app_name = optarg;
             netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
                                   NETSNMP_DS_LIB_APPTYPE, app_name);
           } else {
             usage(argv[0]);
           }
           break;
    #ifndef DISABLE_MIB_LOADING
         case 'P':
           cp = snmp_mib_toggle_options(optarg);
           if (cp != NULL) {
             fprintf(stderr, "Unknown parser option to -P: %c.\n", *cp);
             usage(argv[0]);
           }
           break;
     #endif /* DISABLE_MIB_LOADING */
        case 'v':
           version();
           break;
        case 'x':
           if (optarg != NULL) {
             netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID,
                                   NETSNMP_DS_AGENT_X_SOCKET, optarg);
           } else {
             usage(argv[0]);
           }
           break;
        default:
           fprintf(stderr, "invalid option: -%c\n", arg);
           usage(argv[0]);
           break;
         }
     }
     if (do_help) 
     {
       netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
                            NETSNMP_DS_AGENT_NO_ROOT_ACCESS, 1);
     }
     else
     {    
         netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,NETSNMP_DS_AGENT_ROLE, 1);
#if 0
         if (!dont_fork) 
         {
             if (netsnmp_daemonize(1, snmp_stderrlog_status()) != 0)
                 exit(1);
         }            
 #endif         
         SOCK_STARTUP;
     }
     
     init_agent(app_name);
     
     register_oids();
     
     //load app_name.conf
     init_snmp(app_name);
     
     
     if (do_help) 
     {
         fprintf(stderr, "Configuration directives understood:\n");
         read_config_print_usage("  ");
         exit(0);
     }    
     
     netsnmp_running = 1;
     reg_sig();    
     
     while(netsnmp_running) 
     {
         if (reconfig) 
         {
             free_config();
             read_configs();
             reconfig = 0;
         }
         agent_check_and_process(1);
     }    
    snmp_shutdown(app_name);
     
     shutdown_agent();
     
     SOCK_CLEANUP;
     
     exit(0);
     
 }
 4.Makefile
# Makefile for SNMP Agent (snmp_agent_mib)
# Compiler and flags
 CC = gcc
 CFLAGS = -g -Wall -I/usr/include/net-snmp
 LDFLAGS += -L/usr/local/lib -Wl,-rpath=/usr/local/lib
 LDFLAGS += -lnetsnmpagent -lnetsnmphelpers -lnetsnmpmibs -lnetsnmp
# Targets
 TARGET = snmp_agent_mib
 SRC = snmp_agent_mib.c
all: $(TARGET)
$(TARGET): $(SRC)
     $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
clean:
     rm -f $(TARGET)
.PHONY: all clean
5.代码直接拷贝编译运行即能使用
需要set的tx可以自行添加.