Linux内核分析与驱动编程 Lecture8:网络接口驱动程序
来源
- 文件:lecture8.pdf(55页,文本型PDF)
- 云盘路径:/田浩然上传的资料/0C110_Linux内核分析与驱动编程/lecture8/lecture8.pdf
- 课程:0C110 Linux内核分析与驱动编程(北京大学,lisuke@ss.pku.edu.cn)
- 主题:网络设备驱动程序
核心内容
1. 网络设备 vs 字符/块设备
- 网络接口驱动程序与字符设备、块设备驱动程序有本质不同
- 本次课介绍一个不与真实硬件相关的虚拟网络接口(snull)
2. 设备注册:struct net_device
- 定义在
<linux/netdevice.h> - 必须动态分配:
struct net_device *alloc_netdev(int sizeof_priv, const char *name, void (*setup)(struct net_device *)) - 示例:
snull_devs[0] = alloc_netdev(sizeof(struct snull_priv), "sn%d", snull_init); alloc_etherdev()简化版(定义在<linux/etherdevice.h>),自动使用eth%d命名register_netdev()注册设备到内核
3. 设备初始化
ether_setup(dev);
dev->open = snull_open;
dev->stop = snull_release;
dev->set_config = snull_config;
dev->hard_start_xmit = snull_tx;
dev->do_ioctl = snull_ioctl;
dev->get_stats = snull_stats;
dev->rebuild_header = snull_rebuild_header;
dev->hard_header = snull_header;
dev->tx_timeout = snull_tx_timeout;
dev->watchdog_timeo = timeout;
dev->flags |= IFF_NOARP;
dev->features |= NETIF_F_NO_CSUM;
dev->hard_header_cache = NULL; /* 禁用缓存 */4. 私有数据结构 snull_priv
struct snull_priv {
struct net_device_stats stats; // 统计信息
int status; // 状态
struct snull_packet *ppool;
struct snull_packet *rx_queue; // 接收包队列
int rx_int_enabled;
int tx_packetlen;
u8 *tx_packetdata;
struct sk_buff *skb;
spinlock_t lock;
};通过 netdev_priv() 获取私有数据区。
5. net_device 重要字段
char name[IFNAMSIZ]— 接口名,含%d时 register_netdev 替换为唯一编号unsigned long state— 驱动状态struct net_device *next— 全局接口链表int (*init)(struct net_device *)— 初始化函数(现已少用,推荐在 register 前初始化)unsigned long rmem_end/rmem_start/mem_end/mem_start— 接收/发送内存地址unsigned long base_addr— I/O 基地址unsigned char irq— 中断号unsigned char if_port— 多端口设备当前端口unsigned char dma— DMA 通道
6. 数据包发送 snull_tx()
- 虚拟设备核心行为:将包回环到另一个 snull 接口
- 修改 IP 头第三字节(C类网段翻转),重建 IP 校验和
- 模拟接收中断 + 传输完成中断
- 支持锁死模拟(
lockup参数定时模拟丢包)
7. 中断处理 snull_napi_interrupt()
- NAPI 兼容的中断处理
- 检查
SNULL_RX_INTR→ 调度netif_rx_schedule() - 检查
SNULL_TX_INTR→ 更新统计,释放 skb - 使用
spin_lock/spin_unlock保护
8. 清理工作
void snull_cleanup(void) {
for (i = 0; i < 2; i++) {
if (snull_devs[i]) {
unregister_netdev(snull_devs[i]);
snull_teardown_pool(snull_devs[i]);
free_netdev(snull_devs[i]);
}
}
}9. 课后作业
- 阅读《Linux Device Drivers》第9,10,11,12,13,14,18章
- 编译加载 snull,观察网络设备是否可用
- 思考 snull 可完成的特殊任务
关键概念
alloc_netdev/register_netdev/unregister_netdevether_setup/alloc_etherdevnetdev_priv/net_device_stats- NAPI (
netif_rx_schedule) IFF_NOARP/NETIF_F_NO_CSUMspinlock_t在驱动中的使用
关联
- 与 Lecture 7(字符设备驱动)对比学习
- 与《Linux Device Drivers》第9-14章关联
- snull 源码是理解网络驱动框架的极佳示例