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

第一编|从比特到 IPv6 路由

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

系统仿真IPv6路由

1. 信息怎样变成网络中的字节

1.1 Bit、Byte 和十六进制

Bit(Binary Digit,二进制位)是计算机中最小的信息单位,只能取 0 或 1。 Byte(字节)通常由 8 个 bit 组成。一个字节可以表示 0..255。

网络协议经常使用Hexadecimal(十六进制),因为一个十六进制数字正好表示 4 个bit:

二进制 0000 = 十六进制 0
二进制 1001 = 十六进制 9
二进制 1010 = 十六进制 a
二进制 1111 = 十六进制 f

因此一个字节 11111111 可以写成 ff。IPv6 地址使用十六进制,MAC 地址也通常使用十六进制。

1.2 Network Byte Order

Network Byte Order(网络字节序)规定多字节整数在线上按高位字节在前的顺序 传输,也叫Big Endian(大端序)。

例如十六进制整数 0x12345678 在线上的四个字节依次是:

12 34 56 78

任何网络协议中的多字节整数都必须明确字节序。接收端不能直接假设主机内存顺序与网络顺序相同;C 代码通常通过 htonl、ntohl、htobe64 等函数转换。项目业务头中的具体字段等学到第七编再逐项解码。

1.3 Header 和 Payload

Header(头部)是协议为了传输和解释数据而添加的元信息;Payload(载荷) 是这一层实际承载的内容。

一个简化的嵌套关系是:

以太网Header
└─ IPv6 Header
   └─ UDP Header
      └─ Application Header(应用头)
         └─ Application Data(应用数据)

对外层协议而言,整个内层通常只是 payload。例如,以太网不需要理解应用数据的字段。

1.4 Encapsulation 与 Decapsulation

Encapsulation(封装)是在原数据外面增加本层头部; Decapsulation(解封装)是接收端删除已经完成使命的外层头部。

图 1 封装:UDP 数据报装进 IP 包,IP 包再装进当前一跳的以太网帧;接收端按相反顺序剥离

图 1 封装:UDP 数据报装进 IP 包,IP 包再装进当前一跳的以太网帧;接收端按相反顺序剥离

例如,UDP 把应用数据封装成 UDP 数据报,IP 再把 UDP 数据报封装成 IP 包,Ethernet 最后把IP 包封装成当前一跳的帧。接收端按相反顺序剥离头部。项目中的多层 SRv6 封装等学完 IPv6后再解释。

1.5 校验题

  1. 一个字节有多少 bit,能表示多少个不同值?
  2. 对 Ethernet 层而言,整个 IPv6 包属于 header 还是 payload?
  3. 封装与修改内层数据有什么区别?

2. 为什么网络需要分层

2.1 常用四层视图

网络不是一个函数完成所有工作,而是分层协作。本书使用下面的简化视图:

层常用英文本层对象主要问题本项目例子
链路层Link Layer,链路层Frame同一条链路上交给哪个接口Ethernet、MAC、veth、XDP
网络层Network Layer,网络层Packet跨多跳到哪个 IP 地址IPv4、IPv6、SRv6
传输层Transport Layer,传输层Datagram/Segment交给目的主机的哪个进程UDP、TCP
应用层Application Layer,应用层Message/Object业务数据怎样解释文件、图片、请求或响应

Frame(帧)是链路层传输单位;Packet(包)是 IP 层传输单位; Datagram(数据报)常指 UDP 单位;Segment(报文段)常指 TCP 单位。 日常日志有时会宽泛地把它们都称为“包”,读代码时必须看具体层次。

2.2 每层只解决自己的问题

以一段普通 UDP 应用数据为例:

  1. 应用层说明数据对业务意味着什么;
  2. UDP 用端口把它交给目的进程;
  3. IP 决定它跨越多跳后到哪个地址;
  4. Ethernet 用下一跳 MAC 完成当前一跳;
  5. 真实链路决定这一跳是否连通、能以多快速度传输。

如果链路层开始解释图片含义,或者控制服务替 Linux 逐包改 MAC,分层边界就被破坏了。

2.3 Control Plane、Data Plane 和 Observer Plane

Control Plane(控制面)交换邻居、拓扑、资源和策略所需的事实。 Data Plane(数据面)实际转发业务包并执行算子。 Observer Plane(观察面)记录事件、统计和图片,供分析与前端展示。

