从 IP 到 SRv6 计算编排 · 第二编

第二编|SRv6 与 SR Policy

2026-08-20 · COMPIN Lab · 阅读约 9 分钟

系统仿真SRv6SR Policy

7. Segment Routing 的核心思想

7.1 从“只写终点”到“写一串指令”

SR(Segment Routing,分段路由)是一种源路由思想:入口把有序 segment 写入包, 中间网络按顺序执行。Source Routing(源路由)不是说业务端侧必须知道全网,而是指 SR domain(分段路由域)的入口节点负责把指令链写进包。

普通 IPv6 包主要表达:

去目的D

SRv6 包可以表达:

先到节点2
再经过节点6提供的一项服务
再到节点9
最后在节点12解封装

7.2 Segment 与 SID

Segment(分段/指令)是要执行的一步。SID(Segment Identifier,分段标识符) 是这条指令的 IPv6 地址表示。

SID 不是单纯“某台机器的地址”。它可以表示:

  • 到达并推进指令链;
  • 从指定下一跳或接口发出;
  • 解封装并查 IPv4/IPv6 表;
  • 进入一个节点已经注册的服务接口。

这正是 SRv6 的“Network Programming(网络编程)”思想:有序 SID 列表像一个很小的网络程序,每个 SID 对应一个节点上已经安装的行为。这里的“编程”不是允许包携带任意代码,而是从节点预先支持的有限行为中选择。

7.3 SRv6

SRv6(Segment Routing over IPv6,基于 IPv6 的分段路由)用 IPv6 地址表示 SID, 并通常用 SRH 携带有序 segment 列表。它复用 IPv6 转发、路由表和扩展头,不需要自定义用户态 IPv6 协议栈。

本项目坚持 Linux 原生 SRv6:

  • 入口用 Linuxseg6 mode encap 添加外层 IPv6 和 SRH;
  • 节点用 Linuxseg6local 执行本地 SID 行为;
  • 普通中继用 Linux IPv6 FIB 转发当前目的地址;
  • 不定义私有 SRH,不让宿主 fabric 推进 SID。

8. SRH 怎样表达有序指令

8.1 SRH 是什么

SRH(Segment Routing Header,分段路由头)是 IPv6 Routing Header Type 4。 重要字段包括:

图 1 SRH(IPv6 Routing Header Type 4)的主要字段

图 1 SRH(IPv6 Routing Header Type 4)的主要字段

字段中文解释初学者应理解的作用
Next Header下一头部SRH 后面是 IPv6、UDP 等什么协议
Hdr Ext Len扩展头长度SRH 占多少字节
Routing Type路由类型SRH 固定为 4
Segments Left剩余 segment 数还有多少指令尚未推进
Last Entry最后条目索引segment list 的边界
Flags标志SRH 处理选项
Tag标签可选策略标识;不要与后文的本地策略编号混淆
Segment ListSID 数组有序指令的线表示

为了便于人阅读,本书总是按执行顺序写:

SID-A → SID-B → SID-C

SRH 在线数组的索引布局与人类执行顺序可能看起来相反,Linux 会按照 Segments Left和当前 IPv6 Destination Address 正确推进。操作人员不要手工猜数组顺序,应检查ip -6 route 安装的 segment 顺序和真实抓包。

8.2 当前 Destination Address 很重要

外层 IPv6 Destination Address 保存当前正在生效的 SID。普通 transit node(中继节点)只按这个目的地址查 FIB,不应该随意检查 SRH 深处的未来指令。

图 2 SRv6 逐段推进:外层 IPv6 目的地址始终是当前生效的 SID,中继节点只按它查 FIB

图 2 SRv6 逐段推进:外层 IPv6 目的地址始终是当前生效的 SID,中继节点只按它查 FIB

当当前 SID 节点执行 End 类行为时,Linux 推进 SRH,把下一 SID 放入 Destination Address,然后继续普通 IPv6 路由。

8.3 Reduced SRH

Reduced SRH(精简 SRH)允许第一个 segment 已经位于 IPv6 Destination Address, 从 SRH 列表中省略重复项。读者只需记住:抓包中当前目的地址和 SRH 数组必须合起来理解,不能只看数组就断言“第一个节点丢了”。

8.4 先掌握固定 segment list,再学习运行期插入

初学者在本编只处理入口已经写好的固定 segment list:读当前 Destination Address、执行当前 SID、推进 Segments Left。系统还支持一种在链路边界临时插入本地服务 SID 的高级行为,但它同时依赖链路速率、算子和业务格式,因此推迟到第八编。现在只需记住:任何高级插入都必须保存并恢复当时真正的 active segment,不能从原始列表猜测当前位置。

