中子-中子互连

Launchpad RFE: https://bugs.launchpad.net/neutron/+bug/1750368

问题描述

目前,为了实现两个或多个 OpenStack 云之间的连接(例如,在不同的 OpenStack 部署之间,或在 OpenStack 区域之间),有一些可用的选项,例如浮动 IP、VPNaaS(基于 IPSec)和 BGPVPN。

然而,这些选项中的任何一个都不适合解决以下所有属性都期望的情况

  1. 按需消耗的互连,无需管理员干预 [1]

  2. 具有网络隔离并允许端到端使用私有 IP 寻址 [2]

  3. 避免数据包加密的开销 [3]

该解决方案的另一个设计要求是避免引入需要在所有涉及的 OpenStack 云上具有管理员权限的组件。

本规范的目标是提供一种解决方案,在两个或多个 OpenStack 部署或区域之间提供网络连接,同时满足这些要求。

用例

示例 1

用户 Foo 拥有 OpenStack 云 A 和 OpenStack 云 B 的凭据,OpenStack A 中的一个路由器 X,OpenStack B 中的一个路由器 Y,两者都使用私有 IPv4 地址空间中的不同子网。

用户 Foo 希望通过 API 消耗一项服务,该服务将建立路由器 A 和路由器 B 之间的 IP 连接。

示例 2

与示例 1 相同,但这次希望在 OpenStack A 中的网络 X 和 OpenStack B 中的网络 Y 之间建立 L2 连接。

示例 3

与示例 1 或 2 相同,但涉及 3 个 OpenStack 部署。

提议的变更

概述

该方案包括引入一个服务插件和一个相应的 API 扩展,涉及一个新的“interconnection”(互连)资源。Neutron 实例上的“interconnection”资源将引用一个本地资源(例如路由器 A)和一个远程资源(OpenStack B:路由器 B),并且语义是希望在两者之间建立连接。

此资源将是两种 API调用的组成部分

  1. 需要连接的用户与每个涉及的 Neutron 实例之间的调用;这些调用的作用是让所有 Neutron 实例都知道连接的需求

  2. 一个 Neutron 实例与另一个 Neutron 实例之间的 API 调用;这些调用的作用是

    • 让每个 Neutron 实例验证本地定义的“interconnection”资源与在其他 Neutron 实例中创建的“interconnection”资源之间的一致性

    • 在验证之后,让两个 Neutron 实例识别要使用的机制和每个互连的参数(取决于机制;可以是互连盒上的 VLAN 对,BGPVPN RT 标识符,VXLAN ID 等)

                               .-------------.
                               | tenant user |
                               '----+---+----'
                                    |   |
   .--------------------------------'   '--------------------.
   | A1. create "interconnection"                            |
   |     between local net X,                                |
   |     and "Neutron B: net Y"                              |
   |                                          A2. create "interconnection"
   |                                              between local net Y,
   |                                              and "Neutron A: net X"
   |                                                         |
   |                                                         |
   |                                                         |
   |                                                         |
   V                         B1. check symmetric inter.      V
.-------------------------.                      (fail) .--------------------.
|                         +---------------------------> |                    |
|   Neutron A             |                             |   Neutron B        |
|                         | <---------------------------+                    |
|                         |  B2. check symmetric inter. |                    |
|                         |                       (ok!) |                    |
|                         |                             |                    |
|                         +---------------------------> |                    |
|                         | <---------------------------+                    |
'-------------------------'  B3. exchange info to build '--------------------'
                   net X        interconnection           net Y
                     |                                      |
                     |                                      |
                   --+                                      +--
                     |      C. interconnection is built     |
                     +--    - - - - - - - - - - - - - -   --+
                     |                                      |
                     |                                      |

请注意,A1/A2/B1/B2 的顺序可以不同,但结果不变:至少其中一个 Neutron 实例最终会确认互连在双方都对称地定义了,并且互连设置阶段最终将在双方进行(参见 操作细节)。

当涉及两个以上的 OpenStack 部署或两个以上的 OpenStack 区域时,这些 API 调用将为每对区域/部署发生。

基本假设,信任模型

此提案中信任模型的基本假设是,请求连接的最终用户委托每个 OpenStack 部署仅提供请求的互连,即不在请求时创建资源之间的连接。

为了遵守此协议,每个 OpenStack 部署都需要,从定义上讲,与其他涉及这些互连的 OpenStack 部署建立信任关系;实际上,当收到来自另一个部署的包时,该包被标识为打算用于自己的本地网络 A(VLAN、VXLAN ID、MPLS 标签等),它需要信任该标识符是由 OpenStack 部署推送的,并且最终尊重这些规范的协议的机制。

