Routing Decision

MikroTik RouterOS 中的路由决策涉及使用 FIB 和 RIB 表为数据包传输选择路径,管理连接网络、默认路由以及用于高效数据包转发的硬件卸载。

路由决策

路由是在网络之间选择路径以将数据包从一台主机移动到另一台主机的过程。路径选择也称为路由决策,依赖于路由信息表。该表包含路由条目,每个条目指定一个目的地以及用于到达它的下一跳。当数据包从一个网段传递到另一个网段时,就发生了一次 hop(跳)。

通常,路由信息分为两部分,RouterOS 也不例外:

  • FIB – 转发信息库(Forwarding Information Base),用于做出数据包转发决策。它包含转发所需的路由信息的一个子集。
  • RIB – 路由信息库(Routing Information Base),包含从路由来源(如连接网络、静态路由、BGP、RIP 和 OSPF)学到的所有前缀。

路由信息库

RIB 包含完整的路由信息,包括静态路由、连接网络以及从动态协议和 MPLS 标签绑定协议(如 OSPF、BGP 和 LDP)学到的路由。
RIB 所做的不仅仅是简单地存储路由:它过滤路由信息以计算每个目标前缀的最佳路由,构建和更新 FIB,并在路由协议之间分发路由。

默认情况下,所有路由都组织在单个 main 路由表中。

连接网络

连接路由表示主机可以直接到达的网络(直接连接到二层广播域)。RouterOS 会为每个在 /ip/address 或 /ipv6/address 下配置了至少一个已启用接口的 IP 网络自动创建一条连接路由。RIB 跟踪连接路由的状态,但不修改这些路由。每条连接路由都有一个对应的 IP 地址项,满足:

  • 连接路由的 dst-address 的 address 部分等于某个 IP 地址项的网络。
  • 连接路由的 dst-address 的 netmask 部分等于该 IP 地址项地址的 netmask 部分。
  • 连接路由的 gateway 等于该 IP 地址项的 actual-interface(与接口相同,bridge 接口端口除外),表示可以到达来自特定三层网络的直连主机的接口。

连接网络示例:

[admin@TempTest] /ip/route> print where connect 
Flags: D - DYNAMIC; A - ACTIVE; c - CONNECT
Columns: DST-ADDRESS, GATEWAY, ROUTING-TABLE, DISTANCE
    DST-ADDRESS      GATEWAY  ROUTING-TABLE  DISTANCE
DAc 10.155.125.0/24  ether1   main                  0
DAc 192.168.1.0/24   vlan2    main                  0

默认路由

当表中没有其他路由匹配目的地时,会使用默认路由。在 RouterOS 中,默认路由对于 IPv4 的 dst-address 为 0.0.0.0/0,对于 IPv6 为 ::/0。如果路由表包含一条活动的默认路由,那么在该表中的查找总是会成功。

通常,家庭路由器的路由表只包含连接网络和一条默认路由,用于将所有出站流量转发到 ISP 的网关:

[admin@TempTest] /ip/route> add gateway=10.155.125.1  
[admin@TempTest] /ip/route> print where dst-address=/0  
Flags: A - ACTIVE; s - STATIC
Columns: DST-ADDRESS, GATEWAY, ROUTING-TABLE, DISTANCE
#    DST-ADDRESS  GATEWAY       ROUTING-TABLE  DISTANCE
4 As 0.0.0.0/0    10.155.125.1  main                  1

硬件卸载路由

具有 三层硬件卸载(L3HW,也称为 IP switching 或 HW routing)的设备可以将数据包转发卸载到交换芯片。启用 L3HW 后,符合条件的路由会显示 H 标志:

[admin@MikroTik] > /ip/route print where static
Flags: A - ACTIVE; s - STATIC, y - COPY; H - HW-OFFLOADED
Columns: DST-ADDRESS, GATEWAY, DISTANCE
#     DST-ADDRESS       GATEWAY         D
0 AsH 0.0.0.0/0         172.16.2.1      1
1 AsH 10.0.0.0/8        10.155.121.254  1
2 AsH 192.168.3.0/24    172.16.2.1      1

