7. 网络层:IPv4/IPv6协议实现、路由子系统

网络层是TCP/IP协议栈的路由中枢与互联核心,是实现全球互联网互联互通的基础。它向上为传输层(TCP/UDP)提供统一的、无差别的数据包传输服务,屏蔽底层链路层的硬件差异与局域网边界;向下负责跨网络的主机寻址、数据包转发、分片与重组,解决“数据包如何从源主机到达目的主机”的核心问题。
无论是同一局域网内的通信,还是跨地域、跨运营商的网络访问,所有数据包的转发路径、寻址逻辑都由网络层决定。生产环境中绝大多数的网络不通、访问延迟高、跨网访问异常等问题,根源都在网络层的路由配置、IP协议处理环节。本章节基于Linux 6.6 LTS内核,源码覆盖net/ipv4/(IPv4核心实现)、net/ipv6/(IPv6核心实现)、net/ipv4/route.c/net/ipv4/fib_trie.c(路由子系统核心)三大核心路径,深度拆解IPv4/IPv6协议的内核实现、数据包收发与转发全流程、路由子系统的核心架构与算法,同时提供生产环境的路由配置、问题排查、调优与避坑指南。

7.1 网络层的核心定位与设计思想

网络层位于传输层与数据链路层之间,是整个TCP/IP栈的“承上启下”层,核心解决三大问题:
  1. 全局寻址:通过IP地址为互联网上的每一台主机提供唯一的全局标识,区分不同的网络与主机,解决“主机在哪里”的问题;
  2. 路径选择:通过路由子系统,为数据包选择从源主机到目的主机的最优转发路径,解决“数据包怎么去”的问题;
  3. 异构网络互联:屏蔽底层链路层的差异(以太网、WiFi、PPP、5G等),为上层提供统一的数据包传输服务,实现不同类型网络的互联互通。
7.1.1 网络层的四大核心设计目标

1.无连接的尽力而为传输

网络层本身不提供可靠传输保障,不保证数据包的可达性、有序性、无重复性,仅负责“尽力而为”的转发,所有可靠性保障完全交给上层传输层(TCP)实现。这种设计极大简化了网络层的实现,让互联网的核心转发设备(路由器)仅需专注于数据包转发,无需维护连接状态,具备极强的可扩展性。

2.全局统一的地址空间

通过IP地址(IPv4 32位、IPv6 128位)构建全局唯一的地址空间,同时通过网络前缀划分不同的局域网,实现分层寻址,既保证了主机的全局可识别,又通过路由聚合减少了核心路由器的路由表规模,是互联网能支撑数十亿设备的核心基础。

3.端到端的透明传输

网络层对上层传输层完全透明,传输层无需关心数据包的转发路径、底层链路类型,只需填充源目IP地址,即可实现端到端的通信。同时通过IP分片与重组机制,适配不同链路层的MTU差异,对上层屏蔽MTU的限制。

4.可扩展的协议头设计

IP协议头通过可选字段/扩展头机制,支持安全加密(IPsec)、源路由、分片、流标签等扩展功能,无需修改核心协议结构,即可适配新的网络需求,保证了协议的长期生命力。
7.1.2 网络层在协议栈中的位置与核心组件
┌─────────────────────────────────────────────────────────────────┐
│  传输层:TCP/UDP/UDPLite,端到端通信控制,端口寻址              │
└───────────────────────────────┬─────────────────────────────────┘
                                ↓
┌─────────────────────────────────────────────────────────────────┐
│  【网络层核心】
│  核心协议:IPv4/IPv6、ICMP/ICMPv6、IGMP
│  核心功能:IP寻址、数据包封装/解封装、分片/重组、路由转发
│  核心子系统:路由子系统(FIB转发信息库、策略路由、路由查找)
└───────────────────────────────┬─────────────────────────────────┘
                                ↓
┌─────────────────────────────────────────────────────────────────┐
│  数据链路层:以太网、ARP/NDISC、MAC寻址、帧封装、网卡驱动      │
└─────────────────────────────────────────────────────────────────┘

