Port Forwarding API

https://blueprints.launchpad.net/neutron/+spec/port-forwarding

端口转发是网络中一种常见的特性,尤其是在 PaaS 和 SaaS 云系统中,旨在为使用不同虚拟机提供服务的不同客户端重用相同的公网 IP。

这对于缺乏大量可分配的公网 IP 的部署尤其重要。

此功能的一个常见用例是客户端请求特定服务,服务平台(PaaS、SaaS)分配虚拟机来运行该服务,然后分配客户端端口来访问该服务。这意味着不同的客户端使用相同的公网 IP,但 TCP/UDP 目标端口用于区分终端虚拟机。

例如,Web 服务器的映射

  • client1 172.24.4.2:4001 TCP => 映射到 10.0.0.2 端口 80 TCP (VM1)

  • client2 172.24.4.2:4002 TCP => 映射到 10.0.0.3 端口 80 TCP (VM2)

本规范将重点关注基于浮动 IP 的端口转发。未来将提交基于路由器外部网关接口的端口转发规范。

问题描述

  • 在 IP 资源有限的环境中,运营商希望重用公网 IP,而不是为每个虚拟机分配自己的公网 IP(浮动 IP)。

  • Docker 支持端口映射功能,因此大量的自动化编排和管理插件利用它。我们希望使 Neutron 与这些工具和系统兼容,并提供类似的 API [1]

提议的变更

为浮动 IP 引入端口转发 API 和实现。

用户可以在浮动 IP 上定义各种端口转发规则,包含内部/客户端端口和外部/目标端口,与他们想要暴露的虚拟机连接。并且用户只能在“空闲”浮动 IP 上创建端口转发规则,即未直接关联到租户虚拟机固定 IP 的浮动 IP。

我们将有四种部署变体

a) 传统路由器:对于通用的路由器部署,端口转发规则将安装在网络节点上的路由器命名空间中,并执行转发功能。

b) HA 路由器:对于 HA 路由器部署,端口转发规则将安装在位于网络节点上的 ACTIVE 和 BACKUP 路由器命名空间中。

c) DVR:由于 [2] 已合并,我们现在能够在 DVR 支持的部署中创建集中的浮动 IP。这有助于将目标虚拟机所在的计算节点与用于端口转发的集中 FIP 映射起来。这种机制不仅在浮动 IP 与绑定到启用 dvr_no_external 选项的主机上的端口关联时,而且在向其添加端口转发属性时,都会集中一个浮动 IP。

d) DVR + HA:如果创建的路由器不是 HA 路由器,则我们可以继续使用选项 (c)。如果路由器是 HA 路由器,则我们将使用集中的 HA 路由器来安装端口转发规则。

在所有部署变体中,端口转发条目 NAT 特定浮动 IP:端口和协议到特定的 Neutron 端口(以及连接到该端口的私有 IP)。这意味着它将维护类似于“FIP:extport 协议”到“Neutron Port Fixed IP:intport 协议”的映射。因此,如果 Neutron 端口包含多个固定 IP,则可以为特定的 Neutron 端口创建多个端口转发条目,使用不同的外部端口,例如

  • FIPX:EXTPORTX PROTOCOLA => Neutron PortQ Fixed IPA:INTPORTA PROTOCOLA (VM1)

  • FIPX:EXTPORTY PROTOCOLA => Neutron PortQ Fixed IPB:INTPORTA PROTOCOLA (VM1)

但是,相同的 Fixed IP:intport 套接字不能映射到不同的协议。

如果删除 Neutron 端口,则与该端口匹配的端口转发条目也会被删除。如果删除浮动 IP,则情况相同。

数据模型影响

作为端口转发功能的一部分,将添加以下新表

CREATE TABLE port_forwarding (
    id CHAR(36) NOT NULL PRI KEY,
    floating_ip_id VARCHAR(36) NOT NULL,
    external_port INT NOT NULL,
    internal_neutron_port_id VARCHAR(36) NOT NULL FOREIGN KEY,
    protocol CHAR(4) NOT NULL,
    socket VARCHAR(20) NOT NULL,
    CONSTRAINT floating_ip_id_external_port_constraint UNIQUE (floating_ip_id, external_port),
    CONSTRAINT internal_neutron_port_id_socket_constraint UNIQUE (
        internal_neutron_port_id, socket)
);

socket 列将存储类似于“Fixed IP:Port”的字符串。

注意

此表缺少 project_id,因为此 port_forwarding 的所有者必须是关联浮动 IP 的所有者。因此,存在一个 project_id 检查,以防止将浮动 IP 与内部 Neutron 端口关联,如果它们的 project_id 不同。此外,允许关联浮动 IP/内部 Neutron 端口存在于共享网络上,供不同 project_id 情况下的管理员用户使用,例如来自共享公共网络(由管理员用户创建)的 FloatingIP 和来自特定内部租户网络(由租户用户创建)的 Neutron 端口,然后管理员用户希望关联它们,这些具有不同的 project_ids。对于普通用户,只有相同 project_id 的情况。

