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

相关推荐
JavaTree20173 小时前
【Spring Boot】Spring Boot解决循环依赖
java·spring boot·后端
cj6341181503 小时前
SpringBoot配置Redis
java·后端
Lisonseekpan4 小时前
Java Stream 流式编程
java·后端
程序员小假5 小时前
运行时有出现过什么异常?
java·后端
凤山老林5 小时前
还在用JDK8?JDK8升级JDK11:一次价值千万的升级指南
java·开发语言·jvm·spring boot·后端·jdk
Java之路行者5 小时前
Spring Boot防重复提交实战:让接口安全提升200%!
spring boot·后端·安全
陈随易6 小时前
改变世界的编程语言MoonBit:配置系统介绍(下)
前端·后端·程序员
知其然亦知其所以然6 小时前
SpringAI + ONNX:打造不花钱、不联网的向量引擎!
后端·spring·aigc
priority_key6 小时前
TCP 如何保证传输的可靠性?
服务器·网络·后端·网络协议·tcp/ip
一语长情6 小时前
Go高并发背后的功臣:Goroutine调度器详解
后端·架构·go