云主机支持SR-IOV设备直通

达芬奇密码2018-07-18 13:19

SR-IOV设备直通作为当前性能最高的网络虚拟化解决方案,一直没有纳入到网易云主机的支持范围内。主要原因是当前云主机使用的管理程序Havana版本的nova对PCI设备直通的支持不够完善。最近根据产品提出的需求,对这部分功能做了一次完善。本文尝试对做出的这些完善做一个总结,梳理一下处理的思路

Havana版本中对PCI设备的管理逻辑

  1. 计算节点:
  • 初始化

    nova要求用户指定计算节点上可以直通的设备白名单(以设备的vendor id和product id为标志)。nova-compute在启动阶段从配置文件中读取用户配置的白名单,并且通过libvirt接口查询到所有的设备列表。分别保存在内存和数据库中。

    • 计算节点的resource tracker中增加pci_trackerpci_tracker的数据结构如下。
       
    • 数据库中保存pci_devicescompute_nodes两张表。

      compute_nodes中记录计算节点上可用设备的类型和数量(pci_stats的内容)

      pci_stats格式:
          [{"count": 32, "vendor_id": "8086", "product_id": "10ed", "extra_info": {}}]

      pci_devices记录每一个可用PCI设备信息和当前状态。

      pci设备状态:
          aviliable 可用
          claimed 已被预占
          allocated 已被占用
  • 虚拟机创建 计算节点收到带有pci设备的调度请求后,为当前请求预留并占用对应的pci设备,更新到resource_trackerPciDeviceList。并且记录到claimsallocations中。

    生成xml文件时,检查system metadata中是否存在pci设备请求,如果存在,则生成对应的hostdev配置项。

  • 虚拟机删除 虚拟机删除时,更新计算节点resource_trackerPciDeviceListallocations。并且更新节点的pci_stats

  1. api节点:在nova的flavor中指定对pci设备的需求类型及数量。当使用这个flavor创建云主机时,在api中会解析flavor中的pci设备需求,并记录在instance对象的system_metadata属性中。
配置文件中指定alias别名:

pci_alias = { "vendor_id":"8086", "product_id":"10ed", "dev_type":"type-VF", "name":"82599" }

flavor中指定使用某个别名的设备及数量
+----------------------------+--------------------------------------+
| Property                   | Value                                |
+----------------------------+--------------------------------------+
| OS-FLV-DISABLED:disabled   | False                                |
| OS-FLV-EXT-DATA:ephemeral  | 0                                    |
| disk                       | 20                                   |
| extra_specs                | {"pci_passthrough:alias": "82599:1"} |
| id                         | 8086001                              |
| name                       | flavor_sriov_8g20g4u                 |
| os-flavor-access:is_public | True                                 |
| ram                        | 8192                                 |
| rxtx_factor                | 1.0                                  |
| swap                       |                                      |
| vcpus                      | 4                                    |
+----------------------------+--------------------------------------+
  1. 调度器:

    Havana版本提供了PciPassthroughFilter的调度器,调度策略为如果instance的system_metadata中包含直通pci设备的请求,则检查计算节点的pci_stats是否满足PCI设备的需求。如果满足则通过过滤,否则过滤失败。

    节点选定之后,会从选定节点的pci_stats中移除相应类型和数量的pci设备,防止并发调度失败。

云主机服务对sriov直通的需求

  1. sriov直通只能与vpc匹配
  2. sriov直通需要适配网络dpdk方案
    • 需要管理pci设备的vlan tag id
    • 虚拟机的配置需要指定interface类型而非hostdev类型
    • 每个PF网卡虚拟出的VF要预留一部分给dpdk使用
    • 虚拟机创建时需要绑定vlan tag和vpc port id

