写于2016年,作为本科毕业论文

约定:1. 虚拟NFV网元=Virtual Router(虚拟路由器)

2. 英文标题 How can Virtual Router live in the Cloud

摘要

IT耗资在前所未有的剧增。企业和运营商在使用云计算技术来降低成本的同时自然而然的想到使用低成本的x86服务器作为硬件,在这之上使用虚拟的路由器网元来节省成本,来代替路由器厂商的高价路由器。
本文利用OpenStack技术进行物理资源的抽象,提供云资源环境,将NFV的路由器网元部署在OpenStack云资源环境中,将网元之间进行拓扑连接组网。在云环境中实现NFV路由器网元的路由与交换功能。用户能够通过统一的界面访问这些NFV的虚拟路由器网元,进而对网元拓扑进行功能和性能的测试。

目标与内容

目前大多数的教育机构的实验室实体设备都存在灵活性低的问题。虚拟实验室一方面不断在专用硬件设备、基础设施上加大投资,另一方面学生在实验拓扑变得越来越复杂,占用的物理设备的数量增加。这就是所谓的“剪刀差”。当设备类型越丰富、数量越多、拓扑越多样的时候,用户能够享受的教学规模也越大。但由于资金、场地等各方面的因素限制,实体实验室能够提供的设备数量有限,设备的类型也单一,一般都是指定某个厂商、固定的设备配置等。可支持学生进行网络实验的网络拓扑也无法多样化。基本上大中型实验项目无法拓展,因此也导致用户无法将自身所学的专业技能发挥到实际项目中,网络规划与设计综合技能有待提高。
在物理的实验室中,用户同时进行实验可能需要数百台物理的交换机或者路由器,如果仅靠使用物理设备进行实验去完成这一系列的路由交换的实验将耗费大量的工作时间。这就是使用虚拟的路由器网元进行实验的优势。
物理的实验室变成基于x86的NFV虚拟网元组成的实验室平台,那么在基础设施服务层面需要有个云计算平台给NFV的虚拟网元进行孵化并组网。由于物理实验室要进行虚拟实验室的转型。那么在虚拟实验室的搭建过程中需要对OpenStack的和规划和部署充分了解。需要充分利用实验室中的物理机资源。由OpenStack进行物理层的抽象,提供一个云资源环境,而NFV的路由器网元部署在OpenStack云资源环境中,最后让做实验的师生们能够访问该NFV的虚拟路由器网元。而且需要提供Web界面给师生们使用,在使用的时候需要对资源有占用时间的规划,如一节课(45分钟)时间,时间结束后需要将占用的资源释放等需求。[1]在网络测试的课程中,由于使用厂商专有的测试设备价格昂贵,而且端口数量有限。需要使用虚拟化的测试网元来代替昂贵的物理的测试端口

项目需求

需求分析

仿真软件不能进行“网络测试分析”实验课,也不方便实验室的统一管理,因此需要引进NFV虚拟网元;实验室网线部署和设备的部署增加了运维;物理设备价格昂贵且容易宕机需要部署虚拟环境云计算OpenStack平台;云计算平台与NFV虚拟网元的结合才能搭建完整的虚拟实验平台提供给师生使用。NFV虚拟网元之间需要有虚拟化支持和网络连通性,才能进行组网完成网络相关实验。使用NFV虚拟的测试网元对整个环境进行测试,保证虚拟实验平台的可用。
而且由于物理设备的有限。学生做实验的时候通常需要分批来进行,要是需要某一台物理的设备宕机了,可能就导致实验进行不下去。因此在物理设备上做实验的问题更加容易出现。一旦物理设备的宕机,如果采购不及时,那么便会长时间影响做实验的效率和课程的进度。
如果学生使用仿真软件进行试验的话,如使用Cisco的VIRL或者使用GNS3等仿真的话,学生均在自己笔记本上进行操作,造成了任务的管理的不方便,而且Cisco的VIRL或GNS3不能进行扩展,只能对软件内包含的特定虚拟镜像进行操作,扩展性不强,而且没有测试的端口包含,不能进行“网络测试分析”的实验课。
物理设备价格昂贵,对于网络工程专业来说,在“路由与交换”、“网络性能测试”的课程中需要用到的路由器和测试设备的价格都很昂贵,一般的实验室只能少批量的采购,由此学生在进行实验课的预习等均会受到物理条件的制约,影响了学生的学习效率。
由此需要将物理的实验室变成基于x86的NFV虚拟网元组成的实验室平台,那么在基础设施服务层面需要有个云计算平台给NFV的虚拟网元进行孵化并组网。而且需要提供Web界面给师生们使用,在使用的时候需要对资源有占用时间的规划,如一节课(45分钟)时间,时间结束后需要将占用的资源释放等需求。由此需要进行云计算平台OpenStack的搭建。
由此综上所述,本章针对虚拟环境管理的需求有以下几点:
1)物理实验室需要转型为虚拟实验室;
2)选择合适的NFV虚拟网元;
3)OpenStack需要对NFV虚拟网元的虚拟化支持;
4)OpenStack需要对NFV虚拟网元的网络连通性支持;
5)需要整个虚拟实验室进行功能性能测试
虚拟实验室需求

特定NFV虚拟网元的需求

在OpenStack平台中部署的NFV虚拟网元需要满足“路由与交换”以及“网络性能测试”应该具备以下的特点。
特定NFV虚拟网元需要与Cisco或者华为的设备的命令类似。对网络知识的配置思想需要相同。而且支持在云环境中正常运行,在师生们做了相关的配置之后,需要按照配置进行路由的选择和流量的转发。可以支持多设备在云计算平台中的拓扑组网,完成比较复杂的实验。由于在虚拟实验室中组网的设备是基于x86服务器的NFV虚拟网元,这些网元需要有虚拟的网卡接口,需要满足学生做实验时配置交换机和路由器时的命令窗口。
师生在配置过程中可以Reserve特定的时间(如45分钟),等约定的时间到了,云平台会自动删除该师生创建的NFV虚拟网元,来保证云平台中一直有空闲的资源留给后续的实验进行。

OpenStack对NFV虚拟网元的支持需求

虚拟化支持需求

NFV虚拟网元在OpenStack云中需要有虚拟化的支持,即OpenStack云平台提供虚拟化,NFV虚拟网元可以在云平台中启动并正常工作。NFV是一个虚拟的镜像,镜像的启动需要有计算资源,内存资源,组网还需要有网络资源。有了虚拟化的支持才能启动NFV的虚拟网元。
目前在开源社区有很多基于NFV的虚拟的路由器,例如VyOS,OpenWRT等。可以将这些镜像加入到虚拟实验室的云计算平台中,满足虚拟实验室的实验需求。
在NFV虚拟网元中有一些开源的路由器的镜像,这些镜像有良好的社区支持,稳定的性能。适合在虚拟实验室云计算平台上进行部署。

网络连通性需求

NFV的虚拟网元之间需要进行网络的互相连通,在虚拟实验室中,师生们需要将NFV的虚拟网元进行组网,形成实验拓扑,而其中的NFV虚拟网元则是交换机和路由器,那么这些交换机和路由器之间需要有网络的连通,基于网络的连通性才能进行相关的路由器和交换机配置使得流量能有基于策略的选择路由和流量转发。
使用基于NFV和ASIC可编程网元的敏捷组网技术,使用Linux bridge将网元之间的网络进行桥接连通,在云计算平台OpenStack Neutron组件的帮助下,实现基于虚拟OpenvSwitch交换机的网络交换,使得NFV和ASIC网元的流量的交换和转发得以实现。
在OpenStack中的网络则是通过Neutron组件进行的。那么NFV的虚拟网元加入到OpenStack中,对Neutron中的虚拟交换机(OpenvSwitch)的兼容性提出了要求,而且在网络工程的实验中不仅需要网络的连通性,还需要基于网络协议的实现。如RIP、OSPF等网络协议也需要在云计算平台中正常工作,满足师生们的实验要求。

OpenStack中NFV虚拟网元的测试需求

在云计算平台的搭建完成之后进行NFV的虚拟网元的组网,在组网完成之后,需要对整个网络进行网络的功能和性能的测试,由于该虚拟实验室是开放给网络工程的师生们使用,必须OpenStack平台对NFV虚拟网元的虚拟化支持功能和对网络拓扑的连通性,以及NFV虚拟网元的配置路由协议(如RIP、OSPF)等网络协议是否生效进行测试。在测试通过之后才能开放该虚拟实验室。

技术背景

虚拟实验室部署的OpenStack需要满足物理资源虚拟化的基本需求。而且由于是生产环境,必须提供高可用部署方案。对NFV虚拟网元的选择上,需要满足路由与交换的配置命令,本文选择了VyOS和OpenWRT。在OpenStack虚拟化技术中Nova调用Libvirt技术。而OpenStack网络技术中Neutron是由虚拟的接口,网桥和Open vSwitch组成的,Neutron提供ML2 Plugin的启动网元方式。在测试中,利用了Spirent的STC软件,vSTC虚拟端口以及Velocity界面。

虚拟实验室OpenStack的部署方案

目前业界有许多云计算技术,主流的有OpenStack、CloudStack等。云计算平台目前较为成熟的是OpenStack方案。
OpenStack包含了一组由社区维护的开源项目,主要项目有Compute (Nova), Object Storage (Swift),Image Service(Glance),Network Service (Neutron)。 Nova提供虚拟计算服务,Swift提供存储服务,Glance提供虚拟机镜像的注册、分发服务,Neutron提供网络服务。
虚拟实验室云计算平台基于OpenStack平台进行实验。虚拟实验室需要进行网络、计算、存储资源的虚拟化,并且提供HA功能。在实验室的x86服务器上进行功能划分。由两台服务器作为Controller节点,两台服务器作为Network节点,剩余机器作为Compute节点。由Controller提供管理服务。Network节点提供网络服务,Compute节点提供计算服务。
虚拟实验室OpenStack组件介绍
在虚拟实验室环境中,为了兼顾性能和可靠性,Keystone进行访问管理,Nova组件进行虚拟化的支持技术,Glance进行镜像的存放和管理,Neutron则是对OpenStack的网络进行管理和调度。Horizon是提供Web界面可以使得温州大学的师生能够访问。最后使用Cinder和Swift进行存储资源的管理调度。
在虚拟实验室的Controller节点上面部署了虚拟镜像文件管理服务glance-registry,以及API的服务glance-api,消息队列服务service rabbitmq-server,以及Web界面的Horizon服务apache服务。nova-api暴露API使得Compute节点的nova-compute接受来自用户的消息,nova-cert提供资源认证服务,nova-scheduler提供资源调度机制,nova-conductor执行虚拟化资源的分配。
在虚拟实验室的Network节点部署网络服务有关的neutron-server,neutron-server接受来自用户Web点击时的操作,对Compute节点的网络agent进行控制,neutron-l3-agent实现对外部网络访问机制。从而实现对Compute节点上的网络的管理和调度。从而对部署在OpenStack之上的NFV虚拟网元进行网络资源的管理。
在虚拟实验室Compute节点上部署了虚拟化组件nova-compute可以提供给Instance虚拟环境的支持,在Instance网络提供方面通过neutron-plugin-openvswitch-agent进行网络连通,neutron-dhcp-agent提供DHCP服务,可以对部署在OpenStack之上的NFV虚拟网元进行计算和网络资源的提供、调度、删除、认证等功能。
网络规划方面,虚拟实验室私有云主要使用Neutron的网络服务,使用Openvswitch的plugin以及Vxlan的Overlay技术的网络模式,多个VLAN标签的划分分别为提供给虚拟机固定IP网络,网络浮动IP网络,外部网络。

