相关技术
IO虚拟化简介
全虚拟化
通过VMM来模拟IO设备实现,VMM截获GuestOS的IO请求,通过软件模拟真实的硬件。VMM必须处理所有虚机的IO请求,然后将所有的IO情况序列化为可以被底层硬件处理的单一IO流。好处是GuestOS不需要考虑硬件设备的情况。问题是效率相对较低。例如 qemu。
一个完整的数据包从虚拟机到物理机的路径是:虚拟机--QEMU虚拟网卡--虚拟化层--内核网桥--物理网卡。
半虚拟化
通过前端和后端模拟实现虚拟化。GuestOS中的半虚拟化驱动为前端,VMM 提供的与GuestOS 通讯的驱动程序为后端。前端驱动将GuestOS的请求通过与VMM之间的特殊通信机制发生给VMM后端需求,后端驱动处理完IO请求之后再发送给物理驱动。全虚拟化为了完成一次操作要涉及到多个寄存器的操作,使得VMM要截获每个寄存器访问并进行相应的模拟,就会导致多次上下文切换。这种方式能很大程度的减少上下文切换的频率,提供更大的优化空间。例如 virtio 。
全虚拟化网卡是虚拟化层完全模拟出来的网卡,半虚拟化网卡通过驱动对操作系统做了改造;
软件的共享IO虚拟化技术
硬件辅助的IO虚拟化主要包括英特尔VT-d, AMD的IOMMU(AMD-Vi)和PCI-SIG 的SR-IOV。前两种属于Directed I/O。物理设备直接分配给虚拟机使用,通过硬件芯片完成GPA到MA 的翻译。IOV 通过在硬件设备中增加一个PCIe 设备,用于呈现一个PF或多个VF,从而可以将每个VF单独分配给不同的虚机使用。
SR-IOV简介
SR-IOV 技术是一种基于硬件的虚拟化解决方案,可提高性能和可伸缩性。SR-IOV 标准将一个PCIe的网络控制器虚拟化成多个PCIe设备,并且每个设备可以直接分配给一个虚拟机,允许在虚拟机之间高效共享 PCIe(Peripheral Component Interconnect Express,快速外设组件互连)设备,并且它是在硬件中实现的,可以获得能够与本机性能媲美的 I/O 性能。SR-IOV 规范定义了新的标准,根据该标准,创建的新设备可允许将虚拟机直接连接到 I/O 设备,越过了hypervisor与虚拟交换机层,这样可以带来低延迟和接近线缆的速度。SR-IOV 规范由 PCI-SIG 在 http://www.pcisig.com上进行定义和维护。单个 I/O 资源可由许多虚拟机共享。共享的设备将提供专用的资源,并且还使用共享的通用资源。这样,每个虚拟机都可访问唯一的资源。因此,启用了 SR-IOV 并且具有适当的硬件和 OS 支持的 PCIe 设备(例如以太网端口)可以显示为多个单独的物理设备,每个都具有自己的 PCIe 配置空间。
SR-IOV 是PCI-SIG的一个IOV的规范,目的是提供一种标准规范,通过为虚拟机提供独立的内存空间,中断,DMA流,来绕过VMM实现数据移动。SR-IOV 架构被设计用于将单个设备通过支持多个VF,并减少硬件的开销。
SR-IOV 两种功能(function):
物理功能(Physical Functions,PF):包含完整的PCIe 功能,包括SR-IOV的扩张能力,该功能用于SR-IOV的配置和管理。PF 能像普通 PCI 设备那样被发现、管理和配置。
虚拟功能(Virtual Functions,VF):包含轻量级的PCIe 功能,它只能处理I/O, 包含数据移动所需要的最小的必要的资源。每个 VF 都是从 PF 中分离出来的。每个物理硬件都有一个 VF 数目的限制。一个 PF,能被虚拟成多个 VF 用于分配给多个虚拟机。
一旦在 PF 中启用了 SR-IOV,就可以通过 PF 的总线、设备和功能编号(路由 ID)访问各个 VF 的 PCI 配置空间。每个 VF 都具有一个 PCI 内存空间,用于映射其寄存器集。VF 设备驱动程序对寄存器集进行操作以启用其功能,并且显示为实际存在的 PCI 设备。创建 VF 后,可以直接将其指定给 IO 来宾域或各个应用程序(如裸机平台上的 Oracle Solaris Zones)。此功能使得虚拟功能可以共享物理设备,并在没有 CPU 和虚拟机管理程序软件开销的情况下执行 I/O。
支持SR-IOV的以太网适配器和控制器
详细清单参考:
https://www.intel.cn/content/www/cn/zh/support/network-and-i-o/ethernet-products/000005722.html;
SR-IOV的优点
SR-IOV 标准允许在 IO 来宾域之间高效共享 PCIe 设备。SR-IOV 设备可以具有数百个与某个物理功能 (Physical Function, PF) 关联的虚拟功能 (Virtual Function, VF)。VF的创建可由PF通过设计用来开启SR-IOV功能的寄存器以动态方式进行控制。缺省情况下,SR-IOV 功能处于禁用状态,PF 充当传统 PCIe 设备。
性能提升(从虚拟机环境直接访问硬件),成本降低(节能、减少了适配器的数量、简化了布线、减少了交换机端口)。
SR-IOV适用的场景
KVM虚拟机在传统网桥模式下,网络稳定是没有问题的,但它和SR-IOV一个本质的区别是,网桥模式本身会消耗宿主机的CPU,在实际场景下,当宿主机的CPU压力(>60%)比较大时,虚拟机内部网卡的发包率(PPS)性能会下降,极端情况会出现丢包。SR-IOV最适合的应用场景:
1. 宿主机CPU压力大(>60%)+虚拟机网卡发包率压力大(pps >5w)
2. 虚拟机网卡发包率压力非常大(pps>10w)
KVM虚拟机中使用SR-IOV
硬件与软件需求
硬件需求
1. CPU必须支持IOMMU(比如英特尔的 VT-d 或者AMD的 AMD-Vi,Power8 处理器默认支持IOMMU),并且在BIOS中已开启。支持PCI-SIG* Single Root I/O Virtualization and Sharing(SR-IOV),并且在BIOS中已开启。
2. 支持SR-IOV的网卡必须插在总线带宽X8以上的扩展槽中。
软件需求
1. VF驱动程序必须与物理网卡兼容,必须安装在虚拟机操作系统内
2. 宿主机安装PF驱动程序
安装kvm等软件包
查看系统是否支持虚拟化
查看系统是否支持虚拟化,egrep -c '(vmx|svm)' /proc/cpuinfo
大于1表示开启了,等于0表示没开启,如果没开启则需要在BIOS中开启intel VT-d
安装软件包
yum install -y kvm virt-* libvirt bridge-utils qemu-img
kvm:软件包中含有KVM内核模块,它在默认linux内核中提供kvm管理程序
libvirts:安装虚拟机管理工具,使用virsh等命令来管理和控制虚拟机。
bridge-utils:设置网络网卡桥接。
virt-*:创建、克隆虚拟机命令,以及图形化管理工具virt-manager
qemu-img:安装qemu组件,使用qemu命令来创建磁盘等。
查看kvm模块是否被加载
查看kvm模块是否被加载lsmod |grep kvm,如果有信息,则表示加载成功。
启动libvirtd
systemctl start libvirtd.service
开启SR-IOV功能
开启IOMMU功能
Centos系统默认没有启动IOMMU功能,在/etc/default/grub文件的GRUB_CMDLINE_LINUX后面添加intel_iommu=on
更新grub,grub2-mkconfig -o /boot/grub2/grub.cfg
重启机器生效,检测是否生效 sudo virt-host-validate
上图表示iommu没有开启,下图表示iommu已经启用。
检测igb模块是否被加载
检测igb模块是否被加载,lsmod | grep igb
如果没有则加载igb,modprobe igb
创建网卡的虚拟功能(VF)
创建网卡的虚拟功能,echo '7' > /sys/class/net/{eth}/device/sriov_numvfs,并检查lspci|grep Ethernet。机器重启后,创建的虚拟虚拟功能失效,需要重新创建,可以将其写在启动脚本中。
创建kvm虚拟机并挂载VF
查询pci设备
virsh nodedev-list | grep 02
pci_0000_02_00_1是PF,pci_0000_02_10_0到pci_0000_02_13_0是VF,使用virsh nodedev-dumpxml pci_0000_02_10_0查看详细信息
将VF从宿主机中解绑
将VF从宿主机中解绑,这样虚拟机才可以使用此VF。virsh nodedev-dettach pci_0000_0b_10_0。
创建虚拟机
创建domain.xml,使用之前解绑的VF
<domain type = 'kvm'> //虚拟机类型,kvm
<name>demo</name> //虚拟机名称
<memory>1048576</memory> //分配内存,单位kb
<vcpu>1</vcpu> //分配vcpu,单位个数
<os>
<type arch = 'x86_64' machine = 'pc'>hvm</type>
<boot dev = 'cdrom'/> //cd 启动
<boot dev = 'hd'/> //硬盘启动
</os>
<features>
<acpi/>
<apic/>
<pae/>
</features>
<clock offset = 'localtime'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<devices>
<emulator>/usr/libexec/qemu-kvm</emulator>
<disk type = 'file' device = 'disk'> //对应的镜像,就是之前使用qemu-img命令新建的img文件,注意路径要正确
<driver name = 'qemu' type = 'qcow2'/>
<source file = '/root/cirros.img'/>
<target dev = 'hda' bus = 'ide'/>
</disk>
<input type ='tablet' bus='usb'/>
<input type = 'mouse' bus = 'ps2'/>
<graphics type = 'vnc' port = '6666' listen = '0.0.0.0' autoport = 'no' keymap = 'en-us'/> //vnc端口系统自动配置
<hostdev mode='subsystem' type='pci' managed='yes'>
<source>
<address domain=’0x0000′ bus='0x02' slot='0x10' function='0x00'/>//对应pci中的信息
</source>
</hostdev>
</devices>
</domain>
定义虚拟机virsh define demo.xml
启动虚拟机virsh start demo
添加pci_passthrough_whitelist
编辑/etc/nova/nova.conf文件
[default]
pci_passthrough_whitelist = { "devname": "eth3", "physical_network": "physnet2"}
该配置表示属于eth3的所有VF可以直通到虚拟机,并且这些VF属于physnet2 网络(physnet2是一个Provider网络)。如果pci_passthrough_whitelist使用pci地址或者devname配置,则PF与所有的VF将会被匹配。此外,可以根据domain、bus、slot、vendor_id、product_id等设置VF白名单(这些属性可以使用virsh nodedev-dumpxml获得)。
pci_passthrough_whitelist = { "address": "[[[[<domain>]:]<bus>]:][<slot>][.[<function>]]", "physical_network": "physnet2" }
pci_passthrough_whitelist = { "address": "*:0a:00.*", "physical_network": "physnet2" }
pci_passthrough_whitelist = { "vendor_id": "<id>", "product_id": "<id>", "physical_network": "physnet2" }
重启nova-compute服务
安装SR-IOV agent
编辑/etc/neutron/plugins/ml2/sriov_agent.ini文件
[securitygroup]
firewall_driver = neutron.agent.firewall.NoopFirewallDriver
[sriov_nic]
physical_device_mappings = physnet2:eth3,pysnet2:eth4
exclude_devices = eth1:0000:07:00.2;0000:07:00.3,eth2:0000:05:00.1;0000:05:00.2
physical_device_mappings表示provider network与网卡的映射关系,exclude_devices表示不使用的VF
启动sriov-agent
# neutron-sriov-nic-agent \
--config-file /etc/neutron/neutron.conf \
--config-file /etc/neutron/plugins/ml2/sriov_agent.ini
配置控制节点
配置mechanism_drivers
编辑/etc/neutron/plugins/ml2/ml2_conf.ini
mechanism_drivers = openvswitch, sriovnicswitch
..
flat_networks = provider,physnet2
添加ml2_conf_sriov.ini文件到neutron-server的启动脚本中
--config-file /etc/neutron/neutron.conf
--config-file /etc/neutron/plugin.ini
--config-file /etc/neutron/plugins/ml2/ml2_conf_sriov.ini
重启neutron-server
配置nova-scheduler
编辑/etc/nova/nova.conf
[DEFAULT]
scheduler_default_filters = RetryFilter, AvailabilityZoneFilter, RamFilter, ComputeFilter, ComputeCapabilitiesFilter, ImagePropertiesFilter, ServerGroupAntiAffinityFilter, ServerGroupAffinityFilter, PciPassthroughFilter
scheduler_available_filters = nova.scheduler.filters.all_filters
重启nova-scheduler
创建使用SR-IOV网卡的虚拟机
创建provider的网络,类型可以是flat或者vlan
openstack network create --project admin --external --provider-network-type flat --provider-physical-network physnet2 sriovnet
创建虚拟机
net_id=`neutron net-show sriovnet | grep "\ id\ " | awk '{ print $4 }'`
port_id=`neutron port-create $net_id --name sriov_port --binding:vnic_type direct | grep "\ id\ " | awk '{ print $4 }'`
nova boot --flavor m1.large --image ubuntu_14.04 --nic port-id=$port_id test-sriov
Openstack环境中使用SR-IOV的局限及碰到的问题
不支持热迁移,只支持冷迁移
冷迁移已经在newton中实现,可以参考https://bugs.launchpad.net/nova/+bug/1512880;热迁移目前还不支持,可以参考https://blueprints.launchpad.net/nova/+spec/sriov-live-migration。
不支持安全组
不支持tunnel
性能测试
创建两台SR-IOV的虚拟机,使用iperf测试互通的性能。可以看出使用SR-IOV的虚拟机的网络带宽接近物理速度。