第339篇:SRv6 骨干网部署案例

关键词

SRv6、Segment Routing、IPv6、骨干网、流量工程、网络编程、SDN、TE


一、案例背景

1.1 为什么要部署 SRv6

传统 MPLS 骨干网的痛点:

  协议栈复杂:
  ┌──────────────────────────────────────────┐
  │  LDP(标签分发)+ RSVP-TE(流量工程)    │
  │  + BGP-LU(跨域标签)+ MPLS 转发          │
  │  └─ 控制面协议太多,运维复杂              │
  └──────────────────────────────────────────┘

  流量工程能力有限:
  ┌──────────────────────────────────────────┐
  │  RSVP-TE 需要逐条建立隧道               │
  │  隧道数量受限于设备规格                  │
  │  网络变化时需要重新建立                   │
  │  不支持随流检测                          │
  └──────────────────────────────────────────┘

  运维复杂:
  ┌──────────────────────────────────────────┐
  │  MPLS 标签管理复杂                        │
  │  标签分配、标签栈、标签转发路径排障难     │
  │  跨域需要方案 B/C                        │
  │  IPv4 地址空间紧张                        │
  └──────────────────────────────────────────┘

  SRv6 的优势:
  ┌──────────────────────────────────────────┐
  │  简化协议栈:只要 IS-IS/BGP + IPv6      │
  ├─ 无需 LDP/RSVP-TE                        │
  ├─ 原生流量工程(TE)                      │
  ├─ 网络可编程(Segment List)              │
  ├─ 原生随流检测(iFIT)                    │
  └─ 平滑演进(现网升级)                    │
  └──────────────────────────────────────────┘

1.2 部署目标

某运营商骨干网 SRv6 部署目标:

现网规模:

节点:50 台核心路由器 链路:120 条 100GE/400GE 流量:峰值 12 Tbps 业务:MPLS L3VPN + L2VPN + Internet

部署目标:

  1. 全部节点支持 SRv6
  2. 控制面使用 IS-IS Extensions for SRv6
  3. 部署 SRv6 BE(Best Effort)
  4. 部署 SRv6 TE(流量工程)
  5. 保留传统 MPLS 能力(平滑演进)
  6. 零业务中断完成升级

二、SRv6 基础配置

2.1 IS-IS SRv6 扩展

# srv6_basic_config.py — SRv6 基础配置

def generate_srv6_underlay():
    """IS-IS SRv6 Underlay 配置"""
    config = """
sysname PE-R1

# ========== IPv6 基础 ==========
ipv6

interface LoopBack0
 ipv6 enable
 ipv6 address 2001:DB8:1::1/128

interface GigabitEthernet0/0/0
 ipv6 enable
 ipv6 address 2001:DB8:10::1/64
 isis ipv6 enable 1

interface GigabitEthernet0/0/1
 ipv6 enable
 ipv6 address 2001:DB8:11::1/64
 isis ipv6 enable 1

# ========== IS-IS for SRv6 ==========
isis 1
 is-level level-2
 network-entity 49.0001.0000.0000.0001.00
 #
 # IPv6 地址族使能
 ipv6 enable topology ipv6
 #
 # SRv6 能力通告
 segment-routing ipv6
  locator PE1-LOCATOR ipv6-prefix 2001:DB8:100::/48
   opcode 1 end                              # END SID
   opcode 2 end-x                            # END.X SID
  #
  locator PE1-LOCATOR2 ipv6-prefix 2001:DB8:200::/48
   opcode 1 end

# ========== Locator 配置 ==========
segment-routing ipv6
 encapsulation source-address 2001:DB8:1::1
 locator PE1-LOCATOR ipv6-prefix 2001:DB8:100::/48
  # 每个 locator 可以分配 65536 个 SID
  opcode 1 end           # END: 节点 SID (2001:DB8:100:0:1::)
  opcode 2 end-x         # END.X: 邻接 SID (2001:DB8:100:0:2::)
  #
  # 自动分配的 SID 范围
  static 32               # 静态 SID 数量
  auto 4096               # 自动分配 SID 数量
"""

    return config


