第340篇:EVPN VXLAN 数据中心互联案例
关键词
EVPN、VXLAN、DCI、数据中心互联、VXLAN隧道、Overlay、多活数据中心、大二层
一、案例背景
1.1 客户需求
某企业数据中心互联需求:
企业信息:
行业:互联网 数据中心:3 个(DC1-主、DC2-备、DC3-备) 服务器:2,000+ 台 虚拟机:5,000+ 要求: └─ VM 可在任意 DC 间自由迁移 └─ 业务多活部署 └─ 故障自动切换 └─ 支持网络自动化(CI/CD集成)
当前网络现状:
DC1:传统三层架构,使用 VLAN DC2:传统三层架构,使用 VLAN DC3:传统三层架构,使用 VLAN DCI:MPLS VPN 互联 问题: └─ VM 迁移时需要更改 IP 地址 └─ VLAN 4094 限制 └─ STP 阻塞端口 └─ 三层互联延迟大 └─ 不支持大规模多活
1.2 为什么要用 EVPN VXLAN
EVPN VXLAN 的优势:
大二层网络:
┌──────────────────────────────────────────┐
│ VXLAN 将 L2 报文封装在 UDP 中传输 │
│ 突破 VLAN 4094 限制(支持 16M VNI) │
│ 跨 DC 的二层连通(VM 不修改 IP) │
│ 无 STP 阻塞(所有链路可用) │
└──────────────────────────────────────────┘
控制面优于传统 VXLAN:
┌──────────────────────────────────────────┐
│ 传统 VXLAN: EVPN VXLAN: │
│ ┌─ 数据面洪泛学习 ┌─ BGP 控制面 │
│ ├─ ARP 广播 ├─ ARP 抑制 │
│ ├─ 无过滤策略 ├─ 路由策略 │
│ └─ 排障困难 └─ 可视化好 │
└──────────────────────────────────────────┘
多活数据中心的关键能力:
┌──────────────────────────────────────────┐
│ Anycast Gateway(分布式网关) │
│ └─ 每个 Leaf 都可以是网关 │
│ └─ VM 迁移后网关不变 │
│ │
│ Type-2/Type-3 路由 │
│ └─ Type-2:MAC/IP 路由 │
│ └─ Type-3:Inclusive Multicast │
│ │
│ DF Election(指定转发者) │
│ └─ BGP DF Election │
│ └─ 避免多归接入导致广播泛洪 │
└──────────────────────────────────────────┘
二、架构设计
2.1 整体拓扑
EVPN VXLAN DCI 架构:
| ┌────── DC1 ──────┐ ┌────── DC2 ──────┐ | ||
|---|---|---|
| [Spine-1] [Spine-2] 【DCI】[Spine-1] [Spine-2] | ||
| │ │ | ||
| └────── DC3 ──────┘ | ||
| [Spine-1] [Spine-2] | ||
| [Leaf1] [Leaf2] | ||
| X | ||
| [Server5] [Svr6] |
DCI 互联: ┌─ 每对 Spine 之间通过 DCI 链路互联 ├─ DCI 链路:100GE × 4(不同路由的裸纤) ├─ 协议:EBGP between DCs └─ Underlay:IS-IS Level-2
2.2 网络设计
关键设计参数:
Underlay:
┌──────────────────────────────────────────┐
│ 协议:IS-IS Level-2 │
│ 互联 IP:10.0.0.0/31(点对点) │
│ LoopBack:10.255.0.0/32(VTEP 源地址) │
│ ECMP:8 路(Spine-Leaf 全互联) │
│ BFD:50ms × 3 │
└──────────────────────────────────────────┘
Overlay(EVPN):
┌──────────────────────────────────────────┐
│ 地址族:L2VPN EVPN │
│ VTEP 源:LoopBack 0 │
│ VXLAN 封装:VNI 10000-20000 │
│ 控制面:EBGP(跨 DC)/ IBGP(DC 内) │
│ │
| AS 规划: │
| ┌─ DC1:AS 65001 │
| ├─ DC2:AS 65002 │
| ├─ DC3:AS 65003 │
| └─ RR:AS 65000(可选) │
└──────────────────────────────────────────┘
VNI 规划:
┌──────────────────────────────────────────┐
│ VNI 10000:Prod-Web(10.10.0.0/16) │
│ VNI 10001:Prod-APP(10.11.0.0/16) │
│ VNI 10002:Prod-DB(10.12.0.0/16) │
│ VNI 20000:Storage-Net(172.16.0.0/12)│
│ │
│ RD 规划: │
│ └─ DC1:10.255.0.1:VNI │
│ └─ DC2:10.255.0.2:VNI │
│ └─ DC3:10.255.0.3:VNI │
│ │
│ RT 规划: │
│ └─ Import/Export:100:VNI │
└──────────────────────────────────────────┘
三、核心配置
3.1 Leaf 交换机配置
# evpn_leaf_config.py — EVPN Leaf 配置
def generate_evpn_leaf():
"""Leaf 交换机 EVPN 配置"""
config = """
sysname LEAF-1-DC1
# ========== Underlay IS-IS ==========
interface LoopBack0
ipv6 enable
ipv6 address 2001:DB8:255:1::1/128
interface 100GE1/0/0
description to-SPINE-1
ipv6 enable
ipv6 address 2001:DB8:10::1/127
isis ipv6 enable 1
isis circuit-level level-2
interface 100GE2/0/0
description to-SPINE-2
ipv6 enable
ipv6 address 2001:DB8:10::3/127
isis ipv6 enable 1
isis circuit-level level-2
isis 1
is-level level-2
network-entity 49.0001.0000.0255.0001.00
ipv6 enable topology ipv6
bfd all-interfaces enable
# ========== Overlay EVPN ==========
# BGP EVPN 配置
bgp 65001
router-id 10.255.1.1
peer 10.255.0.1 as-number 65001 # DC1 RR
peer 10.255.0.1 connect-interface LoopBack0
#
# L2VPN 地址族
l2vpn-family evpn
policy vpn-target
peer 10.255.0.1 enable
peer 10.255.0.1 reflect-client
# ========== VXLAN ==========
bridge-domain 10000
vxlan vni 10000
evpn
route-distinguisher 10.255.1.1:10000
vpn-target 100:10000 export-extcommunity
vpn-target 100:10000 import-extcommunity
# ========== NVE 接口 ==========
interface Nve1
source 10.255.1.1
vni 10000 head-end peer-list protocol bgp
# ========== 业务接口 ==========
interface 25GE1/0/1
description Server-Prod-Web
port link-type trunk
port trunk allow-pass vlan 100
#
bridge-domain 10000
l2 binding vlan 100
# ========== Anycast Gateway ==========
interface Vlanif100
description Prod-Web-Gateway
ip address 10.10.0.254 255.255.255.0
vrrp vrid 100 virtual-ip 10.10.0.254
"""
return config
3.2 Spine 交换机配置
def generate_spine_config():
"""Spine 交换机 EVPN 配置(跨 DC RR)"""
config = """
sysname SPINE-1-DC1
# ========== IS-IS Underlay ==========
interface LoopBack0
ipv6 enable
ipv6 address 2001:DB8:255:1::10/128
interface 100GE1/0/0
description to-DC2-SPINE-1
ipv6 enable
ipv6 address 2001:DB8:100::1/127
isis ipv6 enable 1
isis circuit-level level-2
interface 100GE2/0/0
description to-DC3-SPINE-1
ipv6 enable
ipv6 address 2001:DB8:200::1/127
isis ipv6 enable 1
# ========== 跨 DC EBGP EVPN ==========
bgp 65001
router-id 10.255.0.1
#
# DC 内 IBGP
peer 10.255.1.1 as-number 65001
peer 10.255.1.1 connect-interface LoopBack0
peer 10.255.1.2 as-number 65001
peer 10.255.1.2 connect-interface LoopBack0
#
# 跨 DC EBGP(扮演 RR 角色)
peer 2001:DB8:100::2 as-number 65002 # DC2 Spine
peer 2001:DB8:100::2 ebgp-max-hop 10
peer 2001:DB8:200::2 as-number 65003 # DC3 Spine
peer 2001:DB8:200::2 ebgp-max-hop 10
#
l2vpn-family evpn
# 允许跨域 EVPN 路由交换
undo policy vpn-target
#
peer 10.255.1.1 enable
peer 10.255.1.1 reflect-client
peer 10.255.1.2 enable
peer 10.255.1.2 reflect-client
#
peer 2001:DB8:100::2 enable # DC2
peer 2001:DB8:200::2 enable # DC3
"""
return config
四、VM 迁移验证
4.1 迁移前后验证
# verify_vm_migration.py — VM 迁移验证脚本
from netmiko import ConnectHandler
import paramiko
import time
import json
class VMMigrationVerifier:
"""VM 迁移验证器"""
def __init__(self, vm_ip: str, vm_mac: str, vni: int):
self.vm_ip = vm_ip
self.vm_mac = vm_mac
self.vni = vni
def check_vm_location(self) -> str:
"""通过 MAC 地址查询 VM 所在 Leaf"""
# 模拟:查询 EVPN 的 MAC 表
# 实际环境中需要对接 SDN 控制器
return "LEAF-1-DC1"
def check_mac_table(self, device: dict) -> dict:
"""检查设备的 MAC 表"""
conn = ConnectHandler(**device)
output = conn.send_command(
f"display mac-address {self.vm_mac}"
)
conn.disconnect()
return {"output": output}
def check_evpn_route(self, device: dict) -> dict:
"""检查 EVPN Type-2 路由"""
conn = ConnectHandler(**device)
output = conn.send_command(
f"display bgp evpn all routing-table"
f" mac-route {self.vm_mac}"
)
conn.disconnect()
return {"output": output}
def verify_connectivity(
self, test_ip: str
) -> bool:
"""验证 VM 连通性"""
import subprocess
result = subprocess.run(
["ping", "-n", "3", test_ip],
capture_output=True, text=True,
)
return result.returncode == 0
def monitor_during_migration(
self, target_ip: str,
duration_sec: int = 120
):
"""监测迁移过程中的网络变化"""
import threading
import subprocess
results = {
"total_pings": 0,
"success_count": 0,
"fail_count": 0,
"max_latency": 0,
"fail_periods": [],
}
fail_start = None
for i in range(duration_sec * 10): # 100ms 间隔
start = time.time()
result = subprocess.run(
["ping", "-n", "1", target_ip],
capture_output=True, text=True,
)
elapsed = (time.time() - start) * 1000
results["total_pings"] += 1
if result.returncode == 0:
results["success_count"] += 1
results["max_latency"] = max(
results["max_latency"], elapsed
)
if fail_start:
results["fail_periods"].append({
"start": fail_start,
"end": time.time(),
"duration": time.time() - fail_start,
})
fail_start = None
else:
results["fail_count"] += 1
if not fail_start:
fail_start = time.time()
time.sleep(0.09) # 100ms 总间隔
if fail_start:
results["fail_periods"].append({
"start": fail_start,
"end": time.time(),
"duration": time.time() - fail_start,
})
return results
4.2 自动化迁移检查
# auto_check_evpn.py — EVPN 自动化检查
class EVPNHealthChecker:
"""EVPN 健康检查"""
def __init__(self, devices: dict):
self.devices = devices
def check_vxlan_tunnel(self, device: dict) -> dict:
"""检查 VXLAN 隧道"""
conn = ConnectHandler(**device)
output = conn.send_command(
"display vxlan tunnel"
)
conn.disconnect()
tunnels = []
for line in output.splitlines():
if "up" in line.lower():
tunnels.append(line.strip())
return {
"total_tunnels": len(tunnels),
"up_tunnels": len(
[t for t in tunnels if "up" in t.lower()]
),
}
def check_evpn_peers(self, device: dict) -> dict:
"""检查 EVPN 邻居"""
conn = ConnectHandler(**device)
output = conn.send_command(
"display bgp evpn peer"
)
conn.disconnect()
established = sum(
1 for line in output.splitlines()
if "Established" in line
)
return {"evpn_peers": established}
def check_vni_status(self, device: dict) -> dict:
"""检查 VNI 状态"""
conn = ConnectHandler(**device)
output = conn.send_command(
"display vxlan vni"
)
conn.disconnect()
vnis = {}
for line in output.splitlines():
if "VNI" in line and "up" in line:
parts = line.split()
vnis[parts[0]] = parts[1] if len(parts) > 1 else "up"
return {"vnis": vnis}
def full_check(self) -> dict:
"""全量检查"""
results = {}
for name, info in self.devices.items():
print(f"检查 {name}...")
results[name] = {
"tunnels": self.check_vxlan_tunnel(info),
"peers": self.check_evpn_peers(info),
"vnis": self.check_vni_status(info),
}
return results
五、排障指南
5.1 常见问题
EVPN VXLAN 排障指南:
问题 1:VXLAN 隧道不 UP
排查步骤: 1. display vxlan tunnel 2. display nve interface 3. ping VTEP 源地址(Underlay 可达性) 4. display bgp evpn peer 常见原因: └─ VTEP 源地址 Underlay 不可达 └─ NVE 接口未配置 source └─ EVPN 邻居未 Established
问题 2:VM 迁移后网络不通
排查步骤: 1. 检查新 Leaf 的 MAC 表 2. 检查 EVPN Type-2 路由 3. 检查 ARP 表(抑制) 4. 检查 Anycast Gateway 常见原因: └─ ARP 抑制导致旧 ARP 未刷新 └─ Anycast Gateway 配置不一致 └─ MAC 迁移时间未到
问题 3:跨 DC 流量绕路
排查步骤: 1. traceroute 检查路径 2. display bgp evpn routing-table 3. 检查 RT 的 Import/Export 常见原因: └─ DF Election 未正确选择 └─ 跨 DC EVPN 路由策略不当
5.2 验证脚本
# evpn_verification.sh — EVPN 验证脚本
#!/bin/bash
# EVPN 一键验证
DEVICE=$1
echo "=== EVPN 状态检查: $DEVICE ==="
echo "1. NVE 接口状态"
ssh $DEVICE "display nve interface"
echo "2. VXLAN 隧道"
ssh $DEVICE "display vxlan tunnel"
echo "3. EVPN 邻居"
ssh $DEVICE "display bgp evpn peer"
echo "4. EVPN 路由统计"
ssh $DEVICE "display bgp evpn all routing-table statistics"
echo "5. MAC 表(VNI 10000)"
ssh $DEVICE "display mac-address vni 10000"
echo "6. ARP 表"
ssh $DEVICE "display arp vni 10000"
echo "7. VNI 状态"
ssh $DEVICE "display vxlan vni"
echo "=== 检查完成 ==="
六、经验总结
EVPN VXLAN DCI 关键经验:
1. Underlay 是一切的基础
┌─ Underlay 不通,Overlay 白搭
├─ IS-IS 推荐,OSPF 也可以
├─ BFD 必须使能(50ms × 3)
└─ ECMP 路径数要合理
2. RT 设计要全局统一
┌─ RT 决定了哪些 Leaf 收到哪些 MAC/IP
├─ 建议所有 DC 使用统一的 RT 规划
├─ Type-2(MAC/IP)和 Type-3(IMET)区分清楚
└─ 跨 DC EBGP 要注意 undo policy vpn-target
3. Anycast Gateway 要一致
┌─ 所有 Leaf 上同一个 VNI 的网关 IP/MAC 一致
├─ VRRP 的 virtual-ip 和 virtual-mac 一致
├─ VM 迁移后网关不变
└─ ARP 抑制表要刷新
4. 跨 DCI 的考虑
┌─ DCI 链路带宽和延迟
├─ 跨 DC 的 MAC 迁移时间
├─ 广播域范围控制
└─ 跨 DC 流量是否绕路
5. 运维
┌─ EVPN 排障比传统 VXLAN 更容易(控制面可见)
├─ 关注 Type-2/Type-3 路由数量
├─ 关注 MAC 漂移频率
└─ 建设 EVPN 可视化监控平台
下篇预告:第341篇《VXLAN负载不均故障排查案例》——深入分析VXLAN网络中负载不均的根因,提供从ECMP哈希到流分布的排查方法。
下篇预告:第341篇《VXLAN负载不均故障排查案例》——深入分析VXLAN网络中负载不均的根因,提供从ECMP哈希到流分布的排查方法。