RFC8950:使用 IPv6 下一跳通告 IPv4
摘要
作者介绍了 RFC8950,该标准允许在 IPv6 网络上以 IPv6 下一跳通告 IPv4 路由(无需隧道),使骨干网可以仅运行 IPv6 而将 IPv4 作为边缘可选功能,并给出了基于 FRR 和 Containerlab 的实验演示。
暂无内容
查看缓存全文
缓存时间: 2026/10/16 16:41
# RFC8950:使用 IPv6 下一跳通告 IPv4
来源:https://anuragbhatia.com/post/2026/06/rfc8950-announce-ipv4-with-ipv6-next-hop/
最近几天我一直在研究 [RFC8950](https://datatracker.ietf.org/doc/rfc8950/) 的部署,该协议允许在 IPv6 之上路由 IPv4。虽然逻辑上相当简单,但它在让"**IPv4 成为可选功能**"这一应用场景上非常强大——让 IPv4 骑乘在 IPv6 网络之上(**但完全不需要任何隧道!**)。一些有趣的用例:
1. 大型网络可以完全在其核心层运行纯 IPv6,仅在边缘设备上保留 IPv4。这可以在客户不做任何额外调整的情况下正常工作。客户仍然以传统方式使用,而骨干网的核心可以运行纯 IPv6。
2. IP 转送骨干网可以运行纯 IPv6,同时通过 IPv6 会话与客户/对等方/上游交换 IPv4 路由。这样 IPv4 作为一项"功能"得以保留,但网络本身是纯 IPv6 的,无需 IPv4 接口配置、BGP 会话配置、防火墙配置等开销。
3. IXP(互联网交换中心)可以几乎在不提供 IPv4 的情况下提供服务——只需在 IX 局域网上使用(唯一的)IPv6 地址,并通过纯 IPv6 会话运行路由服务器来同时交换 IPv4 和 IPv6 路由。
因此,464XLAT 对移动网络所做的事情,这项技术有潜力在骨干网上复现。
### 它是如何工作的?
多协议 BGP(MP-BGP)支持通过 IPv6 会话通告 IPv4 路由(下一跳为 IPv4),以及通过 IPv4 会话通告 IPv6 路由(下一跳为 IPv6)。RFC8950 扩展了这一特性,使 IPv4 可以拥有 IPv6 下一跳。因此,对于 IPv4 地址,下一跳是 IPv6;IPv6 可达性通过常规的 NDP 获得,IPv4 数据包则通过以太网帧发送到 NDP 所发现的同一个 MAC 地址。从技术上讲,RFC8950 仅影响控制平面的决策——使用 IPv6 作为控制平面,但数据平面保持不变。IPv4 仍然是 IPv4,以 IPv4 形式在线路上传输——不像某些隧道或 464XLAT 等方案。
### 硬件支持
目前,许多路由平台都已广泛支持,如 Juniper JunOS、Cisco IOS XR、Nokia SR OS、Mikrotik、Huawei、BIRD、FRR 等。因此,如果你运行的是较新版本的操作系统,大概率已经支持该特性。
### 演示实验
下面是一个有趣的实验环境,包含两台客户路由器:C1 和 C2,通过运营商路由器 R1-R2-R3 连接,使用 [Container Lab](https://containerlab.dev/) 构建。所有路由器均运行开源的 [FRR](https://frrouting.org/)。
- C1 在面向 R1 的 WAN 侧是纯 IPv6 的。它通过 IPv6 会话向 R1 发起 10.0.0.0/24 前缀。
- R1 和 R2 是纯 IPv6 的,其接口上没有任何 IPv4 地址(但路由表中携带 IPv4 路由)。
- R3 与 R2 之间是 IPv6,但与 C2 之间仅是 IPv4。因此 C2 就像是一个典型的缺乏 IPv6 部署的企业用户,只需要 IPv4 正常工作。
- R3 拥有 100.64.0.0/24,并在 IPv4 路由表中将其通告给 IPv6 邻居——R2。
- C2 使用 R3 分配的 100.64.0.2/30 地址,仅通过 IPv4 通信。
- C1 和 C2 可以通过这个网络互相访问,其中部分链路是纯 IPv6 的,且完全没有使用任何隧道。
**topology.yml**
```
name: rfc8950
topology:
nodes:
R1:
kind: linux
image: frr-with-bgpd
binds:
- configs/R1.conf:/etc/frr/frr.conf
R2:
kind: linux
image: frr-with-bgpd
binds:
- configs/R2.conf:/etc/frr/frr.conf
R3:
kind: linux
image: frr-with-bgpd
binds:
- configs/R3.conf:/etc/frr/frr.conf
C1:
kind: linux
image: frr-with-bgpd
binds:
- configs/C1.conf:/etc/frr/frr.conf
C2:
kind: linux
image: frr-with-bgpd
binds:
- configs/C2.conf:/etc/frr/frr.conf
links:
- endpoints: ["C1:eth1", "R1:eth1"]
- endpoints: ["R1:eth2", "R2:eth1"]
- endpoints: ["R2:eth2", "R3:eth1"]
- endpoints: ["R3:eth2", "C2:eth1"]
```
```
> clab deploy -t topology.yml
16:37:08 INFO Containerlab started version=0.76.1
16:37:08 INFO Parsing & checking topology file=topology.yml
16:37:09 INFO Creating lab directory path=~/ipv4-over-ipv6/clab-rfc8950
16:37:09 INFO Creating container name=C2
16:37:09 INFO Creating container name=C1
16:37:09 INFO Creating container name=R1
16:37:09 INFO Creating container name=R2
16:37:09 INFO Creating container name=R3
16:37:09 INFO Created link: R3:eth2 ▪┄┄▪ C2:eth1
16:37:09 INFO Created link: C1:eth1 ▪┄┄▪ R1:eth1
16:37:09 INFO Created link: R1:eth2 ▪┄┄▪ R2:eth1
16:37:09 INFO Created link: R2:eth2 ▪┄┄▪ R3:eth1
16:37:09 INFO Adding host entries path=/etc/hosts
16:37:09 INFO Adding SSH config for nodes path=/etc/ssh/ssh_config.d/clab-rfc8950.conf
╭─────────────────┬───────────────┬─────────┬───────────────────╮
│ Name │ Kind/Image │ State │ IPv4/6 Address │
├─────────────────┼───────────────┼─────────┼───────────────────┤
│ clab-rfc8950-C1 │ linux │ running │ 172.20.20.6 │
│ │ frr-with-bgpd │ │ 3fff:172:20:20::6 │
├─────────────────┼───────────────┼─────────┼───────────────────┤
│ clab-rfc8950-C2 │ linux │ running │ 172.20.20.4 │
│ │ frr-with-bgpd │ │ 3fff:172:20:20::4 │
├─────────────────┼───────────────┼─────────┼───────────────────┤
│ clab-rfc8950-R1 │ linux │ running │ 172.20.20.2 │
│ │ frr-with-bgpd │ │ 3fff:172:20:20::2 │
├─────────────────┼───────────────┼─────────┼───────────────────┤
│ clab-rfc8950-R2 │ linux │ running │ 172.20.20.8 │
│ │ frr-with-bgpd │ │ 3fff:172:20:20::8 │
├─────────────────┼───────────────┼─────────┼───────────────────┤
│ clab-rfc8950-R3 │ linux │ running │ 172.20.20.5 │
│ │ frr-with-bgpd │ │ 3fff:172:20:20::5 │
╰─────────────────┴───────────────┴─────────┴───────────────────╯
```
**检查 C1 上到 C2 的路由**
```
C1# show ip bgp 100.64.0.2
BGP routing table entry for 100.64.0.0/24, version 2
Paths: (1 available, best #1, table default)
Advertised to non peer-group peers:
2001:db8:0:1::1
65501 65502 65503
2001:db8:0:1::1 from 2001:db8:0:1::1 (172.20.20.2)
(fe80::a8c1:abff:fe60:5467) (used)
Origin IGP, valid, external, best (First path received)
Last update: Mon Jun 22 18:57:38 2026
C1#
```
**C1 -> C2 traceroute**
```
C1# traceroute 100.64.0.2
traceroute to 100.64.0.2 (100.64.0.2), 30 hops max, 46 byte packets
1 clab-rfc8950-R1.clab (172.20.20.2) 0.004 ms 0.004 ms 0.002 ms
2 clab-rfc8950-R2.clab (172.20.20.8) 0.002 ms 0.003 ms 0.003 ms
3 clab-rfc8950-R3.clab (172.20.20.5) 0.002 ms 0.003 ms 0.003 ms
4 100.64.0.2 (100.64.0.2) 0.002 ms 0.006 ms 0.003 ms
C1#
```
注意:traceroute 中 TTL 超时所使用的源地址取自 Container Lab 部署的 eth0 管理接口的 IPv4 地址。
**如果我查看 R1,它只有 IPv6 会话,但没有 IPv6 前缀**
```
R1# sh bgp ipv6 summary
IPv6 Unicast Summary (VRF default):
BGP router identifier 172.20.20.2, local AS number 65501 vrf-id 0
BGP table version 0
RIB entries 0, using 0 bytes of memory
Peers 2, using 1434 KiB of memory
Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd Desc
2001:db8:0:1::2 4 64512 151 141 0 0 0 00:39:19 0 N/A
2001:db8:0:2::2 4 65502 65 64 0 0 0 00:36:46 0 N/A
Total number of neighbors 2
R1#
```
**检查 R1 上的 IPv4 路由**
```
R1# sh bgp ipv4
BGP table version is 4, local router ID is 172.20.20.2, vrf id 0
Default local pref 100, local AS 65501
Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
RPKI validation codes: V valid, I invalid, N Not found
Network Next Hop Metric LocPrf Weight Path
*> 10.0.0.0/24 fe80::a8c1:abff:fe44:afb8
0 0 64512 i
*> 100.64.0.0/24 fe80::a8c1:abff:fed8:5eb5
0 65502 65503 i
Displayed 2 routes and 2 total paths
R1#
```
### 路由器配置
| 路由器 | 链接 |
| ------ | ---- |
| R1 | [点击此处](https://cdn.anuragbhatia.com/web/post/2026/06/rfc8950-announce-ipv4-with-ipv6-next-hop/R1.conf) |
| R2 | [点击此处](https://cdn.anuragbhatia.com/web/post/2026/06/rfc8950-announce-ipv4-with-ipv6-next-hop/R2.conf) |
| R3 | [点击此处](https://cdn.anuragbhatia.com/web/post/2026/06/rfc8950-announce-ipv4-with-ipv6-next-hop/R3.conf) |
| C1 | [点击此处](https://cdn.anuragbhatia.com/web/post/2026/06/rfc8950-announce-ipv4-with-ipv6-next-hop/C1.conf) |
| C2 | [点击此处](https://cdn.anuragbhatia.com/web/post/2026/06/rfc8950-announce-ipv4-with-ipv6-next-hop/C2.conf) |
相似文章
Show HN: 我们在Linux、Libc和BGP中实现了IPv8互联网草案
goonhost.rocks团队在Linux内核、Musl libc、iproute2、FRRouting和Go区域服务器中实现了IPv8互联网草案,并将其部署在一个拥有112k+条路由的10节点多AS测试平台上。它在隔离的实验环境中运行正常,但在现实场景中则会失效。
告别ARP:纯IPv6网络上的IPv4服务
本文介绍了一份IETF草案提案,旨在在纯IPv6网络上消除ARP和IPv4子网,使IPv4能够作为纯粹的/32服务在IPv6基础设施上运行,无需翻译或隧道化,解决了ARP风暴和IPv4地址稀缺等运营痛点。
免费完整BGP路由信息,支持IPv4和IPv6
一位网络工程师提供免费服务,提供完整的IPv4和IPv6 BGP路由信息,适用于实验室环境,并附带Cisco IOS和IOS XR的详细配置示例。
通过 GRAND 闭合 IPv6 首包间隙
本文将 GRAND 作为一种方法提出,以解决 IPv6 首包延迟问题,通过闭合初始数据包传输中的间隙来提升网络性能。
改造 Go 编译器以高效实现 IPv4 到 IPv6 的映射
Vincent Bernat 探讨了在 Go 的 netip.Addr 中如何高效地将 IPv4 地址映射为 IPv6,比较了标准库新增方法、unsafe 辅助函数,以及改造 Go 编译器来优化维护者偏好的 netip.AddrFrom16(ip.As16()) 模式三种方案。