OSPF和OSPF邻接关系的建立过程

一、OSPF的简单介绍

       OSPF(Open Shortest Path First,开放式最短路优先)是一种典型的链路状态路由协议,由IETF(Internet Engineering Task Force,Internet工程任务组)的OSPF工作小组开发,是目前应用最广泛的IGP(Interior Gateway Protocal,内部网关协议)之一。OSPF中的“O”意为“Open”,即开放的意思,所有的厂商的设备都可以实现OSPF,它们都要遵循公有标准。OSPF支VLSM(Variable Length Subnet Mask,可变长子网掩码)、支持认证、支持路由汇总等,另外区域(Area)的概念引入使得OSPF能够支持更大规模的网络。当网络拓扑发生变化时,OSPF能够快速地感知并进行路由的计算和重新收敛。目前OSPF主要有两个版本,一是OSPFv2,该版本主要针对IPv4;另外一个版本是OSPFv3,该版本主要针对IPv6。本文主要探讨OSPFv2。

二、OSPF的基本概念

2.1 基本原理

       《计算机网络》这本书中是这样表述OSPF的“在OSPF协议中,路由器会将自己的链路状态信息一次性地泛洪给其他路由器”,通俗点的理解是这样的,每台路由器都产生一个描述自家门口情况的通告。这些通告会泛洪到整个网络,从而保证网络中的每台路由器都拥有对该网络的一直认知。路由器将这些链路状态信息存储在LSDB(Link-State Database,链路状态数据库)之中,LSDB内的数据有助于路由器还原全网的拓扑结构。接下来,每台路由器都基于LSDB使用相同的算法进行计算,计算的结果是得到一颗以自己为根的、无环的最短路径“树”。有了这棵树“树”,事实上路由器就已经知道了到达网络各个角落的最优路径。最后,路由器将计算出来的最优路径加载到自己的路由表。

2.2 Router-ID

       OSPF Router-ID(Router Identification,路由器标识符)是一个32bit长度的数值,通常使用点分十进制的形式表现,用于在OSPF域中唯一标识一台OSPF路由器。OSPF要求路由器的Router-ID必须全域唯一,即在同一个域内不允许出现两台OSPF路由器拥有相同Router-ID的情况。

2.3 OSPF的三张表

  • 邻居表
           在OSPF交互链路状态通告之前,两台直连路由器需建立OSPF邻居关系。当一个接口**OSPF后,该接口将周期性地发送OSPF Hello报文,同时也开始侦听Hello报文从而发现直连链路上的邻居。当OSPF在接口上发现邻居后,邻居的信息就会被写入路由器的OSPF邻居表,随后一个邻接关系的建立过程也就开始了。下图是运行了OSPF的华为路由器的邻居表。从这张表中我们可以看见路由器的邻居状态(Full)、Router ID、主从关系(Slave)、接口IP地址等信息。
    OSPF和OSPF邻接关系的建立过程
  • 链路状态数据库
           运行链路状态路由协议的路由器在网络中泛洪链路状态信息,在OSPF中,这些信息被称 LSA(Link-State Advertisement,链路状态通告),路由器将网络中的LSA搜集后装载到自己的LSDB中,因此LSDB可以当作是路由器对网络的完整认知。下图是运行了OSPF的华为路由器的LSDB。
    OSPF和OSPF邻接关系的建立过程
  • OSPF路由表
           OSPF根据LSDB中的数据,运行SPF算法并且得到一颗以自己为根的、无环的最短路径树,基于这棵树,OSPF能够发现到达网络中各个网段的最佳路径,从而得到路由信息并将其加载到OSPF路由表中。下图展示的是一个OSPF路由表。
    OSPF和OSPF邻接关系的建立过程

三、报文类型及其格式

       OSPF协议基于IP运行,协议的数据报文直接采用IP封装,在IP报文头部中对应的协议号为89。多数情况下,OSPF的协议报文使用组播地址作为目的IP地址。OSPF一共定义了五种报文,各有用途下表罗列了这五种报文,以及报文的描述。

类型 报文名称 报文描述
1 Hello 用于发现直连链路上的OSPF邻居,以及维护OSPF邻居关系
2 DD(Database Description,数据库描述) 用于描述LSDB,该报文中携带的是LSDB中LSA的头部数据
3 LSR(Link State Request,链路状态请求) 用于向OSPF邻居请求LSA
4 LSU(Link State Update,链路状态更新) 用于发送LSA,该报文中携带的是完整的LSA数据。LSA是承载在LSU中进行泛洪的
5 LSAck(Link State Acknowledgment,链路状态确认) 设备收到LSU后,LSAck用于对接收的LSA进行确认

3.1 OSPF报文头格式

      OSPF这五种报文具有相同的报文头格式,长度为24字节。
                     OSPF和OSPF邻接关系的建立过程
                                                               OSPF报文头格式

