2.6内核中SNMP统计信息基本操作

本文介绍Linux 2.6内核中网络SNMP统计数据的处理方式,重点讲解UDP协议的SNMP统计信息操作过程及多CPU环境下数据的一致性保证。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请保持文档的完整性,严禁用于任何商业用途。
msn: yfydz_no1@hotmail.com
来源:http://yfydz.cublog.cn

1. 前言

Linux2.6内核中网络SNMP统计数据的处理方式和2.4相比有了比较大的变化,本文介绍2.6下的SNMP信息的操作过程。
各种协议的SNMP统计方法相同,只是参数有所不同,为篇幅简单,使用UDP的统计信息来说明,因为UDP协议的SNMP统计信息较少,以下内核代码版本为2.6.17.11。

2. 数据结构

MIB库单位项基本结构:
SNMP MIB单位项结构简单,就是一个名称字符串和相应的数组索引值:
/* include/linux/snmp.h */
struct snmp_mib {
char *name;
int entry;
};
下面是为方便代码编辑而定义的两个宏:
#define SNMP_MIB_ITEM(_name,_entry) { \
.name = _name, \
.entry = _entry, \
}
#define SNMP_MIB_SENTINEL { \
.name = NULL, \
.entry = 0, \
}

实例,UDP协议SNMP统计表:
static const struct snmp_mib snmp4_udp_list[] = {
SNMP_MIB_ITEM("InDatagrams", UDP_MIB_INDATAGRAMS),
SNMP_MIB_ITEM("NoPorts", UDP_MIB_NOPORTS),
SNMP_MIB_ITEM("InErrors", UDP_MIB_INERRORS),
SNMP_MIB_ITEM("OutDatagrams", UDP_MIB_OUTDATAGRAMS),
SNMP_MIB_SENTINEL
};

其中各项UDP索引宏定义为:
enum
{
UDP_MIB_NUM = 0,
UDP_MIB_INDATAGRAMS, /* InDatagrams */
UDP_MIB_NOPORTS, /* NoPorts */
UDP_MIB_INERRORS, /* InErrors */
UDP_MIB_OUTDATAGRAMS, /* OutDatagrams */
__UDP_MIB_MAX
};

UDP的SNMP MIB库定义,就是一个保存各统计项的数组,struct snmp_mib结构中的索引项就是索引这个数组的值:
/* include/net/snmp.h */
#define UDP_MIB_MAX __UDP_MIB_MAX
struct udp_mib {
unsigned long mibs[UDP_MIB_MAX];
} __SNMP_MIB_ALIGN__;

对于不同的协议,需要统计的参数和数量各自不同,但定义格式都是一样的,其实写程序时麻烦就在定义这块,定义完后操作都很简单了。

3. SNMP统计操作

3.1 以下宏用来定义各协议的SNMP统计信息
/* include/net/snmp.h */
#define DEFINE_SNMP_STAT(type, name) \
__typeof__(type) *name[2]
#define DECLARE_SNMP_STAT(type, name) \
extern __typeof__(type) *name[2]
#define SNMP_STAT_BHPTR(name) (name[0])
#define SNMP_STAT_USRPTR(name) (name[1])

3.2 SNMP统计操作

以下各宏定义了安全地进行SNMP信息增减操作,保证的多CPU情况下也正确:
/* include/net/snmp.h */
#define SNMP_INC_STATS_BH(mib, field) \
(per_cpu_ptr(mib[0], raw_smp_processor_id())->mibs[field]++)
#define SNMP_INC_STATS_OFFSET_BH(mib, field, offset) \
(per_cpu_ptr(mib[0], raw_smp_processor_id())->mibs[field + (offset)]++)
#define SNMP_INC_STATS_USER(mib, field) \
(per_cpu_ptr(mib[1], raw_smp_processor_id())->mibs[field]++)
#define SNMP_INC_STATS(mib, field) \
(per_cpu_ptr(mib[!in_softirq()], raw_smp_processor_id())->mibs[field]++)
#define SNMP_DEC_STATS(mib, field) \
(per_cpu_ptr(mib[!in_softirq()], raw_smp_processor_id())->mibs[field]--)
#define SNMP_ADD_STATS_BH(mib, field, addend) \
(per_cpu_ptr(mib[0], raw_smp_processor_id())->mibs[field] += addend)
#define SNMP_ADD_STATS_USER(mib, field, addend) \
(per_cpu_ptr(mib[1], raw_smp_processor_id())->mibs[field] += addend)
3.3 UDP协议SNMP定义
UDP统计定义:
/* net/ipv4/udp.h */
DECLARE_SNMP_STAT(struct udp_mib, udp_statistics);
UDP各参数增加定义,通常SNMP统计信息是只增不减的,所以只定义了INC操作而没有DEC操作:
/* net/ipv4/udp.h */
#define UDP_INC_STATS(field) SNMP_INC_STATS(udp_statistics, field)
#define UDP_INC_STATS_BH(field) SNMP_INC_STATS_BH(udp_statistics, field)
#define UDP_INC_STATS_USER(field) SNMP_INC_STATS_USER(udp_statistics, field)
在程序中就直接使用上述宏来增加SNMP统计量即可。


内存分配:
DEFINE_SNMP_STAT等宏定义的是指针,因此要提前进行内存分配:
/* net/ipv4/af_inet.c */
static int __init init_ipv4_mibs(void)
{
......
udp_statistics[0] = alloc_percpu(struct udp_mib);
udp_statistics[1] = alloc_percpu(struct udp_mib);
......

4. SNMP参数显示

一般协议的SNMP参数可通过/proc/net/snmp文件获取,自己也可以定义新的文件获取自己协议的SNMP信息,显示过程就是普通的/proc只读文件显示过程,现在在2.6中通常使用seq流来显示:
/* net/ipv4/proc.c */
......
// 打印参数名称
seq_puts(seq, "\nUdp:");
for (i = 0; snmp4_udp_list[i].name != NULL; i++)
seq_printf(seq, " %s", snmp4_udp_list[i].name);

// 打印参数具体数值
seq_puts(seq, "\nUdp:");
for (i = 0; snmp4_udp_list[i].name != NULL; i++)
seq_printf(seq, " %lu",
fold_field((void **) udp_statistics,
snmp4_udp_list[i].entry));
......

值得注意的是具体参数值不是直接从数组取,而是通过fold_field()函数来读取的,实际上是将各CPU的bottom half和user部分所有统计值之和:
/* net/ipv4/proc.c */
static unsigned long
fold_field(void *mib[], int offt)
{
unsigned long res = 0;
int i;
for_each_possible_cpu(i) {
res += *(((unsigned long *) per_cpu_ptr(mib[0], i)) + offt);
res += *(((unsigned long *) per_cpu_ptr(mib[1], i)) + offt);
}
return res;
}

5. 2.4内核处理方式简介

在2.4内核中,和2.6区别重点在于协议的MIB库定义,定义过程是非常直接的,而2.6中通过宏隐藏的多CPU处理的细节:
/* 2.4.26, include/net/udp.h */
extern struct udp_mib udp_statistics[NR_CPUS*2];
struct udp_mib
{
unsigned long UdpInDatagrams;
unsigned long UdpNoPorts;
unsigned long UdpInErrors;
unsigned long UdpOutDatagrams;
unsigned long __pad[0];
} ____cacheline_aligned;
其他宏操作定义形式上就都是一样的了。

6. 结论

2.6的SNMP操作和2.4最大区别就是掩盖了多CPU处理的细节,在定义时不用带多CPU的相关参数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值