第 20 章 SR-IOV 对虚拟网络的支持

从 RHEL OpenStack Platform 6 开始,扩展了SR-IOV(single root I/O virtualization - 单引导 I/O 虚拟化)对虚拟机网络的支持。这意味着,OpenStack 可以不再需要虚拟网桥,而是把物理 NIC 的功能直接扩展到实例中。另外,通过对 IEEE 802.1br 的支持,虚拟 NIC 可以与物理交换机进行集成,并由它进行管理。

20.1. 在 RHEL OpenStack Platform 中配置 SR-IOV

本章包含配置 SR-IOV 以将物理 NIC 传递到虚拟实例的过程。这些步骤假设系统包括了一个 Controller 节点、一个 OpenStack Networking(neutron) 节点和多个 Compute(nova)节点。

请注意:当已存在了适当的 L2 配置(例如,flat 或 VLAN),使用 SR-IOV 端口的实例与使用普通端口(如连接到 Open vSwitch 网桥)的实例间就可以彼此进行通讯。当前,在相同 Compute 节点上的使用 SR-IOV 端口的实例与使用普通 vSwitch 端口的实例间的通讯有一个限制:如果它们在网卡上共享相同的 PF(Physical Function),则无法进行通讯。

20.2. 在 Compute 节点上创建虚拟功能

在带有支持硬件的所有 Compute 节点上执行这些步骤。

注意: 如需了解更多所支持硬件的信息,请参阅相关文档

这个步骤会配置一个系统来传递一个 Intel 82576 网络设备。同时,虚拟功能(Virtual Functions)也会被创建,实例可以使用它们来进行 SR-IOV 到设备的访问。

1. 确认 Intel VT-dAMD IOMMU 已在系统的 BIOS 中启用。请参阅机器的 BIOS 配置菜单,或其它相关信息。

2. 确保在操作系统中启用 Intel VT-dAMD IOMMU

  • 对于 Intel VT-d 系统,请参阅这里
  • 对于 AMD IOMMU 系统,请参阅这里

3. 运行 lspci 命令确保网络设备可以被系统识别:

[root@compute ~]# lspci | grep 82576

网络设备包括在结果中:

03:00.0 Ethernet controller: Intel Corporation 82576 Gigabit Network Connection (rev 01)
03:00.1 Ethernet controller: Intel Corporation 82576 Gigabit Network Connection (rev 01)

4. 执行以下步骤来在 Compute 节点上激活 Virtual Functions:

4a.删除内核模块。在下一步中会对模块进行重新配置:

[root@compute ~]# modprobe -r igb

请注意:在第 4 步中,需要使用支持 SRIOV 的 NIC 所使用的模块,而不是使用其它 NIC 的 igb(如 ixgbemlx4_core)。运行 ethtool 命令来确认驱动。在这个例子中,em1 是我们需要使用的 PF(Physical Function):

[root@compute ~]# ethtool -i em1 | grep ^driver

4b. 启动模块时 max_vfs 的值为 7(或不多于被支持的最多数量)。

[root@compute ~]# modprobe igb max_vfs=7

4c. 使 Virtual Functions 有持久性:

[root@compute ~]# echo "options igb max_vfs=7" >>/etc/modprobe.d/igb.conf

请注意: 对于 Red Hat Enterprise Linux 7,为了使配置具有持久性,在进行完第 4 步后根据 rebuild the initial ramdisk image 中介绍的内容进行相关操作。

请注意:4c.4d. 中进行的设置持久性如下:modprobe 命令在使用相同内核模块的所有 NIC 上启用 Virtual Function,并在系统重新引导后仍然可以保持这个设置。虽然可以只在特定 NIC 上启用 VF,但这可能会造成一些问题。例如,使用以下命令来在 enp4s0f1 接口上启用 VF:

# echo 7 > /sys/class/net/enp4s0f1/device/sriov_numvfs

当系统重启后,这个设备将不会被保留。解决这个问题的一个方法是,把这个设置添加到 rc.local 中,但这个方法仍然有以下限制:

# chmod +x /etc/rc.d/rc.local
# echo "echo 7 > /sys/class/net/enp4s0f1/device/sriov_numvfs" >> /etc/rc.local

请注意:因为额外的 systemd,Red Hat Enterprise Linux 将会并行启动服务,而不是依次启动它们。这意味着,rc.local 在引导过程中被执行的位置是不固定的。因此,一些不可预见的情况可能会出现,我们不推荐使用这个方法。