NFV虚拟网元介绍

VyOS是从Vyatta的社区中fork而来的网络操作系统,该软件提供基于网络的路由,防火墙和VPN的功能。 VyOS是基于Debian GNU / Linux系统的。 VyOS运行在物理和虚拟平台,支持集成包对虚拟机和虚拟平台。VyOS可作为虚拟机部署,VyOS可以被OpenStack云管理,系统作为实例运行,操作系统在云环境中运行,可实现多租户路由,防火墙,以及负载均衡等功能。
另一个NFV的虚拟网元则是OpenWRT。OpenWRT是嵌入式设备上运行的linux系统。在其中加入quagga软件包之后可以实现RIP、OSPF等路由协议的仿真。OpenWRT本身只有10多M大小,占用的资源相当少。并且附带3000左右的软件包,用户可以方便的自定义功能来制作固件。而且OpenStack对OpenWRT也有很好的支持,由此可以将OpenWRT作为NFV虚拟网元加入到虚拟实验室的云平台中。

OpenStack的计算虚拟化技术

OpenStack提供虚拟化的组件是Nova,Nova是云主机虚拟化功能服务提供者。它包含了很多组件,API(nova-api),计算组件(nova-compute),网络组件(nova-network),调度组件(nova-schedule),卷控制组件(nova-volume),消息队列(Queue)以及Web界面DashBoard。
Libvirt 库是一种实现 Linux 虚拟化功能的 Linux API,它支持各种虚拟机监控程序,Nova通过调用Libvirt标准接口实现KVM、LXC、QEMU、UML和Xen的虚拟平台管理机制。其中KVM是nova-compute中Libvirt默认调用的底层虚拟化平台。
Nova组件结构
Libvirt为各种虚拟化工具提供一套方便、可靠的编程接口,用一种单一的方式管理多种不同的虚拟化提供方式。
上层管理平台(如nova-compute)由管理程序支持Libvirt来实现虚拟机的生命周期管理。 Libvirt的目前支持以下基本的虚拟化平台:
Libvirt支持的虚拟化平台
Nova调用底层虚拟机监控程序(如KVM/ QEMU等)和对虚拟化功能的管理主要通过LibvirtDriver类来实现。

OpenStack的网络实现技术

Neutron Server在Neutron服务充当“头”的角色(RESTful),负责接收外部API(服务)的要求,如NovaAPI请求创建一个网络。
Neutron Plugin在中间层充当了“使者”的角色,负责将Neutron Server接受到的信息传达给Neutron agent。
Neutron Agent位于最下一层,充当“工作”角色,负责具体任务和操作执行。比如创建子网等具体任务。
整个物理网络被Neutron服务虚拟化为网络资源池。利用网络资源池的可扩展性,Neutron可以为每个租户创建独立的虚拟网络环境。Neutron提供的网络服务是通过将物理的网络资源虚拟化成L2,L3层的虚拟网络资源。分别对应于一个物理网络环境的交换机和路由器。以下是Neutron网络功能的具体实现:
路由器:为租户提供路由,NAT等服务。 网络:对应于一个2层的物理网络层LAN(VLAN),从租户角度来看,网络是私有的。
子网:指定IPV4或IPv6地址,并描述其相关的配置信息而创建的网络。它被连接到一个二层网络中,指定这个网络可以使用的IP地址的范围。

  1. Linux的虚拟网络
    由虚拟NIC(vNIC)提供虚拟机的虚拟网卡功能,管理程序可以为每个虚拟机创建一个或多个虚拟网卡,实现与传统物理网络的物理网卡相同的网卡功能,交换机也被虚拟化为虚拟交换机(OpenvSwitch),每个虚拟网卡连接Open vSwitch的端口(BR-INT),访问外部网络需要通过物理网卡,因此最后的Open vSwitch需要接入外部物理网络。
    在Linux环境下的虚拟网络设备有以下几种形式:
    网络设备的虚拟化形式
    1)TAP/TUN/VETH
    TAP/ TUN/ VETH是一对虚拟网络设备,二层的TAP收发的是MAC层数据帧,在三层的TUN,接收的是IP数据包。VETH设备是成对出现的,所接收的数据的一个端部会从另一端送出,可以理解为一个虚拟网络电缆。
    2)Linux Bridge
    Linux的网桥(基于Linux内核实现)提供二层的网络功能。其原理是,通过结合到自身的其他Linux的网络设备,连接这些设备到虚拟端口。
    3)Open vSwitch
    虚拟交换机负责连接到物理网络适配器的vNIC,我们可以像在相同的物理交换机的配置中,接入到OpenvSwitch上的每个虚拟机被分配到不同的VLAN网络隔离。可以在OpenStack环境中运行多个vSwitch的可组成分布式虚拟交换机架构。
    Neutron组件结构
    2.Neutron Plugin
    Neutron服务中neutron-server运行在网络控制节点上,提供的RESTful API作为访问入口。Neutron项目采用代码的Plugin插件方式,每个插件API支持一组资源,完成特定的操作,最终由插件代理通过调用适当的RPC来完成。
    3.ML2 plugin
    ML2 plugin结构
    ML2实现的网络/子网/端口三大核心资源,ML2实现网络拓扑结构(扁平,VLAN VXLAN,GRE)和底层虚拟网络(Linux的网桥,OVS)分离机构的类型,并使用扩展驱动的方式。其中,Mechanism Manage管理不同种类的的驱动程序,不同的网络实施机制对应不同的网络形式(如Linux bridge,OVS,NSX等)。

测试方法及工具基本介绍

网络测试是指以科学的方法,如何通过测量手段/工具,取得网络产品或正在运行网络的性能 参数和服务质量参数,这些参数包括可用性、差错率、吞吐量、时延、丢包率、连接建立时间、故障检测和改正时间等。
主要面向的是交换机、路由器、防火墙等网络设备,可以通过手动测试或自动化测试来验证该设备是否能够达到既定功能。
网络测试主要面向的是交换机、路由器、防火墙等网络设备,可以通过手动测试或自动化测试来验证该设备是否能够达到既定功能或者性能。通过一定的网络拓扑结构进行设备连接,测试交换机、路由器的性能,如吞吐量、延迟、丢包等指标,更可以在一个端口中模拟上千万个网络的数量,并可以对其各自的性能进行分析。
在虚拟实验室的云平台中采用的NFV的虚拟路由器网元,通过云平台提供的网络进行相互之间的连接,在云平台网络拓扑的两端加入虚拟测试端口,发送仿真的流量,对云平台网络拓扑中的NFV虚拟路由器网元的功能和性能的测试。

Tcpdump介绍

Tcpdump能够在数据包“头”完全截获分析。它支持用于过滤网络层协议,主机,网络或端口,并提供与,或,非等逻辑语句。 Tcpdump的是一个免费的网络分析工具,提供特别的源代码,开放的接口。
Tcpdump可根据用户的数据包截获上的网络数据包进行分析。作为互联网上经典的的系统管理员必不可少的工具,Tcpdump的其强大的功能和灵活的策略拦截,成为网络系统管理员的一个分析,解决问题的必要手段。

Spirent TestCenter介绍

Spirent TestCenter有美国思博伦公司生产。Spirent TestCenter是数据通信领域广泛认同的、能够对于网络及设备进行性能测试和评估分析的标准测量仪表。帮助用户测试交换机、路由器的性能,如吞吐量、延迟、丢包等指标,更可以在一个端口中模拟上千万个网络的数量,并可以对其各自的性能进行分析,测试出不同的QoS下不同流量的表现。除了对交换机和路由器的基本网络设备的测试,Spirent TestCenter还能够应用在网络安全设备、接入网设备、通信终端、ATM设备进行测试和分析。
在虚拟实验室中利用到的是Spirent虚拟的TestCenter接口,将这个接口放入云平台中,接口可以模拟流量,即可以对整个云平台的组网进行功能和性能的测试。

OpenStack中NFV虚拟网元虚拟化实现

在选择NFV虚拟网元的启动方式中,一种是作为ML2 Plugin启动,一种是作为实例孵化,最后本文选择了实例孵化的实现方式。孵化方式中利用Libvirt进行OpenStack虚拟化的实现。Libvirt对NFV虚拟网元的各个功能提供了很好的支持。Libvirt中有大量预置的参数启动NFV虚拟网元,如网卡信息,串口信息等。在特定的NFV虚拟网元的无法正常启动时,需要改动Spawn函数中的调用参数。

Libvirt虚拟化实现方式

虚拟实验室OpenStack中使用了Libvirt进行虚拟化的实现。Libvirt的为各种虚拟化工具提供一套方便、可靠的编程接口,管理多种不同的虚拟化方式。NFV虚拟网元在OpenStack平台上的虚拟化过程如图
NFV虚拟网元的虚拟化支持流程
OpenStack环境中的Compute节点的Libvirt配置文件中可以对KVM,QUME等虚拟化技术进行选择。在裸机上的部署情况下一般使用KVM技术,因为它使用硬件加速,可以让计算资源分配时间更加短。虚拟实验室在进行搭建的时候使用了KVM虚拟化技术,而QEMU则是软件实现的虚拟化,没有使用硬件加速,使得NFV虚拟网元部署的时间变长,它的优点则是平台的兼容性较强。
Libvirt管理NFV虚拟网元方式
Libvirt中存在libvirtd进程,libvirt中有Qemu和KVM的驱动。在本项目中选择性能较好的KVM作为虚拟化层,在KVM层之上就是虚拟化所生成的Domain,Domain为NFV虚拟网元提供了计算资源。
虚拟实验室的NFV网元需要OpenStack环境的虚拟化实现需要对其进行管理,远程连接,存储管理,网络接口管理,路由功能等实现。而虚拟实验室的Compute节点上的Libvirt提供了以上的功能。通过函数调用和配置参数实现了对NFV虚拟网元的虚拟化支持。Libvirt通过以下几个功能实现了对NFV虚拟网元的计算资源的管理和网卡串口等网络组件的虚拟实现。
Libvirt对NFV虚拟网元支持
1.NFV虚拟网元管理:针对NFV虚拟网元进行生命周期操作。针对具体NFV虚拟网元上则是孵化,关机,快照,删除等功能。
2.远程教学支持:在x86的机器上运行了libvirt daemon,所有的Libvirt功能就都可以访问和使用。这样便实现了虚拟教学的远程操作。由于支持多种网络远程传输,使用最简单的SSH,学生在远程便可以直接访问NFV虚拟路由器的功能,并进行相关的配置。
3.NFV虚拟网元镜像管理:由于NFV虚拟网元的保存形式受Libvirt的支持,支持qcow2、vmdk、raw等虚拟镜像格式。由于Libvirt可以远程工作,学生可以通过远程上传一个NFV的虚拟网元到虚拟实验室中,增加了可操作性。
4.NFV虚拟网元网络接口管理:NFV的虚拟网元是需要两张虚拟网卡来连接OpenStack中的两个子网的。运行了libvirt daemon的主机可以用来管理物理和逻辑的网络接口。通过网络接口的管理,NFV虚拟网元便可以实现作为一个路由器的功能。
5.NFV虚拟网元路由功能:由于Libvirt支持基于路由的网络。在NFV的虚拟网元中则可以实现基于RIP,OSPF等路由策略,由于Libvirt的支持,在虚拟化底层对路由的支持,满足了虚拟实验室的基本需求。