默认情况下,所有路由都是硬件卸载的候选。你可以通过在单个 IPv4 或 IPv6 静态路由上启用或禁用 suppress-hw-offload 选项来微调卸载。 例如,如果大部分流量前往某个服务器网络,则仅为该目的地启用卸载:

/ip route set [find where static && dst-address!="192.168.3.0/24"] suppress-hw-offload=yes

现在只有前往 192.168.3.0/24 的路由具有 H 标志,表明它将是唯一符合被选择进行 HW 卸载条件的路由:

[admin@MikroTik] > /ip/route print where static
Flags: A - ACTIVE; s - STATIC, y - COPY; H - HW-OFFLOADED
Columns: DST-ADDRESS, GATEWAY, DISTANCE
#     DST-ADDRESS       GATEWAY         D
0 As  0.0.0.0/0         172.16.2.1      1
1 As  10.0.0.0/8        10.155.121.254  1
2 AsH 192.168.3.0/24    172.16.2.1      1

警告

H 标志并不表示该路由实际上已被 HW 卸载,它只表示该路由可以被选择进行 HW 卸载。

多路径(ECMP)路由

某些配置(如负载均衡)需要到给定目的地的多条路径。

ECMP(Equal Cost Multi-Path,等价多路径)路由具有多个网关(next-hop)值。所有可到达的 next hops 都会被复制到 FIB 中以进行数据包转发。

你可以手动创建这些路由,也可以由 OSPF、BGP 或 RIP 等协议动态学习它们。到同一目的地的多条同等优先的路由会获得 + 标志,并由 RouterOS 自动分组(参见下面的示例)。

[admin@TempTest] /ip/route> print 
Flags: D - DYNAMIC; I - INACTIVE, A - ACTIVE; C - CONNECT, S - STATIC, m - MODEM; + - ECMP
Columns: DST-ADDRESS, GATEWAY, DISTANCE
#       DST-ADDRESS      GATEWAY       D
0   AS+ 192.168.2.0/24   10.155.125.1  1
1   AS+ 192.168.2.0/24   172.16.1.2    1

默认情况下,ECMP 使用 Layer3 哈希策略,它会对源和目标 IP 地址(IPv4)或源/目标 IP、flow label 和 IP 协议(IPv6)进行哈希。
你可以在 /ip/settings 和 /ipv6/settings 中将哈希策略更改为 Layer4 或 inner Layer3 哈希。
支持的哈希方法包括:

IPv4IPv6
L3srcIPv4, dstIPv4srcIPv6, dstIPv6, flow label, IP proto
L4srcIPv4, dstIPv4, srcPort, dstPort, IP protosrcIPv6, dstIPv6, srcPort, dstPort, IP Proto
L3-InnersrcIPv4, dstIPv4 (if inner IPv4)srcIPv6, dstIPv6, flow label, IP proto (if inner IPv6)Same as L3 if inner is not present.srcIPv4, dstIPv4 (if inner IPv4)srcIPv6, dstIPv6, flow label, IP proto (if inner IPv6)Same as L3 if inner is not present.

路由选择

具有相同目的地的多条路由可以从不同协议或静态配置中学习,但只有一条最佳路由用于转发。RIB 运行路由选择算法,为每个目的地从候选中选出最佳路由。

只有满足以下条件的路由才参与路由选择:

  • 路由未被禁用。
  • 如果路由类型为 unicast,它必须至少有一个可到达的 next-hop。(如果网关来自连接网络且存在一条活动的连接路由,则该网关被视为可到达)
  • 路由不应是 synthetic。

距离最低的候选路由成为活动路由。如果多个候选路由距离相同,则活动路由将被任意选择。

例如,