对Havana版本nova的完善内容

  1. 原生bug的修复
    • pci_tracker初始化阶段,不会从数据库读取原有的设备信息,直接扫描宿主机节点之后重写数据库。导致原有已分配的设备变为可用状态。修改为在初始化时先读取数据库。
    • pci_stats中增加dev_type字段,否则在调度时无法判断设备类型
    • 在原生基础上增加对type-VF类型设备的支持
    • 原生调度器的调度策略只能保证带sriov的请求调度到sriov节点,而不能保证非sriov请求不被调度到sriov节点。因此增加了SriovFilter,计算节点上报use_sriov属性,不带sriov的请求不会被调度到支持sriov的计算节点上。
  2. 云主机服务需求功能开发内容
    • 在api中判断如果使用了pci设备,则需要同时指定使用vpc网络
    • 当节点扫描到新增设备时,为每个设备分配一个vlan tag id
    • 在初始化阶段,扫描到的VF设备,按照PF分开,根据配置项预留相应数量的设备。这部分预留的设备在数据库中就不会被统计出来。
    • 在pci_stats的extra_info字段中增加vlan_tag,dpdk_trunk和phys_function属性值。
      新的pci_stats内容如下:
      
      [{"dev_type": "type-VF", "count": 1, "vendor_id": "8086", "product_id": "10ed", "extra_info": {"vlan_tag": 2, "dpdk-trunk": "0000:01:10.2", "phys_function": [["0x0000", "0x01", "0x00", "0x0"]]}}]
    • 根据请求生成符合需求的xml文件
      <interface type='hostdev' managed='yes'>
          <mac address='fa:16:3e:4e:d6:32'/>
          <driver name='vfio'/>
          <source>
              <address type='pci' domain='0x0000' bus='0x01' slot='0x11' function='0x7'/>
          </source>
          <vlan>
              <tag id='3011'/>
          </vlan>
          <alias name='hostdev0'/>
          <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
      </interface>
    • 在dpdk trunk中绑定/解绑port和vlan-tag
      绑定:
      ovs-vsctl set Interface dpdk-trunk-0000.01.10.2 external_ids:vlan-3012=b2177122-69e0-4076-9618-4303c834213b
      解绑:
      ovs-vsctl remove Interface dpdk-trunk-0000.01.10.2 external_ids:vlan-3012=b2177122-69e0-4076-9618-4303c834213b