网络层的核心组件分为两大部分:
  1. IP协议族:包括IPv4/IPv6核心协议、ICMP/ICMPv6(网络诊断与错误反馈)、IGMP(组播管理),负责数据包的封装、解封装、分片重组、错误反馈;
  2. 路由子系统:包括FIB转发信息库、最长前缀匹配算法、路由缓存、策略路由、动态路由协议适配,负责数据包的转发路径选择。

7.2 IPv4协议核心实现

IPv4(Internet Protocol version 4)是当前互联网的主流网络层协议,使用32位IP地址,理论上可提供43亿个地址,核心定义在RFC 791中。Linux内核中IPv4的完整实现位于net/ipv4/目录,是整个网络层的核心基础。
7.2.1 IPv4头部结构深度解析
IPv4头部最小20字节,最大60字节(通过可选字段扩展),所有字段均为网络字节序(大端序),内核中对应的结构体为struct iphdr,定义在include/uapi/linux/ip.h中:
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字节,用于源路由、安全选项、时间戳等扩展功能
};

核心字段深度解析:
  1. ihl(IP头长度):单位为4字节,最小5(对应20字节固定头部),最大15(对应60字节头部),内核通过该字段区分IP头部和上层载荷。
  2. tot_len(总长度):IP数据包的总长度(头部+载荷),最大65535字节,这也是IP数据包的理论最大长度。当数据包长度超过链路层MTU时,会被拆分为多个分片,每个分片有独立的IP头部。
  3. id+frag_off(分片相关字段):是IP分片与重组的核心。id是数据包的唯一标识,同一个IP包的所有分片使用相同的id;frag_off的高13位是分片偏移(单位8字节),低3位是标志位,其中DF=1表示不分片,MF=1表示后面还有更多分片。
  4. ttl(生存时间):用于防止数据包在网络中无限循环,每经过一个路由器(一跳)TTL减1,当TTL=0时,路由器会丢弃数据包,并回复ICMP超时报文,这也是traceroute工具的核心原理。
  5. protocol(上层协议号):标识IP载荷对应的上层协议,内核通过该字段决定把数据包交给哪个传输层协议处理,是网络层与传输层的衔接核心。
  6. check(头部校验和):仅校验IP头部的完整性,不包含载荷。接收端收到数据包后,会重新计算校验和,与头部的校验和对比,不一致则直接丢弃数据包,保证头部的正确性。
7.2.2 IPv4数据包接收全链路流程
网卡收到的以太网帧,经过链路层处理后,进入IPv4核心接收函数ip_rcv(),完整的内核处理流程分为7个阶段,最终决定数据包是本地交付、转发还是丢弃:

1.合法性校验

进入ip_rcv()函数后,内核首先执行基础校验,校验失败直接丢弃数据包:
  • 检查以太网帧的协议类型是否为IPv4(0x0800);
  • 检查IP版本号是否为4,IP头长度ihl是否≥5,数据包总长度是否小于链路层帧长度;
  • 校验IP头部校验和,不一致则直接丢弃;
  • 执行NetfilterNF_INET_PRE_ROUTING钩子点,处理iptables/nftables的PREROUTING链规则,规则拒绝则丢弃数据包。

2.路由判断

调用ip_route_input()函数,执行路由查找,根据目的IP地址判断数据包的去向:
  • 目的IP是本机地址(包括本地接口IP、广播地址、多播地址):判定为本地交付,进入本地接收流程;
  • 目的IP不是本机地址,且内核开启了IP转发(net.ipv4.ip_forward=1):判定为需要转发,进入转发流程;
  • 目的IP不是本机地址,且未开启IP转发:直接丢弃数据包,回复ICMP主机不可达报文。

3.本地交付流程:分片重组

如果数据包是分片(MF=1或分片偏移>0),调用ip_defrag()函数执行IP分片重组:
  • 根据源IP、目的IP、协议号、数据包id,找到对应的分片队列;
  • 将当前分片加入队列,检查是否所有分片都已到达;
  • 所有分片到达后,重组为完整的IP数据包;
  • 若分片超时(默认30秒)仍未收全,丢弃所有分片,回复ICMP分片重组超时报文。

4.Netfilter本地入钩子处理

执行NetfilterNF_INET_LOCAL_IN钩子点,处理iptables/nftables的INPUT链规则,规则拒绝则丢弃数据包。

5.上层协议分发

根据IP头部的protocol字段,将数据包交给对应的上层传输层协议处理:
  • 协议号6:交给TCP协议,进入tcp_v4_rcv()函数;
  • 协议号17:交给UDP协议,进入udp_rcv()函数;
  • 协议号1:交给ICMP协议,进入icmp_rcv()函数;
  • 未知协议号:丢弃数据包,回复ICMP协议不可达报文。

6.传输层处理

传输层解析对应的协议头,校验端口号、校验和,找到对应的Socket,将数据包放入Socket的接收队列,唤醒等待的用户态进程,完成接收。

7.转发流程(非本地交付场景)

若数据包需要转发,进入ip_forward()函数,核心处理逻辑:
  • 检查数据包的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数据包发送全链路流程
传输层(TCP/UDP)将数据包交给网络层,进入IPv4核心发送函数ip_queue_xmit(),完整的内核处理流程分为6个阶段:

1.IP头部初始化

内核填充IP头部的核心字段:版本号4、ihl=5、TOS、TTL、协议号、源IP地址、目的IP地址,初始化数据包标识id,设置分片标志位。

2.路由查找

调用ip_route_output()函数,根据目的IP地址查找路由表,确定下一跳IP地址、出接口网卡、源IP地址,获取路由项缓存。

3.Netfilter本地出钩子处理

执行NetfilterNF_INET_LOCAL_OUT钩子点,处理iptables/nftables的OUTPUT链规则,规则拒绝则丢弃数据包。

4.PMTU检查与分片处理

检查数据包总长度是否超过出接口的MTU:
  • 若超过MTU且设置了DF不分片标志:返回EMSGSIZE错误,通知传输层,这是PMTU发现的核心机制;
  • 若超过MTU且未设置DF标志:调用ip_fragment()函数,将数据包拆分为多个MTU大小的分片,每个分片添加独立的IP头部,保证分片能在链路层正常传输。

5.Netfilter后路由钩子处理

执行NetfilterNF_INET_POST_ROUTING钩子点,处理iptables/nftables的POSTROUTING链规则,包括SNAT、MASQUERADE地址转换,规则拒绝则丢弃数据包。

6.链路层下发

根据下一跳IP地址,查找ARP表获取对应的MAC地址,封装以太网帧头,交给网卡驱动,通过出接口发送到网络中。
7.2.4 ICMP协议:网络层的错误反馈与诊断工具
ICMP(Internet Control Message Protocol,互联网控制消息协议)是IPv4的配套协议,协议号1,核心作用是网络层的错误反馈与诊断,不负责用户数据传输,是ping、traceroute等网络工具的底层基础。
ICMP报文分为两大类:

   错误报文:用于反馈数据包传输过程中的错误,核心类型包括:

  • 类型3:目的不可达(包括网络不可达、主机不可达、端口不可达、需要分片但DF标志置位等);
  • 类型11:超时(TTL超时、分片重组超时);
  • 类型5:重定向,通知主机更优的路由路径。

   查询报文:用于网络诊断,核心类型包括:

  • 类型8:回显请求(Echo Request),ping命令发送的请求报文;
  • 类型0:回显应答(Echo Reply),ping命令收到的响应报文。
Linux内核中ICMP的实现位于net/ipv4/icmp.c,核心处理逻辑:
  • 收到ICMP错误报文时,内核会将错误信息传递给对应的Socket,通知用户态应用(比如TCP连接收到端口不可达报文,会返回connection refused错误);
  • 收到ICMP回显请求时,内核自动回复回显应答报文,无需用户态参与;
  • 发送数据包出错时,内核自动生成对应的ICMP错误报文,发送给源主机。

7.3 IPv6协议核心实现

IPv6(Internet Protocol version 6)是IPv4的下一代协议,使用128位IP地址,彻底解决了IPv4地址耗尽的问题,同时在安全性、自动配置、扩展性、移动性等方面做了大量优化,是未来互联网的核心基础。Linux内核原生支持IPv6,完整实现位于net/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头部结构深度解析
IPv6头部分为固定基础头部和扩展头部两部分,基础头部固定40字节,所有路由器都必须处理;扩展头部可选,仅源主机和目的主机处理,路由器无需解析,极大提升了转发效率。
1. IPv6固定基础头部
内核中对应的结构体为struct ipv6hdr,定义在include/uapi/linux/ipv6.h中:
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扩展头
IPv6通过扩展头实现可选功能,常见的扩展头包括:

扩展头类型

nexthdr值

核心作用

逐跳选项头

0

每一跳路由器都需要处理的选项,比如超大包支持

目的选项头

60

仅目的主机需要处理的选项

路由头

43

源路由,指定数据包的转发路径,替代IPv4的源路由选项

分片头

44

分片相关信息,仅源主机使用,替代IPv4的分片相关字段

认证头(AH)

51

IPsec认证,保证数据完整性和防篡改

封装安全载荷头(ESP)

50

IPsec加密,保证数据机密性

核心规则:扩展头按固定顺序链式排列,最后一个扩展头的nexthdr字段标识上层协议号(TCP=6、UDP=17),路由器仅需处理逐跳选项头,其他扩展头完全透明,转发效率极高。
7.3.3 IPv6核心配套协议
IPv6取消了IPv4的ARP、ICMP路由器发现等协议,统一通过ICMPv6和NDISC邻居发现协议实现对应的功能,形成了完整的协议体系。

1.ICMPv6协议

ICMPv6是IPv6的核心配套协议,协议号58,不仅实现了IPv4 ICMP的错误反馈、诊断功能,还承载了NDISC邻居发现、组播管理、地址自动配置等核心功能,是IPv6协议栈的核心组成部分。
  • 核心错误报文:目的不可达、超时、参数错误;
  • 核心诊断报文:回显请求/应答(ping6);
  • 邻居发现报文:路由器请求/通告、邻居请求/通告、重定向。

2.NDISC邻居发现协议

NDISC(Neighbor Discovery Protocol,邻居发现协议)基于ICMPv6实现,替代了IPv4的ARP、ICMP路由器发现、重定向、地址冲突检测等功能,核心作用包括:
  • 邻居MAC地址解析:替代ARP,通过邻居请求/通告报文,实现IPv6地址到MAC地址的解析;
  • 路由器发现:主机通过路由器请求报文,发现局域网内的路由器,获取网关地址、网络前缀;
  • 无状态地址自动配置(SLAAC):主机根据路由器通告的网络前缀,自动生成全局IPv6地址,无需DHCP;
  • 地址冲突检测:自动检测局域网内的IPv6地址冲突,保证地址唯一性;
  • 重定向:路由器通知主机更优的下一跳地址。

7.4 路由子系统深度拆解

路由子系统是Linux网络层的核心大脑,负责为每一个IP数据包选择从源到目的的最优转发路径,决定了数据包的出接口、下一跳地址。无论是作为终端主机的Linux服务器,还是作为路由器的Linux网关设备,路由子系统都是网络通信的核心基础。
Linux内核的路由子系统经过多次重构,Linux 3.6+内核完全采用基于Trie树的FIB(转发信息库) 架构,替代了老旧的哈希表路由缓存,路由查找效率、可扩展性、大规模路由表支持能力都得到了质的提升,可支持百万级以上的路由条目,完全满足运营商级路由器的需求。
7.4.1 路由子系统的核心架构
Linux路由子系统分为三大核心模块,各司其职,构成完整的路由处理流程:
┌─────────────────────────────────────────────────────────────────┐
│  路由配置层:用户态工具(ip route、route、frr/quagga动态路由) │
└───────────────────────────────┬─────────────────────────────────┘
                                ↓
┌─────────────────────────────────────────────────────────────────┐
│  路由表管理层:FIB转发信息库、路由策略数据库、Trie树存储结构  │
└───────────────────────────────┬─────────────────────────────────┘
                                ↓
┌─────────────────────────────────────────────────────────────────┐
│  路由查找引擎:最长前缀匹配LPM算法、路由缓存、转发决策        │
└─────────────────────────────────────────────────────────────────┘

  1. 路由配置层:用户态通过ip route命令(iproute2工具集)配置静态路由,或通过FRR/Quagga等动态路由协议(BGP/OSPF/RIP)学习动态路由,通过netlink接口与内核路由子系统交互,更新内核路由表。
  2. 路由表管理层:内核维护多个路由表(默认255个),每个路由表对应一个独立的FIB转发信息库,通过Trie树结构存储路由条目,实现高效的最长前缀匹配查找。同时支持策略路由,根据源IP、端口、协议等条件,选择不同的路由表进行查找。
  3. 路由查找引擎:数据包转发时,根据目的IP地址,执行最长前缀匹配算法,在对应的路由表中找到最优的路由条目,获取下一跳地址、出接口、源IP地址等转发信息,完成转发决策。