另一个方面,显而易见但最好明确说明的是,用于互连的网络标识符的选择和定义,以及保持互连彼此隔离,不受此 API 使用者的控制。在本提案中,这些使用者既不能写入,甚至不能读取这些标识符。

请注意,只有步骤 A1/A2 中的 API 调用才需要租户用户对“interconnection”资源具有写访问权限(但不包括与要使用的网络机制相关的属性)。

步骤 B1/B2/B3 中的调用只需要对这些资源具有只读访问权限;这可以通过引入一个具有对所有“interconnection”资源具有只读访问权限的“interconnection”角色来实现,并且每个 OpenStack 部署都具有其他 OpenStack 部署中具有此角色的用户的凭据。

考虑到以上几点,Keystone 联合对于步骤 A1/A2 和步骤 B1/B2 的调用不是必需的。但是,为步骤 B1/B2 中使用的用户使用 Keystone 联合肯定会有用,并且可以避免需要在每个 Neutron 实例中管理用于彼此 OpenStack 的凭据。

互连机制

虽然这些规范试图对最终用于实现互连的网络技术保持不可知,但假设对于每个“interconnection”,都有两种 OpenStack 部署通用的技术。

提出的方法是一个简单的方法,其中每个 OpenStack 部署根据配置文件确定,在与给定的 OpenStack 部署建立互连时使用哪种技术。

请注意,只有在两个互连之间不同的参数才会保存在配置文件中。两个 Neutron 实例之间的 API 交换用于交换特定于每个互连的参数。

示例互连技术

可以考虑以下技术来实现互连

  • 基于 BGP 的 VPN:已通过 Neutron BGPVPN 互连服务支持(参见 networking-bgpvpn),它允许创建 L2(使用 EVPN)或 L3 连接(使用 BGP/MPLS IP VPN)

  • 使用 networking-l2gw 的 VXLAN 拼接(细节仍需调查)

  • VLAN 拼接(细节仍需调查)

预计第一个实现将至少提供对 BGPVPN 互连技术的支持,该技术已经在各种 Neutron 后端(Neutron 参考驱动程序、OpenDaylight、OpenContrail、Nuage Networks)中得到支持,因此将允许此 API 扩展在第一天就支持所有这些控制器,而无需进行任何额外的控制器驱动程序开发。

操作细节

当创建“interconnection”资源时,Neutron 实例将检查远程 Neutron 实例在互连中指定是否存在对称的互连,并且在变为真之前不会进一步进行。

此检查建立了端到端信任,即双方都请求了连接。

一旦 Neutron 实例确定互连是对称定义的,就会发生进一步的交换以确定用于实现互连的网络参数

  • 刚刚确认对称性的 Neutron(例如 Neutron B)分配所需的网络标识符,并要求远程 Neutron 实例(A)刷新其状态

  • Neutron A 刷新其状态:再次检查对称性(现在成功),同时检索 B 分配的网络标识符,并要求 Neutron B 刷新

  • Neutron B 再次刷新,这次同时检索 A 分配的网络标识符

在上述过程中,“要求远程 Neutron 实例刷新其状态”是通过对 interconnection 上的特定 refresh 操作执行 PUT 来完成的。

互连生命周期

在上一节中,暗示一个 interconnection 在其生命周期中处于不同的状态,然后最终实现。当一个侧面的 interconnection 资源被删除时,另一侧也需要能够更新其自身的状态(仅用于清理或向最终用户提供适当的反馈)。

此外,Neutron 实例与另一个 Neutron 实例之间的交互需要在 API 调用处理路径之外发生,因为不希望本地 API调用的成功取决于与外部组件的操作的成功,而该外部组件可能在当时不可用。

出于所有这些原因,将引入一个状态机来处理互连资源生命周期,触发和定期操作将在 API 调用之外进行,以处理每个状态的操作。

将此状态暴露在 API 中将允许

  • 最终用户了解他们离工作状态还有多近

  • 每个 Neutron 实例可能识别远程状态与本地状态不一致

状态机摘要

TO_VALIDATE

已创建互连资源,但尚未验证对称互连的存在

VALIDATED

已验证对称互连的存在,并且已分配本地互连参数(仍未知远程参数)

ACTIVE(活动)

已知本地参数和远程参数,已设置互连,应该可以工作

TEARDOWN

已采取本地操作以删除此互连,正在采取操作以使远程状态同步

(DELETED)

隐式状态,对应于资源不再存在

../../_images/state-machine-summary.png

REST API 影响

该提案是引入一个 API 扩展 interconnection,暴露一个新的 interconnection 资源。

互连资源

新的 interconnection API 资源将在 interconnection API 前缀下引入,并具有以下属性