def generate_srv6_te_config():
    """SRv6 TE Policy 配置"""
    config = """
sysname PE-R1

# ========== SRv6 TE Policy ==========
segment-routing ipv6
 #
 # TE Policy 定义
 traffic-engineering
  #
  # 策略 1:低延迟路径
  policy TE-POLICY-LOW-LATENCY
   color 100
   endpoint 2001:DB8:2::2                 # 目的 PE
   candidate-paths
    preference 100
     explicit segment-list LOW_LAT_PATH
  #
  # 策略 2:高带宽路径
  policy TE-POLICY-HIGH-BW
   color 200
   endpoint 2001:DB8:2::2
   candidate-paths
    preference 100
     explicit segment-list HIGH_BW_PATH

# ========== Segment List ==========
segment-routing ipv6
 traffic-engineering
  segment-list LOW_LAT_PATH
   index 10 sid 2001:DB8:100:0:1::     # R1 (END)
   index 20 sid 2001:DB8:200:0:5::     # R5 (END)
   index 30 sid 2001:DB8:300:0:2::     # R2 (END)

  segment-list HIGH_BW_PATH
   index 10 sid 2001:DB8:100:0:1::     # R1
   index 20 sid 2001:DB8:400:0:3::     # R3
   index 30 sid 2001:DB8:500:0:4::     # R4
   index 40 sid 2001:DB8:300:0:2::     # R2

# ========== 验证命令 ==========
# display segment-routing ipv6 locator
# display segment-routing ipv6 te policy
# display segment-routing ipv6 te tunnel
"""
    return config

三、部署实施方案

3.1 平滑升级方案

SRv6 平滑演进步骤:

阶段 1:评估和规划(1 个月)

□ 确认所有设备硬件支持 SRv6 □ 确认软件版本支持 □ 设计 SRv6 Locator 和 SID 规划 □ 制定分批次升级计划 □ 制定回退计划

阶段 2:控制面升级(夜间窗口,每批 5 台)

批次 1(测试节点) └─ 升级 2 台边缘路由器 └─ 验证 IS-IS SRv6 扩展正常 └─ 验证 Locator 发布 └─ 验证现有 MPLS 业务不受影响 批次 2-4(核心节点) └─ 每次升级 5 台核心路由器 └─ 验证 IS-IS 邻居不中断 └─ 验证 SRv6 BE 转发 批次 5(全部完成) └─ 所有节点 IS-IS SRv6 使能 └─ 全网 SRv6 BE 就绪

阶段 3:业务迁移(周末窗口)

  1. 在 PE 上配置 SRv6 VPN
  2. 建立 SRv6 L3VPN 隧道
  3. 验证 SRv6 VPN 业务正常
  4. 逐个 VRF 迁移到 SRv6
  5. 保留 MPLS VPN 作为回退
  6. 确认所有 VPN 迁移完成后关 MPLS

阶段 4:流量工程部署

  1. 部署 SRv6 TE Policy
  2. 配置 BGP SR Policy
  3. 对接控制器(SDN)
  4. 构建随流检测(iFIT)

3.2 自动化部署脚本

# srv6_deploy.py — SRv6 自动化部署

from netmiko import ConnectHandler
import json
import time
from concurrent.futures import (
    ThreadPoolExecutor, as_completed
)