7.4.2 核心概念:路由表、路由条目、最长前缀匹配

1.路由表

路由表ID

表名

核心作用

0

系统保留

特殊规则使用,用户不可配置

255

local

本地路由表,存储本机接口IP、广播地址、环回地址的路由,内核自动维护,用户不可手动修改

254

main

主路由表,默认所有静态路由都添加到该表,是最常用的路由表

253

default

默认路由表,默认未使用,可用于配置默认路由

Linux内核默认支持255个独立的路由表,通过路由表ID(0~254)标识,其中4个路由表为系统预留:
除了系统预留的4个表,用户可以自定义251个路由表,用于策略路由,实现复杂的路由转发规则。

2.路由条目

每个路由表由多个路由条目组成,每个路由条目定义了一个目标网络的转发规则,核心组成部分包括:
  • 目标网络前缀:目的IP地址+前缀长度,比如192.168.1.0/24、0.0.0.0/0(默认路由);
  • 下一跳地址:数据包要转发到的下一个路由器的IP地址,直连网段无需下一跳;
  • 出接口:数据包转发的网卡接口,比如eth0、ens33;
  • 路由优先级(metric):当同一个目标网络有多个路由条目时,metric值越小,优先级越高;
  • 路由类型:直连路由、静态路由、动态路由、默认路由。

3.最长前缀匹配(LPM)

最长前缀匹配是路由查找的核心算法,核心规则是:当多个路由条目都匹配目的IP地址时,选择前缀长度最长(子网掩码最长)的条目作为最优路由。
举个例子:目的IP地址为192.168.1.100,路由表中有3个匹配的条目:
  1. 0.0.0.0/0(默认路由,前缀长度0);
  2. 192.168.1.0/24(前缀长度24);
  3. 192.168.1.0/25(前缀长度25)。
其中192.168.1.0/25的前缀长度最长,因此内核会选择该条目作为最优路由,执行转发。
7.4.3 路由子系统的核心实现:FIB与Trie树
Linux内核的路由表通过FIB(Forwarding Information Base,转发信息库) 存储,每个路由表对应一个FIB实例,FIB内部采用Trie树(字典树) 结构存储路由条目,实现O(32)(IPv4)/O(128)(IPv6)时间复杂度的最长前缀匹配查找,即使百万级路由条目,查找性能也不会明显下降。
1. Trie树的核心优势
  • 相比传统的哈希表,Trie树天然支持最长前缀匹配,无需遍历所有匹配的条目,查找效率极高;
  • 支持路由聚合,大幅减少路由表的条目数量,提升核心路由器的转发性能;
  • 无锁化设计,支持多核并行查找,适配现代多核CPU架构,转发性能随CPU核心数线性扩展。
2. 路由查找的完整内核流程
当数据包需要路由查找时,内核执行以下完整流程:
  1. 策略路由匹配:首先检查策略路由规则,根据数据包的源IP、目的IP、协议号、端口、TOS等条件,确定使用哪个路由表进行查找;若没有匹配的策略规则,默认使用main主路由表。
  2. 最长前缀匹配查找:在选定的路由表中,基于目的IP地址,在Trie树中执行最长前缀匹配,找到最优的路由条目。
  3. 路由有效性检查:检查路由条目是否有效,出接口是否up,下一跳是否可达,无效路由则丢弃数据包。
  4. 路由结果缓存:将查找结果缓存到该数据包对应的Socket中,后续同一个流的数据包无需再次执行全量查找,直接使用缓存的路由结果,提升转发效率。
  5. 转发决策:根据路由条目,确定数据包的出接口、下一跳地址、源IP地址,完成转发决策。
