如何在香港服务器的 Linux 系统中结合 VXLAN 与 BGP,构建跨数据中心的虚拟网络?

凌晨 1:50,我抱着保温杯推开香港葵涌机房的安全门。冷风从高密度通道里直往袖口里灌,风扇像在耳边碎碎念。两台香港节点的物理服务器已经点亮了“维护”标签,ToR 交换机的 Console 口还插着上一班同事留下的蓝色线。
今晚的目标很直接:把分布在**香港两处机房(HK1 & HK2)**的几组业务网段通过 VXLAN + BGP EVPN 拉成一个“逻辑二层”,再在边缘做 L3 网关,利用 BGP 做控制平面,彻底告别跨城二层专线的老问题(环路、广播风暴、迁移成本高)。如果一切顺利,天亮前我应该能看到两地虚拟机像在同一交换机下对话。
本文就是把这一整套从规划、部署到踩坑和收尾的过程复盘出来。尽量写给“新人也能照着做、老手也不嫌浅”的你。
1. 场景与目标
场景:两处香港机房,独立的 ToR → Spine → DC 边界 → 跨城 IP 链路(MPLS/VPLS 或普通三层专线/互联网隧道均可)。
目标:
- 利用 Linux 服务器充当 VTEP(VXLAN Tunnel End Point),跨 DC 打通二层;
- BGP EVPN 负责控制平面,分发 MAC/IP 前缀,支持多租户(VLAN/VNI);
- 在每个 DC 的边缘服务器上提供 Anycast 网关(同 IP/MAC),实现就近出入口与无感迁移;
- 尽量兼容 CentOS 7 生产环境(用户侧普遍要求),FRR 作为 BGP 守护进程。
2. 逻辑拓扑
拓扑:
┌────────────── WAN / IP underlay ──────────────┐
[VM A] │ │ [VM B]
| │ RR1/RR2 (FRR) │ |
[Leaf/HK1]===Spine/ToR===DC Edge(HK1) ===(IP/MPLS)=== DC Edge(HK2)===Spine/ToR=== [Leaf/HK2]
(Linux VTEP) ^ ^ (Linux VTEP)
\ | | /
\— VXLAN/EVPN —/ \— VXLAN/EVPN ———————— —/
(VNI 隧道,UDP/4789) (BGP EVPN 控制平面)
- VTEP:两台 Linux 服务器(一台在 HK1,一台在 HK2),各自承载 VXLAN 设备、桥及 SVI。
- RR(Route Reflector):我们用两台轻量 VM 跑 FRR 做 BGP RR,让 VTEP 不需要两两直连。
- Underlay:只要两边的 Loopback(VTEP 源地址) 互通即可,可走运营商 MPLS/专线或加密隧道。
3. 硬件与软件清单(真实参数示例)
| 角色 | 设备/规格 | 关键参数 |
|---|---|---|
| Linux VTEP(HK1/HK2) | 1U 服务器(例:Dell R640) | CPU: Xeon Silver;内存 ≥ 64GB;系统盘 SSD;NIC: Intel X710 10GbE 或 Mellanox CX-4 25GbE |
| ToR 交换机 | 任意支持 L3 underlay 的机型 | 开启 BGP/OSPF 静态路由均可;能放行 UDP/4789 |
| RR 节点 | 2 vCPU / 4GB RAM 虚机 | 跑 FRR,仅做控制平面 |
| OS | CentOS 7.9(3.10 内核) | 支持 VXLAN(内核模块自带),推荐开启 GRO/LRO 视业务 |
| 路由守护 | FRR 8.x | 支持 l2vpn evpn |
说明:CentOS 7 的 3.10 内核已原生支持 VXLAN。要用 VRF/高级 EVPN 功能时更建议新内核(例如 4.18+),但本文在 CentOS 7 上的核心能力完全可跑通。
4. 地址与标识规划(关键表格)
4.1 ASN、Loopback、BGP 对等体
| 站点 | 设备 | Loopback/VTEP | ASN | BGP 邻居 |
|---|---|---|---|---|
| HK1 | VTEP1 | 10.255.0.11/32 | 65001 | RR1(10.255.255.1)、RR2(10.255.255.2) |
| HK2 | VTEP2 | 10.255.0.12/32 | 65002 | RR1、RR2 |
| RR1 | RR1 | 10.255.255.1/32 | 65000 | VTEP1、VTEP2 |
| RR2 | RR2 | 10.255.255.2/32 | 65000 | VTEP1、VTEP2 |
Underlay 只要保证 Loopback 可达(静态或 IGP/BGP 均可)。
4.2 租户、VLAN/VNI、网段与 RT/RD
| 租户 | VLAN | VNI | 子网 | Anycast GW | RD | RT (Import/Export) |
|---|---|---|---|---|---|---|
| tenant-A | 10 | 1010 | 10.10.10.0/24 | 10.10.10.1/24 | 65000:1010 | 65000:1010 |
| tenant-B | 20 | 1020 | 10.20.20.0/24 | 10.20.20.1/24 | 65000:1020 | 65000:1020 |
RD 唯一标识路由,RT 控制导入导出。VLAN ↔ VNI 一一对应,便于管理。
5. 前置系统准备
5.1 关闭可能影响转发的过滤/反向路由
# 启用三层转发
sysctl -w net.ipv4.ip_forward=1
# 关闭桥上 iptables 过滤(避免性能损耗/误拦)
sysctl -w net.bridge.bridge-nf-call-iptables=0
sysctl -w net.bridge.bridge-nf-call-ip6tables=0
sysctl -w net.bridge.bridge-nf-call-arptables=0
# 关闭严格 rp_filter(否则 EVPN/多路径下可能被丢)
sysctl -w net.ipv4.conf.all.rp_filter=0
sysctl -w net.ipv4.conf.default.rp_filter=0
5.2 MTU 统一
VXLAN 头部约 50 字节(外层 IP/UDP/VXLAN),建议 underlay 链路 MTU ≥ 1550;若内网统一启用 Jumbo,则设为 9000 并全链路一致。
ToR/WAN 设备连带调齐,不然跨 DC 大包会碎片或丢弃。
6. 安装 FRR(CentOS 7)
实际生产中我使用 FRR 官方 repo。下面给出 repo 文件示意(版本号按需替换):
/etc/yum.repos.d/frr.repo
[frr]
name=FRRouting
baseurl=https://rpm.frrouting.org/repo/frr-stable/el7/$basearch
enabled=1
gpgcheck=0
安装:
yum clean all
yum install -y frr frr-pythontools
systemctl enable frr
/etc/frr/daemons 确保开启 zebra=yes、bgpd=yes。
7. 配置 Linux Bridge + VXLAN(以 VTEP1 为例)
我在 HK1/HK2 两台服务器上名称与流程一致,便于自动化和脑内对照。
7.1 接口与桥
# 1) Loopback 作为 VTEP 源地址(建议在 /etc/sysconfig/network-scripts/ 下持久化)
ip addr add 10.255.0.11/32 dev lo
# 2) 创建 VLAN-aware Bridge
ip link add br0 type bridge vlan_filtering 1 mcast_snooping 1
ip link set br0 up
# 3) 创建 VXLAN 设备,命名用 "vxlan<VNI>" 便于 FRR 识别与绑定
ip link add vxlan1010 type vxlan id 1010 local 10.255.0.11 dstport 4789 nolearning ageing 0
ip link add vxlan1020 type vxlan id 1020 local 10.255.0.11 dstport 4789 nolearning ageing 0
ip link set vxlan1010 up
ip link set vxlan1020 up
# 4) 把 VXLAN 接口加入桥
ip link set vxlan1010 master br0
ip link set vxlan1020 master br0
# 5) 在 br0 上定义 VLAN(self 表示在桥自身启用该 VLAN,用于创建 SVI)
bridge vlan add vid 10 dev br0 self
bridge vlan add vid 20 dev br0 self
# 6) SVI(Anycast 网关,可用桥子接口)
ip link add link br0 name br0.10 type vlan id 10
ip link add link br0 name br0.20 type vlan id 20
ip addr add 10.10.10.1/24 dev br0.10
ip addr add 10.20.20.1/24 dev br0.20
ip link set br0.10 up
ip link set br0.20 up
# 7) 把本地接入口(例如 VM 的 tap 或物理下联)放入 br0,并打上对应 VLAN
# 例:本机 KVM 的虚拟网卡 tapA 承载 tenant-A
ip link set tapA master br0
bridge vlan add vid 10 dev tapA pvid untagged
同样流程在 VTEP2(HK2)执行一遍,唯一不同是:
Loopback 改为 10.255.0.12/32;
Anycast 网关地址保持一致(10.10.10.1/24 和 10.20.20.1/24),MAC 也需要一致(见下节)。
7.2 Anycast 网关的 MAC 统一
我们用 keepalived 在两边设置相同的 虚拟 MAC(VRRP 风格),或者直接手动固定 SVI MAC(不同发行版支持方式不同)。
在 CentOS 7 上,实战中我选择 keepalived:
/etc/keepalived/keepalived.conf(两边一致)
vrrp_instance V10 {
state BACKUP
interface br0.10
virtual_router_id 10
priority 100
advert_int 1
virtual_ipaddress {
10.10.10.1/24 dev br0.10
}
# 强制统一 VRRP MAC(00:00:5E:00:01:<VRID>)
garp_master_delay 1
}
vrrp_instance V20 {
state BACKUP
interface br0.20
virtual_router_id 20
priority 100
advert_int 1
virtual_ipaddress {
10.20.20.1/24 dev br0.20
}
}
两边都用 BACKUP + 同优先级,配合 EVPN 的 ARP 抑制能减少动静。若想“就近优先”,把本地 DC 的优先级调更高。
8. FRR:BGP EVPN 配置(VTEP 与 RR)
8.1 RR(以 RR1 为例,RR2 同理)
/etc/frr/frr.conf 关键片段:
router bgp 65000
bgp router-id 10.255.255.1
no bgp default ipv4-unicast
neighbor VTEPS peer-group
neighbor VTEPS remote-as external
neighbor VTEPS update-source lo
neighbor 10.255.0.11 peer-group VTEPS
neighbor 10.255.0.12 peer-group VTEPS
address-family l2vpn evpn
neighbor VTEPS activate
exit-address-family
RR 不需要学习/下发 IPv4 unicast,只负责 EVPN 反射。生产上至少两个 RR。
8.2 VTEP(以 HK1 的 VTEP1 为例)
/etc/frr/frr.conf:
frr defaults traditional
log syslog informational
service integrated-vtysh-config
!
router bgp 65001
bgp router-id 10.255.0.11
no bgp default ipv4-unicast
neighbor RR peer-group
neighbor RR remote-as 65000
neighbor RR update-source lo
neighbor 10.255.255.1 peer-group RR
neighbor 10.255.255.2 peer-group RR
address-family l2vpn evpn
advertise-all-vni
neighbor RR activate
# 可选:开启二层泛洪优化
advertise-svi-ip
exit-address-family
!
# 绑定 VNI 与 VLAN(两种方式;推荐按 VNI 接口名自动识别)
evpn vni 1010
rd 65000:1010
route-target import 65000:1010
route-target export 65000:1010
bridge-domain 10
evpn vni 1020
rd 65000:1020
route-target import 65000:1020
route-target export 65000:1020
bridge-domain 20
!
# 接口告知 FRR:vxlan1010/1020 属于哪个 VNI
interface vxlan1010
vxlan local-tunnelip 10.255.0.11
bridge-access 10
!
interface vxlan1020
vxlan local-tunnelip 10.255.0.11
bridge-access 20
!
line vty
!
HK2(VTEP2)把 ASN 改为 65002、Router-ID 改为 10.255.0.12,其余一致。
核心点:VNI 与 VLAN(Bridge-Domain) 映射清晰;RR 邻居激活在 l2vpn evpn 地址族。
9. 验证步骤(我现场的检查清单)
BGP 邻居状态
vtysh -c "show bgp l2vpn evpn summary"
预期:两条到 RR1/RR2 的会话 Established。
EVPN 路由(MAC/IP 前缀)
vtysh -c "show bgp l2vpn evpn route type macip"
vtysh -c "show bgp l2vpn evpn"
预期:能看到对端 VTEP 发布的 MAC/IP;本地学习到的也会被通告。
内核 FDB / 邻表
bridge fdb show dev vxlan1010
ip neigh show dev br0.10
预期:远端 VTEP 的 MAC 条目显示为 offload master br0(具体显示视内核/工具版本)。
连通性
- 跨 DC 同 VLAN 主机互 ping(大包 -s 8500 测 MTU);
- 入站/出站走就近网关(traceroute 验证)。
- tcpdump -i vxlan1010 观察是否正常封装解封。
性能
- iperf3 测试单流与多流吞吐;
- 观察 CPU(softirq 比例)、NIC 队列、offload 开关(ethtool -k <nic>)。
10. 我真正踩到的坑(以及当场怎么解)
| 症状 | 根因 | 解决过程(现场) |
|---|---|---|
BGP 起不来(Active/Idle 抖动) |
Underlay 没把 Loopback 路由通告出去,RR 到不到 VTEP 的源地址 | 临时加静态路由做验证,随后在 ToR 上把 VTEP 的 /32 汇总进 IGP |
VXLAN 不通(ping 走内网丢包) |
ToR/WAN 侧丢了 UDP/4789 或 DF bit 导致碎片 | 与网络同事核对 ACL,放行 4789;同时把链路 MTU 从 1500 → 1550/9000 统一 |
| 偶发单向不通 | rp_filter 严格模式导致异向流量被丢 |
在 VTEP 上 rp_filter=0 全局关闭,问题消失 |
| 广播风暴/未知单播泛洪 | 某台接入主机环路/镜像口误接 | 临时在桥上对可疑端口降速/限泛洪,逐个排查 MAC,定位到一台被错误桥接的容器宿主机 |
| EVPN 路由学不到 | RT 配错(VNI1010 进口/出口 RT 与对端不一致) | show bgp l2vpn evpn 对比 RT,统一改成 65000:1010/1020 |
| 大包丢失 | 内核默认 gso/gro 与中间设备 MTU 不一致 |
统一链路 MTU 并逐段抓包验证;必要时在边界做 ip link set mtu 或 ethtool -K 调整 |
11. 运维与监控建议(我落地的做法)
BFD:在 EVPN 邻居上启用 BFD(FRR 支持),加快收敛。
日志分级:FRR 输出到 syslog,针对 bgpd/zebra 单独切割滚动。
采样:对 vxlan*、br0 和物理 eth* 做流量采样(sFlow/NetFlow),辅以 node_exporter 指标(软中断、队列长度、掉包)。
容量规划:跟踪 neigh/fdb 容量阈值:
sysctl -w net.ipv4.neigh.default.gc_thresh1=4096
sysctl -w net.ipv4.neigh.default.gc_thresh2=16384
sysctl -w net.ipv4.neigh.default.gc_thresh3=32768
自动化:Ansible 以 VNI/VLAN/RT 为变量项,一次性生成两地 VTEP 与 RR 配置;命名规范统一(vxlan<VNI>、br0.<VLAN>)。
变更回滚:保留 frr.conf.bak、/etc/sysconfig/ 接口文件快照;ToR 侧预留静态回退路径。
12. 一次完整落地的小结(可直接复用的步骤序列)
- Underlay 打通:保证 VTEP Loopback(10.255.0.11/12)互通。
- 系统调优:ip_forward=1、关闭 bridge-nf-call-* 与严格 rp_filter、统一 MTU。
- 安装 FRR:启 zebra/bgpd。
- 建桥与 VXLAN:br0 + vxlan<VNI> + bridge vlan + br0.<VLAN> SVI。
- Anycast 网关:keepalived 统一虚拟 MAC & VIP(两地一致)。
- BGP EVPN:VTEP 与 RR 邻居;为各 VNI 指定 RD/RT,advertise-all-vni。
- 验证:BGP/EVPN 路由、FDB、tcpdump、iperf3;大包与路径就近性。
- 监控收口:BFD、日志、采样、容量阈值;自动化与回滚方案。
13. 结尾:天亮前的那杯咖啡
凌晨 4:10,我在 HK2 的控制室做了最后一轮 iperf3。两地的虚机在同一子网里跑得飞快,trace 显示就近网关生效,BGP EVPN 的路由表干净利落。机房外的天已经泛着灰蓝,我拧上保温杯盖,顺手把 ToR 边上那根 Console 线绕好。
这套基于 Linux + VXLAN + BGP EVPN 的跨 DC 虚拟网络不是“炫技”,而是我能在凌晨 2 点站在机房里、可控、可回滚、可运维 的工程选择。
如果后来你也在凌晨的机房里为一条跨城链路皱眉,也许这篇笔记能让你少绕点路——至少在 UDP/4789 和 MTU 上,先别再被我踩过的坑绊住了。
附:关键命令速查(方便现场复制)
# BGP/EVPN
vtysh -c "show bgp l2vpn evpn summary"
vtysh -c "show bgp l2vpn evpn route type macip"
vtysh -c "show evpn vni"
vtysh -c "show interface vxlan1010"
# Linux 网络
ip -d link show vxlan1010
bridge fdb show dev vxlan1010
bridge vlan show
tcpdump -i vxlan1010 -nnvv
ethtool -k eth0
# 性能
iperf3 -c <remote VM ip> -t 30 -P 4
延伸:如果你需要把 L3 前缀(Type-5)也纳入 EVPN,建议升级内核并在 FRR 中启用 evpn 的 IP 前缀通告能力,再在边界与数据中心核心路由做策略控制;大规模多租户可引入 VRF(CentOS 7 可加载 vrf 模块,但生产更推荐更高版本内核/发行版)。
安全:跨城隧道若经过公网,请为 Underlay 链路加密(例如 WireGuard/IPsec),并限制只允许 RR/VTEP 控制面访问端口。