属性名称

类型

访问

注释

id

uuid

RO

project_id

uuid

RO

type

enum

RO

routernetwork_l2network_l3

state

enum

RO 将在资源生命周期中由 Neutron 更新

参见 互连生命周期 中的状态

name

string

RW

local_resource_id

uuid

RO

路由器或网络 UUID

remote_resource_id

uuid

RO

路由器或网络 UUID

remote_keystone

string

RO

远程 keystone 的 AUTH_URL

remote_region

string

RO

远程 keystone 中的区域

remote_interconnection_id

uuid

RO

Neutron 将在资源生命周期中更新

远程互连的 uuid

local_parameters

字典

remote_parameters

字典

此资源将与典型的 CRUD 操作一起使用

  • POST /v2.0/interconnection/interconnections

  • GET /v2.0/interconnection/interconnections

  • GET /v2.0/interconnection/interconnections/<uuid>

  • PUT /v2.0/interconnection/interconnections/<uuid>

  • DELETE /v2.0/interconnection/interconnections/<uuid>

此外,引入了一个额外的 REST 操作来触发对 interconnection 资源的 refresh 操作

  • PUT /v2.0/interconnection/interconnections/<uuid>/refresh

当触发此操作时,发出调用的 Neutron 实例将尝试检索(GET)远程 Neutron 实例上的 interconnection 资源,该资源与本地资源的 type 相同,本地资源的 local_resource_id 作为远程资源的 remote_resource_id,本地资源的 local_resource_id 作为远程资源的 remote_resource_id。根据当前本地状态以及查找此类资源是否成功或失败,本地状态机将转换。

示例

这显示了 Neutron-Neutron 互连的网络之间 API 交换示例。

API 调用 A1,从租户用户到 Neutron A

POST /v2.0/interconnection/interconnections
     {'interconnection': {
         'type': 'network_l3',
         'local_resource_id': <uuid of network X>,
         'remote_keystone': 'http//<keystone-B>/identity',
         'remote_region': 'RegionOne',
         'remote_resource_id': <uuid of network Y>
      }}

Response: 200 OK

{'interconnection': {
     'id': <uuid 1>,
     ...
 }}

API 调用 B1,从 Neutron A 到 Neutron B

GET /v2.0/interconnection/interconnections?local_resource_id=<uuid of network Y>&remote_resource_id=<uuid of network X>

Response: 404 Not Found

API 调用 A2,从租户用户到 Neutron B

POST /v2.0/interconnection/interconnections
     {'interconnection': {
         'type': 'network_l3',
         'local_resource_id': <uuid of network Y>,
         'remote_keystone': 'http//<keystone-A>/identity',
         'remote_region': 'RegionOne',
         'remote_resource_id': <uuid of network X>
      }}

Response: 200 OK

{'interconnection': {
     'id': <uuid 2>,
     ...
 }}

API 调用 B2,从 Neutron B 到 Neutron A

GET /v2.0/interconnection/interconnections/local_resource_id=<uuid of network X>&remote_resource_id=<uuid of network Y>

Response: 200 OK

{'interconnection': {
     'id': <uuid 1>,
     ...,
     'local_parameters': {}
 }}

API 调用 B3’,从 Neutron B 到 Neutron A

PUT /v2.0/interconnection/interconnections/<uuid 1>/refresh

Response: 200 OK

API 调用 B3’’,从 Neutron A 到 Neutron B

GET /v2.0/interconnection/interconnections/local_resource_id=<uuid of network Y>&remote_resource_id=<uuid of network X>

Response: 200 OK

{'interconnection': {
     'id': <uuid 2>,
     ...,
     'local_parameters': {
         'foo': '42'
     }
 }}

API 调用 B3’’’,从 Neutron A 到 Neutron B

PUT /v2.0/interconnection/interconnections/<uuid 2>/refresh

Response: 200 OK

API 调用 B3’’’’,从 Neutron B 到 Neutron A

GET /v2.0/interconnection/interconnections/<uuid 1>

Response: 200 OK

{'interconnection': {
     'id': <uuid 1>,
     ...,
     'remote_interconnection_id': <uuid 2>,
     'remote_parameters': {
         'foo': '42'
     },
     'local_parameters': {
         'bar': '43'
     }
 }}

命令行客户端影响

python-neutronclient 将更新以引入一个 OSC 扩展来创建/删除/更新/删除 interconnection 资源。

客户端库影响

python-neutronclient 和 openstacksdk 需要更新以支持对 interconnection 资源进行创建/删除/更新/删除操作。

鸣谢

Przemyslaw Jasek 为探索导致此提案的想法做出了贡献,在 Orange 实习了六个月。

参考资料