1.概述
SR-IOV全称Single Root I/O Virtualization,是Intel在2007年提出的一种基于硬件的虚拟化解决方案。
在虚拟化场景中,CPU与内存是最先解决的,但是I/O设备一直没有很好的解决办法,Intel有VT-d(Virtualization Technology for Directed I/O)可以将物理服务器的PCIe设备直接提供给虚拟机使用,也就是常说的“直通”(passthrough),但是直通面临一个问题是PCIe设备只能给一个虚拟机使用,这肯定是不行的,所以SR-IOV应运而生,一个物理设备可以虚拟出多个虚拟设备给虚拟机使用。
SR-IOV是一种规范,使得单根端口下的单个快速外围组件互连 (PCIe) 物理设备显示为管理程序或客户机操作系统的多个单独的物理设备,既有直通设备的性能优势,又可以支持多个虚拟机,一举两得。
2.基本概念
SR-IOV使用physical functions(PF)和virtual functions(VF)为SR-IOV设备管理全局功能。
PF包含SR-IOV功能的完整PCIe设备,PF作为普通的PCIe设备被发现、管理和配置。PF通过分配VF来配置和管理SR-IOV功能。禁用SR-IOV后,主机将在一个物理网卡上创建一个PF。
VF是轻量级PCIe功能(I/O 处理)的PCIe设备,每个VF都是通过PF来生成管理的,VF的具体数量限制受限于PCIe设备自身配置及驱动程序的支持,启用SR-IOV后,主机将在一个物理NIC上创建单个PF和多个VF。 VF的数量取决于配置和驱动程序支持。
每个SR-IOV设备都可有一个PF(Physical Functions),并且每个PF最多可有64,000个与其关联的VF(Virtual Function)。PF可以通过寄存器创建VF,这些寄存器设计有专用于此目的的属性。一旦在PF中启用了SR-IOV,就可以通过PF的总线、设备和功能编号(路由ID)访问各个VF的PCI配置空间。
每个VF都具有一个PCI内存空间,用于映射其寄存器集。VF设备驱动程序对寄存器集进行操作以启用其功能,并且显示为实际存在的PCI设备。创建VF 后,可以直接将其指定给虚拟机或各个应用程序。此功能使得虚拟功能可以共享物理设备,并在没有CPU和虚拟机管理程序软件开销的情况下执行I/O。
3.先决条件
PCIe Passthrough的方式是直接把一个PCIe设备指派给guest虚拟机,这样guest虚拟机可以完全控制设备并提供接近于原生性能。但是,PCIe passthrough的实现是和SR-IOV冲突的,因为在SR-IOV实现中,虚拟机是直接分配一个VF 。这样多个虚拟机可以通过分配的VF来使用同一个PCIe设备。
设备指定分配需要CPU和firmware都支持IOMMU(I/O Memory Management Unit)。IOMMU负责I/O虚拟地址(I/O Virtual Address)和物理内存地址转换。这样虚拟机就能够使用guest物理地址来对设备编程,通过IOMMU转换成物理主机内存地址。
IOMMU groups是一组和系统中其他设备隔离的设备集合。也就是说,IOMMU groups代表了具有IOMMU粒度(也就是必须将整个IOMMU group分配给同一个虚拟机)和与系统中所有其他IOMMU group隔离。这种方式允许IOMMU和其他IOMMU group区别进行数据处理,即IOMMU group的内部和外部隔离。
设备分配的关键是虚拟机和PCIe设备虚拟化功能(virtual functions, VFs)隔离数据处理。在PCIe和服务器标准定义的访问控制服务(Access Control Service, ACS)能力是保证IOMMU groups隔离的运行标准。如果没有原生的ACS,或者不能确保硬件厂商提供该能力,则会破坏IOMMU的保护功能导致暴露点对点(peer-to-peer)DMA。
原生ACS支持在服务器的root ports也是建议,否则会导致安装设备被一股脑分组打包。有两种root ports:基于处理器(北桥)root ports和基于控制器hub(南桥) root ports。
总结一下就是:
1.CPU必须支持IOMMU(例如VT-d或AMD-Vi)。
2.Firmware必须支持IOMMU。
3.CPU root ports必须支持ACS或等同ACS能力。
4.建议所有位于PCIe设备和root ports之间的PCIe switches 和 bridges 都支持ACS。例如,如果switch不支持ACS,则所有这个Swtich之后的设备都会共享一个相同的IOMMU group,也就只能分配给一个虚拟机了。
4.OpenStack SR-IOV的安装配置
为了启用SR-IOV,需要执行以下步骤:
1.计算节点上创建VF。
2.计算节点配置nova-compute的PCI设备。
3.控制节点配置neutron-server。
4.控制节点配置nova-scheduler。
5.计算节点上启动neutron-sriov-agent。
4.1计算节点上创建VF
1.确保BIOS中开启了SR-IOV和IOMMU(arm环境下叫SMMU)。
2.开启linux内核中的IOMMU功能:
# 编辑/etc/default/grub文件
GRUB_CMDLINE_LINUX_DEFAULT="intel_iommu=on iommu=pt"
# ARM环境下为
GRUB_CMDLINE_LINUX_DEFAULT="iommu.passthrough=on iommu=pt"
生成新的内核启动文件:
grub2-mkconfig -o /boot/grub2/grub.cfg
3.在计算节点查看对应网卡的最大VF的个数:
at /sys/class/net/enp49s0f1/device/sriov_totalvfs
7
其中enp49s0f1是网卡名称,可以看到最大支持7个VF,之后配置的个数不能超过这个值。
4.设置网卡的VF个数:
echo '7' > /sys/class/net/enp49s0f1/device/sriov_numvfs
可以同ip命令查看网络设备如下:
ip a | grep enp49s0f1
3: enp49s0f1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
34: enp49s0f1v0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
35: enp49s0f1v1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
36: enp49s0f1v2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
37: enp49s0f1v3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
38: enp49s0f1v4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
40: enp49s0f1v6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
45: enp49s0f1v5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
使用lspci查看网卡pci设备:
spci -D | grep Ethernet
0000:31:00.0 Ethernet controller: Intel Corporation I350 Gigabit Network Connection (rev 01)
0000:31:00.1 Ethernet controller: Intel Corporation I350 Gigabit Network Connection (rev 01)
0000:31:10.1 Ethernet controller: Intel Corporation I350 Ethernet Controller Virtual Function (rev 01)
0000:31:10.5 Ethernet controller: Intel Corporation I350 Ethernet Controller Virtual Function (rev 01)
0000:31:11.1 Ethernet controller: Intel Corporation I350 Ethernet Controller Virtual Function (rev 01)
0000:31:11.5 Ethernet controller: Intel Corporation I350 Ethernet Controller Virtual Function (rev 01)
0000:31:12.1 Ethernet controller: Intel Corporation I350 Ethernet Controller Virtual Function (rev 01)
0000:31:12.5 Ethernet controller: Intel Corporation I350 Ethernet Controller Virtual Function (rev 01)
0000:31:13.1 Ethernet controller: Intel Corporation I350 Ethernet Controller Virtual Function (rev 01)
5.设置VF持久化:
echo "echo '7' > /sys/class/net/enp49s0f1/device/sriov_numvfs" >> /etc/rc.local
4.2计算节点配置PCI设备
编辑nova-compute服务的配置文件nova.conf,一般为/etc/nova/nova.conf:
[pci]
passthrough_whitelist = { "address": "[[[[<domain>]:]<bus>]:][<slot>][.[<function>]]", "physical_network": "sriovnet1" }
根据上面lspci的结果可以配置如下的pci设备:
[pci]
passthrough_whitelist = [{"physical_network": "sriovnet1", "address": "*:31:12.*"}]
其中*通配符匹配所有字符,所以地址为0000:31:12.1和0000:31:12.5的两个pci设备会被匹配。
4.3控制节点配置neutron-server
编辑neutron-server的配置文件ml2_conf.ini,一般为/etc/neutron/plugins/ml2/ml2_conf.ini。
添加驱动sriovnicswitch:
[ml2]
mechanism_drivers = openvswitch,sriovnicswitch
修改vlan范围:
[ml2_type_vlan]
network_vlan_ranges = sriovnet1
最后重启neutron-server:
systemctl restart neutron-server
4.4控制节点配置nova-scheduler
编辑nova-sheduler服务的配置文件nova.conf,一般为/etc/nova/nova.conf。
确保available_filters是全部的filters,并且添加PciPassthroughFilter到enabled_filters中。
[filter_scheduler]
available_filters = nova.scheduler.filters.all_filters
enabled_filters = AvailabilityZoneFilter, ComputeFilter, ComputeCapabilitiesFilter, ImagePropertiesFilter, ServerGroupAntiAffinityFilter, ServerGroupAffinityFilter, PciPassthroughFilter
最后重启nova-scheduler:
systemctl restart openstack-nova-scheduler
4.5计算节点上启动neutron-sriov-agent
1.安装neutron-sriov-agent
yum install -y openstack-neutron-sriov-nic-agent
编辑neutron-sriov-nic-agent的配置文件,一般为/etc/neutron/plugins/ml2/sriov_agent.ini
[sriov_nic]
physical_device_mappings = sriovnet1:enp49s0f1
exclude_devices =
[securitygroup]
firewall_driver = neutron.agent.firewall.NoopFirewallDriver
启动neutron-sriov-agent:
systemctl enable neutron-sriov-nic-agent
systemctl start neutron-sriov-nic-agent
4.6打开L2 FDB(可选)
FDB(Forwarding DataBase)是对OVS agent或Linux agent的L2层agent的扩展。它的目的是更新使用普通端口(Port)的现有实例的FDB表,这使SR-IOV实例与正常实例之间的沟通成为了可能。FDB扩展的用例是:
1.直接端口(direct port)和普通端口(normal port)实例位于同一计算节点上。
2.使用浮动IP地址的直接端口(direct port)实例和网络节点位于同一宿主机上。
编辑计算节点上的openvswitch_agent.ini或者linuxbridge_agent.ini
[agent]
extensions = fdb
[FDB]
shared_physical_device_mappings = sriovnet1:enp49s0f1
重启neutron-openvswitch-agent或者neutron-linuxbridge-agent服务。
4.7验证
1.查看neutron-sriov-nic-agent服务的状态
openstack network agent list --agent-type nic
2.创建sriov网络
openstack network create --provider-physical-network sriovnet1 \
--provider-network-type vlan --provider-segment 1000 \
sriov-net
3.创建sriov子网
openstack subnet create --network sriov-net \
--subnet-range 10.12.21.0/24 \
--allocation-pool start=10.12.21.131,end=10.12.21.132 \
sriov-subnet
4.创建port
openstack port create --network sriov-net --vnic-type direct \
sriov-port
5.使用port创建实例
port_id=$(openstack port show sriov-port -c id -f value)
openstack server create --flavor m1.large \
--image uniontechos-server-20-1060a-amd64-beta \
--nic port-id=$port_id \
test
或者添加到已有实例上
openstack server add port test $port_id
进入实例内部查看
查看网卡设备的信息,可以看到ens4网卡的驱动为igbvf,说明透传成功
4.8出现的问题
1.创建实例或者添加port时nova-compute报错。
attach device xml: <interface type="hostdev" managed="yes">
<mac address="fa:16:3e:fe:47:d2"/>
<source>
<address type="pci" domain="0x0000" bus="0x0b" slot="0x10" function="0x5"/>
</source>
<vlan>
<tag id="1000"/>
</vlan>
</interface>
attach_device /usr/lib/python3.6/site-packages/nova/virt/libvirt/guest.py:304
attaching network adapter failed.: libvirt.libvirtError: 内部错误:无法执行 QEMU 命令 'device_add':vfio 0000:0b:10.5: group 3 is not viable
这是因为IOMMU给内存创建隔离区的最小粒度不是Device,而是group。需要硬件设备支持PCIe ACS,或者通过Linux Patch的方式获得PCIe ACS的能力。
2.创建完实例后实例获取不到IP地址。
因为创建sriov-net是基于物理网络设备的,所以需要物理网络中存在DHCP服务器,可以手动进行IP地址的配置。
3.创建完实例后,IP访问失败。
创建的sriov网络类型是vlan,流量从实例中流出的时候会打上对应的vlan tag导致IP访问失败。其中vlan tag的作用用于隔离Provider网络,这样可以在同一网络下连接无sriov port的实例和带有sriov port的实例。
5.总结
SR-IOV的优缺点
5.1.优点
1.性能好,可以从虚拟机直接访问宿主机的硬件,同时提高包的转发率,低延迟,减少主机CPU消耗。
2.比PCI直通的方式更加灵活,成本降低节省资本和运营开销。
3.通过IOMMU实现隔离更安全。
5.2.缺点
1.使用SR-IOV时,不支持防火墙,需要在neutron的配置文件中关闭。
2.宿主机无法监控VF的状态。
3.SR-IOV不支持vxlan。
4.需要硬件支持。
5.3.其他
1.Train版本后支持了SR-IOV实例的热迁移。
2.indirect模式(vnic-type: macvtap或virtio-forwarder)的SR-IOV Port可以透明地迁移到虚拟机,direct模式(vnic-type: direct或direct-physical)下的SR-IOV Port在迁移前预先分离,迁移完成后再进行连接,这对用户来说是不透明的。为了避免在使用direct模式SR-IOV进行热迁移时失去网络连接,用户应在实例中创建故障转移bond,例如vnic类型的normal或indirect模式的SR-IOV的Port。
3.Victoria版本之后支持向已有实例添加SR-IOV的Port。