ML2分层端口绑定技术在SDN开发中的应用(一)

时间:2022-06-05 08:26:47

最近公司sdn项目在控制器开发过程中,需要运用到Neutron liberty版本中比较新的ML2分层端口绑定(Hierarchical Port Binding),使用此技术主要目的是为了解决基于硬件SDN交换机在使用OpenFlow协议实现租户网络隔离使用VLAN协议时,还是会受到VLAN 4096的限制,造成租户网络容量无法突破4096。使用分层端口绑定技术可以很好的,在neutron架构下的实现突破4096的限制。为学习分层端口绑定技术首先就需要先仔细阅读neutron-specs/specs/kilo/ml2-hierarchical-port-binding.rst此篇文章,周末抽时间仔细阅读粗略翻译了一下,供大家学习参考。以下是部分原文翻译:

 

ML2分层端口绑定(ML2 Hierarchical Port Binding)

在Openstack Neutron的liberty版本ML2机制driver已经支持分层网络拓扑,每一层级网络拓扑都有各自的网络segment id。例如一个机制driver可以绑定一个静态的网络VXLAN segment id值,因为与ToR交换机相连的计算节点需要动态的分配VLAN id,因此另一个机制driver,例如OVS,就可以绑定计算节点到需要的动态VLAN上。

 

问题描述

传统的ML2插件不完全支持分层网络拓扑技术。在一个分层的虚拟网络中使用不同的网络segment,在不同的网络级别可能存在不同的网络类型(VLAN、VXLAN、GRE等等其他)。它可能是由一个或多个top-level静态网络段与在较低的水平动态分配的网络段组成。例如,ToR和核心交换机可以使用VXLAN段封装在虚拟的网络流量,而TOR交换机和计算节点之间的那些同一个的虚拟网络的流量可以使用动态分配的VLAN段。

ML2分层端口绑定技术在SDN开发中的应用(一)

    在分层网络的低层级里的动态分配segment值,是特别重要的保证neutron部署超出4k VLAN限制的物理网络。VLAN的分配管理可以在低级的层级网络中,允许超过4K的虚拟网络的存在和计算节点通过VLAN访问,只要保证从TOR交换机到各个计算节点链路不同时大于4K的VLAN的。

    支持分配动态segment值功能在Juno版本进入ML2插件。但目前还没有办法支持在ToR交换机层上由一个机制driver动态分配segment值,并用不同的机制driver来支持计算节点上的L2 agent。但需要的是一个初始化的机制driver来为虚机网络的port绑定一个静态segment值,并且可由不同的机制driver在下一个分层里分配一个动态segment值,并且此种绑定可持续进行,直到绑定功能完成。

    上面的图显示静态VXLAN segment连接了ToR和core交换机,但是Neutron server和L2 agent之间通过RPC调用管理的隧道端点很可能已经不是现在vxlan网络类型。取而代之的是网络类型在交换机之间封装格式和隧道端点之间被指定。每个network_type值应该明确定义为的标准的或专有的协议,实现必须的互操作性,并在异构部署共存。

 

修改提案

    ML2将支持分层网络技术,通过机制drivers绑定端口和在每一个层级为端口分配网络segment值。例如一个机制driver可以绑定静态VXLAN segment,从而导致与静态网络相连的ToR交换机,在与连接的计算节点之间的链路上会分配一个动态的VLAN值。因此第二个机制driver,例如VOS或HyperV driver,将绑定那个动态VLAN值到计算节点。

一个新的功能和特性将加入到PortContext类中,来实现分层端口绑定。

class PortContext(object):

    # ...

    @abc.abstractmethod

    def continue_binding(self, segment_id, next_segments_to_bind):

        pass

 

    @abc.abstractproperty

    def segments_to_bind(self):

        pass

 

       新加入的continue_binding()方法可以通过一个机制driver的bind_port()方法来调用,并替代已经存在的set_binding()方法。按当前的情况,如果一个机制driver能完成绑定,它会调用PortContext.set_binding(segment_id, vif_type, vif_details, status)方法。如果机制driver只能部分建立绑定,它将调用continue_binding(segment_id, next_segments_to_bind)。如果机制driver不能再绑定,它将什么都不调用。

       正如set_binding()时,传递给continue_binding()的segment_id,将会被continue_binding驱动所绑定。新的new_segments参数指定一组可以通过该端口绑定在下一阶段可以使用的网络segment段。它通常将包含一个动态分配的segment给下一个driver驱动程序,用来继续或完成绑定。

       现在,机制driver是尝试使用PortContext.network.network_segments的segments属性值来绑定。这些都是网络的静态segment方式。新的PortContext.segments_to_bind将替代所有的drivers。在绑定初始阶段,PortContext.segments_to_bind将包含于PortContext.network.network_segments相同的segment。但在后续绑定阶段,它将包含由前一级driver的next_segments_to_bind,并传递给PortContext.continue_binding()。

       ML2插件现在是尝试使用所有注册的机制driver,按照mechanism_drivers配置文件的顺序进行加载。为了支持分层端口绑定,只需要进行一小点改动,以避免在绑定循环中任何可能的配置错误和部署异常。在每个绑定阶段,任何已经在高一级绑定的driver,在现在的级别继续绑定相同的segment是会排除的。这种方法允许相同个driver在分层网络多个级别使用不同的segment,但是不能使用相同的segment。同样,如果超过设置的绑定级别数量,绑定将会失败并记录错误日志。

       最后,为了通过机制driver去查看分层绑定的详细信息,PortContext的bound_segment, original_bound_segment, bound_driver, original_bound_driver属性将被新的属性所替换

    # ...

    @abc.abstractproperty

    def binding_levels(self):

 

    @abc.abstractproperty

    def original_binding_levels(self):

 

    @abc.abstractproperty

    def top_bound_segment(self):

 

    @abc.abstractproperty

    def original_top_bound_segment(self):

 

    @abc.abstractproperty

    def bottom_bound_segment(self):

 

    @abc.abstractproperty

    def original_bottom_bound_segment(self):

 

       如果port已经完全或部分绑定,binding_levels和original_binding_levels属性返回一个列表字典,描述每个绑定级别。BOUND_DRIVER和BOUND_SEGMENT被定义,并且根据需要附加key在今后版本也可添加。第一条记录描述top级绑定,通常是port的网络静态segment信息。当完全绑定后,最后一条记录是bottom级绑定信息,将提供port的binding:vif_type和binding:vif_details属性值。

      在分层绑定的存在下,使用旧bound_segment,original_bound_segment,bound_driver,和/或original_bound_driver属性的一些机制驱动需要访问top级绑定,同时其他driver需要访问bottom级绑定。因此,旧的属性将被新提供访问的属性替代。

 

数据模型的影响

为了给机制driver提供存储多级绑定信息,修改ML2数据库是必须的。driver和segment列从ml2_port_bindings and ml2_dvr_port_bindings移到新的ml2_port_binding_levels表。这个表将 包含port_id, host, level列作为主key。不需要单独的dvr表。

DB迁移将提供现有的绑定数据移动到新表上的升级。数据库降级将保留现有的单级绑定数据,但保留在降级现有的多层次的绑定还没有合理的方式。

 

REST API的影响

neutron的REST API不需要做改变。只有top级别的静态segment可以访问。现在还不需要通过REST API暴露动态segment。portbinding扩展方法在未来修改后可以暴露更多的多级绑定信息。

 

其他部署影响

    当部署在非分层网络不需要做什么改变。但当部署在分层网络,机制driver将需要做些改变。此外,当VLAN作为低级绑定方式,L2 agent的配置将受到影响。

    机制机制需要确定他们是否可以通过NETWORK_TYPE以及任何相关信息绑定到一个网段。例如,如果NETWORK_TYPE是'flat'或'VLAN',L2 agent的机制driver查看physical_network,并使用数据库的信息,来确保该主机上的L2 agent具有physical_network的segment的映射。这是现有机制的驱动程序是运行方。

    在分层端口绑定环境里,ToR交换机是采用动态VLAN segment,并且连接到它的主机使用的是标准L2 agent,主机上的L2 agent配置physical_network名的mapping信息,对应在此physical_network下switch分配动态VLAN。

    如果动态VLAN segment在交换机范围内进行分配,那么每个ToR交换机应该有一个唯一对应的physical_network名称。switch的机制driver将使用这个physical_network名为其创建部分绑定动态segment。在连接到该交换机的主机在L2 agent必须有一个(桥或接口)的映射到相同physical_network名,从而允许正常的L2 agent机制的驱动来完成绑定。

    如果动态VLAN segment在交换机端口范围进行分配,因此每个交换机端口将有一个相应的唯一physical_network名,只连接到该交换机的端口上的主机应具有该physical_network的mapping映射信息。由于多级的网络部署可能需要使用一个特定的供应商专有的switch,该供应商应提供的文件和部署工具来帮助管理员。

 

开发影响

    支持分级绑定机制的驱动程序将使用额外的驱动程序API调用。其他驱动只需要一个非常小的更新使用REPortContext.segments_to_bind代替端口Context.network.network_segments,和使用新的属性用于访问所述*或低级绑定的segment或驱动。

 

根据以上内容,能对分层端口绑定的概念有了基本了解,结合具体ML2代码分析研究,才能对此功能有更进一步的认识。

 

参考资料:

ML2:Hierarchical Port Binding

https://github.com/openstack/neutron-specs/blob/master/specs/kilo/ml2-hierarchical-port-binding.rst

 

作者简介:赵俊峰,现为华胜信泰信息产业发展有限公司 云计算部Openstack开发工程师。主要从事Power和x86混合环境下Openstack相关计算、网络、存储相关服务软件开发和系统架构设计工作。