OpenStack之子网池和地址Scope

本文讨论子网池和地址scopes。

子网池 Subnet Pools

通过观看Vancouver峰会的视频学习子网池知识.

… [#] http://www.youtube.com/watch?v=QqP8yBUUXBM&t=6m12s

子网池在Kilo版本中引入。它们相对简单。“SubnetPool” 具有任意数量的 “SubnetPoolPrefix” 对象关联与它。这些前缀为CIDR形式。每个CIDR是一段可用于分配的地址空间。

子网池支持IPv6和IPv4.

子网model对象现在有了一个“subnetpool_id”属性,为了向后兼容其值默认为空。“subnetpool_id”属性保存了子网池的UUID,其作为特定子网的地址段的来源。

创建子网时,可选择性的指定“subnetpool_id”参数。如果指定的话,“cidr”字段就不再需要了。如果指定“cidr”,它将从池中分配,并假定地址池包含它,而且还没有分配任何它的地址。如果“cidr”不指定,可指定“prefixlen”属性。如果不指定的话,默认的前缀长度将从子网池中获得。这样考虑一下,分配逻辑需要知道子网的大小。可由以下三者中获得:特定的CIDR,prefixlen 或 默认值。特定CIDR是可选的,如果提供,分配逻辑将试着使用它。如果不能接受它,请求将失败。

子网池不允许子网重叠.

子网池配额

配额机制应用于子网池。它不同于Neutron中的其它配额机制,因为它不为first类对象的实例计数。它计算的是由多少地址空间被使用了。

对于IPv4,以单个地址计算配额是合情理的。所以,如果你被给与一个/24的网段,你的配额应设置为256。三个/26网段的话配额应设置为192。此机制鼓励更有效的使用IPv4地址空间,在工作于全局可路由的地址时,这就变得非常重要。

对于IPv6,Neutron中最小的可用子网是/64。没有理由分配其它大小的子网使用在Neutron网络上。看起来很有趣为/64子网设置配额大小为:4611686018427387904。为避免此情况,我们以/64为单位计算IPv6配额。所以,配额为3将允许三个/64的子网。如果将来我们需要分配一些更小的,我们需要保证代码可以处理非整数的配额支出。

分配

分配进行以最小化地址池分配的方式进行。相关代码位于[1]。首先,可用的前缀使用一个差值计算:pool - allocations。结果将被压缩,参见文档[2],以及按照大小排序。子网被从最小的可用前缀分配,此前缀足够满足请求。

… [1] neutron/ipam/subnet_alloc.py (_allocate_any_subnet)
… [2] http://pythonhosted.org/netaddr/api.html#netaddr.IPSet.compact

地址 Scopes

在子网池和地址scope出现之前,不可能直到一个网络地址在一定的上下文中是否可路由,因为此地址是在子网创建时给定的,对于其它地址而言时不能验证的。地址scope依靠控制地址空间来解决此问题。它使用以存在的“SubnetPool”理念进行分配。

地址scope是:“其中的地址不允许重叠” ,因此提供更灵活的控制和解耦租户地址重叠。

在Mitaka版本之前,只有一个隐含的“shared”地址scope。任意的地址重叠都是被允许的,使得其更像“free for all”。为使事情变得理性,正常用户不能使用router去跨越不同的project的插入的网络,NAT被使用在内部网络和外部网络之间。就像是每个project都由私有的地址scope。

问题是此模型不能支持那些不使用NAT或者不支持NAT的用例(如,IPv6),或者我们想要允许不同的project能够跨越插入它们的网络。

AddressScope仅能覆盖一个地址组。但是,它们对于IPv4和IPv6都能很好的工作。

路由 Routing

参考实现借助地址scope。在地址scope内,地址可自由的路由(barring任何的防火墙规则和其它外部限制)。scope之间,如果不使用地址翻译,路由是被禁止的。

现在,浮动IP是唯一的流量跨越scope边界的地方。当一个浮动IP关联与一个固定IP时,固定IP被允许通过1:1 的NAT规则访问浮动IP的地址scope。这意味着固定IP不仅可访问外部网络,也可访问与外部网络在同一个地址scope的任何内部网络。即如下的图示:

+----------------------+      +---------------------------+
|    address scope 1   |      |      address scope 2      |
|                      |      |                           |
| +------------------+ |      |   +------------------+    |
| | internal network | |      |   | external network |    |
| +-------------+----+ |      |   +--------+---------+    |
|               |      |      |            |              |
|       +-------+--+   |      |     +------+------+       |
|       | fixed ip +----------------+ floating IP |       |
|       +----------+   |      |     +--+--------+-+       |
+----------------------+      |        |        |         |
                              | +------+---+ +--+-------+ |
                              | | internal | | internal | |
                              | +----------+ +----------+ |
                              +---------------------------+

由于DVR中的非对称路由,以及DVR的本地router不知道位于其它主机的浮动IP信息,在DVR多主机场景下有限制。当DVR在多主机内,当流量的目的地址时一个内部的其它主机的固定IP时,关联与浮动IP的此固定IP不能跨越scope边界去访问与外部网络处于相同地址scope的内部网络。参见:https://bugs.launchpad.net/neutron/+bug/1682228。

RPC

参考实现中的L3代理需要知道每个router的每个端口的地址scope,以便正确的映射ingress流量。

网络上来自相同地址族的每个子网要求来自相同的子网池。因此,地址scope也将时相同的。如果不是这样的,很难去匹配端口的ingress流量到合适的scope。也许时counter-intuitive,但是L3地址scope需要驻留到拓扑中非L3的事物上(例如,L2接口),以便能够决定ingress流量的scope。当下,我们使用 ports/networks。将来,我们也许能依靠其它的一些东西做区分,像是远端MAC地址或者其它。

地址scope ID设置在“address_scopes”属性下的字典结构的每个端口上。每个地址族的scope不同。如果没有指定属性,假设其为空,适用两个地址族。空值意味值地址处于“implicit”地址scope,其持有所有没有确定地址族的地址。地址scope出现之前,Neutron中存在的所有子网在此地址族。

以下示例显示,router端口的上下文中json的内容:

"address_scopes": {
    "4": "d010a0ea-660e-4df4-86ca-ae2ed96da5c1",
    "6": null
},

为了实现跨越scope边界的浮动IP,L3代理需要知道浮动IP的目标scope。理论上,固定IP地址不能够消除歧义,不同的scopes会有重叠的地址。scope由浮动IP的固定端口计算而来(代码文件[#]),关联到“fixed_ip_address_scope”属性下的浮动IP字典中。这里显示json格式数据(经过了裁剪):

{
     ...
     "floating_ip_address": "172.24.4.4",
     "fixed_ip_address": "172.16.0.3",
     "fixed_ip_address_scope": "d010a0ea-660e-4df4-86ca-ae2ed96da5c1",
     ...
}

… [#] neutron/db/l3_db.py (_get_sync_floating_ips)

Model

子网池和地址scope的model位于文件neutron/db/models_v2.py 和文件 neutron/db/address_scope_db.py。需要注意他们是如何关联与现有的Neutron对象。现有的Neutron子网可选的参考于单个子网池::

+----------------+        +------------------+        +--------------+
| Subnet         |        | SubnetPool       |        | AddressScope |
+----------------+        +------------------+        +--------------+
| subnet_pool_id +------> | address_scope_id +------> |              |
|                |        |                  |        |              |
|                |        |                  |        |              |
|                |        |                  |        |              |
+----------------+        +------------------+        +--------------+

L3 Agent

L3代理在多地址scope的支持上是受限的。在参考实现的router内,流量被打上ingress和对应于其来源的网络的地址scope的标记。如果流量应路由到不同地址scope的接口,流量将被阻止直到产生异常。

为浮动IP地址流量产生异常。当流量是去往一个浮动IP地址时,应用DNAT,允许流量路由到一个可能跨越地址scope边界的私有IP地址。当来自内部端口流量去往外部网络,并且赋予了浮动IP时,允许此流量。

另外一个异常是对于当SNAT使能时,从内部网络去往外部网络的流量。此情况下,SNAT使用router的固定IP地址应用到流量中。尽管如此,如果外部网络具有明确的地址scope,并与内部网路的相符,不使用SNAT。此情况下,流量不使用NAT,直接路由。此时内部网络的地址在外部网络上有效。

参考实现由一定的局限。即使对于多地址scope,router的实现不能连接两个有重叠IP地址的网络。这里由两个原因。

首先,命名空间中使用单一的路由表。一个使用多路由表的实现正在进行开发中,但是还有未解决的问题。

其次,默认的SNAT特性不支持当前的Linux 连接跟踪实现,除非使用双NAT(一次NAT从地址scope到特定的scope中间地址,另一次NAT从中间地址到外部地址)。如果跨越scope由重复地址,单NAT不能工作。

由于这些复杂性,router将拒绝连接重叠的子网。将来可能有解决此限制的实现。

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页