1、SNMP代理需求
(1) 提供设备相关的信息节点,供SNMP管理端查询,可支持get、get next和walk查询命令。提供SN、WAN口IP、CPU占用率、内存使用率、进程个数、网络接口状态、网络接口当前流量、软件版本信息等节点信息。
(2) 提供对特俗事件到来时的发往SNMP管理端得TRAP告警功能。包括CPU使用率超阈值、内存超阈值、网口流量超阈值、WAN口IP改变、设备重启等告警功能(暂未做)。
提供对snmp v1、v2版本的支持(V3版本将在后面实现)
2、总体设计思想
(1) 开发环境:基于开源软件net-snmp-5.4.2。
(2) MIB库来源:根据功能和节点的定义自行开发。
(3) 程序实现:利用mib2c工具将MIB库转化为代理程序框架,然后基于此框架进行进一步开发。最后将开发的代理程序静态编译进net-snmp框架中,它将注册到net-snmp框架中。注册的方法是分别建立一个文件和头文件,名称明别取为bamboo和bamboo.h,在bamboo中存放自己开发的所有c程序和头文件(如xxx.c和xxx.h),然后在bamboo.h中添加module_require(xxx),并在configure时跟上:—with-mib_modules=”bamboo”来配置Makefile,使之在编译时加载bamboo文件下面的xxx文件(可以有多个xxx文件)。
3、get信息节点的实现,以cpu占用率信息节点为例
(1) 自己编写该节点MIB库,由于eX110只有一个CPU,所以编写一个节点即可:
hr_proc OBJECT-TYPE
SYNTAX Integer32
MAX-ACCESS read-only
STATUS current
DESCRIPTION "cpu usage"
::= { my_cpu 2 }
(2) 利用mib2c工具mib2c_old-api.conf将该mib库转化为get信息节点的程序框架,然后基于该框架,添加需要实现的功能,部分代码如下:
/*由系统基于MIB库生成的与节点相关的信息的结构体*/
#define HRPROC_LOAD 2
struct variable4 hrproc_variables[] = {
{HRPROC_LOAD, ASN_INTEGER, RONLY, var_hrproc, 3, {1, 2, 768}}
};
oid hrproc_variables_oid[] = { 1, 3, 6, 1, 2, 1, 25, 3, 3 };
/*由系统生成的该节点初始化函数,在该初始化函数中注册了针对该节点的处理函数*/
void init_hr_proc(void)
{
REGISTER_MIB("bamboo/hr_proc", hrproc_variables, variable4,
hrproc_variables_oid);
}
/*
* header_hrproc:自己编写实现的函数,该函数将已注册到net-snmp的节点信息和管理端与访问的节点信息作比较。由于规定第一个CPU是用节点编号768开始,并且eX110只有一个CPU,即要求该节点为1.3.6.1.2.1.25.3.3.1.2.768 ,所以将netsnmp 中提供head_generic()函数中将已注册节点最后加“o”这步去掉, 直接将注册的该节点和跟管理端欲访问的节点作对比。
* vp IN - 指向已注册节点数组的指针
* name IN/OUT - 指向管理端欲访问节点的指针
* length IN/OUT - length of IN/OUT oid's
* exact IN - TRUE if an exact match was requested
* var_len OUT - length of variable or 0 if function returned
* write_method
*/
Int header_hrproc(struct variable *vp,
oid * name,
size_t * length,
int exact, size_t * var_len, WriteMethod ** write_method)
{
oid newname[MAX_OID_LEN];
int result;
memcpy((char *) newname, (char *) vp->name,
(int) vp->namelen * sizeof(oid));
//newname[vp->namelen] = 0; //不需要在已注册节点后加“0”.
result = snmp_oid_compare(name, *length, newname, vp->namelen);
if ((exact && (result != 0)) || (!exact && (result >= 0)))
return (MATCH_FAILED);
memcpy((char *) name, (char *) newname,
((int) vp->namelen) * sizeof(oid));
*length = vp->namelen;
*write_method = 0;
*var_len = sizeof(long); /* default to 'long' results */
return (MATCH_SUCCEEDED);
}
/* System specific implementation functions 注册的处理函数*/
u_char *var_hrproc(struct variable * vp,
oid * name,
size_t * length,
int exact, size_t * var_len, WriteMethod ** write_method)
{
int proc_idx;
static unsigned char string[SPRINT_MAX_LEN];
FILE *file;
proc_idx =
header_hrproc(vp, name, length, exact, var_len, write_method);
if (proc_idx == MATCH_FAILED)
return NULL;
switch (vp->magic) {
case HRPROC_LOAD:
get_cpu_usage(cpu_usage); //获取CPU使用率
snprintf(string, sizeof(string), cpu_usage); /* ++by Bamboo */
long_return = atoi(string);
if ((file = fopen("/var/run/snmp.log", "w")) == NULL)
return;
fprintf(file, "string is:%s , value is :%d/n", string, long_return);
fclose(file);
return (u_char *) &long_return; //返回long_return
default:
DEBUGMSGTL(("host/hr_proc", "unknown sub-id %d in var_hrproc/n",
vp->magic));
}
return NULL;
}
/*get cpu usage information for file loadavg5 and save it in string[] */
void
get_cpu_usage(char *string)
{
FILE *file;
char *str;
int i = 0;
char tmp[16];
if ((file = fopen("/proc/loadavg5", "r")) == NULL)
return;
fread(tmp, 1, sizeof(tmp), file);
fclose(file);
str = tmp;
while (*str != '/n') {
if (*str == '.') {
str++;
}
else
*(string + i++) = *str++;
}
*(string + i) = '/0';
return;
}
3、trap告警的实现,以cpu使用率超标Trap的实现为例
(1) 该Trap包需包含信息:a、cpuoverflow 的trap节点1.3.6.1.4.1.3902.151.11.10.3.5.1(自己定义)
b、携带的其他信息携带变量:
SN oid :1.3.6.1.2.1.47.1.1.1.1.11,和对应的值
CPU使用率oid:1.3.6.1.2.1.25.3.3.1.2,和其对应的值
阈值oid: 1.3.6.1.4.1.3902.151.11.10.3.3.9.1,和其对应的值
(2) 实现方法:参考示例notfication.c,并进行信号注册函数的修改,最终实现自己的功能。
(3) 程序实现:
/*cpu超阈值告警初始化,即注册新号处理函数,每30秒执行一次*/
Void init_cpuoverflow(void)
{
snmp_alarm_register(30, /* seconds */
SA_REPEAT, /* repeat (every 30 seconds). */
send_cpuoverflow, /* our callback */
NULL /* no callback data needed */
);
}
/*要调用的回调函数的实现*/
Void send_cpuoverflow(unsigned int clientreg, void *clientarg)
{
/*
* define the OID for the cpuoverflow we're going to send
* NET-SNMP-EXAMPLES-MIB::netSnmpExampleHeartbeatNotification
*/
FILE *file;
oid cpuoverflow_oid[] =
{ 1, 3, 6, 1, 4, 1, 3902, 151, 11, 10, 3, 5, 1};
size_t cpuoverflow_oid_len = OID_LENGTH(cpuoverflow_oid);
static u_long count = 0;
u_char sn[64];
u_char cpu_usage_str[8];
unsigned cpu_usage;
u_char cpu_threshold_str[8];
get_cpu_usage(cpu_usage_str);
cpu_usage = atoi(cpu_usage_str);
snprintf(cpu_threshold_str, sizeof(cpu_threshold_str), nvram_safe_get("cpu_threshold"));
/*if cpu percentage is small than threshold, do not trap*/
if (cpu_usage < atoi(cpu_threshold_str)) //若CPU没超阈值,则返回。
return;
snprintf(sn, sizeof(sn), nvram_safe_get("dev_sn"));
/*
* In the cpuoverflow, we have to assign our cpuoverflow OID to
* the snmpTrapOID.0 object. Here is it's definition.
*/
oid objid_snmptrap[] = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0 };
size_t objid_snmptrap_len = OID_LENGTH(objid_snmptrap);
oid devicesn_oid[] = { 1, 3, 6, 1, 2, 1, 47, 1, 1, 1, 1, 11, 1 };
size_t devicesn_oid_len = OID_LENGTH(devicesn_oid);
oid hrproc_load_oid[] = { 1, 3, 6, 1, 2, 1, 25, 3, 3, 1, 2, 768 };
size_t hrproc_load_oid_len = OID_LENGTH(hrproc_load_oid);
oid cpu_threshold_oid[] = { 1, 3, 6, 1, 4, 1, 3902, 151, 11, 10, 3, 3, 9, 1, 0 };
size_t cpu_threshold_oid_len = OID_LENGTH(cpu_threshold_oid);
/* here is where we store the variables to be sent in the trap */
netsnmp_variable_list *cpuoverflow_vars = NULL; //所有的绑定变量都将保存在该链表中
/*add in the trap definition object 依次手动加载要绑定的变量到链表中*/
snmp_varlist_add_variable(&cpuoverflow_vars,
objid_snmptrap, objid_snmptrap_len,
ASN_OBJECT_ID,
(u_char *) cpuoverflow_oid,
cpuoverflow_oid_len * sizeof(oid));
snmp_varlist_add_variable(&cpuoverflow_vars,
devicesn_oid, devicesn_oid_len,
ASN_OCTET_STR,
sn,
strlen(sn));
snmp_varlist_add_variable(&cpuoverflow_vars,
hrproc_load_oid, hrproc_load_oid_len,
ASN_INTEGER,
(u_char *)&cpu_usage,
sizeof(cpu_usage));
snmp_varlist_add_variable(&cpuoverflow_vars,
cpu_threshold_oid, cpu_threshold_oid_len,
ASN_OCTET_STR,
cpu_threshold_str,
strlen(cpu_threshold_str));
++count; //该trap每执行一次,计数器加1
send_v2trap(cpuoverflow_vars); //发送snmpv2 trap
/* free the created cpuoverflow variable list */
snmp_free_varbind(cpuoverflow_vars);
}