图 2 四层视图与三个平面:观察面故障不能停止数据面,控制器不代替节点做本地转发决策

图 2 四层视图与三个平面:观察面故障不能停止数据面,控制器不代替节点做本地转发决策

本项目的底线是:观察面故障不能停止数据面;控制面不能承载被验证的业务数据;控制器不能代替节点完成本地转发决策。

3. Ethernet、MAC 和一跳交付

3.1 Ethernet 是什么

Ethernet(以太网)是一组常用链路层技术。本项目不模拟真实网卡电信号,但使用 标准 Ethernet 帧表达容器接口之间的一跳数据。

Ethernet 帧至少包含:

Destination MAC | Source MAC | EtherType | Payload

MAC(Media Access Control,介质访问控制地址)是链路层接口标识,通常写成 02:00:00:02:00:01。EtherType 说明 payload 是 IPv4、IPv6 还是其他协议。

3.2 MAC 只负责当前一跳

假设 IPv6 包最终要从节点 1 到节点 10,但节点 1 的当前下一跳是节点 2:

IPv6目的地址 = 节点10或某个SID
Ethernet目的MAC = 节点2在当前链路上的MAC

到节点 2 后,Linux 再次查询 FIB,为下一跳重建新的 Ethernet 头。IP 目的地址可以在多跳期间保持不变,MAC 目的地址通常每一跳都变化。

3.3 MTU

MTU(Maximum Transmission Unit,最大传输单元)是一条链路无需分片即可承载的 最大网络层包长度。IPv6 链路最小 MTU 是 1280 字节。本项目 AF_XDP frame 容量是 2048 字节,所有后续协议头与应用数据的总长度都必须保证完整帧不越界。

头部不是免费的。增加 SRH segment 会增加包长,所以 uSID 压缩能减少重复的 128-bit SID。

3.4 本项目的宿主机转发边界

节点 Linux 依据自己的 IPv6 FIB 和邻居表写入目标 MAC。宿主机 XDP/eBPF 只根据目标 MAC把帧 redirect 到对应 AF_XDP socket;AF_XDP 再把它放入 source→destination 有向链路。

这一节只需记住:节点 Linux 决定下一跳,宿主链路层实施这一跳的传输条件。宿主为什么默认不解释上层数据,以及项目唯一受限例外怎样工作,分别留到第三编和第八编。

4. IPv4 从零开始

4.1 IPv4 地址

IPv4(Internet Protocol version 4,互联网协议第 4 版)使用 32-bit 地址,通常按 四个十进制字节书写:

192.168.0.2

每段范围为 0..255。IPv4 地址标识一个网络接口在某个 IP 网络中的位置,不等同于用户、进程、Docker 容器或物理机器本身。

4.2 Prefix 与 Subnet

Prefix(前缀)表示一组共享高位 bit 的地址。192.168.0.0/24 中的 /24 表示前 24 个 bit 是网络部分,剩余 8 个 bit 是该网络中的接口部分。

Subnet(子网)是按前缀划分出的地址集合。例如:

网络:192.168.0.0/24
可写地址示例:192.168.0.2、192.168.0.5

本书示例只解释前缀匹配,不展开传统广播地址分配规则。

4.3 Default Gateway

Default Gateway(默认网关)是主机在没有更具体路由时交付流量的下一跳。

端侧不需要知道 200 颗卫星的全网拓扑。它只需要:

自己的地址
当前接入卫星的地址和MAC
一条指向接入卫星的默认路由

接入卫星才负责进入核心网络。

4.4 ARP

ARP(Address Resolution Protocol,地址解析协议)把同一 IPv4 链路上的下一跳 IP 解析为 MAC。例如,主机知道下一跳是 10.42.9.1,但发 Ethernet 帧前还要知道对应 MAC。

IPv6 不使用 ARP,而使用后面介绍的 NDP。

4.5 IPv4 头部中的关键字段

初学者需要先认识:

字段作用
Source Address源 IPv4 地址
Destination Address目的 IPv4 地址
TTL每经过一个三层转发节点减 1,防止路由环路无限存活
Protocol指示上层是 ICMP、TCP、UDP 等
Total Length整个 IPv4 包长度

TTL(Time To Live,生存时间)名字像时间,IPv4 转发时实际主要作为跳数上限。

4.6 本项目怎样使用 IPv4