NFV虚拟网元的孵化方式

ML2插件形式启动

NFV虚拟网元实则是一个虚拟的软件实现的路由器。而在OpenStack中本身存在路由器,就是作为OpenStack的其中的一个插件l3-agent。OpenStack中本身的路由器能够连接OpenStack的两个子网。但是不能对OpenStack本身的L3-agent的路由器进行任何基于命令的配置。不能对OpenStack本身的路由器进行RIP,OSPF等路由策略的配置。那么则不能满足我们虚拟实验室的要求。不能进行“路由与交换”、“网络性能测试”这些专业实验课程。
NFV虚拟网元作为ML2 Plugin
而加入的NFV虚拟网元(开源版本)不能作为一个插件,而VyOS的Brocade商业版本Vyatta在OpenStack中官方提供了插件,可以用来替换OpenStack中原本存在的L3-agent。关于VyOS的Brocade的Plugin。直接是Create Router而不是启动节点。但是在OpenStack的Controller节点上并不能安装Plugin,Brocade的Plugin是不支持开源VyOS。作为Plugin形式的启动是可行的,需要对每一个特定的NFV虚拟网元都进行开发一个特定的Plugin,和OpenStack的网络进行通信。OpenStack提供了Plugin的热插拔设计方式,使得这一切变得可以实现。那么这个方式的优势是利用OpenStack本身的框架,可行性较强。缺点也很明显,NFV的虚拟网元具有独特性,需要对每一个虚拟网元单独开发一个特定的Plugin,开发工作和难度都较大。

作为Instance孵化

常见的Instance只是连接OpenStack中的一个子网。通过OpenStack本身的L3-agent的路由器进行对不同子网其他Instance的访问。而将NFV虚拟网元加入OpenStack中则是需要让这个Instance连接2个及以上的子网,实现子网之间的流量通过这个NFV虚拟路由器进行转发。可以将NFV的虚拟网元在OpenStack中当作Instance进行孵化,但是需要将流量通过NFV的虚拟网元,并且能够使得NFV虚拟网元本身的路由和转发功能能够实现。
NFV虚拟网元作为实例启动
OpenStack的安装方式是在物理机上安装Ubuntu再安装OpenStack,版本是Juno,需要物理磁盘的分区及安装。VyOS在OpenStack中直接启动会有一个安装的过程与OpenStack不兼容,在启动VyOS的时候出现了:sda dirves not found的问题。需要在Virtualbox或者VMware上进行install system。而OpenWRT则不需要这个过程。然后在Linux发行版上安装KVM。进行虚拟格式的转换。可以转换成qcow2或者raw格式等。
将转换后的qcow2格式的虚拟文件上传到OpenStack的Glance组件中,然后启动实例就可以运行了。底层使用Libvrit和KVM(或者QEMU)软件虚拟化技术。

Libvirt虚拟化实现NFV虚拟网元

选取创建虚拟机的进程具体说明Nova如何基于Libvirt实现对底层虚拟化平台的调用与管理。以及如何在函数中传递对NFV虚拟网元的配置信息。使得该Instance能够启动在OpenStack中。在LibvirtConnection类中,通过“spawn”方法来实现虚拟机的创建,“spawn”调用方法_create_domain_and_network来启动一个新的Domain,在方法_create_domain_and_network中,实际与Hypervisor建立连接的语句是“domain = self._conn.defineXML(xml)”;在建立与Hypervisor连接的基础上执行defineXML方法,创建并定义一个Domain,但是此时的Domain还未启动,必须执行“domain.createWithFlags(launch_flags)”语句来启动之前定义好的NFV虚拟网元的Domain。
Libvirt孵化NFV虚拟网元

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
方法spawn:
def spawn(self, context, instance, image_meta, injected_files,  
              admin_password, network_info=None, block_device_info=None):  
        """ 
        # 调用之一传进来的参数: 
        # context:上下文信息; 
        # instance:实例信息; 
        # image_meta:从glance获取的镜像文件image的元数据; 
        # injected_files:编码后的注入文件; 
        # admin_password:admin密码; 
        # network_info=self._legacy_nw_info(network_info):转换为传统格式的网络资源信息; 
        # block_device_info:实例错误记录的块设备; 
        """  
        # get_disk_info:确定NFV虚拟网元的磁盘映射信息;  
      # 返回disk_bus、cdrom_bus和mapping的值这些磁盘映射信息给disk_info;;  
        # CONF.libvirt_type:这个参数定义了libvirt的域名类型,参数的默认值为'kvm';  
          
        # get_disk_info返回值:  
        # return {'disk_bus': disk_bus,    # 获取disk类型的磁盘总线;  
        #         'cdrom_bus': cdrom_bus,  # 获取cdrom类型的磁盘总线;  
        #         'mapping': mapping}      # 确定怎样映射从默认的磁盘到虚拟机,返回客户对于设备的磁盘映射;  
        disk_info = blockinfo.get_disk_info(CONF.libvirt_type,  
                                            instance,  
                                            block_device_info,  
                                            image_meta)    
        # 执行所需网络的安装以及建立域;  
        self._create_domain_and_network(xml, instance, network_info,block_device_info)  
        LOG.debug(_("Instance is running"), instance=instance)  
       接下来调用方法to_xml实现为新建立的虚拟机实例获取参数配置数据conf,并把获取的配置数据conf转换为xml格式文件,方法的具体实现如下:
def to_xml(self, instance, network_info, disk_info,  
               image_meta=None, rescue=None,  
               block_device_info=None, write_to_disk=False):  
 # 调用to_xml把conf(实例的配置数据)生成xml格式文件;  
           xml = conf.to_xml()  
           return xml  
        """ 

为新建立的NFV虚拟网元参数获取配置数据conf,并把获取的数据conf转换为xml格式;  XML配置信息
这样可以得到XML配置文件/var/lib/nova/instances/instance_id/libvirt.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  <domain type="kvm">
      <uuid>b123213b-577e-4783-acc9-5a899c8ccc9e</uuid>
      <nova:flavor name="IOSvL2">
  <devices>
      <disk type="file" device="disk">
      <driver name="qemu" type="qcow2" cache="none"/>
      <source file="/var/lib/nova/instances/b123213b-577e-4783-acc9-5a899c8ccc9e/disk"/>
      <target bus="virtio" dev="vda"/>
      </disk>
      <disk type="file" device="disk">
      <driver name="qemu" type="raw" cache="none"/>
      <target bus="ide" dev="hdd"/>
      </disk>
      <interface type="bridge"> 
      <serial type="tcp">
      <source host="0.0.0.0" mode="bind" service="17000"/>
      <protocol type="telnet"/>
  </devices>
  </domain>

上述整个过程就是OpenStack将NFV虚拟网元的配置信息的存入以及Libvirt的虚拟化配置和实现。
其中XML的配置文件是由Libvirt通过to_xml方法生成的。可以通过检查这个XML的配置文件来检查基于x86的虚拟网元在Libvirt的虚拟化过程中是否参数都配置正确。在孵化过程中可以查看XML的配置信息。在Libvirt的虚拟化实现过程中调用的conf配置文件中包含以下参数,instance, network_info, image_meta, disk_info, rescue, block_device_info。XML配置文件中的详细参数有domain type=”kvm”,uuid,name,memory占用,虚拟CPU个数,flavor模型,系统信息sysinfo type=”smbios”,串口serial id”,磁盘id dev=”hd”,驱动类型,虚拟格式,镜像存储地址,网络接口类型及ID,串口的console类型等信息。在NFV虚拟网元的启动过程中,OpenStack进行flavor的配置之后,Libvirt随即调用spawn函数进行孵化,其中大部分的参数都是默认的。而不能进行人工配置。在NFV的虚拟网元不能启动的情况下,可以对Libvirt的参数进行自定义的更改,从而更加符合特定的NFV虚拟网元。

OpenStack的NFV虚拟网元网络实现

在解决网络连通性时,首先分析Neutron网络,通过对NameSpace的Tcpdump抓包,分析流量的Drop的位置。分析Neutron的组件Linux bridge,在Linux bridge上存在iptables对流量的控制机制。 进而编写分析特定的生效的iptables条目的Python脚本,实现自动化删除阻碍流量的iptables。

OpenStack Neutron网络

针对网络连通性根据图中思路分析,进行Neutron网络,NameSpace,Linux bridge,iptables以及工具Tcpdump的组合分析,找到解决网络连通性的方法。
网络连通性分析图
在 Horizon上创建Neutron网络过程如下:首先管理员拿到一组公有IP地址,并且创建一个外部网络和子网。租户创建一个网络和子网。租户创建一个路由器并且连接租户子网到外部网络。
在虚拟网元在OpenStack中孵化成功之后,位于不同Subnet上的VyOS或者OpenWRT再Libvirt的XML文件中可以看到已经拿到了vNIC,在NFV虚拟网元的操作系统中进行网卡的配置后,通过OpenStack的DHCP的port可以得到相对应得IP地址。由于NFV的虚拟网元是连接OpenStack中2个及以上子网数量的,因此路由表中需要对路由转发等策略进行相应的配置。
而在NFV虚拟网元成功启动之后。不同子网的虚拟路由器之间不能相互通信。考虑到OpenStack的Neutron的Vlan Tag导致的不能用VyOS去ping通不同网段的设备。在VyOS不同的网段ping不通的结果下。分析了VyOS和OpenStack的问题、多个VyOS在Virtualbox里网络设置成“混杂”模式可以正常使用,但是在OpenStack中无法使用的情况。
分析Neutron的网络:
虚拟网元流量分析图
图中NFV虚拟网元流量从vm01到vm02需要通过eth0,到vnet0,接着通过qbr(Linux bridge),再经过一对虚拟接口qvb以及qvo。然后到达OpenvSwitch,从br-int经过int-br-eth,接着经过物理网络之后就向上经过同样的虚拟设备最后到达vm02。由图中可见,流量在经过eth1时进行了vlan的tag转换,因此vlan不是影响跨网段Instance连通性的障碍。
在OpenvSwitch的结构图中存在许多veth端口和Linux Bridge形式的br-int,那么在veth的成对出现的接口上,可以被视作一根“网线”。而在br-int的Linux Bridge上默认作为桥接作用(初始化的OVS)。
在OpenStack的插件中使用的是OpenvSwitch(OVS),在流量的分析中经过了OpenvSwitch,而流量经过qvo的veth之后就进入到OpenvSwitch了,而初始化的OpenvSwitch没有配置任何的策略,可以被视作一根“网线”。
OpenvSwitch结构图

NFV 虚拟网元的Namespace

NFV虚拟网元连接不同网络之间的路由通信:在Neutron上每创建一个网络都会新建一个Network NameSpace服务,Namespace是网络隔离的一种表现形式,那么现在假设有了两个网络,也就有了两个Network NameSpace,但是这两个NameSpace是相互独立的,因为他们在不同的网络中。现在如果想打通这两个网络,我们就需要另外一个Network NameSpace——Router Network NameSpace,Router Network NameSpace可以拥有2个以上的网络接口。在传统的网络环境中,我们知道如果要和一个网络通信,只要和其网关相通就可以了。
在这里也是采用这样的原理,在Neutron中我们可以使用命令将两个需要相互连通的网络加入到Router Network NameSpace中,这时Router Network NameSpace中就会出现两个网络接口连接到OVS bridge-int上,并且这两个网络接口的IP地址就是两个网络的网关。除此以外,我们需要在Router Network NameSpace中设置net.ipv4.ip_forward参数为1,这样就可以在Router Network NameSpace内部进行不同网段数据的转发,至此两个不同网络就可以打通了。
如果启动一个OpenStack的L3-agent。那么OpenStack后台是这样的命令

1
2
Running command: ['sudo', '/usr/bin/neutron-rootwrap', '/etc/neutron/rootwrap.conf', 'ip', 'netns', 'exec', 'qrouter-5e2876fb-508b-4065-b9a3-b78c2797802d', 'neutron-ns-metadata-proxy', '--pid_file=/var/lib/neutron/external/pids/5e2876fb-508b-4065-b9a3-b78c2797802d.pid', '--metadata_proxy_socket=/var/lib/neutron/metadata_proxy', '--router_id=5e2876fb-508b-4065-b9a3-b78c2797802d', '--state_path=/var/lib/neutron', '--metadata_port=9697', '--debug', '--verbose', '--log-file=neutron-ns-metadata-proxy-5e2876fb-508b-4065-b9a3-b78c2797802d.log', '--log-dir=/var/log/neutron'] 

OpenStack L3-agent NameSpace连接方式
如果NFV的虚拟网元(VyOS、OpenWRT)作为Instance启动,那么OpenStack后台是这样的命令,创建虚拟网元的Namespace然后去连接qrouter的Namespace。

1
2
Running command: ['sudo', '/usr/bin/neutron-rootwrap', '/etc/neutron/rootwrap.conf', 'ip', 'netns', 'exec', 'qrouter-5e2876fb-508b-4065-b9a3-b78c2797802d', 'ip', '-o', 'link', 'show', 'qr-109b42a1-8d'] 

OpenStack NFV虚拟网元 NameSpace连接方式
那么Instance的Namespace和OpenStack L3-agent所创建的Router拥有不一样的Namespace的标示符和连接方式。Openstack不认为作为Instance启动的VyOS给分配一个Router类型的NameSpace。因此作为Instance启动的NFV虚拟路由器和OpenStack本身的路由器的不同点主要是qrouter的Namespace是使用“qr”虚拟网络组件进行连接的,而作为Instance启动的NFV虚拟路由器的Namespace是通过Linux bridge的“qbr”进行连接的。那么总结起来,不同点就是Namespace的连接方式上,即Linux bridge的连接导致的网络通信中断。

Neutron网络流量定位

在OpenStack中可以使用Tcpdump工具进行流量的监控:
stack@vmnet-mn:~$ sudo ip netns list
qdhcp-eb2367bd-6e43-4de7-a0ab-d58ebf6e7dc0
qrouter-4adef4a5-1122-49b8-9da2-3cbf803c44dd
看Namespace更细节的信息:(netns即是namespace)
stack@vmnet-mn:~$ sudo ip netns exec qdhcp-9f7ec6fd-ec9a-4b1b-b854-a9832f190922 ifconfig
通过Namespace进行网络连通性检查:
stack@vmnet-mn:~$ sudo ip netns exec qdhcp-9f7ec6fd-ec9a-4b1b-b854-a9832f190922 ping –c 3 10.1.0.3
流量从vm01到vm02需要通过eth0,到vnet0,接着通过qbr(Linux bridge),再经过一对虚拟接口qvb以及qvo。然后到达OpenvSwitch,从br-int经过int-br-eth,接着经过物理网络之后就向上经过同样的虚拟设备最后到达vm02
L3-agent NameSpace网络监测
Debug流量在哪里被Drop
sudo iptables -t mangle -L -n -x -v
vyos@vyos:~$ /usr/sbin/tcpdump -f “icmp” -i eth0 -vv
root@openstack-compute:/home/jxie# grep -i qbr /var/lib/nova/instances/953cb053-d92b-4c37-8b8a-af91477adb74/libvirt.xml
找到虚拟机对应的虚拟接口:
<source bridge=”qbr7b85ad99-9f”/>
在虚拟接口qvo上tcpdump:
tcpdump -i ‘qvo9016120f-11’(在虚拟接口qvo中tcpdump)
tcpdump -i ‘qbr9016120f-11’(在Linux bridge形式的qbr中tcpdump)
NFV虚拟网元NameSpace网络连接监测
在实验过程中qbr上可以监测到OSPF的hello包,由于NFV虚拟路由器中已经配置了OSPF的路由协议,因此会广播hello包。由于在实验连接vm02中qbr上收到了来自vm01的OSPF的hello。那么可以得出结论。包已经经过了连接vm01的虚拟接口,Linuxbridge形式的qbr以及经过了OpenvSwitch,从而到达了连接vm02的Linuxbridge形式的qbr。
包已经到达了连接目的cirros(vm02)的那段的qbr7b85ad99-9f。从qbr之后到vm02这段流量被Drop了,在连接vm02的qbr上可以tcpdump到包,在连接vm02的eth上却tcpdump不到任何信息。那么qbr是一个Linux bridge,经查证Linux bridge上存在iptables把流量给Drop掉了。有了这个现象就在compute节点的iptables上把两个drop的iptable删除。两个网段的NFV虚拟网元之间就可以ping通。
其中在qbr中有iptables的安全策略隐藏在Linux bridge中。这个是OpenStack的网络保护机制,为了防止恶意租户的sniffer。这个安全机制在OpenStack的security group的设置中是不能被找到的,即使把IP包都设置成Forward模式,这些不同网段的Instance之间的ICMP包或者其他类型的包还是会被Drop掉。因此可以说这个安全机制是“隐藏”的。
Openstack内部本身的Router是之间用qr接口直接连接到br-int上的,因此是绕过了qbr上的iptables策略。整个过程可以在上一节的Namespace中得到证明,所以两个连接Router的Instance能够进行通信并ping通。

隐藏的iptables安全机制

iptables的安全机制是基于Linux系统上。它可以定义多个规则,将规则串起来,就可以组成一个规则列表来实现绝对详细的访问控制。OpenStack使用iptables中的filter和NAT的状态表。每个表含有一些内置链,并且还可以包含用户定义的链。每个链中可以有一个规则列表。每个规则指定对包做特定的操作,如Forward,Drop等。
nova-compute主机上的这些规则允许 VM 与nova-network主机以及其他计算主机上的VM相连接。
-A nova-compute-FORWARD -i br100 -j ACCEPT
-A nova-compute-FORWARD -o br100 -j ACCEPT
但是这些规则仅限于同一个OpenStack子网上连接的Instance(NFV虚拟网元),而对于同时连接多个子网的NFV虚拟路由器,OpenStack是直接Drop的。对于每个实例,它都会在此 filter 表内创建一个链及一些规则(
在OpenStack中启动NFV虚拟路由器之后,Nova组件孵化了一个实例。nova-compute为每个实例创建一个链。在图中则是每个Instance实例(NFV虚拟网元)iptables所创建的链和规则。链的名称是 nova-compute-inst-1。
实例的链和规则
在OpenStack的实例对应iptables所创建的链和规则来看有以下几个特点:
1.所有针对此实例的流量,无论是转发而来的还是从本地过程生成的,都会进入此实例的特定链。
2.所有来自该实例所在的子集的IP的流量都是允许的。
3.所有来自特定DHCP服务器的DHCP流量都是允许的。
4.所有其他流量均放弃(Drop)。
iptables的应用
那么对于连接多个OpenStack子网的Instance(NFV虚拟网元)是对应第4点,所以所有到另一个OpenStack子网的Instance(NFV虚拟网元)的全部流量被iptables所Drop。具体表现就是两个虚拟网元之间不能进行通信。
如果把对应的iptables删除之后,虚拟网元通过整个Neutron网络的连通性便得到了解决。可以看到VyOS(或者OpenWRT、vSTC)成功地转发了包。
以下是一个可以自动寻找生效的iptables的Python脚本:
Debug到底是哪一条在生效:
特定NFV虚拟网元的iptables的定位

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
!/usr/local/bin/env python
# -*- coding: utf-8 -*-
from itertools import combinations
import subprocess
import os
import paramiko
import random

file = open('/home/jxie/add_all.sh','r')
iptables_list = []

for line in file:
    iptables_list.append(line.rstrip())


def vyos_ping_check():
        hostname=raw_input('10.61.34.119')
        username='jxie'
        password='!'
        ssh=paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        ssh.connect(hostname,22,username,password)
        stdin,stdout,stderr=ssh.exec_command('ping -c 5 192.168.2.11')
        print stdout.readlines()
        ssh.close
        if 'ttl=64' in stdout.readline:
                return True
        else:
                return False
def test():
    while 1:
        i = random.randint(10, 200)
        if i%5 == 0:
            return False
        else:
            return True


def main():
    with open('/tmp/result.txt','w') as f:
        for sub in iptables_list:
                subprocess.call(sub.split())
                print test()
                if test() == False:
                    f.write(sub + os.linesep)
                    subprocess.call(('echo iptables -D ' + sub[15:]).split())
                else:
                    subprocess.call(('echo iptables -A ' + sub[15:]).split())

if __name__ == '__main__':
    main()

小结

NFV虚拟网元作为Instance孵化的同时Openstack不认为作为Instance启动的VyOS给分配一个Router类型的Namespace。其中在连接Instance的Linux Bridege中有iptables的安全策略隐藏。这个是OpenStack的网络保护机制,为了防止恶意租户的sniffer。而Openstack内部本身的Router绕过了iptables策略,使得连接到这个路由器的流量得以转发。而删除对应Drop的iptables链的规则之后,不同OpenStack子网的虚拟网元之间的网络连通性便可以得到解决。

虚拟实验室测试实现及Kilo版本更新

在解决OpenStack的虚拟和化网络连通性之后,可以对VyOS或者OpenWRT虚拟路由器网元进行RIP和OSPF等网络协议的配置,可以满足网络工程的师生们能够进行“路由与交换”的实验的需求,通过Spirent的Velocity界面的虚拟资源的编排和Spirent TestCenter Virtual(vSTC)虚拟网元组网,最后通过Spirent TestCenter的界面进行经测试打流,生成测试报告。可以满足网络工程的师生们进行“网络性能测试”实验的需求。最后的测试说明了该虚拟实验室的功能和性能已经达到了要求。

OpenStack测试方法实现

将OpenStack云平台上启动多个Intance(NFV虚拟网元),相互之间能够ping通,而且Instance在绑定Floating ip之后能够访问外网,即可以说明OpenStack云平台正常工作。 在仿真的测试过程中,可以在OpenStack搭建的云计算平台上,使用NFV虚拟网元(VyOS、OpenWRT)等虚拟的路由器进行组网,在拓扑搭建完成之后,可以配置相关的路由协议(RIP、OSPF等),实现复杂网络的连通性。在网络测试方面,利用Spirent TestCenter虚拟接口工具在拓扑的两端接入,发送流量包,对中间组网的虚拟网络设备进行功能和性能的测试。

Spirent Velocity实现接入界面

Spirent Velocity基于云计算的设计无缝地集成了Spirent TestCenter Virtual和Spirent Avalanche Virtual测试设备,Velocity通过调用OpenStack的接口,实现对OpenStack的资源编排,并且提供更高效的资源占用的方式,用户可以使用“拖拽”NFV虚拟网元的方式组件网络,并且保存已经存在的拓扑,针对每一个独立的拓扑环境设置用户所需要Reserve的时间。到时间结束之后,Velocity会自动删除拓扑中的资源,把资源返回给OpenStack资源池。而删除资源并不会影响本身所保存的拓扑。
在Velocity中可以调用在OpenStack的Glance中的Spirent TestCenter Virtual(vSTC),通过vSTC与NFV虚拟网元的联合组网,可以满足网络工程的“路由与交换”实验以及“网络性能测试”等实验课的需求。Velocity作为温州大学虚拟实验室的WEB接口,用户通过用户名和密码登录。
学生Web界面

Spirent TestCenter测试实现

Spirent TestCenter的界面,进行流量通过NFV虚拟网元的打流测试。
Spirent TestCenter的界面
测试是基于RFC2544协议的。RFC2544协议是RFC组织提出的用于评测网络互联设备的国际标准。吞吐量测试是被测设备在不丢包的情况下,所能转发的最大数据流量。用户以一个用户定义的恒定速度发送,然后通过二分查找算法找到一个不丢包的速率。结果是在不同的帧长下每秒的吞吐量。常见的帧长有 64,512,1024,1518字节等。流量通过VyOS的测试结果如图
VyOS吞吐量测试报告
这样整个虚拟实验室的NFV虚拟网络的功能和性能已经满足了上述的需求。

OpenStack kilo版本的port-security

在OpenStack的kilo版本加上了ML2PortSecurityExtensionDriver,在OpenStack的NFV的虚拟网元的流量便可以相互之间进行包的通信。
在 /etc/neutron/plugins/ml2/ml2_conf.ini 添加如下配置:
extension_drivers=port_sercurity
port_security_enabled=False
在创建网络时需要加上port-security参数:
创建network:neutron net-create net2 –port-security-enabled=False
给network分配地址:neutron subnet-create net2 7.7.7.0/24 –enable-dhcp=True –name subnet2
创建port,并且把security-group disable掉:neutron port-create net2 –no-security-group
在port上启动instance:nova boot –flavor 1 –key_name oskey –image 405fb039-0df0-4c5d-aea6-7a472e5ec553 –nic port-id=92eb7fc3-6e11-487e-8d62-2ffc51a6ee00 openwrt1
port-security状态False之后,iptables则不需要删除。

总结

虚拟云平台NFV实验室有效性及前景

仿真软件不能进行实验的统一管理,不能进行“网络测试分析”实验课。物理实验室网线部署和设备的部署增加了运维;物理设备价格昂贵且容易宕机需要部署虚拟环境云计算OpenStack平台,并且使用价格便宜的x86服务器支持NFV虚拟化网元(VyOS、OpenWRT),在网络测试方面需要引进测试的NFV虚拟网元(vSTC);而云计算平台与NFV虚拟网元的结合需求的难点主要有虚拟化和网络连通性两个方面,在本文中得到了有效和解决和研究,得到了较好的阐述,在用户WEB接口方面使用了Spirent的Velocity进行资源的管理和调度。
虚拟实验室整体架构

参考文献

[1]思博伦技术专栏. 完整验证NFV的性能[J]. 《电信网技术》2015年6月第6期,2015,06:63-64.
[2]杨益锋. 实现和测试网络功能虚拟化(NFV)以确保运营商级交付[J]. 《电信网技术》2014年6月第6期,2015,06:83-84.
[3]房秉毅,李素粉,郭玉华,陈 冰. NFV标准化现状与PoC进展分析[J]. TELECOMMUNICATIONS TECHNOLOGY.2015,09:73-80.
[4]房秉毅,李素粉. 基于开源OpenStack架构的NFV基础设施云平台[J]. TELECOMMUNICATIONS TECHNOLOGY.2015,01:1-4.
[5]费越. 基于SDN技术的系统集成测试研究[D]. 北京邮电大学硕士学位论文.2015,03:5-15.
[6]杨健. 网络功能虚拟化系统测试技术研究[D]. 北京邮电大学硕士学位论文.2014,12:10-23.
[7]Rashid Mijumbi, Joan Serrat, Juan-Luis Gorricho, Niels Bouten, Filip De Turck, Raouf Boutaba. Network Function Virtualization: State-of-the-art and Research Challenges[J]. IEEE COMMUNICATIONS SURVEYS & TUTORIALS,2015,09:1-5.
[8]Raj Jain and Subharthi Paul, Washington University. Network Function Virtualization: Network Virtualization and Software Defined Networking for Cloud Computing: A Survey[J],CLOUD NETWORKING AND COMMUNICATION,2013,09:24-35.
[9]Joao Martins and Mohamed Ahmed, NEC Europe Ltd.; Costin Raiciu and Vladimir Olteanu, University Politehnica of Bucharest; Michio Honda, Roberto Bifulco, and Felipe Huici, NEC Europe Ltd. ClickOS and the Art of Network Function Virtualization[J], 211th USENIX Symposium on Networked Systems Design and Implementation. 2013,09:24-35.
[10]Sevil Mehraghdam,Matthias Keller,Holger Karl. Specifying and Placing Chains of Virtual Network Functions[J], arXiv:1406.1058v1 [cs.NI]. 2014,01:2-5.

镜像制作

按照步骤完成OpenStack部署。加入一块硬盘,使用Linux dd命令把OpenStack的节点拷贝到硬盘中,可用gzip压缩,利用liveCD和分区对拷的方式使裸机启动,利用lvm进行硬盘调整。

自动化

开发shell脚本(dialog)实现自动化

curl

选择菜单

curl

自动化感知网卡

curl

配置网卡

curl

进行安装

curl
ps:此方案经验证

OpenStack容器化

Docker是一个革命性的产品。革命是很残酷,Kolla项目,对于OpenStack创业公司来说,以前折腾的部署工具,包括Fuel,基本都报废,日后都要改成容器分发,用ansible或K8S来管理OpenStack。

OpenStack社区要想发展下去,就必须证明自己可以管理容器的能力。如何证明呢?就只能吃自己狗食,把OpenStack自己先容器化。Kolla项目经过一年努力,已经可以生产使用。

我为什么不在CSDN中写博客了
Image source: dargadgetz

不得不说一开始csdn做得还不错。中国最大的程序猿平台。我也是从2014年就开始写了一些博客到现在。不过可能现在做博客的多了,比如Github、Wordpress逼格都比较高一些,我也可以学习一下markdown语法。而csdn上的广告越来越多,不过Github、Wordpress维护起来比较麻烦。所以我就比较重要的文章发在这里。一些小的工程文档就扔在csdn就当纪录一下。

链接如下: 我的csdn博客

目录:
第一章 背景介绍
1.1实验背景
1.2实验目的
1.3实验环境搭建
第二章 可行性分析
2.1 Floodlight对Openvswitch的控制
2.2 OpenvSwitch对QoS策略的支持
第三章 实验方案设计
3.1 OpenFlow QoS总体方案设计
3.2 控制平面功能设计
3.3 转发平面功能设计
第四章OpenFlow QoS实现
4.1 QoS控制器模块实现
4.2 CLI指令配置模块实现
4.3 DiffServ流量控制模块实现
第五章OpenFlow QoS功能测试
5.1 系统测试环境介绍
5.1.1 测试平台
5.1.2 实验拓扑
5.2 实验测试方法
5.2.1网络流量测试工具
5.2.2 流量控制功能验证方法
5.3 流量控制功能验证
5.3.1系统端口速率TCP限速测试
5.3.2系统端口TCP带宽保障测试
5.3.3系统视频流速率带宽保障测试
5.4 实验总结
附录 流量种类Map表、Qos视频

第一章:背景介绍

1.1、实验背景

数据中心提供多种业务,但一般只进行尽力而为的转发,不单独为某一业务带宽提供额外的保障,这就造成某些关键性业务无法得到很好地保证(如视频业务),可能影响业务的正常运转(视频不流畅)。
近年来,随着网络技术的快速发展,网络业务种类日益多元化,网络带宽容量需求日益扩大。某些国内最大的海量视频数据流媒体,每天2-2.5亿视频播放量,千万级用户访问行为和视频播放需求,为了能够更好地满足用户对于视频流的播放需求,基于互联网架构的流媒体服务应该具有更好的QoS服务保证。新型网络业务的广泛应用,包括视频通话、电话会议、VOIP等,使得人们对服务质量(Quality of Service,QoS)要求越来越高。网络如何有效保障业务的服务质量受到越来越多人的关注。随着新型业务的多元化,传统网络体系架构暴露出了越来越多的弊病,例如网络结构复杂化和网络设备性能的饱和,对网络新业务的推广提出了严峻的考验,已经不能满足各种新型业务对服务质量的需求。
因此,一场新型网络体系架构的革命蓄势待发,软件自定义网络——一种可编程网络体系架构应运而生。OpenFlow是SDN的产物,是一种新型网络交换模型,该模型利用开放流表(FlowTable)实现用户对网络数据处理的可编程控制。针对当前 OpenFlow网络对 QoS管理的需求,结合对传统IP网络区分服务模(DiffServ)QoS技术的研究,设计并实现了一套基于 DiffServ模型和OpenFlow网络架构的QoS系统。按照预定的设计方案通过搭建小型网络拓扑对其进行验证,并对实验结果进行分析,验证设计的QOS系统显著的提高了对网络QoS 性能的全局掌控,降低了底层交换设备的工作负载。

1.2、实验目的

带宽保障属于QoS的一种,本实验包含多种QoS策略。下文统一称为QoS。对数据中心中提供的某种业务(如视频业务)进行带宽预留与保障,当总体流量大于链路承载能力时,优先保证指定业务的带宽。
针对视频传输控制,实时传输协议(RTP)、实时传输控制协议(RTCP)、实时流协议(RTSP)、资源预订协议(RSVP)等协议是基于TCP协议,且现在越来越多的视频流基于TCP协议传输。
本实验将完成TCP流量带宽限制、带宽保障和特定Video Packet(视频流)流量的保障。

1.3、实验环境搭建

为了验证网络流量控制的性能,搭建了一个简单的DiffServ的小型网络,如图所示:
实验拓扑图

其中OpenFlow控制器为运行Floodlight控制器程序的Linux(Ubuntu)主机,Floodlight和OVS为运行OpenFlow网络的控制器和交换机。OVS与控制器直连,提供多种服务的服务集群,PC1和PC2分别连接在右OVS上。实验结果通过数据流获得的网络带宽来验证和转发的速率来验证。从服务器向PC1发送2种优先级不同的TCP流A、B,网络总带宽为10Gbit/s。在PC1上通过对A、B流量的分析,得到实验数据。
从实验结果可知,QoS系统能够正确地区分不同的QoS等级的服务,并提供差别服务质量保证。QoS使用前,不同的流公平占用网络带宽,QoS使用后,不同的QoS等级的数据流获得的网络带宽不同。从而实现对数据中心中提供的某种业务(如视频业务)进行带宽预留与保障。

2.1 Floodlight对Openvswitch的控制

OpenFlow协议支持控制器到交换机消息交互,controller-to-switch消息由控制器发起,用来管理或获取交换机的状态,主要包括 6 种其子消息类型。Features 在建立传输层安全会话(Transport Layer Security Session)的时候,控制器发送 feature请求消息给交换机,交换机需要应答自身支持的功能。
(一)Configuration控制器设置或查询交换机上的配置信息。交换机仅需要应答查询消息。
(二)Modify-state控制器管理交换机流表项和端口状态等。
(三)Read-state控制器向交换机请求一些诸如流、网包等统计信息。 (四)Packet-out控制器通过交换机指定端口发出网包。
(五)Barrier控制器确保消息依赖满足,或接收完成操作的通知。
(六)asynchronous消息由switch发起,用来将网络事件或交换机状态变化更新到控制器。
交换机与控制器通过被动或主动的控制进行状态信息更新、流表更新,是得控制器对交换设备进行网络拓扑管理、路由控制等,实现控制端对全局网络的实时掌控。

2.2 OpenvSwitch对QoS策略的支持

QoS中的流量监管(Traffic Policing)就是对流量进行控制,通过监督进入网络端口的流量速率,对超出部分的流量进行“惩罚”(这个惩罚可以是丢弃、也可是延迟发送),使进入端口的流量被限制在一个合理的范围之内。例如可以限制TCP报文不能占用超过50%的网络带宽,否则QoS流量监管功能可以选择丢弃报文,或重新配置报文的优先级。
QoS流量监管功能是采用令牌桶(Token-Bucket)机制进行的。这里的“令牌桶”是指OpenvSwitch的内部存储池,而“令牌”则是指以给定速率填充令牌桶的虚拟信息包。
交换机在接收每个帧时都将添加一个令牌到令牌桶中,但这个令牌桶底部有一个孔,不断地按你指定作为平均通信速率(单位为b/s)的速度领出令牌(也就是从桶中删除令牌的意思)。在每次向令牌桶中添加新的令牌包时,交换机都会检查令牌桶中是否有足够容量,如果没有足够的空间,包将被标记为不符规定的包,这时在包上将发生指定监管器中规定的行为(丢弃或标记)。
在OpenvSwitch中采用HTB,Hierarchical Token Bucket令牌桶机制来保障和限制流量的带宽。后文将详细说明HTB机制在Queue队列上的应用。

TB的基本工作原理

第三章:实验方案设计

3.1 OpenFlow QoS总体方案设计

DiffServ在实现上由PHB、包的分类机制和流量控制功能三个功能模块组成,其中流量控制功能包括测量、标记、整形和策略控制。当数据流进入DiffServ 网络时,OpenvSwitch通过标识 IP 数据包报头的服务编码点(Type of Service,ToS)将IP包划分为不同的服务类别,作为业务类别分类的标示符。
当网络中的其他OpenvSwitch在收到该IP包时,则根据该字段所标识的服务类别将其放入不同的队列,并由作用于输出队列的流量管理机制按事先设定的带宽、缓冲处理控制每个队列,即给予不同的每一跳行为(Per-Hop Behavior,PHB)。
在实际应用时,DiffServ将IPv4协议中IP服务类型字段(TOS),作为业务类别分类的标示符。理论上,用户可以在0x000000至0xffffff 范围内为每个区分服务编码点对应的服务级别分配任意PHB行为。每个服务等级为分类的业务流提供不同的QoS保证,如下所示:

Openflow QoS平面结构图

在实际应用时,具体工作流程如下:
(1)OVS对业务进行转发,同时运行在入端口上的策略单元,对接受到的业务流进行测量和监控,查询数据业务是否遵循了SLA,并依据测量的结果对业务流进行整形、丢弃和重新标记等工作。这一过程称为流量调整(traffic conditioning,TC)或流量策略(traffic policing,TP)。
(2)业务流在入端口进行了流量调整后,再对其DSCP字段进行检査,根据检查结果与本地 SLA 等级条约进行对比并选择特定的PHB。根据PHB,所指定的排队策略,将不同服务等级的业务流送入OpenvSwitch出端口上的不同输出队列进行排队处理,并遵循约定好带宽缓存及调度。当网络发生拥塞时,还需要按照 PHB对应的丢弃策略为不同等级的数据包提供差别的丢弃操作。
(3)当业务流进入到OpenvSwitch时,只需根据DSCP字段进行业务分类,并选择特定PHB,获得指定的流量调整、队列调度和丢弃操作。最后业务流进入网络中的下一跳,获得类似的DiffServ处理。
数据包的分类和调节示意图

3.2 控制平面功能设计

QoS控制负责对接收到指令进行解析和执行,实现集中式控制、布式处理。交换设备端口处流量控制分为入端口处流量整形和出端口处队列管理和调度。其中,交换机入端口处的流量整形和限制,具体通过调用ovsdb对应接口函数对入端口速率限制和入端口突发量等参数进行设置来实现。交换机出端口处主要采用队列管理和队列调度机制对流出网络的数据流进行控制。
队列管理和队列调度是流量调度的两个关键环节,为了在分配有限的网络资源时,保证业务流之间的公平性。队列管理为入队的报文分配缓存,当缓存溢出时对报文进行丢弃,目的是减小因排队造成的端点间的延迟。队列调度负责通过预设的调度算法将队列中等待处理的分组调度到相应的输出链路上。
QoS控制平面流程图

3.3 转发平面功能设计

Linux内核流量机制提供了多种队列管理和队列调度的算法。其中无类的队列规则能够实现队列管理功能,如 RED、WRED算法,分类的队列规则能够实现队列调度功能,如HTB、CBQ、PRIO算法。本系统中交换机出端口处的队列调度和队列管理机制的实现,我们采用了HTB(Hierarchical Token Bucket)队列调度算法,实现底层转发结点上的队列管理。其中,队列调度机制通过对Open vSwitch的linut-htb队列模块进行配置来实现。
OpenvSwitch交换机转发流程图

交换机端口处的流量整形和限制,队列调度机制通过对OpenvSwitch的linut-htb队列模块进行配置来实现。

OpenvSwitch交换机对流量整形

DiffServ模型中对入端口处的流量整形和丢弃,出端口处的流量调度和丢弃处理分别以流量整形模块、队列管理模块和队列调度模块进行部署。这几个模块对业务流进行直接的操作,前提是依据控制的分类、标记和入队操作。其中,流量整形模块利用入端口处的流量策略控制机制实现,出端口处的队列管理模块采用分层令牌桶 (Hierarchical Token Bucket,HTB)调度算法进行实现。这些组件OpenFlow交换机上进行实现。
核心策略HTB, Hierarchical Token Bucket功能组件:
(一)Shaping:仅仅发生在叶子节点,依赖于其他的Queue
(二)Borrowing: 当网络资源空闲的时候,借点过来为我所用
(三)Rate:设定的发送速度
(四)Ceil:最大的速度,和rate之间的差是最多能向其他流量借多少

OpenvSwitch交换机HTB实现

在CLI上输入Queue队列命令如下:


sudo ovs-vsctl -- set port s1-eth1 qos=@defaultqos -- set port s1-eth2 qos=@defaultqos -- --id=@defaultqos create qos type=linux-htb other-config:max-rate=1000000000 queues=0=@q0,1=@q1,2=@q2 -- --id=@q0 create queue other-config:min-rate=1000000000 other-config:max-rate=1000000000 -- --id=@q1 create queue other-config:max-rate=20000000 -- --id=@q2 create queue other-config:max-rate=2000000 other-config:mix-rate=200000

分别在OpenvSwitch的端口出创建三个Queue队列机制,速率则可以由自己定义。

第四章:OpenFlow QoS 实现

4.1 QoS 控制器模块实现

在整个管理系统中 QoS 控制管理模块处于核心的地位,部署在 OpenFlow 控制器上,提供 DiffServ 模型的流表控制管理功能。OpenFlow 网络的流表下发等控制行为是通过 QoS 控制器来决策并完成的。其中,流表的下发需要控制器和被控制的OpenFlow 交换机通过 OpenFlow 协议规范来完成。
本系统设计并实现的基于DiffServ模型的流量控制模块提供以下基本的流量控制功能:
(1)限制特定流量带宽和速率;
(2)保障特定用户、服务或客户端的带宽;
(3)保障特定视频流的带宽;
QoS控制器的QoSPolicy代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Map<String, Object> row;
IResultSet policySet = storageSource  
.executeQuery(TABLE_NAME, ColumnNames, null, null );//从strogeSource中读信息 
for( Iterator<IResultSet> iter = policySet.iterator(); iter.hasNext();){
row = iter.next().getRow();//遍历信息
QoSPolicy p = new QoSPolicy();
if(!row.containsKey(COLUMN_POLID) || !row.containsKey(COLUMN_SW)
//获取OVS的ID 
|| !row.containsKey(COLUMN_QUEUE)//获取队列ID
|| !row.containsKey(COLUMN_ENQPORT)//获取端口 
|| !row.containsKey(COLUMN_SERVICE)){
      logger.error("Skipping entry with required fields {}", row);
      //获取服务类型
      continue;
        		}

4.2 CLI指令配置模块实现

模块的具体实现将在后续章节进行详细阐述。控制平面上模块间的交互动作如下:
(1)CLI 指令配置模块下发管理员的配置指令;
(2)QoS 控制器读取指令,通过流表控制程序实现流表管理机制;
(3)QoS 读取指令,通过查询、配置接口,对底层交换机状态、端口配置、队列配置进行对应的操作。
系统转发平面由位于系统的底层,由传输结点组成,因此除了对流经网络的分类业务流进行数据的传输外,还需要对数据流进行流量控制、带宽调整、等操作,而流分类、标记机制由控制器进行控制和管理。
以添加一条Queue队列为例:


 try:
   	cmd = "--controller=%s:%s --type ip --src %s --dst %s --add --name %s" % (c,cprt,src,dest,name)    //*在Linux命令端口加入Queue队列*  
   	print './circuitpusher.py %s' % cmd
   	c_proc = subprocess.Popen('./circuitpusher.py %s' % cmd, shell=True)
   	print "Process %s started to create circuit" % c_proc.pid   //*circuit创建完成*  
   	#wait for the circuit to be created
   	c_proc.wait()
   except Exception as e:
   	print "could not create circuit, Error: %s" % str(e)  
   try:
   	subprocess.Popen("cat circuits.json",shell=True).wait() //*把策略写入json*  
   except Exception as e:
   	print "Error opening file, Error: %s" % str(e)
   	#cannot continue without file
   	exit()

4.3 DiffServ流量控制模块实现

控制器模块是对 Floodlight 控制功能的扩展,即通过编程实现一些预定的QoS 配置功能。该模块位于OpenFlow 控制器上,主要提供基于分类业务的QoS策略,主要包括基于DSCP和 IP 头多元组匹配分类策略,数据流入队策略,主要完成三个功能:
(1)从命令配置组件读取QoS流规则,对流规则进行解析,提取流分类、QoS控制器标记和入队的流匹配字段规则;
(2)将流匹配规则以底层OpenFlow交换机可以理解的流表形式按OpenFlow 协议进行封装;
(3)通过安全通道将上述包含新流表信息的控制消息下发至相关底层交换机结点。
具体实现如下所示:
(1)流分类
流分类通过对到达数据流进行比传统五元组更高精度的 IP 包头元组匹配,即流表匹配域中的匹配字段。系统可以通过上层控制器流表推送规则来调整流分类的匹配规则。
(2)测量和标记
主要通过配置流规则对分类后的具有某种相同特征的流设置相应的动作指令,即通过set_nw_tos动作来修改IP的TOS值,此动作需在OpenvSwitch入端口中执行,确保进入的数据流打上标签。核心网络结点则直接根据 IP 根据包头的DSCP值进行相应的基于PHB的分类和入队操作。
(3)入队
数据流在进行了分类和标记处理后,入队操作则根据标记的 DSCP 值将数据流推送到交换机指定端口上的指定队列上排队等转发处理动作。入队操作通过“enqueue =queue:enqueueport”的格式提供管理员进行配置,queue为队列编号,enqueueport 为queue 所在的端口号。QoS 控制器模块是在Floodlight 控制器上进行的QoS的扩展,由java语言进行开发,其中,分类的QoS服务的包括QoS 服务和QoS策略的添加、删除、修改等。

QoS策略则为每类QoS服务提供分类、标记和入队操作的匹配规则。主要包括策略编号 policyid、IP 包头域、交换机通用唯一标识符(Universally Unique Identifier,UUID)标示符dpid(datapath id)和本条策略(policy)匹配的服务类型编号sRef及本条策略的优先级(priority),QoSPolicy类的具体定义如下:


public class QoSPolicy {
public long policyid;
public String type;/*IP 包头域*/
public short ethtype;
public byte protocol;
public short ingressport;
public int ipdst;
public int ipsrc;
public byte tos;
public short vlanid;
public String ethsrc;
public String ethdst;
public short tcpudpsrcport31
public short tcpudpdstport;
public String dpid; /*交换机 UUID*/  
pubic short set_nw_tos;/*重新标记 DSCP 值*//*入队操作,Enqueue 1:2,其中 1 表示 queue 队列号,2 表示 enqueue 入队
端口号*/  
public short queue;
public short enqueueport;/*默认情况下服务类型为 Best Effort*/  
public String sRef; /*policy 策略对应服务编号 sRef*/
public short priority = 0; /*policy 策略优先级*/
}

QoS 策略添加函数addPolicy通过指令接口获得QoSPolicy的匹配规则,同时通过调用 flowPusher 将流规则下发到特定底层交换机,以String类型的 swid 作为标记,具体代码实现如下:


public void addPolicy(QoSPolicy policy, String swid) {
/*从 policy 结构体中获取流表修改表项*/
OFFlowMod flow = policyToFlowMod(policy);
logger.info("Adding policy-flow {} to switch {}",flow.toString(),swid);
/*将 dpid 哈希值作为流名称的唯一标识码*/
flowPusher.addFlow(policy.name+Integer.toString(swid.hashCode()), flow,swid);
}

指令配置模块通过调用addPolicy函数分别添加流控规则实现对数据流的分类、标记和入队操作。


elif obj_type == "policy":
	 print "Trying to add policy %s" % json
	 url = "http://%s:%s/wm/qos/policy/json" % (controller,port)  #preserve immutable         
	 _json = json
try:
	 req = helper.request("POST",url,_json)
	 print "[CONTROLLER]: %s" % req
	 r_j = simplejson.loads(req)
	 if r_j['status'] != "Please enable Quality of Service":
      	 write_add("policy",_json)
	 else:
	 	print "[QoSPusher] please enable QoS on controller"
	 except Exception as e:
	   print e
	   print "Could Not Complete Request"
	   exit(1)
	 helper.close_connection()
	 else:
	   print "Error parsing command %s" % type
	   exit(1)

现基于 Linux 操作系统的终端来完成。CLI 指令配置模块程序通过调用 QoS 控制器API接口和QoS代理 API 接口实现 QoS 的配置功能。
下面对指令配置模块为管理员提供的主要输入指令及其功能进行详细的分 析:

  1. 帮助指令
    语法:–help 功能:显示帮助信息。提示管理员当前输入指令的功能,和可进一步扩展的 指令。
  2. 状态指令
    语法:status [ enable | disable ]
    功能:查看、打开或关闭管理系统QoS功能。当设置为enable时,开启系统 管理功能,系统读取流规则库文件和队列规则库文件,并下发配置到对应模块。
    当设置为disable时,关闭 QoS 功能,删除对应模块的配置列表。
  3. 列举指令
    语法:list [swId] [msgType]
    功能:swId为交换机编号,及控制域内可控结点的编号。msgType可以分为 两类:控制器端的QoS服务、QoS策略的流表控制规则和交换机端QoS代理的队列配置规则。
  4. 配置指令
    语法:add | dele [moduleType] [cfgContent]
    功能:moduleType 可以为 conType(控制器类型)或 swType(交换机类型), 与两种类型对应的cfgContent配置信息同样分为两类,控制器类型配置信息为 QoS服务、QoS策略配置信息,交换机类型为QoS代理端口队列配置信息。
  5. 退出指令
    语法:exit
    功能:退出控制程序和当前指令配置界面。

第五章OpenFlow QoS功能测试

5.1 系统测试环境介绍

5.1.1 测试平台

物理机安装VMware Workstation 10。下载SDN Hub(sdnhub.org)构建的all-in-one tutorial VM并导入到VMware。这是一个预装了很多SDN相关的软件和工具的64位的Ubuntu 12.10虚拟机映像。内置软件和工具如下:
·SDN控制器:Opendaylight,Ryu,Floodlight,Pox和Trema
·示例代码:hub,2层学习型交换机和其它应用
· Open vSwitch 1.11:支持Openflow 1.0,实验性的支持 Openflow 1.2和1.3
·Mininet:创建和运行示例拓扑
·Eclipse和Maven
·Wireshark:协议数据包分析

5.1.2 实验拓扑

通过Mininet的custom下的Python文件建立自定义拓扑
Mininet自定义拓扑

MAC地址00:00:00:00:00:00:00:01、00:00:00:00:00:00:00:02分别为OpenvSwitch1和OpenvSwitch2,连接OpenvSwitch1的为服务器,提供视频流、Web等服务,连接OpenvSwitch2的为主机Host1,Host2。

Floodlight显示拓扑

5.2 实验测试方法

5.2.1网络流量测试工具

需要一些软件辅助功能验证的执行,如用于分析数据流的网络带宽性能测试工具iperf。
TCP测试
客户端执行:iperf -s是windows平台下命令。
服务器执行:iperf -c 10.0.0.2

5.2.2 流量控制功能验证方法

这部分实验对OpenFlow软交换机上DiffServ模块实例提供的整体 DiffServ功能进行正确性验证。当被标记的数据流通过OpenvSwitch时,在其上应用的 QoS 代理对交换机进行的队列配置应具有对这些数据流的分组进行汇聚分类和转发的能力。如果Host1到 Host2方向上的数据流的带宽与事先配置的HTB队列调度算法设置的带宽一致,则可验证OpenFlow QoS管理系统上的DiffServ模型流量控制功能的正确性。

5.3 流量控制功能验证

5.3.1 系统端口速率TCP限速测试

为了验证管理系统指令配置模块的配置的结果,从Host进行打包测试,验证配置端口速率限制的正确性。首先由服务器作为服务端,Host1作为客户端进行TCP打包,然后加入QoS策略再进行TCP打包测试。从打包结果可以看出QoS策略完成了端口队列速率限制的功能。
首先不加入策略,服务器到Host1的TCP带宽为2Gbps测试如下:

显示不加入任何Queue的带宽 开启QoS的服务成功:

显示QoS功能开启

在OpenvSwitch1的接口上创建Queue队列机制:

OVS的接口上创建Queue队列机制

创建一条实际的QoS Policy策略:

创建QoS Policy

在Floodlight控制器中已经声明 Protocol=“6”是TCP流量

显示流量种类的Map表

创建QoS Policy策略成功,并且写入json文件中:

显示Policy

再利用iperf工具测试服务器到Host1的TCP速率

显示TCP带宽

不加入队列机制时由服务器向Host1发送的数据流速率在2Gbps左右,在加入了两条限制队列之后(一条为限制限制在2Mbps,另一条限制在100kbps) 实验结果显示,由服务器向Host1发送的数据流速率分别限制在2Mbps和100kbps左右,与前面配置的预期结果一致,证明了QoS系统对底层交换设备流量控制功能的正确性。
同理,对其他流量可以做限速来保障需要额外带宽的流量。

系统端口TCP带宽保障测试

在第一个测试的基础上改变OVS上的Queue队列机制,Queue0的机制是保障最低的带宽为100Mbps:

显示Queue0队列

再定义一条具体的TCP流基于Queue0

定义TCP流基于Queue0队列

将具体的TCP流基于Queue0的QoS策略写入Json文件

Policy写入Json文件

使用iperf进行测试带宽:

显示TCP流带宽

在加入Queue0队列之后速度比之前2Gbps降低,但是Queue0的策略是保障最低带宽(100Mbps),所以带宽还是达到了500Mbps。达到题目的要求。

5.3.3系统视频流速率带宽保障测试(具体到视频流)

在Floodlight控制器中已经声明 Protocol=“4b”是Packet_Video流量,说明可以具体到特定视频流的带宽保障。
该流量类型在Floodlight控制器的Counter模块中定义。

显示视频流Map表

将该流量写入QoS Policy策略机制使用Queue0带宽保障队列:

定义视频流

视频流QoS Policy写入成功:

5.4实验总结

上述实验可证明本实验完成三个具体QoS策略:

1
2
3
A. 限制基于TCP流量或者其他流量来保障服务级别高的带宽。  
B. 直接保障基于TCP流量或者其他流量的带宽。  
C. 还可以借助Floodlight控制器对视频流进行单独区分并且保障其带宽。  

下面对本文的主要研究内容和成果做以下的总结:
(1)本文通过简要的分析OpenFlow和QoS技术,结合OpenFlow网络技术控制和转发分离的思想和对QoS服务质量系统性管理的缺乏,提出了一种适用于OpenFlow网络的QoS管理机制。
(2)通过开源软交换机上进行二次开发,实现基于 OpenFlow 协议的传统 DiffServ 模型流分类、标记和入队的流表控制机制,和基于HTB算法的队列管理和队列调度算法的流量控制机制。
(3)将控制器和交换机进行集中式控制分布式处理的方式进行部署,设计并实现了控制灵活、扩展性高的 QoS 系统。
创新点:设计并实现基于可编程网络流表控制QoS系统框架模型,限制基于TCP流量或者其他流量来保障服务级别高的带宽。直接保障基于TCP流量或者其他流量的带宽。还可以借助Floodlight控制器对视频流进行单独区分并且保障其带宽。
但该存在的不足是无法在Mininet上模拟视频流。控制平面缺乏对网络流量的实时监控和资源利用率等信息的采集,不能根据网络环境提供动态的 QoS 策略,缺乏自适应性,因此更加智能和自适应的 QoS 管理体系是下一步的主要研究方向。

附录
流量种类Map表:


public class TypeAliases {
    protected static final Map<String,String> l3TypeAliasMap = 
            new HashMap<String, String>();
    static {
        l3TypeAliasMap.put("0599", "L3_V1Ether");
        l3TypeAliasMap.put("0800", "L3_IPv4");
        l3TypeAliasMap.put("0806", "L3_ARP");
        l3TypeAliasMap.put("8035", "L3_RARP");
        l3TypeAliasMap.put("809b", "L3_AppleTalk");
        l3TypeAliasMap.put("80f3", "L3_AARP");
        l3TypeAliasMap.put("8100", "L3_802_1Q");
        l3TypeAliasMap.put("8137", "L3_Novell_IPX");
        l3TypeAliasMap.put("8138", "L3_Novell");
        l3TypeAliasMap.put("86dd", "L3_IPv6");
        l3TypeAliasMap.put("8847", "L3_MPLS_uni");
        l3TypeAliasMap.put("8848", "L3_MPLS_multi");
        l3TypeAliasMap.put("8863", "L3_PPPoE_DS");
        l3TypeAliasMap.put("8864", "L3_PPPoE_SS");
        l3TypeAliasMap.put("886f", "L3_MSFT_NLB");
        l3TypeAliasMap.put("8870", "L3_Jumbo");
        l3TypeAliasMap.put("889a", "L3_HyperSCSI");
        l3TypeAliasMap.put("88a2", "L3_ATA_Ethernet");
        l3TypeAliasMap.put("88a4", "L3_EtherCAT");
        l3TypeAliasMap.put("88a8", "L3_802_1ad");
        l3TypeAliasMap.put("88ab", "L3_Ether_Powerlink");
        l3TypeAliasMap.put("88cc", "L3_LLDP");
        l3TypeAliasMap.put("88cd", "L3_SERCOS_III");
        l3TypeAliasMap.put("88e5", "L3_802_1ae");
        l3TypeAliasMap.put("88f7", "L3_IEEE_1588");
        l3TypeAliasMap.put("8902", "L3_802_1ag_CFM");
        l3TypeAliasMap.put("8906", "L3_FCoE");
        l3TypeAliasMap.put("9000", "L3_Loop");
        l3TypeAliasMap.put("9100", "L3_Q_in_Q");
        l3TypeAliasMap.put("cafe", "L3_LLT");
    }    
    protected static final Map<String,String> l4TypeAliasMap = 
            new HashMap<String, String>();
    static {
        l4TypeAliasMap.put("00", "L4_HOPOPT");
        l4TypeAliasMap.put("01", "L4_ICMP");
        l4TypeAliasMap.put("02", "L4_IGAP_IGMP_RGMP");
        l4TypeAliasMap.put("03", "L4_GGP");
        l4TypeAliasMap.put("04", "L4_IP");
        l4TypeAliasMap.put("05", "L4_ST");
        l4TypeAliasMap.put("06", "L4_TCP");
        l4TypeAliasMap.put("07", "L4_UCL");
        l4TypeAliasMap.put("08", "L4_EGP");
        l4TypeAliasMap.put("09", "L4_IGRP");
        l4TypeAliasMap.put("0a", "L4_BBN");
        l4TypeAliasMap.put("0b", "L4_NVP");
        l4TypeAliasMap.put("0c", "L4_PUP");
        l4TypeAliasMap.put("0d", "L4_ARGUS");
        l4TypeAliasMap.put("0e", "L4_EMCON");
        l4TypeAliasMap.put("0f", "L4_XNET");
        l4TypeAliasMap.put("10", "L4_Chaos");
        l4TypeAliasMap.put("11", "L4_UDP");
        l4TypeAliasMap.put("12", "L4_TMux");
        l4TypeAliasMap.put("13", "L4_DCN");
        l4TypeAliasMap.put("14", "L4_HMP");
        l4TypeAliasMap.put("15", "L4_Packet_Radio");
        l4TypeAliasMap.put("16", "L4_XEROX_NS_IDP");
        l4TypeAliasMap.put("17", "L4_Trunk_1");
        l4TypeAliasMap.put("18", "L4_Trunk_2");
        l4TypeAliasMap.put("19", "L4_Leaf_1");
        l4TypeAliasMap.put("1a", "L4_Leaf_2");
        l4TypeAliasMap.put("1b", "L4_RDP");
        l4TypeAliasMap.put("1c", "L4_IRTP");
        l4TypeAliasMap.put("1d", "L4_ISO_TP4");
        l4TypeAliasMap.put("1e", "L4_NETBLT");
        l4TypeAliasMap.put("1f", "L4_MFE");
        l4TypeAliasMap.put("20", "L4_MERIT");
        l4TypeAliasMap.put("21", "L4_DCCP");
        l4TypeAliasMap.put("22", "L4_Third_Party_Connect");
        l4TypeAliasMap.put("23", "L4_IDPR");
        l4TypeAliasMap.put("24", "L4_XTP");
        l4TypeAliasMap.put("25", "L4_Datagram_Delivery");
        l4TypeAliasMap.put("26", "L4_IDPR");
        l4TypeAliasMap.put("27", "L4_TP");
        l4TypeAliasMap.put("28", "L4_ILTP");
        l4TypeAliasMap.put("29", "L4_IPv6_over_IPv4");
        l4TypeAliasMap.put("2a", "L4_SDRP");
        l4TypeAliasMap.put("2b", "L4_IPv6_RH");
        l4TypeAliasMap.put("2c", "L4_IPv6_FH");
        l4TypeAliasMap.put("2d", "L4_IDRP");
        l4TypeAliasMap.put("2e", "L4_RSVP");
        l4TypeAliasMap.put("2f", "L4_GRE");
        l4TypeAliasMap.put("30", "L4_DSR");
        l4TypeAliasMap.put("31", "L4_BNA");
        l4TypeAliasMap.put("32", "L4_ESP");
        l4TypeAliasMap.put("33", "L4_AH");
        l4TypeAliasMap.put("34", "L4_I_NLSP");
        l4TypeAliasMap.put("35", "L4_SWIPE");
        l4TypeAliasMap.put("36", "L4_NARP");
        l4TypeAliasMap.put("37", "L4_Minimal_Encapsulation");
        l4TypeAliasMap.put("38", "L4_TLSP");
        l4TypeAliasMap.put("39", "L4_SKIP");
        l4TypeAliasMap.put("3a", "L4_ICMPv6");
        l4TypeAliasMap.put("3b", "L4_IPv6_No_Next_Header");
        l4TypeAliasMap.put("3c", "L4_IPv6_Destination_Options");
        l4TypeAliasMap.put("3d", "L4_Any_host_IP");
        l4TypeAliasMap.put("3e", "L4_CFTP");
        l4TypeAliasMap.put("3f", "L4_Any_local");
        l4TypeAliasMap.put("40", "L4_SATNET");
        l4TypeAliasMap.put("41", "L4_Kryptolan");
        l4TypeAliasMap.put("42", "L4_MIT_RVDP");
        l4TypeAliasMap.put("43", "L4_Internet_Pluribus");
        l4TypeAliasMap.put("44", "L4_Distributed_FS");
        l4TypeAliasMap.put("45", "L4_SATNET");
        l4TypeAliasMap.put("46", "L4_VISA");
        l4TypeAliasMap.put("47", "L4_IP_Core");
        l4TypeAliasMap.put("4a", "L4_Wang_Span");
        l4TypeAliasMap.put("4b", "L4_Packet_Video");
        l4TypeAliasMap.put("4c", "L4_Backroom_SATNET");
        l4TypeAliasMap.put("4d", "L4_SUN_ND");
        l4TypeAliasMap.put("4e", "L4_WIDEBAND_Monitoring");
        l4TypeAliasMap.put("4f", "L4_WIDEBAND_EXPAK");
        l4TypeAliasMap.put("50", "L4_ISO_IP");
        l4TypeAliasMap.put("51", "L4_VMTP");
        l4TypeAliasMap.put("52", "L4_SECURE_VMTP");
        l4TypeAliasMap.put("53", "L4_VINES");
        l4TypeAliasMap.put("54", "L4_TTP");
        l4TypeAliasMap.put("55", "L4_NSFNET_IGP");
        l4TypeAliasMap.put("56", "L4_Dissimilar_GP");
        l4TypeAliasMap.put("57", "L4_TCF");
        l4TypeAliasMap.put("58", "L4_EIGRP");
        l4TypeAliasMap.put("59", "L4_OSPF");
        l4TypeAliasMap.put("5a", "L4_Sprite_RPC");
        l4TypeAliasMap.put("5b", "L4_Locus_ARP");
        l4TypeAliasMap.put("5c", "L4_MTP");
        l4TypeAliasMap.put("5d", "L4_AX");
        l4TypeAliasMap.put("5e", "L4_IP_within_IP");
        l4TypeAliasMap.put("5f", "L4_Mobile_ICP");
        l4TypeAliasMap.put("61", "L4_EtherIP");
        l4TypeAliasMap.put("62", "L4_Encapsulation_Header");
        l4TypeAliasMap.put("64", "L4_GMTP");
        l4TypeAliasMap.put("65", "L4_IFMP");
        l4TypeAliasMap.put("66", "L4_PNNI");
        l4TypeAliasMap.put("67", "L4_PIM");
        l4TypeAliasMap.put("68", "L4_ARIS");
        l4TypeAliasMap.put("69", "L4_SCPS");
        l4TypeAliasMap.put("6a", "L4_QNX");
        l4TypeAliasMap.put("6b", "L4_Active_Networks");
        l4TypeAliasMap.put("6c", "L4_IPPCP");
        l4TypeAliasMap.put("6d", "L4_SNP");
        l4TypeAliasMap.put("6e", "L4_Compaq_Peer_Protocol");
        l4TypeAliasMap.put("6f", "L4_IPX_in_IP");
        l4TypeAliasMap.put("70", "L4_VRRP");
        l4TypeAliasMap.put("71", "L4_PGM");
        l4TypeAliasMap.put("72", "L4_0_hop");
        l4TypeAliasMap.put("73", "L4_L2TP");
        l4TypeAliasMap.put("74", "L4_DDX");
        l4TypeAliasMap.put("75", "L4_IATP");
        l4TypeAliasMap.put("76", "L4_ST");
        l4TypeAliasMap.put("77", "L4_SRP");
        l4TypeAliasMap.put("78", "L4_UTI");
        l4TypeAliasMap.put("79", "L4_SMP");
        l4TypeAliasMap.put("7a", "L4_SM");
        l4TypeAliasMap.put("7b", "L4_PTP");
        l4TypeAliasMap.put("7c", "L4_ISIS");
        l4TypeAliasMap.put("7d", "L4_FIRE");
        l4TypeAliasMap.put("7e", "L4_CRTP");
        l4TypeAliasMap.put("7f", "L4_CRUDP");
        l4TypeAliasMap.put("80", "L4_SSCOPMCE");
        l4TypeAliasMap.put("81", "L4_IPLT");
        l4TypeAliasMap.put("82", "L4_SPS");
        l4TypeAliasMap.put("83", "L4_PIPE");
        l4TypeAliasMap.put("84", "L4_SCTP");
        l4TypeAliasMap.put("85", "L4_Fibre_Channel");
        l4TypeAliasMap.put("86", "L4_RSVP_E2E_IGNORE");
        l4TypeAliasMap.put("87", "L4_Mobility_Header");
        l4TypeAliasMap.put("88", "L4_UDP_Lite");
        l4TypeAliasMap.put("89", "L4_MPLS");
        l4TypeAliasMap.put("8a", "L4_MANET");
        l4TypeAliasMap.put("8b", "L4_HIP");
        l4TypeAliasMap.put("8c", "L4_Shim6");
        l4TypeAliasMap.put("8d", "L4_WESP");
        l4TypeAliasMap.put("8e", "L4_ROHC");
    }
}

Floodlight官网提供的视频

FitVids.

Code可以参考这里:
Github