字段 长度 含义
Version 1字节 版本,OSPF的版本号。对于OSPFv2来说,其值为2。
Type 1字节 类型,OSPF报文的类型,有下面几种类型:1:Hello报文;2:DD报文;3:LSR报文;4:LSU报文;5:LSAck报文。
Packet length 2字节 OSPF报文的总长度,包括报文头在内,单位为字节。
Router ID 4字节 发送该报文的路由器标识。
Area ID 4字节 发送该报文的所属区域。
Checksum 2字节 校验和,包含除了认证字段的整个报文的校验和。
AuType 2字节 验证类型,值有如下几种表示, 0:不验证;1:简单认证;2:MD5认证。
Authentication 8字节 鉴定字段,其数值根据验证类型而定。当验证类型为0时未作定义;类型为1时此字段为密码信息;类型为2时此字段包括Key ID、MD5验证数据长度和***的信息。MD5验证数据添加在OSPF报文后面,不包含在Authenticaiton字段中。

3.2 Hello报文

       Hello报文是最常用的一种报文,其作用为建立和维护邻接关系,周期性的在使能了OSPF的接口上发送。报文内容包括一些定时器的数值、DR、BDR以及自己已知的邻居。
                     OSPF和OSPF邻接关系的建立过程
                                                               OSPF Hello报文格式

字段 长度 含义
Network Mask 32比特 发送Hello报文的接口所在网络的掩码。
HelloInterval 16比特 发送Hello报文的时间间隔。
Options 8比特 可选项:E:允许Flood AS-External-LSAs MC:转发IP组播报文 N/P:处理Type-7 LSAsDC:处理按需链路
Rtr Pri 8比特 DR优先级。默认为1。如果设置为0,则路由器不能参与DR或BDR的选举。
RouterDeadInterval 32比特 失效时间。如果在此时间内未收到邻居发来的Hello报文,则认为邻居失效。
Designated Router 32比特 DR的接口地址。
Backup Designated Router 32比特 BDR的接口地址。
Neighbor 32比特 邻居,以Router ID标识。

下面是抓包图:
OSPF和OSPF邻接关系的建立过程

3.3 DD报文

       两台路由器在邻接关系初始化时,用DD报文(Database Description Packet)来描述自己的LSDB,进行数据库的同步。
                     OSPF和OSPF邻接关系的建立过程
                                                               OSPF DD报文格式

字段 长度 含义
Interface MTU 16比特 在不分片的情况下,此接口最大可发出的IP报文长度。
Options 8比特 可选项: E:允许Flood AS-External-LSAs;MC:转发IP组播报文;N/P:处理Type-7 LSAs;DC:处理按需链路。
I 1比特 当发送连续多个DD报文时,如果这是第一个DD报文,则置为1,否则置为0。
M (More) 1比特 当发送连续多个DD报文时,如果这是最后一个DD报文,则置为0。否则置为1,表示后面还有其他的DD报文。
M/S (Master/Slave) 1比特 当两台OSPF路由器交换DD报文时,首先需要确定双方的主从关系,Router ID大的一方会成为Master。当值为1时表示发送方为Master。
DD sequence number 32比特 DD报文***。主从双方利用***来保证DD报文传输的可靠性和完整性。
LSA Headers 可变 该DD报文中所包含的LSA的头部信息。

下面是抓包图:OSPF和OSPF邻接关系的建立过程

3.4 LSR报文

      两台路由器互相交换过DD报文之后,知道对端的路由器有哪些LSA是本地的LSDB所缺少的和哪些LSA是已经失效的,这时需要发送LSR报文(Link State Request Packet)向对方请求所需的LSA。内容包括所需要的LSA的摘要。
                     OSPF和OSPF邻接关系的建立过程
                                                        OSPF LSR报文格式

字段 长度 含义
LS type 32比特 LSA的类型号。
Link State ID 32比特 根据LSA中的LS Type和LSA description在路由域中描述一个LSA。
Advertising Router 32比特 产生此LSA的路由器的Router ID。

下面是抓包图:
OSPF和OSPF邻接关系的建立过程

3.5 LSU报文

       路由器收到邻居发送过来的LSR后,会以LSU报文进行回应,在LSU报文中就包含了对方请求的LSA的完整信息,一个LSU可以包含多个LSA。
                     OSPF和OSPF邻接关系的建立过程
                                                        OSPF LSU报文格式

字段 长度 含义
Number of LSAs 32比特 LSA的数量。

下面是抓包图:
OSPF和OSPF邻接关系的建立过程

3.6 LSAck报文

       为了确保LSA能够可靠送达,当一台路由器收到邻居发送过来的LSU报文时。需要对报文中含有的LSA进行确认,这个确认行为可以回复一个LSAck报文。
                     OSPF和OSPF邻接关系的建立过程
                                                        OSPF LSU报文格式

下面是抓包图:
OSPF和OSPF邻接关系的建立过程
四、邻接关系及其建立

4.1 邻接关系

       在《报文类型及其格式》一节中,我们已经知道了路由器在运行了OSPF之后会进行一系列的报文交互,最后完成LSDB的同步,路由器形成了对网络拓扑的一致认知,并开始独立计算路由。此时,我们称这两台路由器形成了邻接关系。接下来具体学习邻接关系建立过程之前我们先了解8种OSPF的邻居状态。

