Linux 内核发包流程与路由控制实战
在网络调优、性能优化、SDN、NFV、容器网络等场景下,理解 Linux 内核发包路径和路由控制机制是必修课。
本文将从内核网络栈的原理入手,再结合 iproute2 命令和 策略路由给出实战案例。
一、Linux 内核发包流程(TX Path)
Linux 的发包路径可以分为 用户态 → 内核协议栈 → 网卡驱动 → 物理链路 四大阶段。
1. 用户态到内核
应用调用
send()/sendto()/write()
→ 进入内核系统调用入口数据被拷贝到 内核 socket 缓冲(SKB)
根据 socket 类型(TCP/UDP/RAW)进入对应的协议处理函数
- TCP:进入
tcp_sendmsg()
- UDP:进入
udp_sendmsg()
- TCP:进入
2. 协议栈处理(L4 → L3 → L2)
内核构造 sk_buff (skb) 结构,这是一块带有元数据的网络数据缓冲区。
流程:
传输层(L4)
- TCP:加 TCP 首部(端口、序号、校验和)
- UDP:加 UDP 首部(端口、长度、校验和)
网络层(L3)
- 查路由表(
fib_lookup
) - 决定下一跳 IP、出接口
- 加 IP 首部(源/目的地址、TTL、协议号、校验和)
- 查路由表(
链路层(L2)
- 根据下一跳查 ARP 缓存(或触发 ARP 请求)
- 加以太网头(MAC 源地址、目的地址、类型字段)
3. qdisc(队列规则)与流量整形
- 数据进入 TC(Traffic Control)队列
- 默认是
pfifo_fast
,可替换为fq_codel
、htb
等进行 QoS、带宽限制、优先级队列
命令示例:
# 查看当前 qdisc
tc qdisc show dev eth0
# 修改为 FQ(减少延迟)
tc qdisc replace dev eth0 root fq
4. 网卡驱动与 DMA
- 内核将 skb 交给网卡驱动
- 驱动将数据放入 TX 环形缓冲区(TX Ring Buffer)
- 通过 DMA 直接搬运到网卡硬件
- 网卡硬件发出数据帧到物理链路(光纤/电缆)
5. 关键优化点
- GSO/TSO:大包分片在网卡进行(减少 CPU 处理开销)
- XDP:绕过协议栈直接在驱动层处理数据(用于高性能转发/过滤)
- 多队列 RSS:多核并行发包
二、路由控制原理
Linux 内核使用 FIB(Forwarding Information Base) 进行路由决策。
核心思路:最长前缀匹配(Longest Prefix Match)
1. 路由查找顺序
策略路由(Policy Routing):
- 根据规则(IP、端口、接口、fwmark)决定查哪个路由表
路由表查找:
- 按最长匹配前缀找到路由项
邻居子系统(ARP/NDP):
- 找出下一跳的 L2 地址
2. 查看路由表
ip route show
输出示例:
default via 192.168.1.1 dev eth0
192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.100
10.0.0.0/8 via 192.168.1.254 dev eth0
三、路由控制实战
1. 添加静态路由
# 发往 10.10.0.0/16 通过 192.168.1.254
ip route add 10.10.0.0/16 via 192.168.1.254 dev eth0
2. 策略路由(多出口场景)
场景:服务器有两个网卡,分别连两条不同的运营商线路,需要按源地址走不同出口。
# 添加自定义路由表
echo "200 net1" >> /etc/iproute2/rt_tables
echo "201 net2" >> /etc/iproute2/rt_tables
# 在表 net1 中添加路由
ip route add default via 192.168.1.1 dev eth0 table net1
# 在表 net2 中添加路由
ip route add default via 172.16.1.1 dev eth1 table net2
# 添加策略规则
ip rule add from 192.168.1.100 table net1
ip rule add from 172.16.1.100 table net2
验证:
ip rule show
ip route show table net1
3. 按端口路由(配合 iptables)
如果要按 TCP 端口选择出口,可以用 fwmark:
# 将目标端口 80 的流量打标 1
iptables -t mangle -A OUTPUT -p tcp --dport 80 -j MARK --set-mark 1
# 策略路由匹配 fwmark
ip rule add fwmark 1 table net1
4. 临时切换默认路由
ip route change default via 192.168.1.1 dev eth0
四、案例:高性能转发调优
场景:Linux 作为软件路由器(如容器网关、KVM 虚拟机宿主机)
优化思路:
- 打开转发功能:
sysctl -w net.ipv4.ip_forward=1
- 使用 XDP/eBPF 在驱动层转发包(减少协议栈延迟)
- 调整邻居缓存大小与超时:
sysctl -w net.ipv4.neigh.default.gc_thresh3=8192
- 优化路由查找性能(大规模路由表场景使用 FIB Trie 压缩)
五、关键知识点总结
发包路径:用户态 → 内核协议栈(L4→L3→L2)→ TC 队列 → 网卡驱动 → DMA → 链路
路由决策:
- 策略路由优先于常规路由
- 查找过程遵循最长前缀匹配
实战技巧:
- 静态路由:
ip route add
- 多出口策略路由:
ip rule
+ 自定义路由表 - 按端口路由:
iptables
mangle + fwmark
- 静态路由:
性能优化:
- 多队列 + RSS
- GSO/TSO
- XDP/eBPF
- 合理的 ARP 缓存与路由压缩
。