Linux内核学习轨迹第八部:网络层:IPv4/IPv6协议实现、路由子系统(第七节)
7. 网络层:IPv4/IPv6协议实现、路由子系统
7.1 网络层的核心定位与设计思想
- 全局寻址:通过IP地址为互联网上的每一台主机提供唯一的全局标识,区分不同的网络与主机,解决“主机在哪里”的问题;
- 路径选择:通过路由子系统,为数据包选择从源主机到目的主机的最优转发路径,解决“数据包怎么去”的问题;
- 异构网络互联:屏蔽底层链路层的差异(以太网、WiFi、PPP、5G等),为上层提供统一的数据包传输服务,实现不同类型网络的互联互通。
7.1.1 网络层的四大核心设计目标
1.无连接的尽力而为传输
2.全局统一的地址空间
3.端到端的透明传输
4.可扩展的协议头设计
7.1.2 网络层在协议栈中的位置与核心组件
┌─────────────────────────────────────────────────────────────────┐
│ 传输层:TCP/UDP/UDPLite,端到端通信控制,端口寻址 │
└───────────────────────────────┬─────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ 【网络层核心】
│ 核心协议:IPv4/IPv6、ICMP/ICMPv6、IGMP
│ 核心功能:IP寻址、数据包封装/解封装、分片/重组、路由转发
│ 核心子系统:路由子系统(FIB转发信息库、策略路由、路由查找)
└───────────────────────────────┬─────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ 数据链路层:以太网、ARP/NDISC、MAC寻址、帧封装、网卡驱动 │
└─────────────────────────────────────────────────────────────────┘
- IP协议族:包括IPv4/IPv6核心协议、ICMP/ICMPv6(网络诊断与错误反馈)、IGMP(组播管理),负责数据包的封装、解封装、分片重组、错误反馈;
- 路由子系统:包括FIB转发信息库、最长前缀匹配算法、路由缓存、策略路由、动态路由协议适配,负责数据包的转发路径选择。
7.2 IPv4协议核心实现
7.2.1 IPv4头部结构深度解析
struct iphdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u8 ihl:4, // IP头长度,单位4字节,最小5(20字节),最大15(60字节)
version:4; // IP版本号,固定为4
#elif defined(__BIG_ENDIAN_BITFIELD)
__u8 version:4,
ihl:4;
#endif
__u8 tos; // 服务类型,用于QoS优先级控制
__be16 tot_len; // IP数据包总长度,包括头部+载荷,最大65535字节
__be16 id; // 数据包标识,用于IP分片重组
__be16 frag_off; // 分片偏移+标志位,DF(不分片)、MF(更多分片)标志
__u8 ttl; // 生存时间,每经过一个路由器减1,为0时丢弃数据包
__u8 protocol; // 上层协议号,1=ICMP,6=TCP,17=UDP,136=UDPLite
__sum16 check; // IP头部校验和,仅校验IP头部,不包含载荷
__be32 saddr; // 源IP地址
__be32 daddr; // 目的IP地址
// 可选字段:最多40字节,用于源路由、安全选项、时间戳等扩展功能
};
- ihl(IP头长度):单位为4字节,最小5(对应20字节固定头部),最大15(对应60字节头部),内核通过该字段区分IP头部和上层载荷。
- tot_len(总长度):IP数据包的总长度(头部+载荷),最大65535字节,这也是IP数据包的理论最大长度。当数据包长度超过链路层MTU时,会被拆分为多个分片,每个分片有独立的IP头部。
- id+frag_off(分片相关字段):是IP分片与重组的核心。id是数据包的唯一标识,同一个IP包的所有分片使用相同的id;frag_off的高13位是分片偏移(单位8字节),低3位是标志位,其中DF=1表示不分片,MF=1表示后面还有更多分片。
- ttl(生存时间):用于防止数据包在网络中无限循环,每经过一个路由器(一跳)TTL减1,当TTL=0时,路由器会丢弃数据包,并回复ICMP超时报文,这也是traceroute工具的核心原理。
- protocol(上层协议号):标识IP载荷对应的上层协议,内核通过该字段决定把数据包交给哪个传输层协议处理,是网络层与传输层的衔接核心。
- check(头部校验和):仅校验IP头部的完整性,不包含载荷。接收端收到数据包后,会重新计算校验和,与头部的校验和对比,不一致则直接丢弃数据包,保证头部的正确性。
7.2.2 IPv4数据包接收全链路流程
1.合法性校验
- 检查以太网帧的协议类型是否为IPv4(0x0800);
- 检查IP版本号是否为4,IP头长度ihl是否≥5,数据包总长度是否小于链路层帧长度;
- 校验IP头部校验和,不一致则直接丢弃;
- 执行NetfilterNF_INET_PRE_ROUTING钩子点,处理iptables/nftables的PREROUTING链规则,规则拒绝则丢弃数据包。
2.路由判断
- 目的IP是本机地址(包括本地接口IP、广播地址、多播地址):判定为本地交付,进入本地接收流程;
- 目的IP不是本机地址,且内核开启了IP转发(net.ipv4.ip_forward=1):判定为需要转发,进入转发流程;
- 目的IP不是本机地址,且未开启IP转发:直接丢弃数据包,回复ICMP主机不可达报文。
3.本地交付流程:分片重组
- 根据源IP、目的IP、协议号、数据包id,找到对应的分片队列;
- 将当前分片加入队列,检查是否所有分片都已到达;
- 所有分片到达后,重组为完整的IP数据包;
- 若分片超时(默认30秒)仍未收全,丢弃所有分片,回复ICMP分片重组超时报文。
4.Netfilter本地入钩子处理
5.上层协议分发
- 协议号6:交给TCP协议,进入tcp_v4_rcv()函数;
- 协议号17:交给UDP协议,进入udp_rcv()函数;
- 协议号1:交给ICMP协议,进入icmp_rcv()函数;
- 未知协议号:丢弃数据包,回复ICMP协议不可达报文。
6.传输层处理
7.转发流程(非本地交付场景)
- 检查数据包的TTL,若TTL≤1,丢弃数据包,回复ICMP超时报文;
- TTL减1,重新计算IP头部校验和;
- 执行NetfilterNF_INET_FORWARD钩子点,处理iptables/nftables的FORWARD链规则,规则拒绝则丢弃;
- 查找转发路由,确定下一跳IP地址和出接口;
- 执行NetfilterNF_INET_POST_ROUTING钩子点,处理POSTROUTING链的SNAT/地址转换规则;
- 检查数据包长度是否超过出接口MTU,若超过且DF=1,丢弃数据包,回复ICMP目的不可达(需要分片)报文;若超过且DF=0,执行IP分片;
- 交给链路层,封装以太网帧,通过出接口发送到下一跳。
7.2.3 IPv4数据包发送全链路流程
1.IP头部初始化
2.路由查找
3.Netfilter本地出钩子处理
4.PMTU检查与分片处理
- 若超过MTU且设置了DF不分片标志:返回EMSGSIZE错误,通知传输层,这是PMTU发现的核心机制;
- 若超过MTU且未设置DF标志:调用ip_fragment()函数,将数据包拆分为多个MTU大小的分片,每个分片添加独立的IP头部,保证分片能在链路层正常传输。
5.Netfilter后路由钩子处理
6.链路层下发
7.2.4 ICMP协议:网络层的错误反馈与诊断工具
错误报文:用于反馈数据包传输过程中的错误,核心类型包括:
- 类型3:目的不可达(包括网络不可达、主机不可达、端口不可达、需要分片但DF标志置位等);
- 类型11:超时(TTL超时、分片重组超时);
- 类型5:重定向,通知主机更优的路由路径。
查询报文:用于网络诊断,核心类型包括:
- 类型8:回显请求(Echo Request),ping命令发送的请求报文;
- 类型0:回显应答(Echo Reply),ping命令收到的响应报文。
- 收到ICMP错误报文时,内核会将错误信息传递给对应的Socket,通知用户态应用(比如TCP连接收到端口不可达报文,会返回connection refused错误);
- 收到ICMP回显请求时,内核自动回复回显应答报文,无需用户态参与;
- 发送数据包出错时,内核自动生成对应的ICMP错误报文,发送给源主机。
7.3 IPv6协议核心实现
7.3.1 IPv6与IPv4的核心差异
|
特性维度 |
IPv6 |
IPv4 |
|
地址长度 |
128位,理论可提供3.4×10³⁸个地址,彻底解决地址耗尽问题 |
32位,仅43亿个地址,已耗尽 |
|
头部结构 |
固定40字节基础头部,通过扩展头实现功能扩展,路由器无需处理扩展头,转发效率更高 |
可变长度头部(20~60字节),可选字段需要路由器处理,转发效率低 |
|
地址自动配置 |
原生支持SLAAC无状态地址自动配置,无需DHCP即可自动生成IP地址 |
仅支持DHCP手动配置、静态配置,无原生自动配置能力 |
|
邻居发现 |
通过NDISC邻居发现协议实现MAC地址解析、路由发现、地址冲突检测,替代IPv4的ARP、ICMP路由器发现、重定向 |
通过ARP协议实现MAC地址解析,ICMP实现路由发现、重定向 |
|
分片机制 |
仅源主机可以执行分片,路由器不支持分片,通过PMTU发现保证数据包不超过路径MTU |
源主机和路由器都可以执行分片 |
|
广播地址 |
取消广播地址,全部使用组播地址实现广播功能,避免广播风暴 |
支持广播地址,易引发广播风暴 |
|
安全性 |
原生支持IPsec安全加密,强制实现IPsec协议栈 |
IPsec为可选扩展,非原生强制 |
|
校验和 |
取消IP头部校验和,由链路层和传输层保证数据完整性,提升转发效率 |
必须校验IP头部校验和,增加路由器开销 |
7.3.2 IPv6头部结构深度解析
1. IPv6固定基础头部
struct ipv6hdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u8 priority:4,
version:4;
#elif defined(__BIG_ENDIAN_BITFIELD)
__u8 version:4, // IP版本号,固定为6
priority:4; // 流量优先级,用于QoS控制
#endif
__u8 flow_lbl[3]; // 流标签,用于标识同一个数据流,实现QoS转发
__be16 payload_len; // 载荷长度,包括扩展头+上层数据,不包含基础头部
__u8 nexthdr; // 下一个头部类型,标识扩展头或上层协议号
__u8 hop_limit; // 跳数限制,替代IPv4的TTL,每经过一跳减1
struct in6_addr saddr; // 源IPv6地址,128位
struct in6_addr daddr; // 目的IPv6地址,128位
};
- 取消了头部校验和、分片标识、分片偏移等字段,路由器无需处理这些内容,转发效率大幅提升;
- 通过nexthdr字段实现扩展头的链式结构,每个扩展头的nexthdr字段指向下一个头部,实现灵活的功能扩展;
- 新增flow_lbl流标签字段,可标识同一个业务流,路由器可基于流标签实现QoS转发,无需解析上层协议内容。
2. IPv6扩展头
|
扩展头类型 |
nexthdr值 |
核心作用 |
|
逐跳选项头 |
0 |
每一跳路由器都需要处理的选项,比如超大包支持 |
|
目的选项头 |
60 |
仅目的主机需要处理的选项 |
|
路由头 |
43 |
源路由,指定数据包的转发路径,替代IPv4的源路由选项 |
|
分片头 |
44 |
分片相关信息,仅源主机使用,替代IPv4的分片相关字段 |
|
认证头(AH) |
51 |
IPsec认证,保证数据完整性和防篡改 |
|
封装安全载荷头(ESP) |
50 |
IPsec加密,保证数据机密性 |
7.3.3 IPv6核心配套协议
1.ICMPv6协议
- 核心错误报文:目的不可达、超时、参数错误;
- 核心诊断报文:回显请求/应答(ping6);
- 邻居发现报文:路由器请求/通告、邻居请求/通告、重定向。
2.NDISC邻居发现协议
- 邻居MAC地址解析:替代ARP,通过邻居请求/通告报文,实现IPv6地址到MAC地址的解析;
- 路由器发现:主机通过路由器请求报文,发现局域网内的路由器,获取网关地址、网络前缀;
- 无状态地址自动配置(SLAAC):主机根据路由器通告的网络前缀,自动生成全局IPv6地址,无需DHCP;
- 地址冲突检测:自动检测局域网内的IPv6地址冲突,保证地址唯一性;
- 重定向:路由器通知主机更优的下一跳地址。
7.4 路由子系统深度拆解
7.4.1 路由子系统的核心架构
┌─────────────────────────────────────────────────────────────────┐
│ 路由配置层:用户态工具(ip route、route、frr/quagga动态路由) │
└───────────────────────────────┬─────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ 路由表管理层:FIB转发信息库、路由策略数据库、Trie树存储结构 │
└───────────────────────────────┬─────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ 路由查找引擎:最长前缀匹配LPM算法、路由缓存、转发决策 │
└─────────────────────────────────────────────────────────────────┘
- 路由配置层:用户态通过ip route命令(iproute2工具集)配置静态路由,或通过FRR/Quagga等动态路由协议(BGP/OSPF/RIP)学习动态路由,通过netlink接口与内核路由子系统交互,更新内核路由表。
- 路由表管理层:内核维护多个路由表(默认255个),每个路由表对应一个独立的FIB转发信息库,通过Trie树结构存储路由条目,实现高效的最长前缀匹配查找。同时支持策略路由,根据源IP、端口、协议等条件,选择不同的路由表进行查找。
- 路由查找引擎:数据包转发时,根据目的IP地址,执行最长前缀匹配算法,在对应的路由表中找到最优的路由条目,获取下一跳地址、出接口、源IP地址等转发信息,完成转发决策。
7.4.2 核心概念:路由表、路由条目、最长前缀匹配
1.路由表
|
路由表ID |
表名 |
核心作用 |
|
0 |
系统保留 |
特殊规则使用,用户不可配置 |
|
255 |
local |
本地路由表,存储本机接口IP、广播地址、环回地址的路由,内核自动维护,用户不可手动修改 |
|
254 |
main |
主路由表,默认所有静态路由都添加到该表,是最常用的路由表 |
|
253 |
default |
默认路由表,默认未使用,可用于配置默认路由 |
2.路由条目
- 目标网络前缀:目的IP地址+前缀长度,比如192.168.1.0/24、0.0.0.0/0(默认路由);
- 下一跳地址:数据包要转发到的下一个路由器的IP地址,直连网段无需下一跳;
- 出接口:数据包转发的网卡接口,比如eth0、ens33;
- 路由优先级(metric):当同一个目标网络有多个路由条目时,metric值越小,优先级越高;
- 路由类型:直连路由、静态路由、动态路由、默认路由。
3.最长前缀匹配(LPM)
- 0.0.0.0/0(默认路由,前缀长度0);
- 192.168.1.0/24(前缀长度24);
- 192.168.1.0/25(前缀长度25)。
7.4.3 路由子系统的核心实现:FIB与Trie树
1. Trie树的核心优势
- 相比传统的哈希表,Trie树天然支持最长前缀匹配,无需遍历所有匹配的条目,查找效率极高;
- 支持路由聚合,大幅减少路由表的条目数量,提升核心路由器的转发性能;
- 无锁化设计,支持多核并行查找,适配现代多核CPU架构,转发性能随CPU核心数线性扩展。
2. 路由查找的完整内核流程
- 策略路由匹配:首先检查策略路由规则,根据数据包的源IP、目的IP、协议号、端口、TOS等条件,确定使用哪个路由表进行查找;若没有匹配的策略规则,默认使用main主路由表。
- 最长前缀匹配查找:在选定的路由表中,基于目的IP地址,在Trie树中执行最长前缀匹配,找到最优的路由条目。
- 路由有效性检查:检查路由条目是否有效,出接口是否up,下一跳是否可达,无效路由则丢弃数据包。
- 路由结果缓存:将查找结果缓存到该数据包对应的Socket中,后续同一个流的数据包无需再次执行全量查找,直接使用缓存的路由结果,提升转发效率。
- 转发决策:根据路由条目,确定数据包的出接口、下一跳地址、源IP地址,完成转发决策。
7.4.4 策略路由:高级路由转发能力
- 多线多出口场景:电信流量走电信出口,联通流量走联通出口,实现智能选路;
- 源地址路由:不同源IP段的主机,走不同的网关和出口;
- 服务质量控制:不同端口、不同协议的流量,走不同的转发路径,实现QoS保障;
- 策略分流:HTTP流量走代理,SSH流量直连,实现精细化的流量控制。
# 1. 添加自定义路由表,在/etc/iproute2/rt_tables中添加
echo "100 telecom" >> /etc/iproute2/rt_tables
echo "200 unicom" >> /etc/iproute2/rt_tables
# 2. 向自定义路由表添加路由
# 电信路由表添加默认路由,网关为电信网关
ip route add default via 192.168.1.1 dev eth0 table telecom
# 联通路由表添加默认路由,网关为联通网关
ip route add default via 192.168.2.1 dev eth1 table unicom
# 3. 添加策略路由规则
# 源IP为192.168.1.0/24的流量,使用telecom路由表,优先级100
ip rule add from 192.168.1.0/24 table telecom priority 100
# 源IP为192.168.2.0/24的流量,使用unicom路由表,优先级200
ip rule add from 192.168.2.0/24 table unicom priority 200
# 4. 查看规则和路由表
ip rule show
ip route show table telecom
7.5 工程实践:路由配置、问题排查与避坑指南
7.5.1 常用路由配置命令(iproute2)
|
操作场景 |
命令示例 |
|
查看主路由表所有路由 |
ip route show /ip r |
|
查看指定路由表的路由 |
ip route show table telecom |
|
查看本地路由表 |
ip route show table local |
|
添加静态路由(目标网段通过网关转发) |
ip route add 10.0.0.0/8 via 192.168.1.1 dev eth0 |
|
添加直连路由(目标网段直连出接口) |
ip route add 192.168.3.0/24 dev eth1 |
|
添加默认路由 |
ip route add default via 192.168.1.1 dev eth0 |
|
删除路由 |
ip route del 10.0.0.0/8 via 192.168.1.1 |
|
修改路由(修改metric优先级) |
ip route change 10.0.0.0/8 via 192.168.1.1 metric 10 |
|
查找目的IP的路由 |
ip route get 8.8.8.8 |
|
清空路由表 |
ip route flush table main |
7.5.2 网络不通标准化路由排查流程
第一步:确认本机IP与链路层连通性
# 查看本机IP地址和网卡状态,确认网卡up
ip addr
# ping网关地址,确认局域网连通性
ping 192.168.1.1
第二步:检查路由表是否有对应路由
# 查看本机IP地址和网卡状态,确认网卡up
ip addr
# ping网关地址,确认局域网连通性
ping 192.168.1.1
第三步:检查IP转发是否开启(路由器/网关场景)
# 查看IP转发是否开启,1=开启,0=关闭
sysctl net.ipv4.ip_forward
# 临时开启IP转发
sysctl -w net.ipv4.ip_forward=1
# 永久开启,写入/etc/sysctl.conf
net.ipv4.ip_forward=1
第四步:检查防火墙/Netfilter规则
# 查看iptables规则,确认FORWARD/INPUT/OUTPUT链是否有DROP规则
iptables -nvL
第五步:跟踪转发路径
# 使用traceroute/mtr跟踪数据包的转发路径,定位在哪一跳出现问题
traceroute 8.8.8.8
mtr --report 8.8.8.8
第六步:检查MTU与PMTU黑洞
# 测试不同MTU的连通性,确认是否存在MTU黑洞
ping -s 1472 -M do 8.8.8.8
7.5.3 生产环境核心调优参数
# /etc/sysctl.conf 网络层核心调优参数
# 开启IP转发(网关/路由器场景必须开启)
net.ipv4.ip_forward = 1
# 开启反向路径过滤,防IP欺骗攻击
net.ipv4.conf.all.rp_filter = 1
# 忽略ICMP广播请求,防Smurf攻击
net.ipv4.icmp_echo_ignore_broadcasts = 1
# 忽略 bogus ICMP 错误响应
net.ipv4.icmp_ignore_bogus_error_responses = 1
# TCP timestamps 开启,支持PMTU发现
net.ipv4.tcp_timestamps = 1
# 开启PMTU发现,避免IP分片
net.ipv4.ip_no_pmtu_disc = 0
# ICMP重定向报文处理,关闭接受重定向,防攻击
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
# IPv6转发开关
net.ipv6.conf.all.forwarding = 1
7.5.4 高频避坑指南
1.路由环路问题
2.MTU黑洞问题
- 调整两端的MTU为路径最小MTU,通常设置为1400字节;
- 开启TCP MSS钳制,在网关设备上限制TCP的MSS大小,避免大包;
- 关闭DF标志,允许IP分片(不推荐,会降低性能)。
3.默认路由冲突问题
4.策略路由规则优先级错误
5.路由表与防火墙规则不匹配
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐


所有评论(0)