一、整体架构图(自底向上)
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)轮询模式(避免中断风暴)
⚙️ 查看中断:
bashbash 深色版本 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)
- 执行
iptables
的PREROUTING
链 - 可做 DNAT、包过滤、连接跟踪(conntrack)
🔍 示例:
cssbash 深色版本 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) |
广播/组播 | 特殊处理 |
📊 查看路由表:
sqlbash 深色版本 ip route show
7. Netfilter INPUT 钩子
scss
c
深色版本
nf_hook(NF_INET_LOCAL_IN)
- 执行
iptables
的INPUT
链 - 常用于防火墙、访问控制
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
封装后放入队列 - 触发
socket
的data_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 请求
- Netfilter :
OUTPUT
和POSTROUTING
链 - 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 内核网络协议栈处理报文的流程如下:
- 收包:网卡通过 DMA 将数据写入 Ring Buffer,触发软中断;
- 协议栈 :
netif_receive_skb
进入协议栈,经过PREROUTING
、IP 层路由决策;- 本机处理 :如果是本机 IP,进入
INPUT
链,再送到 TCP/UDP 层;- Socket:放入 socket 接收队列,唤醒等待进程;
- 应用层 :
recv()
系统调用将数据拷贝到用户空间。发包流程相反,经过
OUTPUT
、路由、POSTROUTING
,最后由网卡发出。整个过程由
sk_buff
贯穿,支持 NAPI、GRO、XDP 等高性能机制。"
✅ 八、总结
阶段 | 关键处理 |
---|---|
硬件层 | DMA、中断、NAPI |
数据链路层 | MAC 处理、VLAN、网桥 |
网络层 | IP 处理、路由、netfilter |
传输层 | TCP 状态机、UDP 直传 |
Socket 层 | 接收/发送队列管理 |
应用层 | 系统调用接口 |
掌握这个流程,说明你对 Linux 网络的理解已经深入到 内核源码级别,