10.2 BGP 的报文格式
BGP 的报文承载于 TCP 报文,如图10-7所示。
图10-7 BGP 报文承载于 TCP 报文
BGP 报文所对应的 TCP 端口号是179。与其他协议一样,BGP 报文也分为2部分:BGP Header、BGP Data。下面我们分别讲述。
10.2.1 BGP 报文头格式
BGP 报文分为4种类型,所有类型的 BGP Header,都是一样的格式,如图10-8所示。
图10-8 BGP Header 报文格式
BGP Header 包括3个字段:Marker、Length、Type,下面我们分别讲述。
Marker
Marker 占有16个字节,其值全部设为“1”(This 16-octet field is included for compatibility; it MUST be set to all ones. RFC 4271)。
Length
Length 字段占有2个字节,其标识整个 BGP 报文的长度(计量单位是“字节”),等于 BGP Header 长度与 BGP Data 长度之和。
Type
Type 字段占有1个字节,标识 BGP 的报文类型。BGP 报文类型一共有4种。
(1)Open(Type = 1): 用于建立BGP对等体之间的连接关系
(2)Keepalive(Type = 2): 周期性地向BGP邻居发出Keepalive消息, 用来保持 TCP连接的有效性
(3)Update(Type = 3): 携带的是路由更新(删减、增加)信息
(4)Notification(Type = 4): 当BGP检测到错误状态时, 就向对等体发出Notification消息, 之后BGP连接会立即被关闭
BGP Update 报文(Type = 3),就是“传说”中的 BGP 路由通告报文。由于另外3种报文并不是本章的重点,所以接下来我们值讲述 BGP Update 的报文格式。
10.2.2 BGP Update报文格式
BGP 路由通告,简单地说就是:路由器将存放于自身 BGP 表中的路由信息,通过 BGP Update 消息,发送给它的 BGP 邻居(peer)。
不过需要强调的是,BGP 每次通告的是它的“变量”路由信息,而不是全量。这意味着路由器第1次将自己所有 BGP 路由信息通告给其邻居以后,后续的路由通告,只须通告“变化”的路由信息即可。
所谓“变化”,指的就是当前的路由信息与上次通告时的路由信息相比,哪些是“删除”的路由,哪些是“新增”的路由。
所以我们会在 BGP Update 报文中看到“删除路由”、“新增路由”等相关字段,如图10-9所示。
10-9 BGP Update 消息报文格式
图10-9所示的 BGP Update 报文格式,分为3个部分。
(1)撤销路由的信息,包含2个字段:Withdrawn Routes Length,Withdrawn Routes。当上次通告的路由,有些路由已经无效时,本次路由通告需要靠这两个字段告知邻居将这些无效的路由撤销(删除)
(2)新增路由的路径属性,包含两个字段:Total Path Attribute Length,Path Attributes。这个表示新增的路由,除了目的网段以外的其他相关的路径属性
(3)新增路由的可达信息,包含1个字段:Network Layer Reachability Information,表示的是新增路由的目的网段信息(意思是,这些网段的路由是可达的)。
下面我们分别讲述这3部分内容。
10.2.2.2 撤销路由的信息
由于所要撤销的路由(Withdrawn Routes)是一个变长字段(包含 0~n 个撤销路由),所以需要用 Withdrawn Routes Length(撤销路由长度,占用2个字节)来标识所有的撤销路由的长度(计量单位是字节)。
当然,如果 Withdrawn Routes Length = 0,则表示没有需要撤销的路由(Withdrawn Routes Length 字段的后面,也不会再有 Withdrawn Routes 字段)。
Withdrawn Routes,是一个列表(List),包含 N 个二元组“
图10-10 Withdrawn Routes 数据结构
图10-10表达了 n 个二元组
1个路由表项中表达目的地址的方法是“网段 + 掩码长度”,二元组(Length, Prefix)中的“Length”表述的就是掩码长度,“Prefix”表述的就是网络号。比如“1.1.1.0/24”用这种二元组的方法表示就是<24(length), 1.1.1(prefix)>,当然“1.1.1”要用bit的形式表示:111111100000000111111111(1 * 2553 + 1 * 2552 + 1 * 255)。
如果二元组的 Length = 0(Prefix 也就不用填写了,因为也没地方填写了),那么意味着所有路由都撤销。
10.2.2.3 新增路由的可达信息
新增路由的可达信息(Network Layer Reachability Information,NLRI)的根本含义就是路由表项中的“目的地址”,所以它的数据结构与 Withdrawn Routes 是一样的,也是一个 list,包含 N 个二元组
NLRI 表示路由表项中的“目的地址”,那么路由表项中的“下一跳”该是什么呢?这就涉及到了“新增路由中的路径属性”。
10.2.2.4 新增路由中的路径属性
BGP Speaker 向它的邻居不能仅仅通告1个“目的地址”,最起码还要包含“下一跳”,这个路由表项才会完整。
BGP 将“下一跳”的信息放到了 BGP Update 报文中的“新增路由中的路径属性”字段。除了“下一跳”以外,“路径属性”还包括很多内容,而且非常复杂。
我们先从属性的分类讲起。
1)路径属性的分类
我们知道,一个 BGP Speaker,在收到邻居的路由通告(BGP Update 报文)时,还会继续通告给它的其他邻居(注意前面介绍过的 eBGP 和 iBGP 的区别)。这些属性分类,其目的是为了约束路由器是否支持这些属性,以及是否传递这些属性。
路径属性一共分为4类。
(1)Well-known mandatory(公认/必选)。这些属性必须支持,而且必须体现在 BGP Update 报文中,而且必须再次传递给邻居(在接下来的路由通告报文中,必须包含这些属性),如果需要再次通告给邻居的话
(2)Well-known discretionary(公认/自选)。这些属性必须支持,但是第1个路由公告路由时,不是必须体现在 BGP Update 报文中.如果第1个路由公告路由时,包含了这些属性,那么后续路由通告中必须再传递给邻居
(3)Optional transitive(可选/可传递)。这些属性不要求必须支持。有的路由器支持,有的路由器不支持,这没关系。当1个支持此属性的路由器,通告给一个不支持此属性的路由器时,这个不支持此属性的“吃瓜”路由器,再次通告路由时,是丢弃还是传递此属性,取决于报文中其中一个 bit 的值(1,必须传递;0 必须不传递)
(4)Optional non-transitive(可选/非传递)。这些属性不要求必须支持。有的路由器支持,有的路由器不支持,这没关系。当一个支持此属性的路由器,通告给一个不支持此属性的路由器时,这个不支持此属性的“吃瓜”路由器,再次通告路由时,必须丢弃此属性,不能在 Update 报文中带上此属性
以上所说的分类,其实是表达了路由通告的两个行为:是否必须支持、是否必须传递,如表10-1所示。
表10-1 路径属性分类的含义
是否必须支持 |
是否必须传递 |
|
公认/强制 Well-known mandatory |
必须支持 |
必须传递 |
公认/自定 Well-known discretionary |
必须支持 路由器必须支持,但是第1个公告路由的路由器,可以不带上这些属性 |
必须传递 如果第1个公告路由的路由器,没带上这些属性,那么所谓传递,无从谈起; 如果第1个公告路由的路由器,带上了这些属性,那么以后的路由通告,必须传递 |
可选/可传递 Optional transitive |
N |
不一定 是否传递,取决于报文中有一个 bit 位设置的值:1,必须传递;0 必须不传递 |
可选/非传递 Optional non-transitive |
N |
必须不能传递 |
从某种意义上讲,“必须支持”的属性,就是 BGP 协议规定的“公有属性”,不是“必须支持”的属性,就是厂商的私有属性,厂商可以任意扩展。
当前 BGP Update 消息中的路径属性,我们举例如表10-2所示。
表10-2 路径属性举例
属性名称 |
属性类型 |
Origin |
Well-known mandatory |
AS_Path |
Well-known mandatory |
Next hop |
Well-known mandatory |
MED |
Optional non-transitive |
Local_Preference |
Well-known discretionary |
Atomic_Aggregate |
Well-known discretionary |
Aggregator |
Optional transitive |
Community |
Optional transitive |
Originator_ID |
Optional non-transitive |
Cluster_List |
Optional non-transitive |
Destination Pref (MCI) |
|
Advertiser (Baynet) |
|
Rcid-Path (Baynet) |
|
MP_Reach_NLRI |
|
MP_Unreach_NLRI |
|
Extended_Communities |
2)路径属性的数据结构
BGP Update 消息中,有两个字段表示路径路径属性(如图10-9所示):Total Path Attribute Length,Path Attributes。
Total Path Attribute Length 占有2个字节,它指明了 Path Attributes 字段的所有长度(计量单位是字节)。
Path Attributes 是个变长字段,它是一个 list,包含 N 个三元组
attribute type
attribute type 占有2个字节。attribute type,又细分为2个字段。第1个字段是Attr.Flags(属性标签),第2个字段是Attr.Type Code(属性类型值),如图10-11所示。
图10-11 Attribute Type 的数据结构
Attr.Type Code,是一个整数,表示一个属性类型,比如“ORIGIN”属性的 Attr.Type Code = 1。
而 Attr.Flags 则比较复杂,其前4个 bit,每个 bit 都表示1个含义(后4个 bit,暂时没有使用),如图10-12所示。
图10-12 Attr. Flags 报文结构
这8个 bit 的解释,如下表所示。
表10-3 Attr. Flags 各 bit 的含义
bit |
含义 |
0 Optional |
如果值等于1,则表示属性是可选的(optional) 如果值等于0,则表示属性是公认的(well-known) |
1 Transitive |
针对可选属性,如果值为1,则表示必须传递,如果值为0,则表示必须不传递 针对 well-known 属性,其值必须设置为1(必须传递) |
2 Partial |
针对 Optional Transitive 属性,如果值为1,表示这个属性仅仅是部分,如果值是0,表示这个属性已经是完整的(complete) 针对 well-known 属性 和 optional non-transitive 属性,其值必须为0(complete) |
3 Extend Length |
如果值等于0,则表示接下来的属性长度字段占用1字节 如果值等于1,则表示接下来的属性长度字段占用2字节 |
4~7 unused |
4~7 bit,没有使用,必须设置为0 |
通过表10-3可以看到,我们在“属性的分类”中所讲述的“well known/optional、transitive/non-transitive”,实际上就是由这 4 个 bits 来表示。
attribute length
attribute length,可能占有1个字节,也可能占有2个字节,取决于表10-3中的“Extend Length”这个 bit 的值。如果 Extend Length = 0,attribute length 占有1个字节,如果 Extend Length = 1,attribute length 占有2个字节。
attribute length 表示的是 attribute value 的长度(计量单位是字节)
attribute value
attribute value 是一个变长字段,表示属性的值。至于属性的值具体代表什么含义,与具体的属性类型相关。
3)路径属性的说明
表10-2中列举了 16 个路径属性,这里我们挑选几个比较重要的属性进行介绍。
Origin
Orgin 是一个 Well-known mandatory 属性,Attr.Type Code = 1。它指的是这次路由通告(Update 报文)中的路由来源是什么,不同的值,代表不同的来源。
(1)IGP(attribute value = 0),表示 NLRI 来源于本 AS 的 IGP 导入
(2)EGP(attribute value = 1),表示 NLRI 来源于 EGP(EGP 已经废弃)
(3)INCOMPLETE(attribute value = 1),表示 NLRI 从其他方式获得,比如路由重分布(redistribute)
AS_Path
AS_Path 是一个 Well-known mandatory 属性,Attr.Type Code = 2。
AS_Path 的数据结构是一个三元组
(1)path segment type,表明 path segment value 里的 AS ID 的排列顺序。
如果 path segment type = 1,表明是 AS_SET,无序排列;
如果 path segment type = 2,表明是 AS_SEQUENCE,顺序排列。
值得一提的是,这个顺序排列,其实是倒叙排列。比如通告顺序是:R1(AS1) -> R2(AS2),R2(AS2) -> R3(AS3),
R3(AS3) -> R4(AS4),那么 path segment value = AS4,AS3,AS2,AS1。
(2)path segment length,1个字节长,表明 path segment value 中包含多少个 AS ID(1个字节长,意味着最多有 255 个 AS ID)。
(3)path segment value,是一批 AS ID,表明到达此次通告中的路由,所经过的 AS。这是个变长字段,取决于有多少个 AS ID,每个 AS ID 占用2个字节
AS_Path 的赋值规则是如下。
(1)如果是 iBGP 通告,则不会改变原来的 AS_Path 值,保持不变,通告下去。
(2)如果是 eBGP 通告,则在“path segment value”里面 insert 自己的 AS ID(注意区分path segment type)。
AS_Path 有两大作用,第1个作用是防止 eBGP 路由通告环路,第2个作用是在 BGP 选择最优路径时,发挥作用。
第2个作用,我们放到10.3节讲述,这里我们先讲述第1个作用(防止 eBGP 路由通告环路)。
eBGP 的路由通告是“一传十十传百”,这有可能会引发路由回路。为了阅读方便,我们将图10-4重新贴一下,如图10-13所示。
图10-13 eBGP 的路由通告
图10-13中,R1 自己的路由,经过“R1-R2-R3-R4-R1”这样一个循环,又通告给自己。然后,R1 再通告给 R2 ...... 如此循环反复,无穷无尽。而且,图10-13这样的场景,不仅会造成路由通告环路,还会引发路由环路。
eBGP 解决这个问题的方法就是,在 BGP Update 消息中,在路径属性里附加上 AS_Path 这个字段。比如 R1 通告给 R2,AS_Path 的值是“AS1”(AS_Path 的值实际上是1个三元组列表,这里只是简单示例)。这个路由再通过 R2 通告给 R3 时,AS_Path 的值是“AS2-AS1”,以此类推,当这个路由通过 R4 通告给 R1 时,AS_Path 的值变成了“AS4-AS3-AS2-AS1”。当 AS1 得到这个路由通告时,它发现 AS_Path 里面有自己“AS1”,那么它就将这条路由丢弃。这样就避免了环路。
Next_Hop
Next_Hop 是一个 Well-known mandatory 属性,Attr.Type Code = 3。
BGP Speaker,会将路由通告给它的 peer。那么其所通告的路由中的下1跳(Next_Hop)应该是什么呢?我们从1个例子入手来讲解。如图10-14所示。
图10-14 Next_Hop 组网图
我们先描述一下图10-14中的 TOPO 关系,如下所示。
(1)R1(1.1.1.1/24)/R3(1.1.3.3/24),iBGP peer
(2)R1(1.1.1.1/24)/R4(1.1.1.4/24),eBGP peer
(3)R4(1.1.4.4/24)/R5(1.1.4.5/24),eBGP peer
(4)R5(1.1.5.5/24)/R6(1.1.5.6/24),iBGP peer
(5)R3 连接 8.8.8.0/24 网段
Next_Hop 的赋值规则如下。
(1)iBGP 通告,目的地址也在 iBGP 这个 AS 域内(图10-14中 R3 通告给 R1,目的网段 8.8.8.0/24),Next_Hop 就是宣告路由器的地址(1.1.3.3)
(2)iBGP 通告,目的地址不在 iBGP 这个 AS 域内(图10-14中 R5 通告给 R6,目的网段 8.8.8.0/24),Next_Hop 是上一个 eBGP 宣告时的宣告者地址(图10-14中,上一个 eBGP 宣告,是 R4 宣告给 R5,Next_Hop 是 R4 的 IP 地址:1.1.4.4)
(3)eBGP 通告,Next_Hop 就是宣告路由器的地址(图10-14中:R1 通告给 R4,目的网段 = .8.8.0/24,Next_Hop = 1.1.1.1;R4 通告给 R5,目的网段 = 8.8.8.0/24,Next_Hop = 1.1.4.4)
我们把 Next_Hop 属性叠加到图10-14中,可以有更加直观的认识,如图10-15所示。
图10-15 Next_Hop 示意图
Multi_Exit_Disc
Multi_Exit_Disc 是 Multi_Exit_Discriminate 的缩写,有时也简写为 MED。它是一个 optional non-transitive 属性,Attr.Type Code = 4。
MED 是一个 4 字节的无符号整数,正如其名称“Multi_Exit_Discriminate(多出口辨别)”所暗示的那样,它的目标确实也就是在路由选择时,帮助 BGP 选择哪个出口,如图10-16所示。
图10-16 MED 示意图
图10-16是1个简化的组网图,而且其他条件都不考虑,只考虑 MED 这一个因素。图10-16中,R1/R2,R1/R3,分别建立 eBGP peer。R2 与 R3,都向 R1 公告了路由,目的网段是 8.8.8.0/24,下一跳分别是 R2,R3。这样,R1 就会有两条 BGP 路由,都是前往 8.8.8.0/24,但是下一跳分别是 R2 和 R3。
现在问题来了,R1 该选择哪一个作为下一跳?
BGP 在选择路由时,在其他条件都相同的情况下,会优先选择 MED 小的那条路由。也就是说,图10-16中,BGP 优先会选择 R2 作为下1跳(去往 8.8.8.0/24)。
Local_Pref
Local_Perf 是 Local_Preference的缩写,是一个 well-known 的属性,Attr.Type Code = 5。
Local_Perf(本地优先级),也是“人如其名”,只会在1个 AS 域内的 iBGP 路由通告中传递,不会在 eBGP 路由通告中传递。如果哪位“大哥”故意在 eBGP 通告中附带了这个属性,那么接收者,也得忽略并丢弃这个属性。
Local_Perf 这个属性的目的,也是为了选路,如图10-17所示。
图10-17 Local_Pref 示意图
我们先描述一下图10-17中的 TOPO 关系,如下所示。
(1)R4/R2、R4/R3,分别是 eBGP peer
(2)R2/R1、R3/R1,分别是 iBGP peer
(3)R4 能够到达 8.8.8.0/24 网段
图10-17中,R1 所学习到 BGP 路由信息中,去往 8.8.8.0/24 网段的有2条路由,这2条路由,体现在出接口不同(不同的接口,对应着不同的 iBGP peer)。
那么 R1 会选择哪条路由呢?
BGP 为了解决这个问题,提出了 Local_Pref 属性。Local_Pref 是1个 4 字节无符号整数,它的值代表一个度量(metric),值越大,优先级越高,路由选择时,就会优选。
图10-17中,如果其他条件都一样,那么 R1 就会选择出接口 inf1,即通过 R2 出去。