class SRv6Deployer:
    """SRv6 自动化部署器"""

    def __init__(self, inventory: str):
        with open(inventory, "r") as f:
            self.devices = json.load(f)

    def check_srv6_capability(self, device: dict) -> dict:
        """检查设备 SRv6 能力"""
        try:
            conn = ConnectHandler(**device)
            output = conn.send_command(
                "display segment-routing ipv6 capability"
            )
            support = "support" in output.lower()
            version = conn.send_command("display version")
            conn.disconnect()

            return {
                "device": device.get("hostname", ""),
                "srv6_support": support,
                "version": version.splitlines()[0] if version else "",
            }
        except Exception as e:
            return {"device": device.get("hostname", ""), "error": str(e)}

    def deploy_srv6_base(self, device: dict) -> bool:
        """部署 SRv6 基础配置"""
        try:
            conn = ConnectHandler(**device)
            conn.enable()
            hostname = conn.find_prompt().rstrip("#>")

            config_lines = [
                "ipv6",
                "isis 1",
                " ipv6 enable topology ipv6",
                " segment-routing ipv6",
                f"  locator {hostname}-LOCATOR"
                f" ipv6-prefix 2001:DB8:100::/48",
                "   opcode 1 end",
                "   opcode 2 end-x",
                " segment-routing ipv6",
                f" encapsulation source-address"
                f" 2001:DB8:1::{device.get('id', 1)}",
                f" locator {hostname}-LOCATOR"
                f" ipv6-prefix 2001:DB8:100::/48",
                "  static 32",
                "  auto 4096",
            ]

            output = conn.send_config_set(config_lines)
            has_error = "Error" in output
            conn.save_config()
            conn.disconnect()

            return not has_error
        except Exception as e:
            print(f"部署失败: {e}")
            return False

    def verify_srv6(self, device: dict) -> dict:
        """验证 SRv6 部署"""
        try:
            conn = ConnectHandler(**device)
            conn.enable()

            results = {
                "locator": conn.send_command(
                    "display segment-routing ipv6 locator"
                ),
                "sid_list": conn.send_command(
                    "display segment-routing ipv6 sid"
                ),
                "te_policy": conn.send_command(
                    "display segment-routing ipv6"
                    " te policy"
                ),
            }

            # 检查 IS-IS SRv6 扩展
            results["isis_srv6"] = conn.send_command(
                "display isis segment-routing ipv6"
            )

            conn.disconnect()
            return results
        except Exception as e:
            return {"error": str(e)}

    def deploy_all(self, batch_size: int = 5):
        """批量部署 SRv6"""
        results = {"success": [], "failed": []}

        with ThreadPoolExecutor(
            max_workers=batch_size
        ) as executor:
            futures = {
                executor.submit(
                    self.deploy_srv6_base, dev
                ): dev
                for dev in self.devices
            }

            for future in as_completed(futures):
                dev = futures[future]
                host = dev.get("hostname", "unknown")
                try:
                    if future.result():
                        results["success"].append(host)
                        print(f"✅ {host}: SRv6 部署成功")
                    else:
                        results["failed"].append(host)
                        print(f"❌ {host}: SRv6 部署失败")
                except Exception as e:
                    results["failed"].append(host)
                    print(f"❌ {host}: 异常 - {e}")

        return results

四、SRv6 VPN 业务

4.1 SRv6 L3VPN

# srv6_vpn_config.py — SRv6 VPN 配置

def generate_srv6_l3vpn():
    """SRv6 L3VPN 配置"""
    config = """
sysname PE-R1

# ========== VRF ==========
ip vpn-instance CUSTOMER-A
 ipv6 enable
 route-distinguisher 100:1
 vpn-target 100:1 export-extcommunity
 vpn-target 100:1 import-extcommunity

# ========== CE 接口 ==========
interface GigabitEthernet0/0/2
 description to-CE
 ip binding vpn-instance CUSTOMER-A
 ip address 10.10.0.1 255.255.255.252

# ========== SRv6 VPN(替代传统 MPLS VPN) ==========
bgp 100
 router-id 10.0.0.1
 peer 2001:DB8:2::2 as-number 100         # 对端 PE
 peer 2001:DB8:2::2 connect-interface LoopBack0
 #
 # SRv6 SID 分配
 segment-routing ipv6
  locator PE1-LOCATOR
 #
 ipv4-family vpn-instance CUSTOMER-A
  segment-routing ipv6                    # 使用 SRv6 封装
  peer 10.10.0.2 as-number 65001
  #
 ipv6-family vpn-instance CUSTOMER-A
  segment-routing ipv6
 #
 ipv4-family vpnv4
  peer 2001:DB8:2::2 enable
  peer 2001:DB8:2::2 segment-routing ipv6
"""
    return config


