Neighbor Relationship

介绍邻居关系和邻接关系是如何形成的。

邻居关系

OSPF 是一种链路状态协议,它将路由器接口视为一条 OSPF link。每当 OSPF 启动时,它都会将本地 link-state database 中所有链路的状态加入。

在 OSPF 网络完全可用之前,必须完成几个步骤:

  • 邻居发现
  • 数据库同步
  • 路由计算

链路状态路由协议分发并复制描述路由拓扑的数据库。链路状态协议的泛洪算法确保每台路由器拥有相同的链路状态数据库。路由表基于此数据库计算得出。

完成上述所有步骤后,每个邻居上的链路状态数据库都包含完整的路由域拓扑(网络中有多少台其他路由器、路由器有多少个接口、路由器之间的链路连接哪些网络、每条链路的 cost,等等)。

基本配置示例

要启动 OSPF v2 和 v3 实例,请添加实例和 backbone area:

/routing/ospf/instance
add name=v2inst version=2 router-id=1.2.3.4
add name=v3inst version=3 router-id=1.2.3.4
/routing/ospf/area
add name=backbone_v2 area-id=0.0.0.0 instance=v2inst
add name=backbone_v3 area-id=0.0.0.0 instance=v3inst

模板用于匹配 OSPF 应在其上发现邻居的接口。直接指定 network 或 interface。

/routing/ospf/interface-template
add networks=192.168.0.0/24 area=backbone_v2
add networks=2001:db8::/64 area=backbone_v3
add interfaces=ether1 area=backbone_v3

OSPF 路由器之间的通信

OSPF 运行在 IP 网络层之上,协议号为 89。 目标 IP 地址设置为邻居的 IP 地址或某个 OSPF 组播地址:AllSPFRouters(224.0.0.5)或 AllDRouters(224.0.0.6)。这些地址将在本文后面描述。 每个 OSPF 数据包都以一个标准的 24 字节报头开头。

