简介
边界网关协议(BGP)是互联网涉及的核心技术之一,它使网络能够相互通信。了解如何使用此工具来定义网络拓扑,不仅可以让我们更好地了解互联网络,还可以将这种鲁棒性应用到自己的网络。
在本教程结束时,我们将熟悉BGP的核心概念,并能够把相关的术语传达给其他人。此外,我们还将学会使用BIRD的用户界面建立对等会话并开始发布路由。
本文使用docker容器实现这一目标。为了完成本教程,需要确保已安装docker
和docker-compose
。
准备
首先,需要克隆bird_examples_docker项目。
1 | git clone https://github.com/ncatelli/bird_examples_docker.git |
上述命令将创建三个容器(peer1
,peer2
和peer3
),所有这些容器均已安装BIRD并已建立对等会话。如果还不知道这意味着什么,请不要担心,我们将在设置好BGP并准备就绪后对其进行介绍。
首先连接到peer1并检查所有设置是否正确。
1 | docker-compose exec peer1 bash |
如果发现peer2
和peer3
已经显示Established
,则说明一切正常,我们已准备就绪。在开始使用之前,将简要介绍BGP的工作原理。
原理概述
边界网关协议(BGP)是一种外部网关协议,用于在自治系统之间交换路由信息。自治系统(AS)是路由前缀和策略的组织单位。这些AS由唯一的16位(后来扩展到32位)自治系统编号(ASN)标识。例如,Facebook的ASN为32934或通常显示为AS32934。BGP的强大之处在于其在成千上万个分散式AS之间传递路由协议和策略的能力。
互联网以及许多其他网络由相互之间进行通信的许多自治系统组成。对等会话促进了这种通信,该会话允许两个AS交换策略,路由和链接状态。所有这些信息都在两个BGP守护程序之间交换,这两个守护程序在TCP的179端口上进行侦听。
虽然BGP被认为是用于在Internet上的大型组织之间进行路由的外部网关协议,但它也可以在AS中使用,以使网络工程师能够控制其内部网络的拓扑。这是eBGP和iBGP术语的来源。iBGP将是本教程其余部分的重点。现在,我们将开始使用BIRD及其交互式命令行工具birdc
尝试这些对等会话。
BIRD简介
BIRD是功能齐全的路由守护程序,它支持许多不同的路由协议,包括BGP。BIRD提供了一种简单的配置格式和命令行,用于与会话进行交互。BIRD还内置了对IPv4和IPv6的支持,以及与这两种协议一起使用的相应工具。
检查BGP会话
与我们验证是否正确配置了docker环境的方式类似,我们可以通过运行以下命令查看正在运行的会话:
1 | root@peer1:/# birdc show protocols |
这给了我们很多信息。但是,让我们关注最后两个条目,peer2
和peer3
。我们可以看到它们都是BGP协议,并且info字段显示已经Established
。这些条目中的每一个都对应于peer1
与peer2
和peer3
打开的BGP会话。为了演示这些值与正在运行的会话之间的关系,让我们在peer2上停止Bird服务。在新的终端窗口中,运行以下命令来停止peer2
,模拟网络故障。
1 | docker-compose stop peer2 |
1 | root@peer1:/# birdc show protocols |
通过重新启动peer2
,BIRD应该重新启动,并且随后应重新建立对等会话。
1 | docker-compose start peer2 |
1 | root@peer1:/# birdc show protocols |
通过停止peer2
上的bird
守护程序,我们使端口179上的TCP连接在peer1
和peer2
之间关闭。这样做会将我们的对等会话从Established
更改为Connect
。这两个状态对应于许多BGP状态中的两个,但是出于本教程的考虑,我们将仅关注Established
,并将所有其他值视为未建立。对于那些更好奇的人,可以在Wikipedia上有关BGP的文章中找到有关会话状态的更多信息。
配置BGP会话
尽管现在知道了如何检查会话是否已经建立,但了解这些会话的配置也很重要。为此,我们需要深入研究bird配置文件。让我们看一下peer1
上的/etc/bird下的配置文件。
1 | root@peer1:~# cat /etc/bird/bird.conf |
我们可以看到建立这些初始会话所需的配置非常少。为了更深入地了解这项工作的真正作用,我们将专注于一个特定块:bgp peer2
:
1 | protocol bgp peer2 { |
在本教程的前面,我们讨论了eBGP和iBGP之间的区别以及大型AS如何使用唯一的ASN标识自己。但是,一小部分可用的ASN已保留给专用iBGP使用。这个范围是64512-65534
。知道了这一点,我们可以看到我们已经将私有范围中的ASN分配给了peer2
,peer1
被分配了ASN 64512。
查看下一条语句,我们可以看到具有IP和附加AS的邻居语句。该IP对应于我们尝试与之建立会话的主机或BGP术语中的邻居,而64513对应于我们分配给peer2
主机的AS。可以通过查看peer2
上的配置文件来确认这一点。
1 | root@peer2:/# grep -A4 peer1 /etc/bird/bird.conf |
协议BGP块中的这两个指令处理会话的初始建立。
虽然建立和维护会话对于BGP的运行至关重要,但仅建立会话无法路由任何流量。在下一节中,我们将探讨配置文件中的其他一些元素,以及如何使用它们来发现和宣布节点之间的路由。在继续进行此操作之前,先回顾一下我们当前的拓扑。
当前,我们的网络中有三个节点,peer1
(AS64512),peer2
(AS64513)和peer3
(AS64514)。这些配置在同一广播域中,但是对等的结构类似于peer3
<-> peer1
<-> peer2
。这种结构允许通过我们的路由服务器peer1
从peer2
或peer3
进行路由通信。在继续进行本教程的下一步,即发布路由时,请牢记此拓扑。
IP地址 | 节点名 | AS号 |
---|---|---|
10.0.0.10 | peer1 | 64512 |
10.0.0.11 | peer2 | 64513 |
10.0.100.11 | peer3 | 64514 |
BGP发布路由
内核协议
在开始发布Bird守护程序之间的路由之前,我们应该首先了解BIRD如何在Linux内核和BIRD守护程序之间传递路由。这就是我们前面看到的内核协议块起作用的地方。
1 | protocol kernel { |
kernel块中可以指定许多选项,并且可以在此处找到关于这些选项的更多信息,但是我们要执行的大部分操作由导入/导出定义。
1 | import none; |
告诉BIRD不要将路由从内核路由表中读取到BIRD中。我们将通过直接协议(即配置)获取路由。
1 | export all; |
告诉BIRD将其他公告了解的所有路由导出到内核的路由表中。这使我们可以实际利用此主机上的任何已获取的路由。
1 | metric 0; |
度量标准值由内核用来确定路由的优先级,并选择优先级最低的路由。在这种情况下,我们将其设置为0或未定义,以便我们首选本地路由。
1 | learn; |
最后,我们将设置学习指令,该指令将允许其他守护程序从内核路由表中学习路由。
发现直接路由
现在,我们已经配置了BIRD守护程序以将路由直接推送到内核路由表,我们将需要配置对等端以发现本地直接路由。由于我们会将这些路由直接添加到我们的环回接口,因此在选择的编辑器中,将直接协议配置为仅使用lo
接口。
1 | grep -A2 direct conf/peer2/etc/bird/bird.conf |
由于我们的网络上也有peer3
,因此在此主机上进行相同操作,以防止宣布其他任何路由。
1 | grep -A2 direct conf/peer3/etc/bird/bird.conf |
此时,除了默认的10.0.0.0子网(可以使用birdc
进行验证)以外,我们将没有其他路由学习和发布。
1 | root@peer2:/# birdc show route all |
过滤引用和导出
与内核模块类似,导出和导入可用于控制BGP对等方导入和导出的内容。首先,我们探讨过滤的概念以及如何将其用于控制将宣布或导出哪些路由。
BIRD中的过滤器基本上是在路由上执行的函数,返回接受或拒绝。这使我们能够应用一种简单的编程语言来为我们的路由策略添加逻辑。过滤器可以包含任何内容,从单个语句到非常复杂的逻辑。首先,让我们将none和all指令重新实现为过滤器,然后将它们添加到include指令上方的bird.conf文件中。
1 | filter accept_all { |
1 | filter reject_all { |
现在我们已经有了过滤器,让我们在我们的协议块之一的导入/导出指令中实现它们。在主机peer1
上,让我们看一下peer2
块。
1 | protocol bgp peer2 { |
从功能上讲,这与我们的原始配置相同,但是现在我们可以使用进一步的逻辑扩展这些设置。通过进一步研究过滤器脚本语言,可以了解这些过滤器的功能。为了扩展我们所学的知识,让我们在peer2
上的bird.conf中创建一个过滤器,以控制要向peer1
发布的路由。
1 | filter export_subnets { |
最后,我们需要在peer2
上更新peer1
以使用此导出过滤器。
1 | root@peer2:/# grep -A4 peer1 /etc/bird/bird.conf |
1 | docker-compose restart peer1 peer2 |
发布路由
现在,我们有了开始发布peer1
和peer2
之间的路由所需的所有构造块。在此之前,让我们回顾一下我们所做的事情。首先,我们已将BIRD守护程序配置为使用我们的内核协议在其内部路由表和内核路由表之间进行通信。我们已将BIRD守护程序配置为从具有直接协议的环回接口中学习路由。我们还配置了peer1
从其他对等节点导入路由并导出这些路由。最终,我们将peer2
配置为仅使用export_subnets过滤器将192.168.5.5/32导出到peer1
。但是,目前我们还没有从peer2
通告到peer1
的路由。
1 | root@peer1:/# ip route |
此时,所有设置已经完成,因此可以从环回接口中学习路由。通过将IP添加到peer2
的环回接口上,我们应该能够看到路由的发布。
1 | root@peer2:/# ip a add 192.168.5.5/32 dev lo |
现在,如果我们同时查看peer1
上的birdc和内核路由表,我们应该可以看到peer1
上新IP的路由。
1 | root@peer1:~# ip route |
1 | root@peer1:/# birdc show route all |
ping将显示我们现在可以从peer1
向该主机发送流量。
1 | root@peer1:/# ping -c 1 192.168.5.5 |
现在可以看到这些路由已通过peer1
通告到peer3
。
1 | root@peer3:/# birdc show route all |
1 | root@peer3:/# ping -c 1 192.168.5.5 |
1 | root@peer3:/# traceroute 192.168.5.5 |
我们也可以通过查看AS PATH来了解情况。通过查看与birdc中的路由关联的AS PATH,可以看到从64513到64512的路由在到达peer3
之前发布。
因为将peer1
配置为将路由导出到peer3
,并且由于peer3
配置为从peer1
导入路由,所以我们能够将此路由获取到peer3
的BIRD路由表中。然后,由于我们已将内核协议配置为在BIRD中导出路由,因此这些路由会将其放入peer3
的内核路由表中。
下一步
在这个简单的教程中,我们探讨了许多概念,但是,我们几乎没有涉及bird的概念。随时使用此示例,以发布和过滤路由的方式进一步探索。在以后的教程中,我们将更深入地探讨BGP的工作方式以及用于确定路由的过程,包括如何通信和本地优先级以及BGP守护程序如何使用它们来选择通往服务器的最佳路径。我们还将探讨什么是任播IP,以及如何使用BGP配置高可用性,以及如何使用过滤策略代替直接接口策略来控制向每个节点声明哪些前缀。BGP可以为我们提供对网络拓扑的大量控制,并且了解如何使用BGP可以更好地调整网络以适应自己的需求。