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

第四编|统一任务、Color 和策略安装

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

系统仿真DAGSR Policy任务编排

23. DAG 把普通传输和计算链统一起来

23.1 DAG

DAG(Directed Acyclic Graph,有向无环图)由 vertex(顶点/任务节点)和有向 edge (边/依赖)组成,且不存在沿有向边回到自身的 cycle(环)。

在本项目中:

source → sink

是没有中间算子的普通传输 DAG;

source → gray → mean2x2 → blur3x3 → edge → sink

是图像处理 DAG。它们共享同一个 REQUEST、Color、SR Policy、READY 和数据发送生命周期。

23.2 Task Request 合同

TaskRequest 包含:

字段范围意义
task_id非零 uint32幂等任务身份
origin_endpoint非零 uint16业务发起端身份
destination_endpoint非零 uint16业务目的端身份
dag_profile1 或 21=plain,2=带规范 DAG
dag_json最大 1400 bytesprofile 2 的规范 JSON
placement_modeexact/resilient明确选择放置模型

uint32(unsigned 32-bit integer,无符号 32 位整数)范围为 0..2^32-1;uint16 同理。 任务合同禁止源和目的相同,禁止未知 profile,禁止超长或非 canonical DAG JSON。

Canonical JSON(规范 JSON)使用确定键顺序和紧凑编码,让同一 DAG 只有一种字节表示, 便于严格校验和摘要。

23.3 固定支持的 DAG

当前主要模板:

dag_id链
spp-transport-v1source→sink
image-pipeline-v1source→gray→mean→blur→edge→sink
fire-tile-filter-v1source→bnn→sink

普通传输固定使用 exact,因为它没有算子 Anycast 放置问题;图像 DAG 显式选择 exact 或resilient,不在任务中途自动切换模式。

24. REQUEST、READY 和 REJECTED

24.1 ETS3 线格式

当前端点任务信令 magic 为 ETS3。Magic(魔数)是协议开头的固定字节,用来快速判断 payload 类型和版本。

magic | kind | task_id | origin | destination | profile | placement | dag_length | DAG
 4B      1B      4B       2B          2B          1B        1B          2B

kind 取值:

  • REQUEST=1:请求建立任务;
  • READY=2:入口已成功安装策略;
  • REJECTED=3:请求明确不合法或不能接受。

“事实暂缺、正在等待资源”通常是 pending(待处理),不等于永久 REJECTED。

24.2 来源验证

入口不能只相信 REQUEST 正文里的 origin_endpoint,还要验证:

  • 外部端侧是否从真实 data interface 发来;
  • IPv6 源地址是否对应声明的 endpoint;
  • 集成端侧是否从本地 business veth 发来;
  • 声明 origin 是否等于当前入口身份或已本地接入身份。

这防止普通容器伪造另一个 endpoint 发起任务。

24.3 幂等与重试

Idempotent(幂等)表示相同请求重复一次不会创建第二份不同任务。端侧可以在暂时 没有 READY 时按协议重试;入口按 task_id 合并客户地址并返回已有 READY。

重试不由外部脚本注入,且不能靠延长固定超时掩盖规划错误。

24.4 完整状态机

端侧常驻
  └─ 自然产生任务
       └─ REQUEST
            ├─ 来源/合同非法 ─► REJECTED
            ├─ 当前事实不足 ─► pending,等待事实或端侧重试
            └─ 规划和安装成功
                  └─ READY
                       └─ 端侧发送业务数据

图 1 任务从 REQUEST 到 READY 的完整状态机(没有 FLOW_START,控制器不主动产生任务)

图 1 任务从 REQUEST 到 READY 的完整状态机(没有 FLOW_START,控制器不主动产生任务)

没有 FLOW_START,控制器不产生任务,观察窗口也不激活任务。

25. Color 的完整实现

25.1 Color 到底是什么

本项目的Color(策略分类编号)是入口本地非零 16-bit 整数,把 task_id 映射到 Linux策略路由表。它是转发资源,不是业务含义本身。

分配算法:

start = ((task_id - 1) mod 65535) + 1
从start循环寻找本入口尚未使用的Color

因此通常 Color 接近 task ID 的低 16-bit,但冲突时会选择下一个空闲值。不同入口可以为不同任务使用相同 Color,因为它们的 Linux 路由表互相隔离。