<center> ```mermaid flowchart LR

subgraph OSPFH["OSPF Header"] OSPFHF["Version: 1bytePacket Type: 1bytePacket Length: 2bytesRouter ID: 4bytesArea ID: 4bytesChecksum: 2bytesAuthType: 2bytesAuthentication: 8bytes"] end

IPH["IP Header"] --> OSPFH --> DATA["Data"]

</center>

| 字段 | 描述 |
| :-- | :-- |
| **Packet type** | 存在多种类型的 OSPF 数据包:Hello 数据包、Database Description(DD)数据包、Link-State Request 数据包、Link-State Update 数据包和 Link-State Acknowledgment 数据包。除 Hello 数据包外,所有这些数据包都用于链路状态数据库同步。 |
| **Router ID** | 除非手动配置,否则默认为路由器的一个 IP 地址。 |
| **Area ID** | 允许 OSPF 路由器将数据包关联到正确的 OSPF area。 |
| **Checksum** | 允许接收路由器判断数据包在传输过程中是否损坏。 |
| **Authentication fields** | 这些字段允许接收路由器验证数据包内容未被修改,并且数据包来自其 Router ID 出现在该数据包中的 OSPF 路由器。 |

五种 OSPF 数据包类型确保 LSA 在 OSPF 网络上正确泛洪:

- **Hello packet** - 发现 OSPF 邻居并建立邻接关系。
- **Database Description (DD)** - 检查路由器之间的数据库同步情况。在建立邻接关系之后交换。
- **Link-State Request (LSR)** - 请求邻居数据库中最新的部分。路由数据库中过时的部分在 DD 交换之后确定。
- **Link-State Update (LSU)** - 携带一组专门请求的链路状态记录。
- **Link-State Acknowledgment (LSack)** - 确认其他数据包类型,以确保可靠通信。

## 邻居发现

OSPF 通过从已配置的接口周期性发送 Hello 数据包来发现潜在邻居。默认情况下,*Hello 数据包*以 10 秒的间隔发送。你可以在 OSPF 接口设置中设置 [`hello-interval`](https://manual.mikrotik.com/cli-reference/routing/ospf/interface-template.md#hello-interval) 来更改此值。当路由器收到参数匹配的邻居返回的 Hello 时,就会得知相邻路由器的存在。

Hello 数据包的发送和接收还允许路由器检测邻居的故障。如果在 [`dead-interval`](https://manual.mikrotik.com/cli-reference/routing/ospf/interface-template.md#dead-interval)(默认为 40 秒)内未收到 Hello 数据包,路由器就会开始绕过该故障进行路由。Hello 协议确保相邻路由器就 Hello interval 和 Dead interval 参数达成一致,从而防止因未及时收到 Hello 数据包而误将链路断开的情况。

<center>
```mermaid
flowchart LR

  subgraph HDATA["Hello Data"]
  HDATAF["Netmask
    Hello Interval
    Options | Priority
    Dead Interval
    DR
    BDR
    1st neighbor ID"]
  end

  IPH["IP Header"] --> OSPFH["OSPF Header"] --> HDATA
</center> | 字段 | 描述 | | :-- | :-- | | **Network mask** | 发起路由器接口 IP 地址的 IP 掩码。 | | **Hello interval** | Hello 数据包之间的周期(默认 10s)。 | | **Options** | 用于邻居信息的 OSPF 选项。 | | **Router priority** | 一个 8 位值,用于辅助 DR 和 BDR 的选举(在点到点链路上不设置)。 | | **Router dead interval** | 邻居被视为 down 之前的时间间隔(默认是 Hello interval 的四倍)。 | | **DR** | 当前 DR 的 router ID。 | | **BDR** | 当前 BDR 的 router ID。 | | **Neighbor router IDs** | 发起路由器所有邻居的 router ID 列表。 |

在每种类型的网段上,Hello 协议的工作方式略有不同。在点到点网段上,只可能有一个邻居,无需额外操作。然而,如果网段上可能有多个邻居,则会采取额外操作以使 OSPF 更高效。

除非满足以下条件,否则两台路由器不会成为邻居:

  • 路由器之间可以双向通信。这通过泛洪 Hello 数据包来确定。
  • 接口应属于同一 area。
  • 接口应属于同一子网并具有相同的网络掩码,除非其 network-type 配置为 point-to-point。
  • 路由器应具有相同的认证选项并交换相同的密码(如果有)。
  • Hello 数据包中的 Hello 和 Dead interval 应相同。
  • Hello 数据包中的外部路由和 NSSA 标志应相同。

信息

Network mask、Priority、DR 和 BDR 字段仅在邻居通过广播或 NBMA 网段连接时使用。

广播子网上的发现

连接到广播子网的节点可以发送单个数据包,该数据包会被所有其他连接的节点接收。这允许自动配置和信息复制。广播子网的另一个重要能力是组播。此能力允许发送单个数据包,并被配置为接收组播数据包的节点接收。OSPF 利用此能力来发现 OSPF 邻居并检测双向连通性。

每台 OSPF 路由器都加入 IP 组播组 AllSPFRouters(224.0.0.5)。随后路由器周期性地将其 Hello 数据包组播到 IP 地址 224.0.0.5。所有加入同一组的其他路由器都将收到组播的 Hello 数据包。通过这种方式,OSPF 路由器只需发送单个数据包即可维护与所有其他 OSPF 路由器的关系,而无需向网段上的每个邻居分别发送数据包。

这种方法带来了若干优势:

  • 通过组播或广播 Hello 数据包自动发现邻居。
  • 与其他子网类型相比,带宽占用更少。
  • 在广播网段上存在 n*(n-1)/2 个邻居关系,但只需发送 n 个 Hello 即可维护这些关系。
  • 如果广播具备组播能力,OSPF 运行时不会干扰广播网段上的非 OSPF 节点。
  • 如果不支持组播能力,所有路由器都将收到广播的 Hello 数据包,即使某节点不是 OSPF 路由器。

NBMA 子网上的发现

非广播多路访问(NBMA)网段与广播类似。它们支持两台以上的路由器。唯一的区别是 NBMA 不支持数据链路广播能力。由于这一限制,OSPF 邻居必须最初通过配置来发现。在 RouterOS 上,静态邻居配置在 /routing/ospf/static-neighbor 菜单中设置。为减少 Hello 流量,连接到 NBMA 子网的大多数路由器应将其 Router Priority 设为 0(RouterOS 中默认设置)。有资格成为 Designated Router 的路由器应设置非 0 的优先级值。这可确保在 DR 和 BDR 选举期间,Hello 仅发送给有资格的路由器。

PTMP 子网上的发现

Point-to-MultiPoint 将网络视为一组点到点链路。

从设计上讲,PTMP 网络不具备广播能力,因此与 NBMA 网络一样,OSPF 邻居必须最初通过配置来发现。所有通信都通过在邻居之间直接发送单播数据包来进行。在 RouterOS 上,静态邻居配置在 /routing/ospf/static-neighbor 菜单中设置。在点到多点子网上不会选举 Designated Router 和 Backup Designated Router。

对于支持广播的 PTMP 网络,可以使用名为 "ptmp-broadcast" 的混合类型。此网络类型使用组播 Hello 来自动发现邻居并检测邻居之间的双向通信。在邻居发现之后,"ptmp-broadcast" 会直接向已发现的邻居发送单播数据包。此模式与 RouterOS v6 的 "ptmp" 类型兼容。

主从关系

在数据库同步开始之前,必须建立一种用于交换信息的层级顺序,以确定哪台路由器首先发送 Database Descriptor(DD)数据包(Master)。主路由器是 Router ID 较高的那台。这是基于路由器 priority 的关系,用于安排邻居之间的数据交换,它不影响 DR/BDR 选举(DR 不一定总是 Master)。

数据库同步

OSPF 路由器之间的链路状态数据库同步非常重要。未同步的数据库可能导致路由表计算错误,从而引发路由环路或黑洞。

OSPF 使用两种类型的数据库同步:

  • 初始数据库同步。
  • 可靠泛洪。

当两个邻居之间的连接首次建立时,会发生初始数据库同步。OSPF 在邻居连接首次建立时使用显式数据库下载。此过程称为 Database exchange。OSPF 路由器不发送整个数据库,而是按顺序在一系列 OSPF Database Description (DD) 数据包中仅发送其 LSA 报头。路由器只有在前一个数据包被确认后才会发送下一个 DD 数据包。当收到完整的 DD 数据包序列后,路由器就知道自己缺少哪些 LSA 以及哪些 LSA 更新。随后路由器发送 Link-State Request (LSR) 数据包请求所需的 LSA,邻居则以 Link-State Update (LSU) 数据包泛洪 LSA 作为响应。收到所有更新后,邻居即称为 fully adjacent。

可靠泛洪是另一种数据库同步方法。当邻接关系已经建立,且 OSPF 路由器必须将 LSA 变化告知其他路由器时,会使用此方法。当 OSPF 路由器收到这样的 Link State Update 时,它会在链路状态数据库中安装新的 LSA,向发送方发回确认数据包,将 LSA 重新打包为新的 LSU,并将其发送到除接收接口以外的所有接口。

OSPF 通过比较序列号来判断 LSA 是否为最新。序列号从 0x80000001 开始。数字越大,LSA 越新。每次泛洪该记录时序列号都会递增,接收到更新的邻居会重置 Maximum age 计时器。LSA 每 30 分钟刷新一次,但如果没有刷新,LSA 会在数据库中以 60 分钟的最大存活时间保留。

数据库并非总是在所有 OSPF 邻居之间同步。OSPF 根据网段决定是否必须同步数据库。例如,在点到点链路上,数据库总是在路由器之间同步。在以太网网络上,数据库在特定的邻居对之间同步。

广播子网上的同步

在广播网段上存在 n*(n-1)/2 个邻居关系。如果 OSPF 路由器试图与子网上的每台 OSPF 路由器同步,就会有大量 Link State Update 和 Acknowledgment 在子网上发送。

此问题通过为每个广播子网选举一个 Designated Router 和一个 Backup Designated Router 来解决。所有其他路由器仅与这两台选出的路由器同步并形成邻接关系。这种方法将邻接关系数量从 n*(n-1)/2 减少到只有 2n-3。

右图展示了广播子网上的邻接关系形成。R1 是 Designated Router,R2 是 Backup Designated Router。例如,如果 R3 想向 R1 和 R2 泛洪 Link State Update (LSU),该路由器会将 LSU 发送到 IP 组播地址 AllDRouters(224.0.0.6),只有 DR 和 BDR 监听此组播地址。随后 Designated Router 发送寻址到 AllSPFRouters 的 LSU,更新其余路由器。

DR 选举

DR 和 BDR 路由器根据 Hello 数据包中收到的数据选举产生。子网上的第一台 OSPF 路由器总是被选举为 Designated Router。当添加第二台路由器时,它成为 Backup Designated Router。当现有的 DR 或 BDR 发生故障时,会根据配置的路由器 priority 选举新的 DR 或 BDR。优先级最高的路由器成为新的 DR 或 BDR。

作为 Designated Router 或 Backup Designated Router 会消耗额外资源。如果 Router Priority 设置为 0,路由器不参与选举过程。当某些较慢的路由器不能成为 DR 或 BDR 时,这一点很重要。

NBMA 子网上的同步

NBMA 网络上的数据库同步类似于广播网络上的同步。会选举 DR 和 BDR。数据库最初仅与 DR 和 BDR 路由器交换,泛洪总是经过 DR。唯一的区别是 Link State Update 必须复制并分别发送给每个相邻路由器。