4d.intel_iommu=ptigb.max_vfs=7 参数添加到内核命令行来在内核中激活 Intel VT-d。如果您希望一直使用这个方式引导内核,可以修改当前的设置;或者,您可以创建一个带有这些参数的自定义菜单,这样,您的系统就可以在默认情况下以这种方式启动,并且可以在需要时,不使用这些参数启动内核。

要修改当前内核命令行参数,运行以下命令:

[root@compute ~]# grubby --update-kernel=ALL --args="intel_iommu=pt igb.max_vfs=7"

如需了解更多使用 grubby 的信息,请参阅系统管理指南中的 Configuring GRUB 2 Using the grubby Tool

请注意:如果使用 Dell Power Edge R630 节点,则需要使用 intel_iommu=on 而不是 intel_iommu=pt。您可以通过 grubby 启用它:

# grubby --update-kernel=ALL --args="intel_iommu=on"

创建一个自定义菜单项:

i.grub 中找到默认的项:

[root@compute ~]# grub2-editenv list
saved_entry=Red Hat Enterprise Linux Server (3.10.0-123.9.2.el7.x86_64) 7.0 (Maipo)

ii. a. 把所需的 menuentry 项的内容(以 "menuentry" 开始,以 "}" 结束。它在开始部分包括了前一步命令显示的 saved_entry 的值)从 /boot/grub2/grub.cfg 复制到 /etc/grub.d/40_customb.menuentry 后修改标题 c. 在以 linux16 开始的行的最后添加 intel_iommu=on

例如:

menuentry 'Red Hat Enterprise Linux Server, with Linux 3.10.0-123.el7.x86_64 - SRIOV' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-123.el7.x86_64-advanced-4718717c-73ad-4f5f-800f-f415adfccd01' {
    load_video
    set gfxpayload=keep
    insmod gzio
    insmod part_msdos
    insmod ext2
    set root='hd0,msdos2'
    if [ x$feature_platform_search_hint = xy ]; then
      search --no-floppy --fs-uuid --set=root --hint-bios=hd0,msdos2 --hint-efi=hd0,msdos2 --hint-baremetal=ahci0,msdos2 --hint='hd0,msdos2'  5edd1db4-1ebc-465c-8212-552a9c97456e
    else
      search --no-floppy --fs-uuid --set=root 5edd1db4-1ebc-465c-8212-552a9c97456e
    fi
    linux16 /vmlinuz-3.10.0-123.el7.x86_64 root=UUID=4718717c-73ad-4f5f-800f-f415adfccd01 ro vconsole.font=latarcyrheb-sun16 biosdevname=0 crashkernel=auto  vconsole.keymap=us nofb console=ttyS0,115200 LANG=en_US.UTF-8 intel_iommu=pt igb.max_vfs=7
    initrd16 /initramfs-3.10.0-123.el7.x86_64.img
}

iii. 更新 grub.cfg 以使配置文件中的修改生效:

[root@compute ~]# grub2-mkconfig -o /boot/grub2/grub.cfg

iv. 修改默认的项:

[root@compute ~]# grub2-set-default 'Red Hat Enterprise Linux Server, with Linux 3.10.0-123.el7.x86_64 - SRIOV'

v. 创建 dist.conf 配置文件。

请注意:在执行这个步骤前,请重新查看描述 allow_unsafe_interrupts 的段落:检查 allow_unsafe_interrupts 的设置

[root@compute ~]# echo "options vfio_iommu_type1 allow_unsafe_interrupts=1" > /etc/modprobe.d/dist.conf

5. 重启服务器以使新内核参数生效:

[root@compute ~]# systemctl reboot

6. 查看 Compute 节点上的 SR-IOV 内核模块。运行 lsmod 以确认模块已被加载:

[root@compute ~]#  lsmod |grep igb

这个经过过滤的结果应该包括所需的模块:

igb    87592  0
dca    6708    1 igb

7. 记录下您的网卡的 PCI 厂商 ID(格式是 vendor_id:product_id)。运行带有 -nn 选项的 lspci 命令可以得到这个值。例如:

[root@compute ~]# lspci  -nn | grep -i 82576
05:00.0 Ethernet controller [0200]: Intel Corporation 82576 Gigabit Network Connection [8086:10c9] (rev 01)
05:00.1 Ethernet controller [0200]: Intel Corporation 82576 Gigabit Network Connection [8086:10c9] (rev 01)
05:10.0 Ethernet controller [0200]: Intel Corporation 82576 Virtual Function [8086:10ca] (rev 01)

请注意:根据您的网卡硬件的具体情况,这个参数可能会不同。

8. 使用 lspci 命令查看新创建的 VF:

[root@compute ~]# lspci | grep 82576

这个结果会包括设备和 Virtual Function:

0b:00.0 Ethernet controller: Intel Corporation 82576 Gigabit Network Connection (rev 01)
0b:00.1 Ethernet controller: Intel Corporation 82576 Gigabit Network Connection(rev 01)
0b:10.0 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)
0b:10.1 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)
0b:10.2 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)
0b:10.3 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)
0b:10.4 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)
0b:10.5 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)
0b:10.6 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)
0b:10.7 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)
0b:11.0 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)
0b:11.1 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)
0b:11.2 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)
0b:11.3 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)
0b:11.4 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)
0b:11.5 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)

20.3. 在 Network 节点上配置 SR-IOV

OpenStack Networking(neutron)使用 ML2 机制驱动来支持 SR-IOV。在 Network 网络上执行这些步骤来配置 SR-IOV 驱动。

1./etc/neutron/plugins/ml2/openvswitch_agent.ini 文件中启用 sriovnicswitch。例如,这个配置启用了 SR-IOV 机制驱动和 Open vSwitch。

请注意:sriovnicswitch 不支持 DHCP Agent 的当前接口驱动,因此在使用 sriovnicswitch 时需要 openvswitch(或其它支持 VLAN 的机制驱动)。

[ml2]
tenant_network_types = vlan
type_drivers = vlan
mechanism_drivers = openvswitch, sriovnicswitch
[ml2_type_vlan]
network_vlan_ranges = physnet1:15:20
  • network_vlan_ranges - 在这个例子中,physnet1 被作为网络标签使用,VLAN 的范围是 15-20

请注意:sriovnicswitch 当前只支持 flatvlan 驱动。

2. 可选 - 如果您需要 VF 连接状态和 admin 状态管理,而且您的厂商支持这些功能,请在 /etc/neutron/plugins/ml2/sriov_agent.ini 文件中启用这个选项:

[root@network ~]# openstack-config --set /etc/neutron/plugins/ml2/sriov_agent.ini ml2_sriov agent_required True

3. 可选 - 支持的 vendor_id/product_id 组合是 15b3:1004, 8086:10ca。如果网卡厂商的产品 ID 和这个不同,则需要指定它们。例如:

[ml2_sriov]
supported_pci_vendor_devs = 15b3:1004,8086:10ca

4. 配置 neutron-server.service 来使用 ml2_conf_sriov.ini 文件。例如:

[root@network ~]# vi /usr/lib/systemd/system/neutron-server.service

[Service]
Type=notify
User=neutron
ExecStart=/usr/bin/neutron-server --config-file /usr/share/neutron/neutron-dist.conf --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/plugins/ml2/openvswitch_agent.ini --config-file /etc/neutron/plugins/ml2/sriov_agent.ini  --log-file /var/log/neutron/server.log

5. 重启 neutron-server 服务来使配置生效:

[root@network ~]# systemctl restart neutron-server.service

20.4. 在 Controller 节点上配置 SR-IOV

1. 为了正确调度 SR-IOV 设备,Compute 调度程序需要使用带有 PciPassthroughFilter 过滤的 FilterScheduler。在 Controller 节点上的 nova.conf 文件中应用这个配置。例如:

scheduler_available_filters=nova.scheduler.filters.all_filters
scheduler_default_filters=RetryFilter,AvailabilityZoneFilter,RamFilter,ComputeFilter,ComputeCapabilitiesFilter,ImagePropertiesFilter,CoreFilter, PciPassthroughFilter

2. 重启 Compute 调度器以使修改生效:

[root@compute ~]# systemctl restart openstack-nova-scheduler.service

20.5. 在 Compute 节点上配置 SR-IOV

在所有 Compute 节点上,为每个物理网络关联有效的 VF:

1.nova.conf 文件中定义这些项。在这个例子中,把设备名为 enp5s0f1 的 VF 网络与网络标签为 physnet1 的物理网络相关联。其中由 physical_network 所指定的网络标签是以前在 network_vlan_ranges 中配置的。

pci_passthrough_whitelist={"devname": "enp5s0f1", "physical_network":"physnet1"}

下面的配置会把厂商 ID 为 8086 的 PF 网络与网络标签为 physnet1(由 physical_network 指定)的物理网络进行关联:~ pci_passthrough_whitelist = \{"vendor_id": "8086","product_id": "10ac", "physical_network":"physnet1"} ~

PCI passthrough whitelist 项的格式如下:

["device_id": "<id>",] ["product_id": "<id>",]
["address": "[[[[<domain>]:]<bus>]:][<slot>][.[<function>]]" |
"devname": "Ethernet Interface Name",]
"physical_network":"Network label string"
  • id - id 的值可以是通配符(*),或一个有效的 device/product id。您可以使用 lspci 列出有效的设备名。
  • address - address 的格式与使用带有 -s 选项的 lspci 命令输出中的格式相同。
  • devname - devname 是一个有效的 PCI 设备名称。您可以使用 ifconfig -a 列出全部有效的名称。这个项需要和与一个 vNIC 相关联的 PF 或 VF 值相对应。如果设备由代表一个 SR-IOV PF 的地址或 devname 来定义,则 PF 下的所有 VF 必须和这个项匹配。另外,一个项可以关联0 个或多个标签。
  • physical_network - 在使用 SR-IOV 网络时,"physical_network" 被用来指定设备附加到的物理网络。

您可以为每个主机配置多个 whitelist 项。device_idproduct_id、以及 addressdevname 的值将会和查询 libvirt 所返回的 PCI 设备进行匹配。

2. 重启 nova-compute 服务以使所做的改变生效:

[root@compute ~]# systemctl restart openstack-nova-compute

20.6. 启用 OpenStack Networking SR-IOV agent

可选的 OpenStack Networking SR-IOV agent 启用了对 admin_state 端口的管理。这个 agent 与网络适配器进行集成,允许管理员打开/关闭 VF 的管理状态。

另外,如果 agent_required=True 已在 OpenStack Networking(neutron)服务器上配置,则需要在每个 Compute 节点上都运行 OpenStack Networking SR-IOV Agent。

请注意:当前,不是所有网卡厂商都支持使用这个 agent 管理端口状态。

1. 安装 sriov-nic-agent 软件包以便进行以下步骤:

[root@compute ~]# yum install openstack-neutron-sriov-nic-agent

2./etc/neutron/plugins/ml2/openvswitch_agent.ini 文件中启用 NoopFirewallDriver

[root@compute ~]# openstack-config --set /etc/neutron/plugins/ml2/openvswitch_agent.ini securitygroup firewall_driver neutron.agent.firewall.NoopFirewallDriver

3./etc/neutron/plugins/ml2/sriov_agent.ini 文件中添加映射信息。在这个例子中,physnet1 是物理网络、enp4s0f1 是 physical function。把 exclude_devices 设为空来允许 agent 管理所有相关的 VF。

[sriov_nic]
physical_device_mappings = physnet1:enp4s0f1
exclude_devices =

4. 可选操作 - 为了在 agent 配置中排除特定的 VF,在 sriov_nic 项中列出要排除的 VF。例如:

exclude_devices = eth1:0000:07:00.2; 0000:07:00.3, eth2:0000:05:00.1; 0000:05:00.2

5. 配置 neutron-sriov-nic-agent.service 来使用 ml2_conf_sriov.ini 文件。例如:

[root@compute ~]# vi /usr/lib/systemd/system/neutron-sriov-nic-agent.service

[Service]
Type=simple
User=neutron
ExecStart=/usr/bin/neutron-sriov-nic-agent --config-file /usr/share/neutron/neutron-dist.conf --config-file /etc/neutron/neutron.conf --log-file /var/log/neutron/sriov-nic-agent.log --config-file /etc/neutron/plugins/ml2/sriov_agent.ini

6. 启动 OpenStack Networking SR-IOV agent:

[root@compute ~]# systemctl enable neutron-sriov-nic-agent.service
[root@compute ~]# systemctl start neutron-sriov-nic-agent.service

20.7. 配置一个实例来使用 SR-IOV 端口

在这个例子中,SR-IOV 端口被添加到 web 网络。