25.2 分类器识别哪几种业务

入口 eBPF 分类器读取 IPv6/UDP payload 的 magic:

magic协议task 字段位置
SPP1SPP TileSPP 头 offset 12 的 uint64 task_id
CFV2普通业务流magic 后 offset 4 的 uint32 flow/task ID
FAL1火灾 Alarmmagic 后 offset 4 的 uint32 alarm task ID

查 map 成功时:

skb->mark = Color

已识别任务格式但 map 没有条目时使用保留 mark 65535,避免未知任务意外进入 main route。非组播、非 link-local 的普通 UDP/TCP 可以使用 generic mark 10000;HELLO 等本地控制流量不被任务分类器改写。

25.3 安装顺序

新任务第一次安装包含:

  1. 删除可能存在的同 Color 旧 rule,保证幂等;
  2. 增加 fwmark Color lookup table priority Color;
  3. 在 table 10000+Color 安装目的 endpoint /128 路由;
  4. exact 路由直接携带 encap seg6 mode encap segs ...;
  5. resilient 路由引用一个携带不变 SRH 的稳定 nexthop object;
  6. 把 task_id→Color 写入 pinned eBPF map;
  7. 全部成功后才发送 READY。

Pinned Map(固定挂载的 eBPF 映射)通过 bpffs 路径让不同进程访问同一个内核 map。 本项目路径为:

/sys/fs/bpf/tc/globals/heft_task_colors

25.4 示例

假设 task_id=70001,入口分到 Color=4466:

table = 10000 + 4466 = 14466

概念命令是:

ip -6 rule add fwmark 4466 lookup 14466 priority 4466
ip -6 route replace fd42:10:12c::2/128 table 14466 \
  encap seg6 mode encap segs <segments> via <gateway> dev eth0
heft-task-map ... 70001 4466

业务包本身仍携带 task_id=70001,不携带 4466。Color 只存在入口内核。

25.5 策略替换和撤销

同一 task 重算时保持 task、Color、目的和 placement mode 不变,只用 route replace 更新segment 或 nexthop,避免 delete/add 产生人为流量空窗。

源端真实 detach 后,旧入口依次删除:

  • eBPF map 中的 task key;
  • task table 的目的 route;
  • Color 对应的 ip rule;
  • resilient 任务的 nexthop object。

随后释放 Color 供未来本地任务使用。

26. REQUEST 为什么必须先声明 Exact 或 Resilient

任务请求中的 placement_mode 先声明入口要采用哪一种实例选择模型。本章只建立最小区别;算子实例尚未学完,所以暂时不展开算法和逻辑地址。

26.1 Exact 只先理解为“入口明确选实例”

Exact Placement(精确放置)由入口根据一份事实快照,为每个计算阶段明确选择某个 物理实例,最终形成具体服务 SID 的完整策略。

抽象阶段A -> 明确实例A@某节点
抽象阶段B -> 明确实例B@某节点

第九编才讲入口为什么用 HEFT、怎样计算 primary/backup 以及何时重算。本章不要求读者提前接受一个尚未推导的算法答案。

26.2 Resilient 只先理解为“路径到达时选择实例”

Resilient Placement(弹性放置)不在入口固定具体实例。task 只引用逻辑服务身份, 数据到达该服务时由当前节点的普通 IPv6 FIB 选择 provider。

逻辑阶段A -> 当时可达的某个A实例
逻辑阶段B -> 当时可达的某个B实例

第六编从普通路由开始完整讲 Anycast 地址、provider 候选和 FIB 切换。

26.3 不能混用两套推理

Exact 把实例选择当成一次全链编排;Resilient 把实例选择当成每项服务的局部路由。二者都遵守同一 REQUEST/READY 和 Color 安装生命周期,但不能混用对方的重算或备份语义。全部细节等学完第六编 Anycast 和第九编 HEFT 以后再比较。

26.4 第三、四编自测

  1. 四个控制器模块分别拥有什么状态?
  2. generation 与 sequence 有什么区别?
  3. accepted 拓扑为什么不能立即用于 task planning?
  4. task_id、Color 和 SRH 分别是什么身份?
  5. Color 是否由控制器下发?
  6. Exact 与 Resilient 在哪里选择具体算子实例?

< 返回技术专栏