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 网络的理解已经深入到 内核源码级别

相关推荐
孟陬17 小时前
Claude Code 巧思 `Ctrl+S` 暂存键
前端·后端
雪隐17 小时前
个人电脑玩AI-06让5060 Ti给你打工——不光能画画,Qwen3-TTS还能学人说话,连我老板都信了!
人工智能·后端·python
Oneslide17 小时前
openEuler 17.1GB Everything ISO 离线本地 DNF 源搭建教程
后端
蝎子莱莱爱打怪17 小时前
那不是我的黑历史,那是我的来时路啊!😭😭
后端·程序员
用户2986985301417 小时前
Java 实现 Word 文档文本与图片提取的方法
java·后端
蝎子莱莱爱打怪18 小时前
XZLL-IM干货系列 04|Netty 长连接实战:Pipeline 怎么排、心跳怎么跳、连接怎么管
后端·微服务·面试
Csvn18 小时前
Rsync 文件同步与增量备份 — 运维的数据守门员
后端
苏三说技术18 小时前
推荐一个牛逼的智能代码审查系统
后端
倾颜18 小时前
从 GitHub Actions 到本地兜底发布:AI Mind 容器化上线的一次真实收口
后端
像我这样帅的人丶你还18 小时前
Java 后端详解(二):注解、参数绑定、评论与用户认证
后端