子资源扩展

Neutron floatingips 将使用子资源 port_forwarding 进行扩展,它将包含一些字段来暴露分配给 floatingip 资源的 port_forwarding

对于此新功能,将引入一个新的服务插件,并添加以下方法

  • ‘create_floatingip_port_forwarding()’

  • ‘delete_floatingip_port_forwarding()’

  • ‘get_floatingip_port_forwarding()’

  • ‘get_floatingip_port_forwardings()’

对于更新操作,如果可能,我们将在未来扩展该函数。但目前,我们只支持创建/删除/获取功能。

因此,新子资源的属性映射如下

SUB_RESOURCE_ATTRIBUTE_MAP = {
    'port_forwarding': {
        'parent': {'collection_name': 'floatingips',
                    'member_name': 'floatingip'},
        'parameters': {
            'external_port': {'allow_post': True, 'allow_put': False,
                                 'convert_to':
                                     convert_validate_port_value,
                                 'is_visible': True},
            'internal_port': {'allow_post': True, 'allow_put': False,
                                 'convert_to':
                                     convert_validate_port_value,
                                 'is_visible': True},
            'internal_ip_address': {'allow_post': True,
                                        'allow_put': False,
                                        'validate': {
                                        'type:ip_address_or_none': None},
                                        'is_visible': True},
            'protocol': {'allow_post': True, 'allow_put': False,
                           'validate': {
                              'type:values': constants.IPTABLES_PROTOCOL_MAP.keys()},
                           'is_visible': True,
                           'convert_to': converters.convert_to_protocol},
            'internal_port_id': {'allow_post': True,
                                    'allow_put': False,
                                    'validate': {'type:int':None},
                                    'is_visible': True},
        }
    }
}

REST API 影响

其想法是使用以下定义的属性扩展浮动 IP Rest API,并添加一个新的扩展 floating_ip_port_forwarding

浮动 IP 扩展

属性名称

类型

CRUD

默认值

描述

port_forwardings

列表

R

与特定浮动 IP 资源关联的“port-forwarding”子资源。

浮动 IP 扩展定义将扩展为

RESOURCE_ATTRIBUTE_MAP = {
     'floatingips': {
         'port_forwardings': {'allow_post': False,
                                 'allow_put': False,
                                 'is_visible': True, 'default': None}
     }
}

此新字段将在浮动 IP 资源的 GET/POST/PUT 请求期间公开。这意味着用户不能通过 CRU FloatingIP 更改转发资源,只能使用下面介绍的新端口转发 API 一次创建一个转发。

例如,获取浮动 IP

GET /v2.0/floatingips/<floatingip-uuid>

{
    "floatingip": {
         "floating_network_id": "376da547-b977-4cfe-9cba-275c80debf57",
         "router_id": "d23abc8d-2991-4a55-ba98-2aaea84cc72f",
         "fixed_ip_address": "",
         "floating_ip_address": "172.24.4.228",
         "project_id": "4969c491a3c74ee4af974e6d800c62de",
         "tenant_id": "4969c491a3c74ee4af974e6d800c62de",
         "status": "ACTIVE",
         "port_id": "",
         "id": "2f245a7b-796b-4f26-9cf9-9e82d248fda7",
         "port_forwardings": [
             {
                 "internal_ip_address": "10.0.0.3",
                 "protocol": "tcp",
                 "internal_port": "22",
                 "external_port": "7001"
             },
             {
                 "internal_ip_address": "192.168.4.32",
                 "protocol": "tcp",
                 "internal_port": "22",
                 "external_port": "7002"
             }
         ]
    }
}

对于新的子资源“port_forwarding”,将引入一个新的 URL

  • /v2.0/floatingips/<floatingip-uuid>/port_forwardings

列出端口转发

GET /v2.0/floatingips/<floatingip-uuid>/port_forwardings

{
    "port_forwardings": [
         {
             "id": "ae34051f-aa6c-4c75-abf5-50dc9ac99ef3",
             "external_port": "7003",
             "internal_port": "22",
             "internal_ip_address": "10.0.0.10",
             "protocol": "tcp",
             "internal_port_id": "b930d7f6-ceb7-40a0-8b81-a425dd994ccf"
         },
         {
             "id": "915a14a6-867b-4af7-83d1-70efceb146f9",
             "external_port": "7004",
             "internal_port": "22",
             "internal_ip_address": "10.0.0.11",
             "protocol": "tcp",
             "internal_port_id": "0c56df5d-ace5-46c8-8f4c-45fa4e334d18"
         }
    ]
}
响应参数