def generate_srv6_evpn():
    """SRv6 EVPN VXLAN 配置"""
    config = """
sysname LEAF-1

# ========== SRv6 EVPN ==========
evpn
 vpn-instance EVPN-A
  route-distinguisher 100:1
  vpn-target 100:1 export-extcommunity
  vpn-target 100:1 import-extcommunity

bridge-domain 10
 vxlan vni 10010
 evpn
  route-distinguisher 100:1
  vpn-target 100:1 export-extcommunity
  vpn-target 100:1 import-extcommunity

interface Nve1
 source 2001:DB8:1::1
 vni 10010 head-end peer-list protocol bgp

bgp 100
 router-id 10.0.0.1
 peer 2001:DB8:2::2 as-number 100

 l2vpn-family evpn
  policy vpn-target
  peer 2001:DB8:2::2 enable
  peer 2001:DB8:2::2 segment-routing ipv6   # SRv6 EVPN
"""
    return config

五、验证与排障

5.1 验证命令

# SRv6 部署验证命令集

# 1. Locator 和 SID
display segment-routing ipv6 locator
display segment-routing ipv6 sid

# 2. IS-IS SRv6 扩展
display isis segment-routing ipv6 capability
display isis route ipv6

# 3. TE Policy
display segment-routing ipv6 te policy
display segment-routing ipv6 te tunnel

# 4. SRv6 转发
display segment-routing ipv6 forwarding

# 5. SRv6 VPN
display bgp vpnv4 all routing-table
display ip routing-table vpn-instance CUSTOMER-A

# 6. 端到端连通性
ping ipv6 2001:DB8:2::2
ping -vpn-instance CUSTOMER-A 10.20.0.1

# 7. SRv6 隧道封装验证
display ipv6 routing-table 2001:DB8:2::2

5.2 常见问题

SRv6 部署常见问题:

问题 1:SID 分配失败

原因:Locator 前缀冲突 修复:确保全网 Locator 前缀唯一 验证:display segment-routing ipv6 locator

问题 2:SRv6 隧道不建立

原因:IS-IS SRv6 Capability 不通告 修复: 验证:display isis segment-routing ipv6 display isis lsdb

问题 3:SRv6 VPN 不通

原因:SID 解析失败 修复:检查 Locator 路由是否可达 验证:ping ipv6 2001:DB8:100::1

问题 4:MTU 问题

原因:SRv6 封装增加 IPv6 头(40 字节) + SRH(8-40 字节) 修复:调整接口 MTU 或配置 TCP MSS


六、经验总结

SRv6 骨干网部署关键经验:

  1. 硬件先行
  ┌─ 确认所有硬件支持 SRv6(NP 芯片支持)
  ├─ 确认软件版本符合要求
  ├─ 注意不同厂商 SRv6 实现差异
  └─ 测试环境充分测试后再上线

  2. Locator 规划至关重要
  ┌─ Locator 前缀全网唯一
  ├─ 建议按地域/功能分配 Locator 段
  ├─ 预留足够的 SID 空间
  └─ 好的规划避免后期大规模调整

  3. 平滑演进策略
  ┌─ 先 SRv6 BE,再 SRv6 TE
  ├─ 保留传统 MPLS 作为回退
  ├─ 逐步迁移业务,不要"大爆炸"
  └─ 每步验证通过后才继续

  4. 自动化部署
  ┌─ 批量部署脚本(Ansible/Python)
  ├─ 配置模板化(Jinja2)
  ├─ 验证自动化(pyATS/Genie)
  └─ 监控 Telemetry 数据

  5. 运维转型
  ┌─ 传统 MPLS 排障经验不完全适用
  ├─ SRv6 排障重点是 SID 和 Locator
  ├─ 需要掌握 IPv6 路由协议
  └─ 建设 SRv6 可视化运维平台

下篇预告:第340篇《EVPN_VXLAN数据中心互联案例》——通过DCI互联案例,掌握EVPN VXLAN跨数据中心的部署与排障。


下篇预告:第340篇《EVPN_VXLAN数据中心互联案例》——通过DCI互联案例,掌握EVPN VXLAN跨数据中心的部署与排障。