0%

基于VXLAN EVPN的异地组网

前言:

本文主要介绍了如何使用Openwrt 官方SDK编译最新版FRR,并使用FRRouting建立VXLAN EVPN网络,实现异地组网。

基本拓扑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
                              +-+--+-+
+-----Internet----------++|RR|++---------Internet-------+
| +-+--+-+ |
| |
| |
| |
| |
| |
+-----+--------+ +-----+-------+
| eth0.2 | | eth0.2 |
| eth0.46+---------Private-----10.0.0.0/7---------+eth0.46 |
| Site1 | | Site2 |
+--------------+ +-------------+

说明:

Site 1与Site2之间有内网,接口eth0.46。不同网段,路由可达。ip范围10.0.0.0/7,dhcp动态获取。

RR是公网上拥有固定ip地址的服务器,Site 1和Site2使用eth0.2连接公网。

RR负责为Site 1和Site 2交换MAC地址信息。Site 1与Site 2互访使用内网流量。

交叉编译FRRouting

目前最新版的Openwrt仍然未集成FRRouting,需要进行交叉编译。如果是普通的Linux发行版,可以使用二进制安装。以MT7620平台为例,首先使用docker建立openwrt编译环境。

1
2
3
4
5
git clone https://github.com/mwarning/docker-openwrt-builder.git
cd docker-openwrt-builder
docker build -t openwrt_builder .
mkdir ~/mybuild
docker run -v ~/mybuild:/home/user -it openwrt_builder /bin/bash

下载官方最新稳定版本的SDK,解压

1
2
wget https://downloads.openwrt.org/releases/19.07.7/targets/ramips/mt7620/openwrt-sdk-19.07.7-ramips-mt7620_gcc-7.5.0_musl.Linux-x86_64.tar.xz
tar xvf openwrt-sdk-19.07.7-ramips-mt7620_gcc-7.5.0_musl.Linux-x86_64.tar.xz

使用master的feeds

1
2
3
4
5
6
cd openwrt-sdk-19.07.7-ramips-mt7620_gcc-7.5.0_musl.Linux-x86_64
cat << EOF >feeds.conf
src-git base https://git.openwrt.org/openwrt/openwrt.git
src-git packages https://git.openwrt.org/feed/packages.git
src-git routing https://git.openwrt.org/feed/routing.git
EOF

更新feeds,安装frr

1
2
./scripts/feeds update -a
./scripts/feeds install frr

生成一对密钥,为后续编译出来的ipk签名

1
./staging_dir/host/bin/usign -G -s ./key-build -p ./key-build.pub -c "D2O Local build key"

万事具备,就可以开始make了

1
make package/frr/compile V=s

如无意外,经过一段稍微有点长的时间,就编译完成了。编译完成后会发现bin目录里面多了很多ipk包。这个时候需要用密钥对ipk包进行签名,并生成index。最后把bin目录里面的内容放到一个能够使用http访问的地方。