参数

风格

类型

描述

port_forwardings

plain

xsd:list

一个 port_forwarding 对象列表

更多参数请参见 显示端口转发

显示端口转发

GET /v2.0/floatingips/<floatingip-uuid>/port_forwardings/<port-forwarding-id>

{
    "port_forwarding": {
         "id": "ae34051f-aa6c-4c75-abf5-50dc9ac99ef3",
         "external_port": "7003",
         "internal_port": "22",
         "internal_ip_address": "10.0.0.10",
         "protocol": "tcp",
         "internal_port_id": "b930d7f6-ceb7-40a0-8b81-a425dd994ccf"
     }
}
响应参数

参数

风格

类型

描述

port_forwarding

plain

xsd:dict

一个 port_forwarding 对象

id

plain

xsd:string

port_forwarding 对象的 ID

external_port

plain

xsd:string

暴露的外部协议端口号

internal_port

plain

xsd:string

端口转发映射的内部协议端口号

internal_ip_address

plain

xsd:string

来自特定端口的固定 IP 的 IP 地址

protocol

plain

xsd:string

流量协议类型,例如 TCP 或 UDP。默认值为“TCP”。

internal_port_id

plain

xsd:string

Neutron 内部端口 ID。

创建端口转发

POST /v2.0/floatingips/<floatingip-uuid>/port_forwardings

{
    "port_forwarding": {
         "external_port": "7233",
         "internal_port": "22",
         "internal_port_id": "b930d7f6-ceb7-40a0-8b81-a425dd994ccf"
     }
}

响应参数

参见 显示端口转发

{
    "port_forwarding": {
         "id": "f8a44de0-fc8e-45df-93c7-f79bf3b01c95",
         "external_port": "7233",
         "internal_port": "22",
         "internal_ip_address": "192.168.43.33",
         "protocol": "tcp",
         "internal_port_id": "b930d7f6-ceb7-40a0-8b81-a425dd994ccf"
     }
}

删除端口转发

DELETE /v2.0/floatingips/<floatingip-uuid>/port_forwardings/<port-forwarding-id>

此操作不接受请求体,也不返回响应体。

对现有浮动 IP API 的影响

对现有浮动 IP API 的轻微调整

  • 创建浮动 IP 与当前行为相同。

  • 将 Neutron 内部端口与浮动 IP 关联,如果请求的 URL 与之前相同,则浮动 IP 将像当前的 1:1 DNAT 行为一样工作。如果请求使用新的 URL,则表示请求需要针对浮动 IP 的端口转发功能。

  • 获取浮动 IP 资源与之前相同,如果浮动 IP 资源已经与用于 1:1 DNAT 的 neutron 端口关联。如果浮动 IP 资源包含多个端口转发子资源,最好在浮动 IP 响应主体中显示 port-forwardings 摘要,以区分哪些浮动 IP 资源可用于不同的要求,例如 1:1 DNAT、端口转发。

命令行客户端影响

Openstack Client 将为浮动 IP CLI 增加额外的选项 portforwarding,这将定义端口转发的特性。

安全影响

端口转发本质上与集中式 DNAT 类似,因此不应带来额外的安全隐患。但是,如果用户实际上想使用端口转发,他们必须确保允许与虚拟机 neutron 端口使用的内部 IP 相关的传入安全组。

通知影响

取决于实现规范

其他最终用户影响

性能影响

必须进行性能测试,以查看启用此功能会产生什么开销,当然,如果禁用该功能,则不应注意到任何性能影响。

IPv6 影响

不支持 IPv6

其他部署者影响

部署者可以利用端口转发以独特的方式访问私有 VM/容器,而无需浪费新的公网 IP

开发人员影响

未来的 SNAT 分发计划应考虑端口转发。Kuryr 可以利用端口转发与 Docker 端口映射的兼容性。

备选方案

用户可以使用提供此 NAT 功能的外部 VM,或者为每个 VM 分配新的浮动 IP。

实现

负责人

主要负责人

reedip <reedip.banerjee@nectechnologies.in>

其他贡献者

gal-sagie <gal.sagie@gmail.com>

tian-mingming <tian.mingming@h3c.com>

zhaobo <zhaobo6@huawei.com>

工作项

  1. API 实现

  2. DB 实现

  3. 参考实现

  4. 测试

  5. 文档

依赖项

测试

Tempest 测试

需要添加 tempest 测试

功能测试

需要添加功能测试

API 测试

需要添加 API 测试

Fullstack 测试

需要添加全栈测试。

文档影响

用户文档

需要用户文档

开发人员文档

需要 devref 文档

参考资料