[admin@RB5009_108] /ip/route> print where dst-address=203.0.113.1
Flags: D - DYNAMIC; A - ACTIVE; s - STATIC, o - OSPF
Columns: DST-ADDRESS, GATEWAY, ROUTING-TABLE, DISTANCE
#     DST-ADDRESS     GATEWAY                  ROUTING-TABLE  DISTANCE
  D o 203.0.113.1/32  111.13.0.2%sfp-sfpplus1  main                110
2  As 203.0.113.1/32  111.13.0.2               main                  1

在示例中,一条静态路由和一条 OSPF 路由指向同一目的地。OSPF 安装其路由时使用比静态路由(1)更高的默认距离(110)。距离较低的路由被选为最佳路由。

Nexthop 查找

Nexthop 查找是路由选择过程的一部分。其主要目的是找到直接可达的网关地址(next-hop)。只有在选择了有效的 next-hop 之后,路由器才知道使用哪个接口进行数据包转发。

如果路由的网关地址距离本路由器有几跳(例如 iBGP、multihop eBGP),nexthop 查找会变得更加复杂。此类路由会在 next-hop 选择算法确定直接可达/立即网关的地址(由 immediate-gw 参数显示)之后安装到 FIB 中。

有必要限制可用于查找立即 next-hops 的路由集合。例如,RIP 或 OSPF 路由的 nexthop 值应当是直接可达的,并且只应使用连接路由进行查找。这通过 scope 和 target-scope 属性实现。

scope 大于最大可接受值的路由不会用于 next-hop 查找。每条路由在其 target-scope 属性中指定其 nexthop 的最大可接受 scope 值。此属性的默认值仅允许通过连接路由进行 nexthop 查找,iBGP 路由除外,它们具有更大的默认值,还可以通过 IGP 和静态路由查找 nexthop。 <Columns> <Column>

<center> | Scope | Route type | Target scope | |:--|:-- |:--| | 0 | | | | 10 | Connected | 5 | | 20 | IGP (OSPF, RIP) | 10 | | 30 | Static | 10 | | 40 | eBGP | 10 | | 40 | iBGP | 30 | </center> </Column> <Column> 该矩阵显示哪种路由类型(行)可以基于默认 scope 和 target-scope 值解析路由类型(列)的网关。 <center> | | IGP | Static | eBGP | iBGP | |:--|:--|:--|:--|:--| | **Connected** | + | + | + | + | | **IGP** | | | | + | | **Static** | | | | + | | **eBGP** | | | | | | **iBGP** | | | | | </center> </Column> </Columns>

可以通过调整 target-scope 值来改变默认行为。例如,如果存在 multihop eBGP 配置,通过 IGP 协议路由或静态路由来解析这些路由的 nexthops 可能是个好主意。为此,我们可以设置输入路由过滤器,将 target-scope 更改为大于 IGP 或静态 scope 的值。甚至可以通过调整 scope 和 target-scope 值,通过 iBGP 路由来解析 eBGP 路由。

scope 调整的灵活性甚至允许创建一种疯狂的配置,例如通过 eBGP 解析 OSPF。

路由按 scope 顺序处理,对具有较大 scope 的路由的更新不会影响具有较小 scope 的路由的 nexthop 查找状态。

RIB 为每个地址保留多个 nexthop 对象,每个 scope 和 gateway check 组合对应一个。

当你更改路由的 target-scope 或 gateway check 时,它 不会影响其他路由,因为这些属性附着在 nexthop 对象上而非路由上。

无效的 scope 值会被自动修正:

  • 如果 nexthop scope 设置为 255 - RouterOS 会在内部通过将其 scope 设置为 254 来修正此错误。
  • 如果路由的 scope 不大于网关查找的最大可接受 scope,RouterOS 会通过将 nexthop scope 设置为 target-scope + 1 来修正错误

你可以在 /routing/nexthop 菜单中查看实际的 scope 和 target-scope 值。

你可以通过设置 check-gateway 参数来扩展网关检查。路由器使用 ARP 探测、ICMP 消息或活动的 BFD 会话来验证网关可达性。默认情况下,它每 10 秒发送一次 ICMP echo 请求(ping)或 ARP 请求(arp)。如果网关在 1 秒内未响应,请求将超时;两次超时后,网关被标记为不可达。收到回复会使网关再次可达,并重置超时计数器。在 /routing/settings 菜单中调整这些间隔。