9. Linux 原生 SRv6 行为

9.1 seg6 与 seg6local

LWT(Lightweight Tunnel,轻量隧道)允许 Linux 把封装动作附着在路由上。 encap seg6 mode encap 是入口封装动作;encap seg6local action ... 是本地 SID 行为。

抽象命令如下:

ip -6 route replace <业务目的>/128 \
  encap seg6 mode encap segs <SID-A>,<SID-B> \
  via <下一跳> dev <接口>

这条命令的含义是:命中业务目的后,Linux 增加外层 IPv6 和 SRH,并把包送向第一 SID。

9.2 End

End(端点推进行为)表示当前 SID 在本节点终止,推进到下一个 segment,再按 IPv6 FIB 继续转发。它适合表达“必须经过这个 SRv6 节点”。

End 不执行图像算法,也不等于最终业务交付。

9.3 End.X

End.X(Endpoint with Layer-3 cross-connect,带三层交叉连接的端点行为)推进 SRH 后,把包交给一个指定 IPv6 下一跳和接口。

End.X 可以把包交给一个独立服务 namespace:

服务SID命中服务namespace的End.X
→ 包进入服务接口
→ 用户态进程处理应用数据
→ 包回注同一namespace
→ 按推进后的SRH继续

第五编会把这种服务具体化为图像算子。此处只需理解:它是一个真实网络转发闭环,不是入口进程直接调用另一个函数。

9.4 End.DX4 与 End.DX6

End.DX4(Endpoint Decapsulation and IPv4 Cross-Connect,解封装并 IPv4 交叉连接) 删除外层 SRv6 封装,把内层 IPv4 包交给指定 IPv4 下一跳。

End.DX6(Endpoint Decapsulation and IPv6 Cross-Connect,解封装并 IPv6 交叉连接) 做同样的事,但内层是 IPv6 并交给指定 IPv6 下一跳。

独立飞机/船舶端侧位于自己的 namespace,末端接入卫星使用包含接入节点和 endpoint身份的具体 SID:

fd42:4:<access-node>::6:<endpoint>

该 SID 执行 End.DX6,把内层普通 IPv6 交给真实端侧。

9.5 End.DT6

End.DT6(Endpoint Decapsulation and IPv6 Table Lookup,解封装并查询 IPv6 路由表) 删除外层后,在指定 Linux IPv6 表中重新查询内层目的地址。

网络节点内部的 integrated endpoint(集成端侧)复用物理节点身份,末段可以使用:

fd42:2::<node>

执行 End.DT6 并把包交给节点内集成端侧。独立端侧与集成端侧的末端行为不同,但它们在 REQUEST/READY 和业务合同上没有第二套模型。

9.6 行为对照表

行为是否推进 SRH是否解封装下一步
End是否普通 IPv6 FIB
End.X是否指定 IPv6 下一跳/接口
End.DX4到末端是指定 IPv4 下一跳
End.DX6到末端是指定 IPv6 下一跳
End.DT6到末端是指定 IPv6 路由表查询

10. uSID:压缩物理逐跳路径

10.1 为什么需要压缩

一个完整 IPv6 SID 是 128 bit,即 16 字节。若把十几个物理节点都写成完整 SID,SRH 会快速变大。uSID(micro SID,微型 SID)把共享 locator 后的短指令装入一个 128-bit container(容器),减少重复前缀和零填充。

当前 IETF 标准把这种机制称为 Compressed SRv6 Segment List Encoding(压缩 SRv6 segment list 编码),并定义 NEXT-CSID 等行为 flavor。Flavor(行为变体)是在保留基本 End 语义的同时改变 SID 内部推进方式。

10.2 本项目 16-bit 指令合同

本项目使用:

Locator = fd42:197::/32
每个uSID = 16 bit
高8 bit = node,范围1..255
低8 bit = local function
function 0 = 物理节点transit

一个 128-bit container 在 32-bit locator 之后有 96 bit,可容纳 6 个 16-bit 指令。

例如物理路径 1→2→5→8→10 由入口 1 安装,入口本身不重复编码,后四个节点编码为:

node2  = 0x0200
node5  = 0x0500
node8  = 0x0800
node10 = 0x0a00

container = fd42:197:200:500:800:a00::

每到一个支持 NEXT-C-SID 的节点,Linux 把下一条 16-bit 指令移动到当前 SID 位置,继续转发。

10.3 为什么当前只压缩物理 transit 指令

当前 uSID 只压缩物理 transit node。节点上的具体服务继续使用完整 SID:

fd42:3:<node>::<function>

