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可以自行添加.