状态 状态描述
Down(失效) OSPF路由器的初始状态
Init(初始) 当OSPF路由器收到直连链路上某个邻居发送过来的有效Hello报文,但并未在Hello报文的邻居字段看到自己的Router-ID
Attempt(尝试) 该状态只在NBMA类型的接口中出现
2-Way(双向通信) 当OSPF路由器收到直连链路上某个邻居发送过来的Hello报文,并在Hello报文的邻居字段看到自己的Router-ID
ExStart(j交换初始) 在该状态下路由器协商Master/Slave
Exchange(交换) 该状态下路由器向自己的邻居发送描述自己LSDB的DD报文,报文中含有LSA的头部
Loading(加载) 路由器向邻居发送LSR以便请求完整LSA
Full(全毗邻) LSA列表为空,LSDB完成同步

4.2 邻接关系的建立

              OSPF和OSPF邻接关系的建立过程
                                          R1与R2在直连链路上发现彼此形成邻居关系

       在上图的例子中两个路由器的对应接口都**OSPF,R1的接口**OSPF后开始发送组播的Hello报文,在该报文的OSPF头部中,填写着R1的Router-ID和区域ID,Hello报文的荷载中,填写着其他信息(详细见上图)。R2在收到这个报文后,首先检查对接方的子网掩码、Hello间隔、路由器失效间隔是否一致,如果不一致忽略该报文。如果通过了检查R2将R1状态设置为Init。接下来,R2在自己发送的Hello报文的“邻居”字段中写入R1的Router-ID。而当R1收到R2发送过来的Hello报文并且在“邻居”字段中发现自己的Router-ID时,它意识到邻居R2已经发现了自己,并且认可了自己所发送的Hello报文中的相关参数,于是它将R2添加到自己的邻居表并且把R2的状态设置为2-Way。随后R1在自己发送的Hello报文的“邻居”字段中写入R2的Router-ID,后者收到该报文后,在其邻居表中将R1的状态切换到2-Way。至此,R1与R2形成了邻居关系。
                     OSPF和OSPF邻接关系的建立过程
                                                 R1与R2使用DD报文描述自己的LSDB

       接下来,在ExStart状态下R1及R2需要交互空的DD报文以便协商Master/Slave。由于R2的Router-ID更大,因此它胜出成为Master路由器。用于协商Master/Slave的DD报文并不携带任何LSA头部,而且I比特位被设为1。然后将R2的状态切换到Exchange并发送带有LSA头部的DD报文这个DD报文的DD***为300(也就是R2发送过来的DD***)M比特位设置为1表示后续还有更多的DD报文,而MS比特位设置为0。接着R2收到了R1发送过来的DD报文,于是将R1的状态切换到Exchange,随后自己也开始发送携带LSA头部的DD报文,此时DD报文的DD***为301(在上一个***300 的基础上加1),M及MS比特位均设置为1。由于双方的LSDB中都包含较多LSA,因此需交互多个DD报文,而在该过程中,Master路由器R2将DD***逐次加1,Slave路由器R1则使用前者的DD***来发送自己的DD报文,如此这般有序的进行。
                     OSPF和OSPF邻接关系的建立过程
                                                               R1与R2达到全毗邻状态

       经过数次DD报文交互后,R2发送的DD***达到308,使用该DD***发送了自己最后一个DD报文,在该报文中,它将M比特位设置为0。R2收到该DD报文后,继续发送自己的DD报文描述剩余LSA头部,而恰巧这也是它的最后一个DD报文,它在该报文中将M比特位设置为0。当该报文到达R1后,虽然此时它已经描述完了自己的LSDB,但是它依然需要确认R2所发送的最后一个DD报文,于是它向R2发送一个空的DD报文,该报文的DD***为309。R1及R2收到对方发送的最后-一个DD报文后,便彻底了解了对方的LSDB中所包含的LSA(头部),此时它们需要从对方获取感兴趣的LSA的完整数据,因此R1将R2的邻居状态切换为Loading,D报文,在该报文中,它将M比特位设置为0。R2收到该DD报文后,继续发送自己的DD报文描述剩余LSA头部,而恰巧这也是它的最后一个DD报文,它在该报文中将M比特位设置为0。当该报文到达R1后,虽然此时它已经描述完了自己的LSDB,但是它依然需要确认R2所发送的最后一个DD报文,于是它向R2发送一个空的DD报文,该报文的DD***为309。R1及R2收到对方发送的最后-一个DD报文后,便彻底了解了对方的LSDB中所包含的LSA(头部),此时它们需要从对方获取感兴趣的LSA的完整数据,因此R1将R2的邻居状态切换为Loading,R2同理。接下来,便是数据库同步过程,R1向R2发送LSR报文,用于请求感兴趣的LSA,而R2则使用包含LSA完整数据的LSU报文进行回应,同理,R2也向R1发送用于请求LSA的LSR报文,而后者也使用LSU报文进行回应。双方可能会交互多个LSR及LSU报文,直到LSDB实现同步.R1或R2收到对方发送的LSU报文后,将报文中所包含的LSA加载到自己的LSDB中,并使用LSAck确认这些LSA。当R1或R2发现自已没有其他的LSA需要从邻居获取后,便将邻居的状态切换为Full。