原因是每个完整服务 SID 必须对应真实 namespace 和经过验证的 End.X 行为。如果只在控制器或入口中发明一个微型 function 数字,而 Linux 节点没有对应 LocalSID 行为,这个数字不会自动变成可执行服务。

10.4 混合 segment 链

一条高级 service chain(服务链)可以交替出现:

uSID container(若干物理跳)
→ 完整服务实例SID
→ uSID container(后续物理跳)
→ 另一个完整服务实例SID
→ ...
→ 最终End.DX6或End.DT6

所有条目仍是合法 128-bit IPv6 SID,写入标准 SRH。

11. SR Policy 是什么

11.1 Policy 不是普通最短路

SR Policy(Segment Routing Policy,分段路由策略)是入口节点上的有序 segment 集合以及把某类流量导入该集合的规则。入口称为Headend(头端)。

通用 IETF 模型用三元组识别一条 SR Policy:

<Headend, Color, Endpoint>
  • Headend:策略安装在哪个入口节点;
  • Color:表达意图或类别的非零整数;
  • Endpoint:策略面向的目的。

通用标准还允许 candidate path(候选路径)、preference(偏好)、priority(优先级)和多个带 weight(权重)的 segment list。本项目使用其中更小、可验证的入口本地模型。

11.2 Candidate Path

一条 SR Policy 可以有多个Candidate Path(候选路径)。候选路径各自带 priority(优先级)或 preference(偏好),每条候选又可包含一条或多条 segment list。最简单的理解是“同一个策略目标准备一条常用指令链和一条备用指令链”。怎样选择备用、何时切换,属于使用 SR Policy 的系统规则,不是 SRH 头部自己计算。

11.3 标准 Color 与项目本地编号

RFC 9256 中的 Color 是非零 32-bit 意图值,可参与标准 SR Policy 识别。项目后来会借用这个名字表示入口本地策略编号,但具体位宽、分配和 Linux mark 映射必须等 task 身份解释以后再学习。本编先把 Color 理解成 headend 用于区分策略类别的标签,不需要记项目实现。

11.4 Steering

Steering(流量导入/牵引)是把匹配的业务包送进某条 SR Policy。通用过程是:

包满足本地分类条件
→ policy rule选择专用路由表
→ 该表的路由执行seg6封装
→ 包开始执行segment list

分类条件可以是目的前缀、源地址或本地 mark。第四编会在已经定义 task 之后,完整解释本项目怎样用 eBPF、mark 和多路由表实现 steering。

11.5 期望策略与已安装策略必须区分

用户态算出 segment list,只表示 desired state(期望状态);Linux 成功安装路由以后才是applied state(已应用状态)。若业务在策略安装前发送,包仍可能走 main table 或不可达。因此任何具体业务协议都必须先确认 applied,再允许依赖该策略发送数据。第四编会说明项目如何用明确的 REQUEST/READY 事件表达这条边界。

12. 一个不含业务专有概念的 SRv6 逐跳例子

假设:

  • 普通 IPv6 端侧 A 接入节点 17;
  • 普通 IPv6 端侧 B 接入节点 199;
  • 入口策略要求包依次经过节点 20 和节点 36;
  • 中间物理路径由 uSID container 表达;
  • 最终通过节点 199 的 End.DX6 交付。

概念 segment 链为:

uSID(17→...→20)
→ uSID(20→...→36)
→ uSID(36→...→199)
→ delivery SID@199

数据执行过程:

  1. 端侧 A 发送普通内层 IPv6/UDP 数据;
  2. 节点 17 的本地策略路由命中这类流量;
  3. seg6 mode encap 添加 outer IPv6 和 SRH;
  4. 当前 uSID container 把包逐跳送到节点 20;
  5. 节点 20 推进 container 并按自己的 IPv6 FIB 继续;
  6. 后续 container 把包送到节点 36,再送到节点 199;
  7. 节点 199 命中 delivery SID,执行 End.DX6;
  8. 外层 IPv6/SRH 被移除,端侧 B 收到原内层 IPv6/UDP 数据。

这个例子只验证“入口写指令、节点逐段执行、末端解封装”。服务函数、任务分类、Anycast、图片协议和编排算法都还没有加入;它们会在基础路径已经完全理解以后逐层叠加。

12.1 第二编自测

  1. SID 为什么既可以表示位置,也可以表示功能?
  2. 普通 transit node 为什么不应随意解析 SRH?
  3. End 与 End.DX6 的最大区别是什么?
  4. uSID 为什么可以压缩一串物理节点指令?
  5. SR Policy 与普通 IPv6 FIB 各解决什么问题?
  6. 为什么用户态算出策略不等于 Linux 已经应用策略?

< 返回技术专栏