[admin@CCR2004_2XS_111] /routing/settings> print 
               single-process: no 
  check-gateway-ping-interval: 10s
   check-gateway-ping-timeout: 1s 
     check-gateway-ping-count: 2  

危险

将 gateway 设置为非点对点接口时,不能用于转发目的地有多跳的数据包。 你无法在此类网关上使用 check-gateway 参数,因为不知道目标 IP。

路由存储

路由信息以在常见情况下最小化内存使用的方式进行存储。这些优化可能会有非显而易见的最坏情况,并影响性能。

所有路由和网关都按前缀/地址保存在单个层次结构中。

    Dst [4]/0 1/0+4                             18  <-- number of prefixes
         ^  ^ ^ ^ ^
         |  | | | |
         |  | | | \- bytes taken by Route distinguisher or Interface Id
         |  | | \--- vrf/routing table
         |  | \----- AFI
         |  \------- netmask length of prefix
         \---------- bytes taken by prefix value

         [subject to change without notice]
    

每个 'Dst' 条目对应一个唯一的 'dst-address'(对于路由而言)或网关地址。每个 'Dst' 条目需要一个或多个 'T2Node' 对象。

所有具有相同 'dst-address' 的路由都保存在 Dst 中,并按路由优先级排序形成列表。

信息

最坏情况:拥有许多具有相同 'dst-address' 的路由会非常缓慢,即使它们是非活动的。更新一个包含数万个元素的有序列表会降低性能。 路由顺序仅在路由属性更改时才会改变。如果路由变为活动/非活动,顺序不会改变。

每条路由都有三份路由属性副本:

  • private -- 从对端接收到的内容,在通过 in-filters 之前。
  • updated -- 应用 in-filters 后的结果。
  • current -- 路由当前使用的属性。

定期(在需要时),update 属性会从 private 属性计算得出。这发生在收到路由更新时,或 in-filter 被更新时。

当重新计算路由表时,current 属性会被设置为来自 updated 属性的值。

---
config:
  layout: elk
---
graph LR
    subgraph **RIB**
        direction LR
        P[**Private**] --> F{"in-filter"}
        F --> U[**Update**]
        U --> calc{ Calculation }
        calc --> C[**Current**]
    end

    A@{ shape: f-circ } -->|prefix in| P
    C -->|BGP peer / protocol output| O@{ shape: f-circ }

这意味着,通常如果没有会更改路由属性的 in-filter,private、updated, 和 current 共享相同的值。

路由属性保存在几个组中:

  • L1 Data - 所有标志、额外属性列表、as-path;
  • L2 Data – nexthops、RIP 或 OSPF 度量值、BGP 度量值、路由标记、originators 以及类似属性。
  • L3 Data – distance、scope、kernel type 和 MPLS 信息。
  • extra properties - communities、originator、aggregator-id、cluster-list、unknown

例如,拥有许多不同的 distance 和 scope 路由属性组合将使用更多内存!

使用 regexp 匹配 communities 或 as-path 会缓存结果,以加速过滤。每个 as-path 或 community 值都有一个针对所有 regexp 的缓存,按需填充匹配结果。

信息

最坏情况:在 in-filter 中更改属性会使路由程序使用更多内存!因为 private 和 updated 属性将不同!拥有大量不同的 regexp 会使匹配变慢并占用大量内存!因为每个值都会有一个包含数千个条目的缓存! 有关路由协议使用内存的详细信息,可以在 /routing/stats/memory 菜单中查看

转发信息库

FIB(Forwarding Information Base,转发信息库)包含数据包转发所必需的信息副本:

  • vrf tables
  • active routes
  • policy routing rules
  • other routing decision rules

