实验室项目要求我要在一个 bgp 路由拓扑上做路由数据的采集,前脚刚走的学长就留了一个文档,剩下的只能让我自己来搞了。学长的文档还是挺详细的,但是拓扑构建的过程蛮复杂,在这里详细的记录一下,以防以后又要重新弄或者要交给学弟学妹的时候全忘光了

路由拓扑图如下:

路由拓扑

环境依赖

  • Windows 11
  • WSL2 (Ubuntu)
  • Docker Desktop
  • Frrouting (Docker image)
  • Open vSwitch

环境配置

WSL

WSL2 在 Windows 商店中直接下载 Ubuntu 即可,然后按照提示配置安装,基本不会遇到什么问题。

之所以要在这里提到 WSL 是因为我还是想在这里推广一下我们的北邮源,北邮源其实是清华源的镜像(没错,镜像的镜像),内容更新一样快但因为用的人少所以速度也非常快。如果你是 Ubuntu 22 LTS,只需要把 /etc/apt/source.list 中内容替换为如下内容即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
deb-src https://mirrors.bupt.edu.cn/ubuntu/ jammy main restricted

deb https://mirrors.bupt.edu.cn/ubuntu/ jammy main restricted
deb-src https://mirrors.bupt.edu.cn/ubuntu/ jammy multiverse universe

deb https://mirrors.bupt.edu.cn/ubuntu/ jammy-updates main restricted
deb-src https://mirrors.bupt.edu.cn/ubuntu/ jammy-updates restricted multiverse universe main

deb https://mirrors.bupt.edu.cn/ubuntu/ jammy universe
deb https://mirrors.bupt.edu.cn/ubuntu/ jammy-updates universe

deb https://mirrors.bupt.edu.cn/ubuntu/ jammy multiverse
deb https://mirrors.bupt.edu.cn/ubuntu/ jammy-updates multiverse

deb https://mirrors.bupt.edu.cn/ubuntu/ jammy-backports main restricted universe multiverse
deb-src https://mirrors.bupt.edu.cn/ubuntu/ jammy-backports main restricted universe multiverse

deb https://mirrors.bupt.edu.cn/ubuntu/ jammy-security main restricted
deb-src https://mirrors.bupt.edu.cn/ubuntu/ jammy-security restricted

deb https://mirrors.bupt.edu.cn/ubuntu/ jammy-security universe
deb https://mirrors.bupt.edu.cn/ubuntu/ jammy-security multiverse

你也可以直接运行下面的代码,更方便的替换源

1
sudo sed -i 's#http://archive.ubuntu.com/#http://mirrors.bupt.edu.cn/#g' /etc/apt/sources.list

相信我,速度真的很快

Docker Desktop

直接到官网下载 Windows 版本即可。然后需要在 WSL 已经安装的前提下,打开 Setting - Resources - WSL Integration ,打勾和开关全部拉满。

最后是 Docker 下载镜像也需要换源。网络上很多教程经常提到中科院的 Docker 源,但是现在这玩意已经变成他们校内资源了,所以还是推荐使用网易和阿里云自注册的 Docker 源。Docker Desktop 的换源位置在 Setting - Docker Engine 的 json 文件中,加入如下内容即可

1
2
3
4
"registry-mirrors": [
"https://xxxxxx.mirror.aliyuncs.com",
"http://hub-mirror.c.163.com"
]

xxxxxx 的内容是你在阿里云中注册就能免费拿到的,还是挺靠谱的

Open vSwitch

我发现网上的 Open vSwitch(以下简称 ovs)安装教程基本都是通过源码安装的,即使是学长给我的文档也是这样。源码安装不仅麻烦还得搭配各种奇怪的环境,非常费时费力。我上 Google 查一下,原来 apt 能直接傻瓜安装,真的搞不懂为什么这么多人喜欢捣鼓这东西的源码安装

在 WSL 里直接运行如下指令即可:

1
sudo apt-get install openvswitch-switch

然后用ovs-vswitchd --version检查是否安装成功就行了

Frrouting

由于要搭建拓扑,需要通过 Docker 模拟多个路由器,所以只需要安装 Frrouting 的镜像就行了。而这玩意百度一搜,国内的什么简书、csdn 各大高手的教程又开始源码安装了。我反手 Google 一下,第一页就是 Docker 官网,里面直接告诉我一条命令就能搞定:

1
docker pull frrouting/frr