外部飞机和船舶端侧可以发送普通 IPv4 业务。入口卫星执行 IPv4-in-IPv6 SRv6 封装,出口卫星使用 End.DX4 解封装并交给目的端侧。核心网络不需要给每个中间节点建立IPv4 SRv6 能力;核心转发外层 IPv6。

5. IPv6 从零开始

5.1 为什么地址变成 128 bit

IPv6(Internet Protocol version 6,互联网协议第 6 版)使用 128-bit 地址。它不仅 扩大地址空间,也提供扩展头机制,SRH 正是 IPv6 Routing Header 的一种。

IPv6 地址由 8 组 16-bit 十六进制数组成:

fd42:0001:0000:0000:0000:0000:0000:000a

每组可以省略前导零:

fd42:1:0:0:0:0:0:a

一段连续的全零组可以用一次 :: 压缩:

fd42:1::a

一个地址中不能出现两个 ::,否则无法判断各自代表多少组零。

5.2 IPv6 前缀

IPv6 也使用 CIDR 前缀。CIDR(Classless Inter-Domain Routing,无类别域间路由)用 地址/前缀长度 表达网络。示例:

fd42:1::/48

表示前 48 bit 固定。fd42:1::1 与 fd42:1::c8 都属于这个前缀。

常见长度:

  • /128:一个精确 IPv6 地址;
  • /64:常见接口子网;
  • /48 或 /32:可以继续划分的大定位前缀。

5.3 ULA

ULA(Unique Local Address,唯一本地地址)使用 fc00::/7 范围,作用类似组织内部 使用的 IPv6 地址,不直接作为全球互联网路由地址。本项目的 fd42:* 全部位于 ULA 范围,便于在封闭仿真中定义稳定地址合同。

Link-local Address(链路本地地址)位于 fe80::/10,只在当前链路有效,通常不被 路由器跨链路转发。本项目节点间下一跳常写成:

via fe80::2 dev eth0

因为同一个 fe80::2 可能在不同接口上重复,Linux 命令必须同时给出 dev eth0。

5.5 Multicast

Multicast(组播)让一个发送者把报文交给一组监听者。IPv6 组播地址以 ff 开头。 本项目 HELLO 使用组播传播本地邻居探测,但只有实际收到并正确 ACK 的节点才能成为邻居。

组播不是广播。IPv6 没有 IPv4 那种全网广播地址。

5.6 NDP

NDP(Neighbor Discovery Protocol,邻居发现协议)通过 ICMPv6 完成 IPv6 地址到 MAC 解析、邻居可达性等功能。**ICMPv6(Internet Control Message Protocol for IPv6,IPv6 互联网控制消息协议)**承载错误报告和邻居发现等控制消息。

需要区分两个“邻居发现”:

  • Linux NDP 解决“已知下一跳 IPv6 对应哪个 MAC”;
  • 本项目 HELLO/ACK 解决“物理场景中哪个节点现在真的可达”。

它们工作层次不同,不能互相替代。

5.7 IPv6 基本头部

IPv6 基本头固定 40 字节。关键字段包括:

字段作用
Version固定为 6
Payload Length基本头之后的字节数
Next Header后面是扩展头、UDP、TCP 还是其他协议
Hop Limit类似 IPv4 TTL,每次三层转发减 1
Source Address128-bit 源地址
Destination Address当前 128-bit 目的地址

5.8 Extension Header

Extension Header(扩展头)让 IPv6 在基本头之后串联额外功能。每个头用Next Header指向下一个头。SRH 是 Routing Extension Header(路由扩展头)的 Type 4。

一个 SRv6 封装包可以是:

Outer IPv6 Header
└─ SRH
   └─ Inner IPv6 Header
      └─ UDP
         └─ Application Data

中间普通转发节点只需要按当前 IPv6 Destination Address 查询 FIB;只有当前目的地址命中本地 SID 的节点才执行对应 SRv6 行为。

5.9 IPv4 与 IPv6 不是“新旧开关”

对比IPv4IPv6
地址长度32 bit128 bit
常用写法点分十进制冒号分隔十六进制
邻居解析ARPNDP/ICMPv6
跳数限制TTLHop Limit
扩展机制基本头选项能力有限Extension Header 链
本项目核心 SRv6可作为内层业务作为外层核心和内层业务

SRv6 依赖 IPv6 外层,但它可以承载 IPv4 或 IPv6 内层业务。

5.10 练习

  1. 展开 fd42:1::a 为 8 组十六进制数。
  2. /128 和 /48 哪个匹配范围更精确?
  3. fe80::2 为什么通常必须与接口名一起使用?
  4. Linux NDP 与本项目 HELLO 分别发现什么?

