RFC8950:使用 IPv6 下一跳通告 IPv4

Hacker News Top 新闻

摘要

作者介绍了 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互联网草案

Hacker News Top

goonhost.rocks团队在Linux内核、Musl libc、iproute2、FRRouting和Go区域服务器中实现了IPv8互联网草案,并将其部署在一个拥有112k+条路由的10节点多AS测试平台上。它在隔离的实验环境中运行正常,但在现实场景中则会失效。

告别ARP:纯IPv6网络上的IPv4服务

Lobsters Hottest

本文介绍了一份IETF草案提案,旨在在纯IPv6网络上消除ARP和IPv4子网,使IPv4能够作为纯粹的/32服务在IPv6基础设施上运行,无需翻译或隧道化,解决了ARP风暴和IPv4地址稀缺等运营痛点。

通过 GRAND 闭合 IPv6 首包间隙

Hacker News Top

本文将 GRAND 作为一种方法提出,以解决 IPv6 首包延迟问题,通过闭合初始数据包传输中的间隙来提升网络性能。

改造 Go 编译器以高效实现 IPv4 到 IPv6 的映射

Lobsters Hottest

Vincent Bernat 探讨了在 Go 的 netip.Addr 中如何高效地将 IPv4 地址映射为 IPv6,比较了标准库新增方法、unsafe 辅助函数,以及改造 Go 编译器来优化维护者偏好的 netip.AddrFrom16(ip.As16()) 模式三种方案。