1. 获得有效的网络列表

[root@network ~]# neutron net-list
+--------------------------------------+---------+------------------------------------------------------+
| id                                   | name    | subnets                                              |
+--------------------------------------+---------+------------------------------------------------------+
| 3c97eb09-957d-4ed7-b80e-6f052082b0f9 | corp    | 78328449-796b-49cc-96a8-1daba7a910be 172.24.4.224/28 |
| 721d555e-c2e8-4988-a66f-f7cbe493afdb | web     | 140e936e-0081-4412-a5ef-d05bacf3d1d7 10.0.0.0/24     |
+--------------------------------------+---------+------------------------------------------------------+

这个结果列出了已在 OpenStack Networking 中创建的网络,以及子网的详情。

2.web 网络中创建端口

[root@network ~]# neutron port-create web --name sr-iov --binding:vnic-type direct
Created a new port:
+-----------------------+---------------------------------------------------------------------------------+
| Field                 | Value                                                                           |
+-----------------------+---------------------------------------------------------------------------------+
| admin_state_up        | True                                                                            |
| allowed_address_pairs |                                                                                 |
| binding:host_id       |                                                                                 |
| binding:profile       | {}                                                                              |
| binding:vif_details   | {}                                                                              |
| binding:vif_type      | unbound                                                                         |
| binding:vnic_type     | normal                                                                          |
| device_id             |                                                                                 |
| device_owner          |                                                                                 |
| fixed_ips             | {"subnet_id": "140e936e-0081-4412-a5ef-d05bacf3d1d7", "ip_address": "10.0.0.2"} |
| id                    | a2122b4d-c9a9-4a40-9b67-ca514ea10a1b                                            |
| mac_address           | fa:16:3e:b1:53:b3                                                               |
| name                  | sr-iov                                                                          |
| network_id            | 721d555e-c2e8-4988-a66f-f7cbe493afdb                                            |
| security_groups       | 3f06b19d-ec28-427b-8ec7-db2699c63e3d                                            |
| status                | DOWN                                                                            |
| tenant_id             | 7981849293f24ed48ed19f3f30e69690                                                |
+-----------------------+---------------------------------------------------------------------------------+

3. 使用新端口创建一个实例。创建一个名为 webserver01 的新实例,配置它来使用新端口(端口 ID 是前一个输出中的 id 项中的值):

请注意:您可以使用 glance image-list 命令来获得有效镜像的列表,以及它们的 UUID。

[root@compute ~]# nova boot --flavor m1.tiny --image 59a66200-45d2-4b21-982b-d06bc26ff2d0  --nic port-id=a2122b4d-c9a9-4a40-9b67-ca514ea10a1b  webserver01

新实例 webserver01 被创建,并配置为使用 SR-IOV 端口。

20.8. 检查 allow_unsafe_interrupts 设置

为了完全把带有分配设备的客户机与主机分离,需要平台对中断重映射功能的支持。如果不支持这个功能,主机可能会受到来自于恶意客户机上的中断注入攻击(interrupt injection attack)。而在一个客户端可以被完全信任的环境中,管理员可能会允许使用 allow_unsafe_interrupts 选项进行 PCI 设备的分配。您需要根据具体情况检查是否在主机上启用 allow_unsafe_interrupts。如果主机上的 IOMMU 支持中断重映射功能,则不需要启用这个选项。

1. 使用 dmesg 检查您的主机是否支持 IOMMU 中断重映射功能:

[root@compute ~]# dmesg |grep ecap

当 ecap (0xf020ff → …​1111) 的第 3 位是 1 时,意味着 IOMMU 支持中断重映射。

2. 确认 IRQ 重映射是否已被启用:

[root@compute ~]# dmesg |grep "Enabled IRQ"
[    0.033413] Enabled IRQ remapping in x2apic mode

请注意:如需手工禁用 "IRQ remapping",把 intremap=off 添加到 grub.conf 文件中。

3. 如果主机的 IOMMU 不支持中断重映射,您需要在 kvm 模块中启用 allow_unsafe_assigned_interrupts=1

20.9. 额外需要考虑的因素

  • 在选择 vNIC 类型时请注意,当前还不支持 vnic_type=macvtap
  • 不支持带有附加了 SR-IOV 实例的 VM 迁移。
  • 当前,安全组不能在启用了 SR-IOV 的端口中使用。