linux内核网络协议栈报文的处理过程

一、整体架构图(自底向上)

css 复制代码
深色版本
[ 网卡硬件 ] 
     ↓
[ 网卡驱动(NAPI) → Ring Buffer → 中断/轮询 ]
     ↓
[ 内核网络子系统(netif_receive_skb) ]
     ↓
[ 网桥/虚拟设备(如 br0, veth) → netfilter PREROUTING ]
     ↓
[ IP 层(路由决策、转发 or 本机) ]
     ↓
[ netfilter INPUT → 传输层(TCP/UDP) ]
     ↓
[ Socket 层(接收队列) ]
     ↓
[ 应用层(recv()/read()) ]

发包方向相反。


✅ 二、接收流程(Rx)详解

1. 网卡收包 & 硬件中断

  • 网卡收到数据帧(Ethernet Frame)
  • 将数据写入 Ring Buffer(DMA 写入内存)
  • 触发 硬件中断(MSI-X 或传统 IRQ)
  • 或使用 NAPI(New API)轮询模式(避免中断风暴)

⚙️ 查看中断:

bash 复制代码
bash
深色版本
cat /proc/interrupts | grep eth0

2. 软中断处理(ksoftirqd)

  • 硬件中断触发后,内核调度 软中断(softirq)
  • 软中断类型:NET_RX_SOFTIRQ
  • 执行函数:net_rx_action()
  • 调用驱动注册的 poll() 函数(如 ixgbe_poll

📌 NAPI 机制:

  • 高负载时:切换到轮询模式(减少中断开销)
  • 低负载时:恢复中断模式

3. 进入网络协议栈(netif_receive_skb)

scss 复制代码
c
深色版本
netif_receive_skb(skb)
    → __netif_receive_skb_core()
        → handle_packet()
            → pt_prev->func()  // 如 eth_type_trans 处理以太网类型
  • skb(socket buffer)是核心数据结构

  • 解析 Ethernet Header

    • 源/目的 MAC
    • EtherType(如 0x0800 → IPv4)

4. 桥接/虚拟设备处理(可选)

如果启用了网桥(bridge)、Docker veth、Open vSwitch:

scss 复制代码
c
深色版本
br_handle_frame()
    → br_pass_frame_up()  // 本机处理
    → br_forward()        // 转发到其他端口

5. Netfilter PREROUTING 钩子

scss 复制代码
c
深色版本
nf_hook(NF_INET_PRE_ROUTING)
  • 执行 iptablesPREROUTING
  • 可做 DNAT、包过滤、连接跟踪(conntrack)

🔍 示例:

css 复制代码
bash
深色版本
iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 10.0.0.10:80

6. IP 层处理(ip_rcv)

scss 复制代码
c
深色版本
ip_rcv()
    → ip_rcv_finish()
        → fib_lookup()  // 查路由表

路由决策(FIB:Forwarding Information Base)

目的地址类型 处理路径
本机 IP(VIP 或物理 IP) RTN_LOCAL → 送往上层
其他网段 IP RTN_UNICAST → 转发(需开启 IP Forward)
广播/组播 特殊处理

📊 查看路由表:

sql 复制代码
bash
深色版本
ip route show

7. Netfilter INPUT 钩子

scss 复制代码
c
深色版本
nf_hook(NF_INET_LOCAL_IN)
  • 执行 iptablesINPUT
  • 常用于防火墙、访问控制

8. 传输层处理

TCP 报文:

scss 复制代码
c
深色版本
tcp_v4_rcv()
    → tcp_v4_do_rcv()
        → tcp_rcv_state_process()
            → 根据 TCP 状态机处理(SYN、ACK、DATA)
            → 放入 socket 接收队列(sk_receive_queue)

UDP 报文:

scss 复制代码
c
深色版本
udp_rcv()
    → udp_queue_rcv_skb()
        → __udp_queue_rcv_skb()
            → 放入 socket 接收队列

9. Socket 层(接收队列)

  • 每个 socket 有一个接收队列(sk_receive_queue
  • 数据包被 skb 封装后放入队列
  • 触发 socketdata_ready 回调(唤醒等待进程)

🔔 唤醒机制:

  • 如果应用在 recv() 阻塞,会被唤醒
  • 使用 epoll 时,eventpoll 会收到通知

10. 应用层接收

scss 复制代码
c
深色版本
// 用户态调用
recv(sockfd, buf, len, 0);
// 或
read(sockfd, buf, len);
  • 系统调用进入内核
  • sk_receive_queue 取出 skb
  • 拷贝数据到用户空间 buf
  • 释放 skb

✅ 三、发送流程(Tx)详解(反向)

css 复制代码
深色版本
[ 应用层 send()/write() ]
     ↓
[ Socket 层(发送队列)]
     ↓
[ 传输层(TCP 分段 or UDP 直传)]
     ↓
[ IP 层(路由查找、分片)]
     ↓
[ Netfilter OUTPUT → POSTROUTING ]
     ↓
[ 数据链路层(ARP 解析、封装 Ethernet Header)]
     ↓
[ 网卡驱动(DMA 发送到 Ring Buffer)]
     ↓
[ 网卡硬件(发送到物理网络)]

关键点:

  • 路由查找ip_route_output_flow()
  • ARP 解析:如果目的 MAC 未知,发 ARP 请求
  • NetfilterOUTPUTPOSTROUTING
  • GSO/GRO:大段卸载(发送)和大接收卸载(接收)

✅ 四、关键数据结构

结构 说明
sk_buff(skb) 报文载体,贯穿整个协议栈
sock socket 抽象,包含接收/发送队列
net_device 网络设备抽象(如 eth0)
net 网络命名空间(支持容器)
flowi 路由查找的查询结构

✅ 五、性能优化相关机制

机制 说明
NAPI 减少中断开销
RPS/RSS 多队列网卡负载均衡
GRO/LRO 接收端聚合,减少上层处理次数
GSO/TSO 发送端分段卸载到网卡
XDP eXpress Data Path,在驱动层处理包
AF_XDP 零拷贝用户态网络

✅ 六、查看和调试命令

目的 命令
查看软中断 cat /proc/softirqs
查看网络设备 ethtool -i eth0
查看 socket 状态 ss -ant
抓包 tcpdump -i eth0
查看路由 ip route show
查看 netfilter iptables -L -v -n
跟踪内核函数 perf trace -p $(pidof nginx)

✅ 七、面试回答模板

"Linux 内核网络协议栈处理报文的流程如下:

  1. 收包:网卡通过 DMA 将数据写入 Ring Buffer,触发软中断;
  2. 协议栈netif_receive_skb 进入协议栈,经过 PREROUTING、IP 层路由决策;
  3. 本机处理 :如果是本机 IP,进入 INPUT 链,再送到 TCP/UDP 层;
  4. Socket:放入 socket 接收队列,唤醒等待进程;
  5. 应用层recv() 系统调用将数据拷贝到用户空间。

发包流程相反,经过 OUTPUT、路由、POSTROUTING,最后由网卡发出。

整个过程由 sk_buff 贯穿,支持 NAPI、GRO、XDP 等高性能机制。"


✅ 八、总结

阶段 关键处理
硬件层 DMA、中断、NAPI
数据链路层 MAC 处理、VLAN、网桥
网络层 IP 处理、路由、netfilter
传输层 TCP 状态机、UDP 直传
Socket 层 接收/发送队列管理
应用层 系统调用接口

掌握这个流程,说明你对 Linux 网络的理解已经深入到 内核源码级别

相关推荐
用户49055816081252 小时前
lvs会话同步
后端
夜宵饽饽2 小时前
上下文工程实践 - 工具管理(上篇)
javascript·后端
ERP老兵_冷溪虎山2 小时前
Python/JS/Go/Java同步学习(第十三篇)四语言“字符串转码解码“对照表: 财务“小南“纸式转码术处理凭证乱码崩溃(附源码/截图/参数表/避坑指南)
java·后端·python
努力的小郑2 小时前
MySQL索引(四):深入剖析索引失效的原因与优化方案
后端·mysql·性能优化
智商偏低2 小时前
ASP.NET Core 中的简单授权
后端·asp.net
练习时长一年2 小时前
搭建langchain4j+SpringBoot的Ai项目
java·spring boot·后端
bobz9652 小时前
Proxmox qemu-server
后端
编码浪子3 小时前
趣味学RUST基础篇(异步补充)
开发语言·后端·rust
songroom3 小时前
Rust : 关于Deref
开发语言·后端·rust