到此环境就配置完了,别看这部分这么简单,如果只看国内这些“大神”们的教程,能给你配一整天。

拓扑环境搭建

对于一台计算机来说,只要它启动了bgpd守护进程,那么它即可承担 BGP 路由器的全部功能。目前 BGP 协议的开源实现主要就是 C-BGP 和 FRRouting 。每台计算机上只能跑一个 bgpd 进程,但使用 Docker 可以实现多机虚拟化,且 FRRouting 提供了封装好的 Docker 镜像,所以推荐使用 FRRouting 。这种情况下,一台机器上的每一个 FRRouting 的 Docker 实例就可以看做是一个独立的虚拟机,每个虚拟机上仅运行了 bgpd 进程及其依赖的进程。

但如果直接在一台机器上跑多个 FRRouting 的 Docker 容器的话,是无法看到 AS 路径的,因为这种情况下,所有的 Docker 实例均在同一个网段下,是可以直连通信的,无法模拟域间路由下的“多跳”环境。

这要求我们实现一个模拟域间路由下“多跳”的方式:手动将这些 AS 划分到不同的子网下。这需要使用 Open vSwitch 的网桥相关的功能。编写一个脚本文件ovs.sh,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#!/bin/bash
# Direct Connect Between Routes
# 使用ovs创建一个网桥/交换机 命名为brConn
ovs-vsctl add-br brConn
#
# Prefix Block
#
# LINK BETWEEN AS65531 - AS65533
ovs-docker add-port brConn ethTo65533 AS65531 --ipaddress=100.100.7.1/30
ovs-docker add-port brConn ethTo65531 AS65533 --ipaddress=100.100.7.2/30
# LINK BETWEEN AS65531 - AS65534
ovs-docker add-port brConn ethTo65534 AS65531 --ipaddress=100.100.8.1/30
ovs-docker add-port brConn ethTo65531 AS65534 --ipaddress=100.100.8.2/30
# LINK BETWEEN AS65532 - AS65533
ovs-docker add-port brConn ethTo65533 AS65532 --ipaddress=100.100.9.1/30
ovs-docker add-port brConn ethTo65532 AS65533 --ipaddress=100.100.9.2/30
# LINK BETWEEN AS65532 - AS65534
ovs-docker add-port brConn ethTo65534 AS65532 --ipaddress=100.100.10.1/30
ovs-docker add-port brConn ethTo65532 AS65534 --ipaddress=100.100.10.2/30
# LINK BETWEEN AS65533 - AS65534
ovs-docker add-port brConn ethTo65534 AS65533 --ipaddress=100.100.11.1/30
ovs-docker add-port brConn ethTo65533 AS65534 --ipaddress=100.100.11.2/30
# LINK BETWEEN AS65533 - AS65535
ovs-docker add-port brConn ethTo65535 AS65533 --ipaddress=100.100.12.1/30
ovs-docker add-port brConn ethTo65533 AS65535 --ipaddress=100.100.12.2/30
# LINK BETWEEN AS65534 - AS65535
ovs-docker add-port brConn ethTo65535 AS65534 --ipaddress=100.100.13.1/30
ovs-docker add-port brConn ethTo65534 AS65535 --ipaddress=100.100.13.2/30
# LINK BETWEEN AS65536 - AS65531
ovs-docker add-port brConn ethTo65531 AS65536 --ipaddress=100.100.14.1/30
ovs-docker add-port brConn ethTo65536 AS65531 --ipaddress=100.100.14.2/30
# LINK BETWEEN AS65536 - AS65532
ovs-docker add-port brConn ethTo65532 AS65536 --ipaddress=100.100.15.1/30
ovs-docker add-port brConn ethTo65536 AS65532 --ipaddress=100.100.15.2/30
#
#
# VALID PREFIX BLOCK BETWEEN EACH AS.
ovs-docker add-port brConn eth1 AS65531 --ipaddress=104.193.81.1/24
ovs-docker add-port brConn eth1 AS65532 --ipaddress=104.193.82.1/24
ovs-docker add-port brConn eth1 AS65533 --ipaddress=104.193.83.1/24
ovs-docker add-port brConn eth1 AS65534 --ipaddress=104.193.84.1/24
ovs-docker add-port brConn eth1 AS65536 --ipaddress=104.193.86.1/24