7.4.4 策略路由:高级路由转发能力
传统的路由仅根据目的IP地址进行转发,而策略路由(Policy Based Routing,PBR)可以根据源IP地址、源端口、目的端口、协议类型、TOS、数据包标记等多种条件,选择不同的路由表和转发路径,实现更灵活、更复杂的路由控制。
Linux内核的策略路由通过ip rule规则实现,规则按优先级排序,优先级数字越小,优先级越高,内核按优先级从小到大依次匹配规则,匹配成功后使用对应的路由表执行查找。
策略路由典型应用场景:
  1. 多线多出口场景:电信流量走电信出口,联通流量走联通出口,实现智能选路;
  2. 源地址路由:不同源IP段的主机,走不同的网关和出口;
  3. 服务质量控制:不同端口、不同协议的流量,走不同的转发路径,实现QoS保障;
  4. 策略分流: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)
Linux系统中,传统的route命令已被废弃,推荐使用iproute2工具集的ip route命令,功能更强大、更灵活,以下是生产环境最常用的配置命令:

操作场景

命令示例

查看主路由表所有路由

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 网络不通标准化路由排查流程
生产环境中遇到网络不通、ping不通的问题,按以下流程可快速定位路由层面的问题:

第一步:确认本机IP与链路层连通性

# 查看本机IP地址和网卡状态,确认网卡up
ip addr
# ping网关地址,确认局域网连通性
ping 192.168.1.1
若网关ping不通,问题出在局域网链路层,检查网线、交换机、VLAN配置、ARP表。

第二步:检查路由表是否有对应路由

# 查看本机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

若Linux作为网关/路由器,必须开启IP转发,否则无法转发跨网段的数据包。

第四步:检查防火墙/Netfilter规则

# 查看iptables规则,确认FORWARD/INPUT/OUTPUT链是否有DROP规则
iptables -nvL
防火墙规则可能会拦截数据包,导致路由正常但网络不通,需要调整防火墙规则放行对应流量。

第五步:跟踪转发路径

# 使用traceroute/mtr跟踪数据包的转发路径,定位在哪一跳出现问题
traceroute 8.8.8.8
mtr --report 8.8.8.8

通过traceroute可以定位数据包在哪一跳被丢弃,是本机、中间路由器,还是目的主机的问题。

第六步:检查MTU与PMTU黑洞

# 测试不同MTU的连通性,确认是否存在MTU黑洞
ping -s 1472 -M do 8.8.8.8

若大包不通、小包通,说明路径中存在MTU不匹配的问题,需要调整MTU大小,或开启PMTU发现。
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.路由环路问题

错误的路由配置会导致路由环路,数据包在两个路由器之间无限循环,TTL耗尽被丢弃,网络不通。典型场景:两个路由器互相设置对方为默认网关,或静态路由配置错误。
排查方法:通过traceroute看到IP地址循环出现,即可确认路由环路;
解决方案:修正路由配置,确保每个目标网段只有唯一的转发路径。

2.MTU黑洞问题

路径中某一跳的MTU小于两端的MTU,且DF不分片标志被设置,导致大包被丢弃,且无法收到ICMP需要分片的报文,出现“小包通、大包不通”的现象,称为MTU黑洞。
解决方案:
  • 调整两端的MTU为路径最小MTU,通常设置为1400字节;
  • 开启TCP MSS钳制,在网关设备上限制TCP的MSS大小,避免大包;
  • 关闭DF标志,允许IP分片(不推荐,会降低性能)。

3.默认路由冲突问题

服务器配置了多个网卡,每个网卡都设置了默认路由,导致数据包转发路径混乱,网络不通。Linux内核中,默认路由的metric值决定了优先级,若多个默认路由metric相同,会导致内核随机选择转发路径。
解决方案:仅保留一个主默认路由,其他出口通过静态路由+策略路由实现,避免多个默认路由冲突。

4.策略路由规则优先级错误

策略路由规则的优先级数字越小,优先级越高,很多人会搞反优先级,导致规则匹配顺序错误,路由不生效。
解决方案:配置规则时,优先级数字从100开始递增,越重要的规则,优先级数字越小,同时通过ip rule show确认规则的排序是否正确。

5.路由表与防火墙规则不匹配

策略路由配置了多出口,但防火墙的SNAT规则没有对应配置,导致数据包从非默认出口转发时,源IP地址错误,无法收到响应。
解决方案:为每个出口配置对应的SNAT规则,确保从对应出口转发的数据包,源IP地址为该出口网卡的IP。
Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