1. 课程导论:网卡驱动与协议栈的关系

1.1 网卡驱动与协议栈的协作模型

在 Linux 网络子系统中,网卡驱动与协议栈通过 sk_buff(套接字缓冲区)结构体进行数据交换。驱动负责物理层与数据链路层的收发,协议栈负责网络层及以上的封装、路由与调度。两者之间通过 net_device 结构体进行抽象绑定,形成完整的发包/收包流水线。

核心概念:网卡驱动是协议栈与物理硬件之间的桥梁,sk_buff 是贯穿整个流程的数据载体。
网卡驱动与协议栈协作架构 应用层 socket / sendmsg 协议栈 TCP/UDP → IP → 路由 邻居子系统 ARP / NDISC 流量控制 (qdisc) 队列调度 / 整形 网卡驱动 ndo_start_xmit 物理网卡硬件 sk_buff 是数据载体 贯穿应用层 → 硬件 net_device 是抽象接口 驱动注册 ndo_start_xmit 协议栈调用 dev_queue_xmit 触发队列调度

1.2 数据包从应用到网线的完整旅程

一次典型的网络发包流程,从用户态应用程序调用 send() 开始,到数据帧从网卡物理端口发出为止,共经历 7 个关键阶段:

阶段 所在层级 核心函数/机制 关键数据结构
1. 系统调用 应用层 → 内核 __sys_sendto() struct msghdr
2. 传输层封装 协议栈 tcp_sendmsg() / udp_sendmsg() struct sk_buff
3. 网络层路由 协议栈 ip_output() / ip_finish_output() struct rtable
4. 邻居解析 邻居子系统 neigh_output() struct neighbour
5. 队列调度 流量控制层 dev_queue_xmit() → qdisc 入队 struct Qdisc
6. 驱动发送 网卡驱动 ndo_start_xmit() struct net_device
7. 硬件发送 物理层 DMA 传输 / MAC 发送 TX 描述符环
关键路径:从 send() 到 ndo_start_xmit() 之间,sk_buff 会经历多次克隆、分片和排队。理解 sk_buff 的引用计数管理是避免内存泄漏的核心。
数据包从应用到网线的完整旅程 ① 系统调用 send() → __sys_sendto() ② 传输层封装 TCP/UDP 头 + 数据 ③ 网络层路由 IP 头 + 路由查找 ④ 邻居解析 ARP / ND 表查找 ⑤ 队列调度 qdisc 入队/出队 ⑥ 驱动发送 ndo_start_xmit() ⑦ 硬件发送 DMA → MAC → PHY sk_buff 在此过程中 不断被封装、克隆、排队 驱动通过 TX 描述符环 将 sk_buff 数据映射到 DMA 缓冲区供硬件发送

1.3 课程目标与前置知识

课程目标

  • 理解 sk_buff 核心机制:掌握 sk_buff 的结构布局、头指针操作、数据克隆与共享、引用计数管理。
  • 掌握协议栈发包路径:从 send() 系统调用到 ndo_start_xmit() 的完整代码流程。
  • 精通队列调度算法:深入分析 pfifo_fast、HTB、TBF、FQ_Codel 等 qdisc 的入队/出队逻辑。
  • 驱动开发实战:编写或修改网卡驱动的 ndo_start_xmit() 回调,处理 TX 完成中断与环形缓冲区。
  • 性能调优:分析发包瓶颈,利用 perf、ftrace、tc 等工具进行诊断与优化。

前置知识要求

知识领域 具体要求 推荐资料
C 语言与内核编程 熟悉指针、链表、内存分配;了解内核模块编写 《Linux Device Drivers》第 1-3 章
Linux 网络基础 理解 TCP/IP 协议栈分层;会用 socket API 《TCP/IP Illustrated》Vol.1
内核数据结构 了解 list_head、hlist、rcu 等基础结构 内核源码 include/linux/list.h
驱动开发入门 了解 pci_driver、net_device_ops 注册流程 内核源码 drivers/net/ethernet/
注意:本课程涉及大量内核源码分析,建议读者具备至少 6 个月以上的 Linux 内核编程经验。如果对 spin_lock / RCU 等同步机制不熟悉,建议先阅读《Linux 内核设计与实现》第 9-10 章。

1.4 课程章节概览

本课程共 30 章,分为 5 个模块:

模块 章节范围 核心内容
基础篇 第 1-6 章 sk_buff 结构详解、协议栈发包路径、邻居子系统
队列调度篇 第 7-14 章 qdisc 框架、pfifo_fast/HTB/TBF/FQ_Codel 源码分析
驱动开发篇 第 15-22 章 ndo_start_xmit 实现、TX 环形缓冲区、NAPI 与中断
性能调优篇 第 23-27 章 perf/ftrace 分析、零拷贝、XDP 发包、多队列优化
实战项目篇 第 28-30 章 自定义 qdisc 编写、网卡驱动移植、发包延迟优化实战
学习建议:每章都配有可运行的实验代码和 trace 脚本。建议在 qemu + buildroot 搭建的实验环境中动手验证,不要只看源码。
课程模块结构图 基础篇 第1-6章 sk_buff 结构 协议栈路径 队列调度篇 第7-14章 qdisc 框架 调度算法 驱动开发篇 第15-22章 ndo_start_xmit TX 环形缓冲区 性能调优篇 第23-27章 perf/ftrace XDP / 多队列 实战项目篇 第28-30章 自定义 qdisc 驱动移植实战 课程设计遵循“由浅入深、理论与实践结合”原则 每章均包含可运行的实验代码与 trace 脚本 建议在 qemu + buildroot 环境中动手验证

1.5 实验环境准备

本课程推荐使用以下环境进行实验:

  • 内核版本:Linux 5.10 LTS(长期支持版,社区维护活跃)
  • 发行版:Ubuntu 20.04 / 22.04 或 Debian 11
  • 虚拟化:qemu 6.0+ + buildroot 2022.02(用于快速构建最小根文件系统)
  • 工具链:gcc 9+、make、flex、bison、elfutils
  • 调试工具:perf、ftrace、bpftrace、tc、ethtool
快速开始:使用 git clone https://github.com/torvalds/linux.git -b v5.10 获取内核源码,make defconfig && make -j$(nproc) 编译内核,然后通过 qemu 启动测试。
# 编译内核示例
$ cd linux-5.10
$ make defconfig
$ make -j$(nproc) bzImage
$ make modules
$ make modules_install

# 使用 qemu 启动
$ qemu-system-x86_64 \
    -kernel arch/x86/boot/bzImage \
    -initrd /path/to/initramfs.cpio.gz \
    -append "console=ttyS0" \
    -netdev user,id=net0 \
    -device e1000,netdev=net0