IPv6¶
本节描述了 OpenStack Networking 对 IPv6 的参考实现,包括以下内容
如何启用双栈(IPv4 和 IPv6 均启用)实例。
这些实例如何获取 IPv6 地址。
这些实例如何通过路由器与其他子网或互联网通信。
这些实例如何与其他 OpenStack 服务交互。
在 OpenStack Networking 中启用双栈网络只需创建一个子网,并将 ip_version 字段设置为 6,然后设置 IPv6 属性(ipv6_ra_mode 和 ipv6_address_mode)。ipv6_ra_mode 和 ipv6_address_mode 将在下一节中详细描述。最后,需要提供子网的 cidr。
本节不包括以下内容
单栈 IPv6 项目网络
OpenStack 控制服务器和服务的 IPv6 网络通信。
通过 IPv6 传输网络连接到 OpenStack API
IPv6 多播
IPv6 支持与任何树外路由器、交换机、服务或代理的结合使用,无论其物理或虚拟形态如何。
Neutron 子网和 IPv6 API 属性¶
从 Juno 开始,OpenStack Networking 服务 (neutron) 为子网对象提供了两个新的属性,允许 API 用户配置 IPv6 子网。
有两种 IPv6 属性
ipv6_ra_modeipv6_address_mode
这些属性可以设置为以下值
slaacdhcpv6-statefuldhcpv6-stateless
这些属性也可以不设置。
IPv6 寻址¶
ipv6_address_mode 属性用于控制 OpenStack 如何处理寻址。来宾实例可以通过多种不同的方式获取 IPv6 地址,此属性将这些选择暴露给 Networking API 的用户。
路由器通告¶
ipv6_ra_mode 属性用于控制子网的路由器通告。
IPv6 协议使用互联网控制消息协议数据包 (ICMPv6) 作为一种分发网络信息的方式。类型标志设置为 134 的 ICMPv6 数据包称为“路由器通告”消息,其中包含有关路由器的信息以及来宾实例可以用来发送网络流量的路由。
ipv6_ra_mode 用于指定 Networking 服务是否应为子网生成路由器通告消息。
ipv6_ra_mode 和 ipv6_address_mode 组合¶
ipv6 ra 模式 |
ipv6 地址模式 |
neutron 生成的通告 (radvd) A,M,O |
外部路由器 A,M,O |
描述 |
|---|---|---|---|---|
N/S |
N/S |
Off |
未定义 |
与 Juno 之前的 IPv6 行为的向后兼容性。 |
N/S |
slaac |
Off |
1,0,0 |
来宾实例使用 SLAAC 从非 OpenStack 路由器获取 IPv6 地址。 |
N/S |
dhcpv6-stateful |
Off |
0,1,1 |
参考实现中当前未实现。 |
N/S |
dhcpv6-stateless |
Off |
1,0,1 |
参考实现中当前未实现。 |
slaac |
N/S |
1,0,0 |
Off |
参考实现中当前未实现。 |
dhcpv6-stateful |
N/S |
0,1,0 |
Off |
参考实现中当前未实现。 |
dhcpv6-stateless |
N/S |
1,0,1 |
Off |
参考实现中当前未实现。 |
slaac |
slaac |
1,0,0 |
Off |
来宾实例使用 OpenStack 管理的 radvd 使用 SLAAC 获取 IPv6 地址。 |
dhcpv6-stateful |
dhcpv6-stateful |
0,1,0 |
Off |
来宾实例使用 dnsmasq 使用 DHCPv6 有状态和 dnsmasq 使用 DHCPv6 的可选信息获取 IPv6 地址。 |
dhcpv6-stateless |
dhcpv6-stateless |
1,0,1 |
Off |
来宾实例使用 OpenStack 管理的 radvd 使用 SLAAC 获取 IPv6 地址,并使用 dnsmasq 使用 DHCPv6 获取可选信息。 |
slaac |
dhcpv6-stateful |
无效组合。 |
||
slaac |
dhcpv6-stateless |
无效组合。 |
||
dhcpv6-stateful |
slaac |
无效组合。 |
||
dhcpv6-stateful |
dhcpv6-stateless |
无效组合。 |
||
dhcpv6-stateless |
slaac |
无效组合。 |
||
dhcpv6-stateless |
dhcpv6-stateful |
无效组合。 |
A - 自主地址配置标志, M - 管理地址配置标志, O - 其他配置标志
注意
如果 M 标志设置为 1,则 O 标志可以是 1 或 0。这是因为如 RFC 4861 中所述,当 M 标志设置为 1 时,可以忽略 O 标志:
“如果设置了 M 标志,则 O 标志是冗余的并且可以忽略,因为 DHCPv6 将返回所有可用的配置信息。”
因此,neutron 生成的通告将 M 标志设置为 1,O 标志设置为 0。
项目网络注意事项¶
数据平面¶
所有数据平面模块,包括 OVN 和 Open vSwitch,都支持在来宾和路由器端口之间转发 IPv6 数据包。与 IPv4 类似,无需特殊配置或设置即可启用数据平面以使用 IPv6 正确转发源到目的地的包。请注意,这些数据平面可以很好地在同一网络上的主机之间转发链路本地地址 (LLA) 数据包,而无需 OpenStack 组件的参与或设置,只要所有端口都已连接并学习了 MAC 地址即可。
警告
对此唯一的例外是 IPv6 子网创建的网络上的 MTU 值设置。如果 MTU 小于 1280 字节(RFC 8200 中指定的最小链路 MTU 值),则可能导致配置网络上的 IPv6 和 IPv4 地址出现问题,从而使子网无法使用。因此,API 在创建子网时会验证 MTU 值,以避免此问题。
子网地址¶
目前有三种方法可用于子网在 OpenStack 中获取其 cidr
通过命令行或 Horizon 在子网创建期间直接分配
在子网创建期间引用子网池
使用前缀委托 (PD) 客户端从 PD 服务器请求子网的前缀
将来,可以使用其他技术将子网分配给项目,例如使用外部 IPAM 模块。
端口的地址模式¶
注意
理论上,外部 DHCPv6 服务器可以覆盖 OpenStack 基于 EUI-64 地址分配的完整地址,但这将是不明智的,因为它不会在整个系统中保持一致。
IPv6 支持三种不同的寻址方案,用于地址配置和提供可选的网络信息。
- 无状态地址自动配置 (SLAAC)
使用路由器通告进行地址配置。
- DHCPv6-stateless
使用路由器通告进行地址配置,并使用 DHCPv6 提供可选信息。
- DHCPv6-stateful
使用 DHCPv6 进行地址配置和可选信息。
可以设置 OpenStack,以便 OpenStack Networking 直接提供路由器通告、DHCP 中继和 DHCPv6 地址及其网络信息,或者可以将其委托给外部路由器和服务,具体取决于正在使用的驱动程序。Neutron 子网有两个属性 - ipv6_ra_mode 和 ipv6_address_mode – 用于确定如何向项目实例提供 IPv6 寻址和网络信息
ipv6_ra_mode:确定谁发送路由器通告。ipv6_address_mode:确定实例如何获取 IPv6 地址、默认网关或可选信息。
为了使上述两个属性有效,子网对象的 enable_dhcp 必须设置为 True。
警告
当更新已经绑定了端口的网络时,并且在启用了自主地址配置(无状态地址自动配置、DHCPv6-stateless)的子网中,端口将使用新地址更新。如果子网是 DHCPv6-stateful,则不会发生这种情况。同样,如果端口绑定了 IPv6 子网(网络没有其他 IPv4 子网),并且稍后添加了 IPv4 子网,则端口将不会更新。
有关更多详细信息,请参阅错误 https://bugs.launchpad.net/neutron/+bug/1719806。
解决方法是手动使用 fixed_ips 更新端口,并在请求中添加子网。
使用 SLAAC 进行寻址¶
在使用 SLAAC 时,ipv6_ra_mode 和 ipv6_address_mode 的当前支持组合如下。
ipv6_ra_mode |
ipv6_address_mode |
结果 |
|---|---|---|
未指定。 |
SLAAC |
使用 EUI-64 分配地址,并使用外部路由器进行路由。 |
SLAAC |
SLAAC |
使用 EUI-64 分配地址,并且 OpenStack Networking 提供路由。 |
为 ipv6_ra_mode 配置 SLAAC 会配置 neutron 路由器,使其使用 radvd 代理发送路由器通告。以下列表捕获了在此场景中路由器通告消息中设置的地址配置标志值。
自主地址配置标志 = 1
管理地址配置标志 = 0
其他配置标志 = 0
包含 SLAAC 启用的 IPv6 子网的新或现有 neutron 网络将导致连接到网络的 neutron 端口全部接收 IPv6 地址。这是因为当路由器通告消息在 neutron 网络上多播时,网络上的所有 IPv6 兼容端口都会接收到它们,并且每个端口将根据路由器通告消息中包含的信息配置 IPv6 地址。在某些情况下,IPv6 SLAAC 地址将添加到端口,除了端口已经分配的其他 IPv4 和 IPv6 地址之外。
注意
如果没有创建路由器并添加到子网,则实例的 SLAAC 寻址将无法成功,因为不会生成路由器通告消息。
DHCPv6¶
对于 DHCPv6,当前支持的组合如下
ipv6_ra_mode |
ipv6_address_mode |
结果 |
|---|---|---|
DHCPv6-stateless |
DHCPv6-stateless |
通过路由器通告(参见 SLAAC 上文)分配地址,并通过 DHCPv6 提供可选信息。 |
DHCPv6-stateful |
DHCPv6-stateful |
使用 DHCPv6 分配地址和可选信息。 |
为 ipv6_ra_mode 配置 DHCPv6-stateless 会配置 neutron 路由器,使其使用 radvd 代理发送路由器通告。以下列表捕获了在此场景中路由器通告消息中设置的地址配置标志值。同样,为 ipv6_address_mode 配置 DHCPv6-stateless 会配置 neutron DHCP 实现以提供其他网络信息。
自主地址配置标志 = 1
管理地址配置标志 = 0
其他配置标志 = 1
为 ipv6_ra_mode 配置 DHCPv6-stateful 会配置 neutron 路由器,使其使用 radvd 代理发送路由器通告。以下列表捕获了在此场景中路由器通告消息中设置的地址配置标志值。同样,为 ipv6_address_mode 配置 DHCPv6-stateful 会配置 neutron DHCP 实现以通过 DHCPv6 提供地址和附加网络信息。
自主地址配置标志 = 0
管理地址配置标志 = 1
其他配置标志 = 0
注意
如果没有创建路由器并添加到子网,则实例的 DHCPv6 寻址将无法成功,因为不会生成路由器通告消息。
注意
如果 M 标志设置为 1,则 O 标志可以是 1 或 0。这是因为如 RFC 4861 中所述,当 M 标志设置为 1 时,可以忽略 O 标志:
“如果设置了 M 标志,则 O 标志是冗余的并且可以忽略,因为 DHCPv6 将返回所有可用的配置信息。”
因此,neutron 生成的通告将 M 标志设置为 1,O 标志设置为 0。
路由器支持¶
neutron 路由器对于 IPv6 的行为与 IPv4 略有不同。
充当网络默认网关端口的内部路由器端口将共享所有与网络关联的 IPv6 子网的通用端口。这意味着将有一个 IPv6 内部路由器接口,其中包含与网络关联的每个 IPv6 子网的多个 IPv6 地址,以及一个单独的 IPv4 内部路由器接口,用于 IPv4 子网。另一方面,外部路由器端口允许具有分配给它们的双栈配置,即 IPv4 和 IPv6 地址。
分配了全局单播地址 (GUA) 前缀和地址的 Neutron 项目网络不需要在 neutron 路由器外部网关端口上进行 NAT 才能访问外部世界。由于缺乏 NAT,外部路由器端口不需要 GUA 来向外部网络发送和接收。这意味着 neutron 外部网络不一定需要 GUA IPv6 子网前缀。默认情况下,与外部网关端口关联的 IPv6 链路本地地址 (LLA) 可用于路由目的。为了处理这种情况,neutron 中的 router-gateway-set API 的实现已进行了修改,以便与 neutron 路由器关联的外部网络不需要 IPv6 子网。上游路由器的 LLA 地址可以通过两种方式学习。
在没有上游路由器通告消息的情况下,可以将外部路由器网关 LLA 设置为 neutron L3 代理配置文件中的
ipv6_gateway标志。这还需要不将任何子网与该端口关联。上游路由器可以发送路由器通告,neutron 路由器将自动学习下一跳 LLA,前提是未分配任何子网且未设置
ipv6_gateway标志。
实际上,ipv6_gateway 标志优先于从上游路由器接收到的路由器通告。如果希望使用 GUA 作为下一跳,可以通过为外部路由器端口分配一个子网,并将上游路由器的 GUA 地址作为该子网的网关来实现。
注意
在隔离网络(没有路由器端口的网络)中,项目应该能够使用 LLA 进行通信,而无需 OpenStack 的过多参与。本节的作者尚未证明在所有场景下都是如此。
注意
在使用 neutron L3 代理,通过 SLAAC 自动配置 IPv6 地址,并且代理从 ICMPv6 路由器通告中学习其默认 IPv6 路由时,可能需要将 net.ipv6.conf.<physical_interface>.accept_ra sysctl 设置为 2,才能使路由正常工作。有关更详细的描述,请参阅 bug。
Neutron 的分布式路由器功能和 IPv6¶
启用分布式虚拟路由器功能后,IPv6 可以工作,但所有入站/出站流量都通过集中式路由器(因此,不是分布式的)。需要更多的工作才能完全启用此功能。
高级服务¶
VPNaaS¶
VPNaaS 支持 IPv6,但 Kilo 及更早版本中的支持存在一些错误,可能会限制其使用方式。在 Liberty 版本中,正在进行更彻底和完整的测试和错误修复。基于 IPv6 的 VPN-as-a-Service 的配置方式与 IPv4 配置类似。 peer_address 和 peer_cidr 都可以指定为 IPv6 地址。上述寻址模式和路由器模式的选择不应影响支持。
FWaaS¶
FWaaS 允许创建基于 IPv6 的规则。
NAT 和浮动 IP¶
目前,OpenStack Networking 不提供任何支持 IPv6 的 NAT 形式。与 IPv4 不同,目前没有为 IPv6 提供浮动 IP 的内置支持。假设项目之间的 IPv6 寻址使用 GUA,并且项目之间没有重叠。
安全注意事项¶
有关安全注意事项的更多信息,请参阅 OpenStack Networking 中的 Security groups 部分。
配置客户机接口¶
OpenStack 目前不支持 RFC 4941 中定义的隐私扩展,也不支持 RFC 7217 中定义的 Opaque Identifier 生成方法。接口标识符和 DUID 必须直接从 MAC 地址派生,如 RFC 2373 中所述。计算实例不应设置为利用这两种方法来生成其接口标识符,否则它们可能无法在网络上正常通信。例如,在 Linux 客户机中,这些由以下两个 sysctl 变量控制
net.ipv6.conf.*.use_tempaddr(隐私扩展)
这允许根据 RFC3041 语义使用不可更改的接口标识符进行 IPv6 地址寻址。应禁用它(设置为零),以便使用稳定的基于 EUI64 的值构造无状态地址。
net.ipv6.conf.*.addr_gen_mode
这定义了如何生成链路本地和自动配置的 IPv6 地址。应将其设置为零(默认值),以便使用基于 EUI64 的值生成 IPv6 地址。
注意
对 addr_gen_mode 的支持是在内核版本 4.11 中添加的。
其他类型的客户机可能有类似的配置选项,请参阅您的发行版文档以获取更多信息。
与 IPv4 不同,给定网络的 MTU 可以在路由器发送的路由器通告消息以及 DHCP 消息中传递。
OpenStack 控制和管理网络注意事项¶
从 Kilo 版本开始,已经做了大量工作以确保项目网络可以处理双栈 IPv6 和 IPv4 传输,涵盖上述各种配置。OpenStack 控制网络可以在双栈配置下运行,并且可以通过 IPv6 网络访问 OpenStack API 端点。目前,Open vSwitch (OVS) 隧道类型 - STT、VXLAN、GRE,都支持 IPv4 和 IPv6 端点。
前缀委托¶
警告
此功能是实验性的,测试覆盖率较低。目前树中没有参考实现来实现此功能。可能需要使用第三方驱动程序才能使用它。
从 Liberty 版本开始,OpenStack Networking 支持 IPv6 前缀委托。本节描述了使用 IPv6 前缀委托自动分配子网 CIDR 所需的配置和工作流程步骤。这允许您作为 OpenStack 管理员依赖于外部(到 OpenStack Networking 服务)DHCPv6 服务器来管理您的项目网络前缀。
配置 OpenStack Networking 以进行前缀委托¶
要启用前缀委托,请编辑 /etc/neutron/neutron.conf 文件。
ipv6_pd_enabled = True
注意
驱动程序可能需要额外的配置。
这告诉 OpenStack Networking 在用户在创建子网时未提供 CIDR 或子网池 ID 时使用前缀委托机制进行子网分配。
需求¶
要使用此功能,您需要一个能够进行前缀委托的 DHCPv6 服务器,该服务器可以从您的 OpenStack Networking 节点访问。这可以在 OpenStack Networking 节点或其它位置上运行的软件,也可以是物理路由器。为了本指南的目的,我们使用开源 DHCPv6 服务器 Dibbler。Dibbler 可以在许多 Linux 包管理器中找到,也可以从源代码在 tomaszmrugalski/dibbler 获取。
本指南假定您正在网络节点上运行 Dibbler 服务器,该网络节点存在外部网络桥接。如果您已经有可用的前缀委托 DHCPv6 服务器,则可以跳过以下部分。
配置 Dibbler 服务器¶
安装 Dibbler 后,编辑 /etc/dibbler/server.conf 文件
script "/var/lib/dibbler/pd-server.sh"
iface "br-ex" {
pd-class {
pd-pool 2001:db8:2222::/48
pd-length 64
}
}
配置文件中使用的选项是
script指向在委托或释放前缀时运行的脚本。只有在希望实例在子网上具有外部网络访问权限时才需要此脚本。下面会对此进行详细说明。iface侦听前缀委托消息的网络接口名称。pd-pool您希望委托的前缀来自的更大的前缀。如果不需要外部网络访问权限,则给定的示例就足够了,否则需要一个唯一的全球可路由前缀。pd-length委托前缀的长度。这必须是 64 才能与当前的 OpenStack Networking 参考实现一起工作。
为了为您的实例提供外部网络访问权限,您的 Dibbler 服务器还需要为每个委托的前缀创建新的路由。这通过配置文件中命名的脚本文件来完成。编辑 /var/lib/dibbler/pd-server.sh 文件
if [ "$PREFIX1" != "" ]; then
if [ "$1" == "add" ]; then
sudo ip -6 route add ${PREFIX1}/64 via $REMOTE_ADDR dev $IFACE
fi
if [ "$1" == "delete" ]; then
sudo ip -6 route del ${PREFIX1}/64 via $REMOTE_ADDR dev $IFACE
fi
fi
脚本文件中使用的变量是
$PREFIX1Dibbler 服务器正在添加/删除的前缀。$1正在执行的操作。$REMOTE_ADDR请求 Dibbler 客户端的 IP 地址。$IFACE收到请求的网络接口。
以上是此场景下您所需要的全部内容,有关安装、配置和运行 Dibbler 的更多信息,请参阅 Dibbler 用户指南,网址为 Dibbler – a portable DHCPv6。
要启动 Dibbler 服务器,请运行
# dibbler-server run
或者以无头模式运行
# dibbler-server start
在使用 DevStack 时,重要的是在 stack.sh 脚本完成后启动服务器,以确保已创建所需的网络接口。
用户流程¶
首先,创建一个网络和 IPv6 子网
$ openstack network create ipv6-pd
+---------------------------+--------------------------------------+
| Field | Value |
+---------------------------+--------------------------------------+
| admin_state_up | UP |
| availability_zone_hints | |
| availability_zones | |
| created_at | 2017-01-25T19:26:01Z |
| description | |
| headers | |
| id | 4b782725-6abe-4a2d-b061-763def1bb029 |
| ipv4_address_scope | None |
| ipv6_address_scope | None |
| mtu | 1450 |
| name | ipv6-pd |
| port_security_enabled | True |
| project_id | 61b7eba037fd41f29cfba757c010faff |
| provider:network_type | vxlan |
| provider:physical_network | None |
| provider:segmentation_id | 46 |
| revision_number | 3 |
| router:external | Internal |
| shared | False |
| status | ACTIVE |
| subnets | |
| tags | [] |
| updated_at | 2017-01-25T19:26:01Z |
+---------------------------+--------------------------------------+
$ openstack subnet create --ip-version 6 --ipv6-ra-mode slaac \
--ipv6-address-mode slaac --use-prefix-delegation \
--network ipv6-pd ipv6-pd-1
+------------------------+--------------------------------------+
| Field | Value |
+------------------------+--------------------------------------+
| allocation_pools | ::1-::ffff:ffff:ffff:ffff |
| cidr | ::/64 |
| created_at | 2017-01-25T19:31:53Z |
| description | |
| dns_nameservers | |
| dns_publish_fixed_ip | None |
| enable_dhcp | True |
| gateway_ip | :: |
| headers | |
| host_routes | |
| id | 1319510d-c92c-4532-bf5d-8bcf3da761a1 |
| ip_version | 6 |
| ipv6_address_mode | slaac |
| ipv6_ra_mode | slaac |
| name | ipv6-pd-1 |
| network_id | 4b782725-6abe-4a2d-b061-763def1bb029 |
| project_id | 61b7eba037fd41f29cfba757c010faff |
| revision_number | 2 |
| service_types | |
| subnetpool_id | prefix_delegation |
| tags | |
| updated_at | 2017-01-25T19:31:53Z |
+------------------------+--------------------------------------+
子网最初是使用临时 CIDR 创建的,然后才能通过前缀委托分配一个。可以使用此临时 CIDR 存在任意数量的子网,而不会引发重叠错误。subnetpool_id 自动设置为 prefix_delegation。
要触发前缀委托过程,请在子网和具有连接到外部网络的活动接口的路由器之间创建一个路由器接口
$ openstack router add subnet router1 ipv6-pd-1
然后,前缀委托机制通过外部网络发送请求到您的前缀委托服务器,服务器会回复委托的前缀。然后,子网将使用新的前缀进行更新,包括向所有端口发出新的 IP 地址
$ openstack subnet show ipv6-pd-1
+-------------------+--------------------------------------+
| Field | Value |
+-------------------+--------------------------------------+
| allocation_pools | 2001:db8:2222:6977::2-2001:db8:2222: |
| | 6977:ffff:ffff:ffff:ffff |
| cidr | 2001:db8:2222:6977::/64 |
| created_at | 2017-01-25T19:31:53Z |
| description | |
| dns_nameservers | |
| enable_dhcp | True |
| gateway_ip | 2001:db8:2222:6977::1 |
| host_routes | |
| id | 1319510d-c92c-4532-bf5d-8bcf3da761a1 |
| ip_version | 6 |
| ipv6_address_mode | slaac |
| ipv6_ra_mode | slaac |
| name | ipv6-pd-1 |
| network_id | 4b782725-6abe-4a2d-b061-763def1bb029 |
| project_id | 61b7eba037fd41f29cfba757c010faff |
| revision_number | 4 |
| service_types | |
| subnetpool_id | prefix_delegation |
| tags | [] |
| updated_at | 2017-01-25T19:35:26Z |
+-------------------+--------------------------------------+
如果配置了前缀委托服务器以委托全局可路由的前缀并设置路由,那么具有此子网上端口的任何实例现在都应该具有外部网络访问权限。
删除路由器接口会导致子网恢复为临时 CIDR,并且所有端口的 IP 地址都会更新。前缀租约将根据需要自动释放和续订。
参考¶
巴塞罗那峰会提供的以下演示文稿为使用 OpenStack 设置 IPv6 提供了一个很好的指南:Deploying IPv6 in OpenStack Environments。