当前位置:首页>Linux>Linux 网络协议栈:从 socket 到网卡驱动的数据包旅程

Linux 网络协议栈:从 socket 到网卡驱动的数据包旅程

  • 2026-10-11 05:40:20
Linux 网络协议栈:从 socket 到网卡驱动的数据包旅程

前言

你在浏览器里敲了个回车,数据穿越了 7 层协议、3 个内核队列、2 次 DMA,最后从网线飞出去。

网络协议栈是 Linux 最复杂的子系统之一。一条消息从 send() 到网线,经历 socket -> 传输层 -> 网络层 -> 邻居子系统 -> netfilter -> qdisc -> 驱动 -> 硬件。不懂全路径,调优就是瞎蒙。

01

PART 01:七层内核网络栈

应用层 -> socket -> 系统调用 -> Socket 层 -> 传输层(TCP/UDP)-> 网络层(IP+路由+netfilter) -> 邻居子系统(ARP) -> qdisc-> 设备驱动(Ring Buffer + NAPI) -> 硬件(NIC + DMA)

send() -> tcp_sendmsg() -> 拷贝到 sk_buff -> tcp_push() -> IP 路由 -> Netfilter 钩子 -> ARP 查找 -> qdisc 入队 -> 驱动 xmit -> DMA -> 网线

网卡 -> DMA -> Ring Buffer -> 硬中断 -> NAPI -> 软中断 -> Netfilter -> IP -> TCP -> socket 队列 -> recvmsg() -> 用户态

02

PART 02:Socket 缓冲区

每个 TCP socket 有独立的发送/接收缓冲区。发送缓冲区满时 send() 阻塞——这是背压机制。

cat /proc/sys/net/core/wmem_default     # 默认 16KBcat /proc/sys/net/core/wmem_max         # 最大 128KBcat /proc/sys/net/ipv4/tcp_wmem         # min default maxcat /proc/sys/net/ipv4/tcp_rmem

BDP = 带宽 x RTT。缓冲区 >= BDP 才能跑满带宽。1Gbps x 100ms = 12.5MB。

echo "4096 131072 25000000" > /proc/sys/net/ipv4/tcp_rmemecho "4096 131072 25000000" > /proc/sys/net/ipv4/tcp_wmemecho 25000000 > /proc/sys/net/core/rmem_maxecho 25000000 > /proc/sys/net/core/wmem_max

03

PART 03:TCP 协议深度拆解

SYN -> SYN+ACK -> ACK,内核通过 SYN Queue 和 Accept Queue 管理。队列满则丢连接。

net.core.somaxconn = 65535            # Accept Queue 长度net.ipv4.tcp_max_syn_backlog = 65535  # SYN Queue 长度netstat -s | grep overflow            # 查看队列溢出

攒数据到 MSS 才发。交互式场景引入 200ms 延迟,应禁用:

setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
算法
特点
适用场景
cubic
默认,丢包即降速
通用互联网
bbr
基于带宽/RTT,不怕丢包
高延迟/有损网络
bbr2
BBR 改进版
混合场景

BBR 在 0.1% 丢包时吞吐几乎不受影响,cubic 下降 90%。

04

PART 04:Netfilter + qdisc + NAPI

iptables 规则线性遍历。1000 条规则吞吐下降 30%,5000 条下降 60%。

优化:ipset 替代多条规则、nftables 哈希查找、eBPF/XDP 完全绕过。

Linux 默认 fq_codel。每个流独立队列,延迟超标时主动丢包(解决 BufferBloat)。

高吞吐场景下传统中断方式导致 CPU 被淹没。NAPI 批量轮询收包,减少中断次数。

RSS 多队列 + 中断亲和性将中断分散到多 CPU:

ethtool -L eth0 combined 8echo 1 > /proc/irq/N/smp_affinity  # 分配中断到 CPU 0ethtool -C eth0 rx-usecs 1         # 低延迟模式

05

PART 05:全链路排查三板斧

1. 有丢包吗?   ethtool -S eth0 | grep drop   netstat -s | grep -E "overflow|drop"2. 延迟在哪?   ss -ti | grep -E "rtt|retrans"3. CPU 瓶颈?   cat /proc/interrupts | grep eth0   perf top -e net:*

Nginx 10Gbps 带宽利用率 30%。排查:Ring Buffer 太小(增大)、中断集中(开 RSS)、qdisc 丢包(增大队列)、iptables 8000 条规则(ipset 替代)。结果提升到 85%。

总结

网络调优 = BDP 缓冲区 + TCP_NODELAY + BBR + RSS 多队列 + fq_codel + ipset/nftables。七层协议每层都可能卡,每层都有解。

06

PART 06:GRO/TSO 硬件卸载

GRO(Generic Receive Offload) 将多个小包合并为一个大 skb,减少协议栈处理次数。TSO(TCP Segment Offload) 让网卡硬件完成 TCP 分段,减少 CPU 开销。

ethtool -k eth0 | grep -E "gro|gso|tso"# GRO 开启(默认),CPU 降低 30%ethtool -K eth0 gro on# TSO 开启(大文件传输场景)ethtool -K eth0 tso on

某些虚拟化环境(VMware ESXi)和网络抓包场景需要关闭 GRO,否则 tcpdump 看不到单个小包。

07

PART 07:epoll 与内核软中断

网络收包的后半段在软中断(softirq)中执行。软中断过多会导致 ksoftirqd 进程占用大量 CPU。

# 查看软中断统计cat /proc/softirqs | grep NET# 如果 NET_RX 大幅增长,说明软中断处理压力大# 需要 RSS 多队列或升级网卡

软中断的 CPU 时间占比可以通过 /proc/softirqs 观察。如果 NET_RX 占用了大量 CPU 时间且集中在单核,说明需要打开 RSS 多队列。

END

最新文章

随机文章