这个脚本首先创建了一个网桥 brConn(可以将它简单理解为一个交换机)。第二部分内容就是使用 ovs 提供的接口,为 Docker 实例创建网卡,并将网卡全部挂接到同一个 brConn 网桥上。网卡名字为 eThTo**** ,表示这个 Docker 实例中的这张网卡是为了去与哪个 Docker 进行直连通信。第三部分的内容是为 AS 设立它们的合法网络空间(或者说网络资源)。

注意到所有的网卡前缀长度均是 30 位,这意味着这个子网下只有两个 IP 地址是合法的(子网可用 2 位,最多有 4 个 IP 地址,扣除掉两位全为 0 的和两位全为 1 的非法地址),这两个 IP 地址分别作为具有直连关系的两个 AS 间的链路两端网卡的 IP 地址,这样就实现了网络隔离,换句话说,在上述拓扑示例图中,只有具有直连关系的 AS 是在同一个网段下的,可以相互通信,不具有直连关系的 AS 不再同一个网段内,不能直连通信。

接下来需要运行如下所示的docker.sh脚本,它启动了 6 个 FRRouting Docker 实例。默认情况下,FRRouting 的实例仅包括一个本地回路网卡和另一个 Docker 自带的网卡,这两个网卡都不是我们要用的。我们需要使用之前 ovs 创建的虚拟网卡。

1
2
3
4
5
6
7
8
9
#!/bin/bash
# Start Five Atonomous System Container
# 启动6个FRRouting容器
docker run -itd --privileged --name AS65531 --net=none frrouting/frr /bin/bash
docker run -itd --privileged --name AS65532 --net=none frrouting/frr /bin/bash
docker run -itd --privileged --name AS65533 --net=none frrouting/frr /bin/bash
docker run -itd --privileged --name AS65534 --net=none frrouting/frr /bin/bash
docker run -itd --privileged --name AS65535 --net=none frrouting/frr /bin/bash
docker run -itd --privileged --name AS65536 --net=none frrouting/frr /bin/bash

另一个脚本是 destroyAllTopo3.sh ,会销毁掉 brConn 以及对应的网卡,并移除所有运行中的 Docker 实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/bash
ovs-vsctl del-br brAS65531
ovs-vsctl del-br brAS65532
ovs-vsctl del-br brAS65533
ovs-vsctl del-br brAS65534
ovs-vsctl del-br brConn
ovs-vsctl del-br br1To3
ovs-vsctl del-br br1To4
ovs-vsctl del-br br2To3
ovs-vsctl del-br br2To4
ovs-vsctl del-br br3To4
ovs-vsctl del-br br3To5
ovs-vsctl del-br br4To5
docker rm -f $(docker ps -aq)

拓扑节点配置

严格按照如下顺序执行配置

  1. 开启 ovs 服务
1
sudo /usr/share/openvswitch/scripts/ovs-ctl start
  1. 用 root 权限**先后**执行docker.shovs.sh,创建出 6 个 Frrouting 实例
  2. 对于这 6 个实例(AS65531 ~ AS65536)中的每一个,使用命令docker exec -it (ASN_NAME) bash进入到实例中,然后对 6 个实例的每一个,执行下述命令,这三条命令会在容器中启动bgpd守护进程和ospfd守护进程。
1
2
3
sed -i 's/bgpd=no/bgpd=yes/g' /etc/frr/daemons
sed -i 's/ospfd=no/ospfd=yes/g' /etc/frr/daemons
nohup /usr/lib/frr/frrinit.sh start &
  1. 仍然使用docker exec -it (ASN_NAME) bash进入到实例中,对于 6 个实例的每一个,根据ASN_NAME的不同,拷贝下述命令到终端中并执行:
1
2
3
4
5
6
7
8
9
10
11
12
13
# AS65536
vtysh
config
router bgp 65536
neighbor 100.100.14.2 remote-as 65531
neighbor 100.100.15.2 remote-as 65532
network 104.193.86.1/24
no bgp ebgp-requires-policy
no bgp network import-check
exit
exit
write
exit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# AS65531
vtysh
config
router bgp 65531
neighbor 100.100.7.2 remote-as 65533
neighbor 100.100.8.2 remote-as 65534
neighbor 100.100.14.1 remote-as 65536
network 104.193.81.1/24
no bgp ebgp-requires-policy
no bgp network import-check
exit
exit
write
exit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# AS65532
vtysh
config
router bgp 65532
neighbor 100.100.9.2 remote-as 65533
neighbor 100.100.10.2 remote-as 65534
neighbor 100.100.15.1 remote-as 65536
network 104.193.82.1/24
no bgp ebgp-requires-policy
no bgp network import-check
exit
exit
write
exit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# AS65533
vtysh
config
router bgp 65533
neighbor 100.100.7.1 remote-as 65531
neighbor 100.100.9.1 remote-as 65532
neighbor 100.100.11.2 remote-as 65534
neighbor 100.100.12.2 remote-as 65535
network 104.193.83.1/24
no bgp ebgp-requires-policy
no bgp network import-check
exit
exit
write
exit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# AS65534
vtysh
config
router bgp 65534
neighbor 100.100.8.1 remote-as 65531
neighbor 100.100.10.1 remote-as 65532
neighbor 100.100.11.1 remote-as 65533
neighbor 100.100.13.2 remote-as 65535
network 104.193.84.1/24
no bgp ebgp-requires-policy
no bgp network import-check
exit
exit
write
exit
1
2
3
4
5
6
7
8
9
10
11
12
# AS65535
vtysh
config
router bgp 65535
neighbor 100.100.12.1 remote-as 65533
neighbor 100.100.13.1 remote-as 65534
no bgp ebgp-requires-policy
no bgp network import-check
exit
exit
write
exit

这些命令首先会启动 vtysh 终端(这是一个现有的 BGP 协议通用的控制终端,大部分的 BGP 协议实现都会用这个相同的终端),然后将配置对应的 AS 号、通过给出的 IP 地址与邻居建立 Peer 关系,宣告自己的前缀,并设置了两个路由策略(no ebgp-requires-policy, no bgp network import-check),这两个策略是必须的,否则路由器会过滤掉路由宣告。

拓扑实验

路由信息查看

全部设置完毕后,随便找一个实例进入,启动 vtysh 终端,使用命令show ip bgp,会看到类似下图的 BGP 路由表;

路由表示例

而命令show ip bgp summary能看到 BGP 邻居表,具体细节可以看这里

需要注意的是,由于这个拓扑是静态的,因此第一次查看路由表应该只能看到本地路由,如果想看到整个拓扑的路由表请往下看。

数据采集

可以使用以下命令配置 Frrouting 的日志输出,通过查看日志及时 Debug:

1
2
3
4
5
6
7
8
9
mkdir /var/log/frr
# 必须将输出目录的用户/用户组设置为frr
# 如果不这么做,由于docker实例所挂载的文件系统下,所有文件的所有者都是root,frr会因为权限不足无法生成文件。
chown frr /var/log/frr/
vtysh
config
log file /var/log/frr/frr.log
exit
write

使用下述命令转储路由更新信息:

1
2
3
4
5
6
7
8
9
10
11
12
# 创建一个frrouting的输出目录,并将这个目录的用户/用户组设置为frr
# 如果不这么做,由于docker实例中所有文件的所有者都是root,frr会因为权限不足无法生成文件。可以通过查看日志的方式去进行确认。
# 如果日志配置成功,但仍然无法dump出信息,可以去查看日志
mkdir /home/updates
chown frr updates

# 进入某个FRRouting实例后
vtysh
config
dump bgp updates /home/updates/%Y%m%d-%H:%M:%S 30 // 每30sdump一次路由更新报文
# dump bgp all PATH 将会 dump 所有类型bgp报文
# dump bgp routes-mrt PATH 将会 dump 路由表

上述命令只会 dump 路由更新报文(MRT 格式,需要bgpdump等工具进一步解析),由于拓扑是稳定的、不会更新的,因此大部分情况下输出的都是空文件,你可以选择一个 AS 去使用 network 命令宣告个长度大于等于 25 的前缀。注意这个宣告的前缀必须属于这个 AS 的合法前缀空间。例如 AS65536 拥有的网络资源为 104.193.86.1/24,那么在 AS65536 的 vtysh 终端就能使用命令network 104.193.86.2/25宣告一个合法的前缀。需要注意的是,至少发生一次路由宣告后,整个拓扑的路由表才会更新。

转储出的文件是存储在 docker 实例中的,由于默认的 docker 实例并没有挂载持久化存储,因此无法直接把转储出的文件从容器中转移到 WSL 上,需要在 root 权限下使用 docker cp 命令,例如:

1
docker cp 2cd200541a0b:/home/updates/20220931-06:19:30 .

这样以后就能把采集到的 BGP 路由数据存储到本地了