每条路由都有一个 dst-address 属性,它指定此路由可用于的所有目标地址。如果多条路由适用于某个特定 IP 地址,则使用最具体的一条(具有最大 netmask 的那条)。在路由表包含多条具有相同 dst-address 和 netmask 的路由的情况下,所有同等最佳的路由会合并为一条 ECMP 路由,安装到 FIB 中并标记为 ''active''

只有一条最佳路由可用于数据包转发。
查找与给定地址匹配的最具体路由称为 routing table lookup。

当转发决策使用额外信息(例如数据包的源地址)时,称为 policy routing。策略路由实现为一个策略路由规则列表,这些规则基于数据包的目的地址、源地址、源接口和路由标记(可由防火墙 mangle 规则更改)来选择不同的路由表。

路由表查找

FIB 使用数据包中的以下信息来确定其目的地:

  • 源地址
  • 目的地址
  • 源接口
  • 路由标记

可能的路由决策有:

  • 本地接收数据包
  • 丢弃数据包(静默丢弃或通过向数据包发送者发送 ICMP 消息)
  • 将数据包发送到特定接口上的特定 IP 地址

路由决策动作由 /routing/settings 中通过 policy-rules 参数定义的策略规则确定。
默认情况下:

[admin@CCR2004_2S+_107] /routing/settings> print 
               single-process: no         
  check-gateway-ping-interval: 10s        
   check-gateway-ping-timeout: 1s         
     check-gateway-ping-count: 2          
                 policy-rules: mangle     
                               vrf-lookup 
                               vrf-unreach
                               local      
                               user       
                               main  
  • 在由 mangle 规则标记的路由表中查找目的地。
  • 如果接口属于某个 VRF 或数据包被引导到某个 VRF,则尝试在 VRF 表中查找。
  • 如果 VRF 查找失败,则拒绝该数据包。
  • 检查数据包是否必须本地投递(目的地址是路由器的地址)。
  • 处理用户定义的 routing rules(来自 "user" 链)
  • 在 main 路由表中查找目的地。

根据所需任务的复杂程度,你可以更改默认规则的顺序,或通过添加自定义规则来微调配置。

例如,如果目的地 1.2.3.4 必须仅在 other_table 中解析,并且你打算额外使用 mangle,那么添加你的路由规则并将 mangle 动作移到你的自定义规则之下:

[admin@r1] /routing/settings> set policy-rules=vrf-lookup,vrf-unreach,local,user,mangle,main
[admin@r1] /routing/rule> add dst-address=1.2.3.4 action=lookup-only-in-table table=other_table
[admin@r1] /routing/rule> print 
Flags: X - disabled, I - inactive; * - default 
 0    dst-address=1.2.3.4 action=lookup-only-in-table table=other_table 

如果某个规则具有动作:

  • drop 或 unreachable,则将其作为路由决策过程的结果返回。
  • lookup,则在规则中指定的路由表中查找数据包的目的地址。如果查找失败(没有路由匹配数据包的目的地址),则 FIB 继续处理下一条规则。
  • lookup-only-in-table 与 lookup 类似,只是如果表中没有任何路由匹配该数据包,则查找失败。

否则:

  • 如果路由类型为 blackhole,则将此动作作为路由决策结果返回。
  • 如果这是一条连接路由或网关值是一个接口的路由,则返回该接口和数据包的目的地址作为路由决策结果。
  • 如果此路由的网关值是 IP 地址,则返回此地址和关联的接口作为路由决策结果。
  • 如果此路由有多个 nexthop 值,则根据配置的 hash policy 以轮询方式选择其中之一。

请记住,通常为静态路由将接口设置为网关并不是个好主意。接口网关仅在两种场景中有用:

  • 在点对点类型接口上;
  • 在目的地址直接连接的接口上。

如果路由决策在广播网络上返回一个接口和数据包的目的地址作为结果,路由器将尝试通过发送 ARP 探测来在接口上解析数据包的目的地址。如果同一广播域中没有主机具有该 IP 地址,转发将失败,因此此类网关不能用于路由目的地有多跳的数据包。