1
2
3
make package/index V=s
cp key-build.pub /var/www/nginx/html/d2o_fun.pub
cp -R ./bin/* /var/www/nginx/html/

路由器安装FRR

来到路由器上安装frr,添加公钥,添加自定义的软件源。然后opkg安装就好了

1
2
3
4
5
6
7
8
wget https://d2okkk.net/19.07.7/d2o_fun.pub
opkg-key add d2o_fun.pub
cat << EOF >/etc/opkg/d2o.conf
src/gz d2o_base https://d2okkk.net/19.07.7/packages/mipsel_24kc/base
src/gz d2o_packages https://d2okkk.net/19.07.7/packages/mipsel_24kc/packages
EOF
opkg update
opkg install frr frr-vtysh frr-zebra frr-bgpd frr-watchfrr frr-staticd kmod-vxlan ip ip-bridge

Route Reflector的配置

Route Reflector(RR)是在公网上拥有固定IP的云主机,直接使用二进制包安装FRR就行了。配置也是参照Vincent大神的。只是BGP直接listen全网。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
vtysh
conf t
router bgp 65005
neighbor ixp peer-group
neighbor ixp remote-as external
neighbor ixp ebgp-multihop 30
neighbor ixp update-source x.x.x.x(云主机的公网地址)
neighbor ixp capability extended-nexthop
bgp listen range 0.0.0.0/0 peer-group ixp
address-family l2vpn evpn
neighbor ixp activate
advertise-all-vni
advertise-svi-ip
exit-address-family

Site1和Site2的配置

安装好FRR之后先编辑/etc/frr/daemons

1
bgpd=yes

然后就可以开启frr进程了

1
/etc/init.d/frr start

配置bgp l2vpn,其中x.x.x.x是RR的公网地址

1
2
3
4
5
6
7
8
9
10
11
vtysh
conf t
router bgp 65008(ASN不重要,只要和RR不一样,组成eBGP就行,因为只有eBGP才支持multihop)
neighbor x.x.x.x remote-as external
neighbor x.x.x.x ebgp-multihop 30
neighbor x.x.x.x capability extended-nexthop
address-family l2vpn evpn
neighbor x.x.x.x activate
advertise-all-vni
advertise-svi-ip
exit-address-family

配置完成后会发现BGP会话无法起来,先排除RR的TCP179端口是否已打开。

回到frrshow bgp neighbor x.x.x.x发现neighbor一直在Waiting for NHT

说明需要添加RR的主机路由到默认网关。

1
2
2023.2.15更新:
只要frr配置ip nht resolve-via-default就可以了,不需要再添加主机路由。

如果Openwrt是静态ip上网,在luci web里面添加静态路由就可以了。类似这样/etc/config/network

1
2
3
4
config route
option interface 'wan'
option target 'x.x.x.x'
option gateway '192.168.1.1'

如是PPPOE拨号,就需要使用到ppp-up脚本添加主机路由。/etc/ppp/ip-up.d/pppoe.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
#!/bin/sh

# parameters
# $1 the interface name used by pppd (e.g. ppp3)
# $2 the tty device name
# $3 the tty device speed
# $4 the local IP address for the interface
# $5 the remote IP address
# $6 the parameter specified by the 'ipparam' option to pppd

echo $@ >/tmp/ppp_parameters

PPP_FW=/tmp/firewall.pppoe
gateway_length=`expr length $5`
echo ${gateway_length}
GW=$5
LOCAL_IP=$4
DEV=$1

case "$1" in
pppoe-wan)
if [ ${gateway_length} -le 15 ]; then
echo IPv4
ip route add x.x.x.x via $GW dev $DEV
else
echo "IPV6 or Unrecognized IP format '$5'"
fi
;;
*)
;;
esac

VXLAN接口的配置

把BGP Session搞up之后,就可以配置VXLAN接口了。我这里使用VNI 5,VNI由24比特组成,可以支持16M的子网。只要2个site的VNI相同就可以互相通信。在这里我分配了一个Overlay使用的互联地址段100.69.0.0/24。

登录LUCI WEB,选择网络—接口,新建接口

两个site分别使用静态地址100.69.0.1/24和100.69.0.2/24,创建桥接到vxlan5,mtu 1450。

由于Site1和Site2之间的私网是通过dhcp获取地址的,使用/etc/udhcpc.user 脚本来触发建立隧道。

1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/sh
case "$1" in
bound)
if [ eth0.46 = "${interface}" ]; then
ip route add 10.0.0.0/7 via ${router}
ip link del vxlan5
ip link add vxlan5 type vxlan id 5 local ${ip} dstport 4789 nolearning
ip link set vxlan5 type bridge_slave neigh_suppress on learning off
fi
;;
esac
exit 0

别忘了在防火墙开启UDP 4789,如无意外100.69.0.1和100.69.0.2就可以互相ping通了。

在Site1和Site2的frr上使用show bgp l2vpn evpn 可以看到从RR学习到的Type2和Type3的路由。

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
OpenWrt# show bgp l2vpn evpn 
BGP table version is 0, local router ID is 198.18.22.130
Status codes: s suppressed, d damped, h history, * valid, > best, i - internal
Origin codes: i - IGP, e - EGP, ? - incomplete
EVPN type-1 prefix: [1]:[ESI]:[EthTag]:[IPlen]:[VTEP-IP]
EVPN type-2 prefix: [2]:[EthTag]:[MAClen]:[MAC]:[IPlen]:[IP]
EVPN type-3 prefix: [3]:[EthTag]:[IPlen]:[OrigIP]
EVPN type-4 prefix: [4]:[ESI]:[IPlen]:[OrigIP]
EVPN type-5 prefix: [5]:[EthTag]:[IPlen]:[IP]

Network Next Hop Metric LocPrf Weight Path
Route Distinguisher: 198.18.8.244:2
*> [2]:[0]:[48]:[f6:96:37:a3:82:8f]:[32]:[100.69.0.2]
11.92.111.32 0 65005 65008 i
RT:65008:5 ET:8
*> [2]:[0]:[48]:[f6:96:37:a3:82:8f]:[128]:[fe80::f496:37ff:fea3:828f]
11.92.111.32 0 65005 65008 i
RT:65008:5 ET:8
*> [3]:[0]:[32]:[11.92.111.32]
11.92.111.32 0 65005 65008 i
RT:65008:5 ET:8
Route Distinguisher: 198.18.22.130:2
*> [2]:[0]:[48]:[4a:73:1d:22:4c:e3]:[32]:[100.69.0.1]
11.94.117.77 32768 i
ET:8 RT:65022:5
*> [2]:[0]:[48]:[4a:73:1d:22:4c:e3]:[128]:[fe80::4873:1dff:fe22:4ce3]
11.94.117.77 32768 i
ET:8 RT:65022:5
*> [3]:[0]:[32]:[11.94.117.77]
11.94.117.77 32768 i
ET:8 RT:65022:5

参考: