网络数据解封装全流程详解(控制流+数据流)
一、控制流阶段(建立通信管道)
目标:注册接口、分配资源,为解封装铺路
方向:自上而下(应用层 → 硬件层)
| 层级 | 核心操作 | 接口类型 | 关键接口示例 |
|---|---|---|---|
| 应用层 | 注册数据到达回调 | 回调注册接口 | epoll_ctl(EPOLL_CTL_ADD) |
| 内核协议栈 | 向驱动注册协议处理函数 | 协议处理接口 | netdev_ops.ndo_start_xmit |
| 驱动层 | 配置DMA缓冲区,注册硬件中断 | 硬件控制接口 | request_irq(), iowrite32() |
| 硬件层 | 启用接收电路 | 寄存器配置 | NIC寄存器写入(如RX_ENABLE) |
流程示例:
- 应用调用
epoll_create()→ 内核分配事件监听结构体 - 驱动加载时调用
register_netdev()→ 内核记录网卡操作函数集 - 硬件初始化时配置DMA描述符环 → 网卡开始监听物理信号
二、数据流阶段(执行解封装)
目标:自底向上剥离协议头,提交有效载荷
方向:自下而上(硬件层 → 应用层)
接口类型:强制解封装接口(下层调用上层注册的接口)
| 层级 | 核心操作 | 调用接口 | 协议头处理 |
|---|---|---|---|
| 硬件层 | 剥离前导码/CRC,写入DMA缓冲区 | 硬件自动完成 | 去除物理层冗余信息 |
| 驱动层 | 读取DMA数据,校验MAC帧 | netif_receive_skb() | 剥离MAC头(14字节) |
| 内核协议栈 | IP校验、分片重组,TCP/UDP解析 | ip_rcv(), tcp_rcv() | 剥离IP头(20字节)→ TCP头(20字节) |
| 应用层 | 从Socket缓冲区读取裸数据 | epoll回调 | 获取HTTP/FTP等应用数据 |
流程示例:
- 网卡收包 → 触发中断 → 驱动调用
netif_receive_skb(skb) - 内核IP层校验后调用
tcp_v4_rcv(skb)→ 剥离TCP头存入Socket缓冲区 - 内核通过
epoll回调通知应用层调用recv()读取数据
三、关键接口对比
| 接口类型 | 控制流接口 | 数据流接口 |
|---|---|---|
| 调用方向 | 上层→下层注册 | 下层→上层调用 |
| 典型代表 | register_netdev(), epoll_ctl() | netif_rx(), tcp_rcv() |
| 作用阶段 | 系统初始化/资源分配 | 数据到达时实时处理 |
| 是否强制 | 可选(按需注册) | 必须调用(否则丢包) |
四、全流程图示
控制流(初始化):
应用层 → epoll_ctl() → 内核 → register_netdev() → 驱动 → request_irq() → 硬件
数据流(解封装):
硬件 → 中断 → 驱动 → netif_rx() → 内核 → ip_rcv() → tcp_rcv() → epoll回调 → 应用层
五、设计原则总结
- 控制流先于数据流:
-
- 没有注册
epoll回调,应用无法获知数据到达;没有注册netdev_ops,驱动无法提交数据。
- 没有注册
- 解封装不可逆:
-
- 必须按
MAC → IP → TCP → 应用数据顺序剥离,驱动不能跳过IP层直接提交给应用。
- 必须按
- 分层隔离:
-
- 驱动层不知道
tcp_rcv()的实现细节,只需按协议调用接口。
- 驱动层不知道
该设计是Linux内核(5.15+)、DPDK和硬件Offload的通用规范。