Havana版nova resize操作流程

  1. nova api中的检查

    • 指定节点迁移的场景下必须检查:
      1. 源节点和目的节点必须在同一个一级az下
      2. 目的节点nova-compute服务必须处于up状态
      3. 检查节点的ceph兼容性
        • 源节点和目的节点同ceph pool 可以迁移
        • 源节点和目的节点均为本地存储 可以迁移
        • 源节点和目的节点不同ceph pool 不能迁移
        • 源节点和目的节点不同存储类型 不能迁移
    • compute api中,resize根据传入参数不同区分migrate和resize操作
      1. resize操作不允许先后flavor一致
      2. 计算resize操作的资源差额,并预留这部分差额
      3. 云主机task_state状态更新为resize_prep
      4. 准备resize/migrate的调度参数
        • resize配置了允许resize到本节点,并且目标flavor小于原flavor时,指定强制resize到本节点
        • 指定了force_host参数时,指定强制resize到force_host节点
        • migrate配置不允许迁移到本节点时,设置调度策略中忽略当前节点
      5. 记录resize action(action-list可以看到这个操作)
    • conductor api中,resize_instance调用到conductor rpcapi的migrate_server,同步调用conductor服务中的migrate_server
      1. 获取instance数据对象
      2. 根据参数转接到cold_migrate
      3. 组装调度请求
      4. 通过调度器获取调度目标节点
        • 调度失败,云主机状态恢复,资源预留释放
        • 调度成功,选择可用的节点
      5. 向选中的节点compute请求prep_resize
  2. 目标节点compute prep_resize

    • 检查节点合法性

      1. 同节点resize合法性检查
      2. 检查rsync daemon
    • 本节点资源预留

      1. 如果禁用resource tracker,则仅生成一个migration对象

      2. 申请资源

        生成一个migration对象

        extrac新flavor的信息到instance system metadata中,带有"new_"前缀。

        检查instance system metadata中如果包含pci设备请求,在当前节点的pci_dev_list里面申请符合条件的pci设备,并且添加到claims中。

        更新节点资源信息到数据库

    • 调用源节点resize_instance

  3. 源节点resize_instance

    • migration对象状态设置为migrating
    • task state置为resize_migrating
    • 迁移源端磁盘
      1. 非共享存储,在目的端创建云主机目录
      2. 源端云主机关机(destroy)
      3. 如果源端云主机挂载了云硬盘,则依次断开与云硬盘的连接
      4. 源端云主机目录变更为xxx_resize
      5. 拷贝本地系统盘
    • 迁移网络配置
    • migration对象状态设置为post-migrating
    • 更新云主机的属性值(host,ceph_pool, az)
      1. 源端修改云主机配置后存储到数据库(是否需要修改对应的pci设备信息????)
    • 云主机task state设置为resize_migrated
    • 调用目标节点finish_resize
  4. 目标节点finish_resize

    • 设置目的端instance的属性值 原有的instance system metadata信息都添加old_前缀 原有带new_前缀的instance system metadata去掉前缀,instance属性值变为resize目的flavor的属性值。
    • 目的端网络初始化
      1. setup_networks_on_host
      2. network_migrate_instance_finish(更新port属性值)
    • 更新本地的network info cache
    • 云主机task state 设置为resize_finish
    • 目的端恢复虚拟机
      1. 重建镜像,xml
      2. 虚拟机上电
    • 云主机task state设置为None,vm_state设置为resized
  5. 目标节点confirm resize

    • 定时任务或手动调用接口触发
    • 调用源节点的confirm_resize
  6. 源节点confirm_resize

    • 删除instance system metadata中old_前缀的属性值
    • 删除源节点的instance目录
    • migration状态置为confirmed
    • drop本节点已经claim的资源
      1. 删除本节点claims中当前instance预占的设备
  7. 虚拟机状态刷新

    • _instance_update(目的端操作)

      当虚拟机状态修改之后需要通过这个方法更新云主机的数据库记录。

    • 定时任务刷新(源端和目的端都存在)

      update_pci_info_for_instance

      vm_state DELETED 
          清理allocations和claims
      task_state RESIZE_MIGRATED     
          清理源端allocations
      task_state RESIZE_FINISH
          claims->allocations
      claims和allocations中都没有pci设备
          根据instance中的pci_requests内容重新获取一次pci设备,更新pci_tracker中的pci_devs_list,claims,allocations

      update_pci_for_migration

      云主机状态为RESIZED或者task_state为RESIZE_PREP,RESIZE_MIGRATING,RESIZE_MIGRATED,RESIZE_FINISH的状态
      从system metadata中获取prefix为new_的配置,并且claim这些设备

resize过程中pci设备管理逻辑的缺陷

Havana版本其实只实现了简单的pci设备管理功能,对虚拟机的resize操作没有支持,因此在上面的resize流程中可以看到全程没有主动管理pci设备的状态。 主要存在问题如下:

  1. 在获取新的flavor信息时没有把其中的pci设备信息保存在instance system metadata中(resize操作所有对虚拟机pci设备的管理都要以此为基础)
  2. 对pci_tracker中pci设备的管理,在整个迁移过程中,只有prep_resize阶段预占了新设备,后续对新设备的管理逻辑依赖于定时任务,并且存在逻辑缺陷。在测试过程中陆续出现了pci设备异常释放,pci设备重复申请,pci释放失败等各种问题。

对resize操作的完善

  1. 重新整理一个新的pci设备管理模型,PCI设备按照这个模型管理。
  1. 为满足sriov虚拟机和非sriov虚拟机之间可以相互转变,并且可以调度到正确的节点上,在nova api中增加对原flavor和新flavor的判断,如果pci设备有变化则节点必然发生变化,resize操作不强制指定节点。
  2. 在resize过程中,保存flavor信息时同步保存pci设备信息到instance system metadata中。
  3. 在原生代码中,只在云主机当前节点上才更新云主机的资源信息。但是在新的管理模型下,虚拟机原始节点上也要更新pci设备占用信息。
  4. revert resize时,需要在目的节点上释放新申请的pci设备,并且回复源节点上已经释放的设备。
  5. sriov虚拟机resize到非sriov虚拟机时,通过nova scheduler选择目的节点时,虽然instance中还包含pci_request信息,但实际上新的flavor已经不需要pci设备,所以在调度结束更新计算节点信息时不需要再占用pci设备。

本文来自网易实践者社区,经作者岳文远授权发布。