一个用于统计接收数据包数量和大小的Linux内核驱动
本项目实现了一个简单的虚拟网络设备驱动,专门用于统计通过该设备的数据包数量和大小。这个驱动不实际传输数据,而是专注于数据包的监控和统计功能,是学习Linux网络设备驱动开发的绝佳示例。
通过这个项目,你将学习到如何创建网络设备接口、处理数据包接收、维护统计信息以及通过sysfs接口暴露内核数据。
struct pktcnt_priv {
struct net_device *dev;
unsigned long packet_count;
unsigned long total_bytes;
struct device *device;
};
这个结构体保存了我们的网络设备实例和统计信息:
dev: 指向关联的网络设备结构体packet_count: 接收到的数据包计数器total_bytes: 接收到的总字节数device: 关联的设备结构体
static int pktcnt_rx(struct sk_buff *skb, struct net_device *dev,
struct packet_type *pt, struct net_device *orig_dev)
{
struct pktcnt_priv *priv = netdev_priv(dev);
// 更新统计信息
priv->packet_count++;
priv->total_bytes += skb->len;
// 释放SKB(因为我们只是统计,不实际处理)
kfree_skb(skb);
return NET_RX_SUCCESS;
}
static int pktcnt_init(struct net_device *dev)
{
struct pktcnt_priv *priv = netdev_priv(dev);
// 初始化私有数据
priv->dev = dev;
priv->packet_count = 0;
priv->total_bytes = 0;
// 设置设备参数
ether_setup(dev);
dev->netdev_ops = &pktcnt_netdev_ops;
// 随机MAC地址
eth_hw_addr_random(dev);
return 0;
}
通过SysFS,我们可以轻松地从用户空间访问驱动统计信息:
static ssize_t packet_count_show(struct device *d,
struct device_attribute *attr, char *buf)
{
struct pktcnt_priv *priv = netdev_priv(to_net_dev(d));
return sprintf(buf, "%lu\n", priv->packet_count);
}
static ssize_t total_bytes_show(struct device *d,
struct device_attribute *attr, char *buf)
{
struct pktcnt_priv *priv = netdev_priv(to_net_dev(d));
return sprintf(buf, "%lu\n", priv->total_bytes);
}
// 定义设备属性
static DEVICE_ATTR_RO(packet_count);
static DEVICE_ATTR_RO(total_bytes);
| 函数指针 | 功能描述 |
|---|---|
ndo_init |
设备初始化 |
ndo_uninit |
设备卸载清理 |
ndo_open |
打开设备 |
ndo_stop |
关闭设备 |
ndo_start_xmit |
数据包发送处理 |
obj-m += pktcnt.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
# 编译模块
make
# 加载模块
sudo insmod pktcnt.ko
# 查看系统日志
dmesg | tail
# 查看网络接口
ip link show
驱动加载后,可以通过以下方式测试和使用:
ip link show查看新创建的网络接口ifconfig pktcnt0 up激活接口ping -I pktcnt0 127.0.0.1cat /sys/class/net/pktcnt0/packet_countcat /sys/class/net/pktcnt0/total_bytes提示: 由于这是一个虚拟设备,发送到该设备的数据包不会真正传输到网络,但会被驱动统计。
进阶挑战: 尝试修改驱动,使其能够统计特定协议(如TCP、UDP或ICMP)的数据包数量和大小。