6. 路由:包怎样逐跳前进

6.1 Route、Next Hop 和 Interface

Route(路由)是一条“某类目的地址应该怎样处理”的规则。典型路由包含:

destination prefix → next hop → output interface

Next Hop(下一跳)是当前节点下一次交付的相邻节点;Interface(接口)是包离开 本节点的出口。

例如:

fd42:1::a/128 via fe80::2 dev eth0

含义不是“节点 2 是最终目的”,而是“要去 fd42:1::a,当前先交给 fe80::2”。

6.2 Longest Prefix Match

Longest Prefix Match(最长前缀匹配)规定:若多条路由都匹配目的地址,选择前缀 长度最长,也就是最具体的一条。

fd42:1::/48       via A
fd42:1::a/128     via B

访问 fd42:1::a 选择 /128 的 B,访问 fd42:1::b 选择 /48 的 A。

Metric(度量值)可以在同等前缀的多条路由之间表达优先级,但它不能战胜更长前缀。

6.3 RIB 与 FIB

RIB(Routing Information Base,路由信息库)保存控制层面学到或配置的路由信息; FIB(Forwarding Information Base,转发信息库)是内核逐包转发实际使用的结果。

通俗类比:RIB 像规划部门的候选路线档案,FIB 像司机手上的当前导航指令。

本项目控制器不替节点安装 FIB。每个节点从收到的拓扑事实计算自己的主/备下一跳,再由唯一 forwarding worker(转发工作线程)调用 Linux 路由接口更新本地 FIB。

6.4 Neighbor Table

路由查询得到下一跳 IPv6 和接口后,还要通过Neighbor Table(邻居表)找到 MAC。所以转发需要两次不同意义的解析:

FIB:目的IPv6 → 下一跳IPv6 + 接口
邻居表:下一跳IPv6 + 接口 → 下一跳MAC

宿主机 XDP 最终读取的是已经写入 Ethernet 头的目标 MAC,不是自己重新查询全网路由。

6.5 Policy Routing

Policy Routing(策略路由)不仅看目的地址,还可以看报文 mark(标记)、源地址等 条件,选择另一张路由表。

普通路由:

destination → main table → route

一个通用策略路由例子:

packet mark = 7
→ ip rule选择table 10007
→ table 10007中的路由决定下一跳

这里先理解“同一目的可以因本地标记而查询不同路由表”。项目怎样从任务身份得到标记,以及怎样把它导入 SR Policy,到第四编再解释。

6.6 BFS 与最短跳数

BFS(Breadth-First Search,广度优先搜索)从起点按“一跳、两跳、三跳”逐层扩展。 在所有边代价相同的图中,它能找到最少跳数路径。

当前系统节点本地 FIB 使用单位边 BFS。物理场景虽然提供 delay_us 和 rate_bps,当前控制面选路成本仍是 hop_count × 1000,也就是跳数乘 1000。不能把它误写成时延感知或带宽感知路由。

6.7 LFA 备份

LFA(Loop-Free Alternate,无环路备选)是在主下一跳失效时可用且不会把包送回 环路的另一个下一跳。对源 S、候选邻居 N 和目的 D,常用判断是:

D(N,D) < D(N,S) + D(S,D)

其中 D(X,Y) 表示 X 到 Y 的图距离。本项目每个节点保存满足条件的第二下一跳;邻居失效时只切换受影响路由,不让一个节点失败导致全系统退出。

6.8 路由不等于 SR Policy

普通 FIB 回答“当前目的 IPv6 下一跳是谁”。SR Policy 回答“这类业务必须依次执行哪些segment”。SR Policy 中的每个 SID 仍需要普通 IPv6 FIB 把它送向当前执行位置。

因此:

SR Policy给出指令顺序
IPv6 FIB完成每条指令之间的逐跳可达

二者缺一不可。

6.9 第一编自测

读者应当能不看答案解释:

  1. 最终目的 IP 为什么与当前一跳 MAC 不是同一个层次?
  2. FIB 和邻居表各自把什么映射成什么?
  3. 为什么最长前缀匹配会选择 /128 而不是 /48?
  4. 控制器持有拓扑为什么不等于控制器必须替节点安装 FIB?
  5. SRv6 封装 IPv4 为什么不叫地址族转换?

< 返回技术专栏