Linux 内核发包流程与路由控制实战


Linux 内核发包流程与路由控制实战

在网络调优、性能优化、SDN、NFV、容器网络等场景下,理解 Linux 内核发包路径路由控制机制 是必修课。

本文将从内核网络栈的原理 入手,再结合 iproute2 命令和 策略路由给出实战案例。


一、Linux 内核发包流程(TX Path)

Linux 的发包路径可以分为 用户态 → 内核协议栈 → 网卡驱动 → 物理链路 四大阶段。

1. 用户态到内核

  1. 应用调用 send()/sendto()/write() → 进入内核系统调用入口

  2. 数据被拷贝到 内核 socket 缓冲(SKB)

  3. 根据 socket 类型(TCP/UDP/RAW)进入对应的协议处理函数

    • TCP:进入 tcp_sendmsg()
    • UDP:进入 udp_sendmsg()

2. 协议栈处理(L4 → L3 → L2)

内核构造 sk_buff (skb) 结构,这是一块带有元数据的网络数据缓冲区。

流程:

  1. 传输层(L4)

    • TCP:加 TCP 首部(端口、序号、校验和)
    • UDP:加 UDP 首部(端口、长度、校验和)
  2. 网络层(L3)

    • 查路由表(fib_lookup
    • 决定下一跳 IP、出接口
    • 加 IP 首部(源/目的地址、TTL、协议号、校验和)
  3. 链路层(L2)

    • 根据下一跳查 ARP 缓存(或触发 ARP 请求)
    • 加以太网头(MAC 源地址、目的地址、类型字段)

3. qdisc(队列规则)与流量整形

  • 数据进入 TC(Traffic Control)队列
  • 默认是 pfifo_fast,可替换为 fq_codelhtb 等进行 QoS、带宽限制、优先级队列

命令示例:

bash 复制代码
# 查看当前 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. 路由查找顺序

  1. 策略路由(Policy Routing)

    • 根据规则(IP、端口、接口、fwmark)决定查哪个路由表
  2. 路由表查找

    • 按最长匹配前缀找到路由项
  3. 邻居子系统(ARP/NDP)

    • 找出下一跳的 L2 地址

2. 查看路由表

bash 复制代码
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. 添加静态路由

bash 复制代码
# 发往 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. 策略路由(多出口场景)

场景:服务器有两个网卡,分别连两条不同的运营商线路,需要按源地址走不同出口。

bash 复制代码
# 添加自定义路由表
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

验证:

bash 复制代码
ip rule show
ip route show table net1

3. 按端口路由(配合 iptables)

如果要按 TCP 端口选择出口,可以用 fwmark

bash 复制代码
# 将目标端口 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. 临时切换默认路由

bash 复制代码
ip route change default via 192.168.1.1 dev eth0

四、案例:高性能转发调优

场景:Linux 作为软件路由器(如容器网关、KVM 虚拟机宿主机)

优化思路:

  1. 打开转发功能:
bash 复制代码
sysctl -w net.ipv4.ip_forward=1
  1. 使用 XDP/eBPF 在驱动层转发包(减少协议栈延迟)
  2. 调整邻居缓存大小与超时:
bash 复制代码
sysctl -w net.ipv4.neigh.default.gc_thresh3=8192
  1. 优化路由查找性能(大规模路由表场景使用 FIB Trie 压缩)

五、关键知识点总结

  • 发包路径:用户态 → 内核协议栈(L4→L3→L2)→ TC 队列 → 网卡驱动 → DMA → 链路

  • 路由决策

    • 策略路由优先于常规路由
    • 查找过程遵循最长前缀匹配
  • 实战技巧

    • 静态路由:ip route add
    • 多出口策略路由:ip rule + 自定义路由表
    • 按端口路由:iptables mangle + fwmark
  • 性能优化

    • 多队列 + RSS
    • GSO/TSO
    • XDP/eBPF
    • 合理的 ARP 缓存与路由压缩

相关推荐
Ronin3057 分钟前
【Linux网络】Socket编程:UDP网络编程实现DictServer
linux·服务器·网络·udp
IT古董41 分钟前
L4 vs L7 负载均衡:彻底理解、对比与实战指南
运维·负载均衡
Gss7771 小时前
HAProxy 技术解析与负载均衡体系梳理
运维·负载均衡
EndingCoder1 小时前
中间件详解与自定义
服务器·javascript·中间件·node.js
SundayBear1 小时前
基于MCU的文件系统
linux·服务器·单片机
爱隐身的官人3 小时前
Linux配置Java/JDK(解决Kali启动ysoserial.jar JRMPListener报错)暨 Kali安装JAVA8和切换JDK版本的详细过程
java·linux·kali
Algebraaaaa4 小时前
Linux 基本命令超详细解释第三期 grep | wc | 管道符‘|’ | echo | tail | 重定向符
linux
鸠摩智首席音效师4 小时前
Nginx 如何启用 HSTS 以加强网络安全 ?
运维·nginx·web安全
小生不才yz6 小时前
(三)命令管理-命令历史-history命令的使用
linux
DIY机器人工房7 小时前
关于解决 libwebsockets 库编译时遇到的问题的方法:
服务器·stm32·单片机·嵌入式硬件·tcp