Single

【转载】这,就是热插拔!

文章转载自DPDK与SPDK开源社区公众号
为了方便引用和保存以后看,转载到了这里

想象这样一个场景:在严重堵车的高速公路上,除了等待道路恢复畅通,似乎并没有什么更好的办法。此刻的你一定恨不得前方恰巧就是高速闸道口可以助你迅速走上人生巅峰。

如果可以有一条在拥堵发生时动态接入的闸道该多好!然鹅,并没有。

但幸运的是,在0-1的世界里,有一种叫Hotplug的技术可以对发生故障的设备做热切换或热修复。

那么问题来了:

Hotplug 到底是什么?
Hotplug 具体有啥作用?
Hotplug与DPDK又有什么关系呢?
01 Hotplug是什么?

TA既不是热狗也不是热干面。

Hotplug是一组涉及主板硬件电气特性、固件、操作系统内核、设备等组件相互加持的一套软硬件技术标准系列,其使得用户可以在系统带电运行的情况下,插入设备直接使用;也能在使用完设备后,在不需要关闭系统电源的情况下拔出设备,整个过程不影响系统的工作和负载。这里提到的设备,大家最先想到应该是最广泛使用的U盘,除此之外,还可以是CPU、内存、网卡等等。

02 Hotplug 有啥作用?

热插拔仅仅是为了设备使用起来更省时省力吗?

对于基于云计算的网络数据中心或者通信企业服务器集群业务来说,TA还具有更广泛且重要的用途:譬如提供7*24 hours Service, 动态Deploy, 灾备等等。

所以,TA至少可以有下图中的4个用途:

1负载调衡;2节能部署;3故障恢复;4热迁移。

03 Hotplug与DPDK又有什么关系呢?

DPDK作为网络传输数据面处理与专注于传输性能优化的核心库与网络设备用户态驱动的集合体,与Hotplug技术又有哪些关系呢?

如果开发者或者用户需要在上述4大场景中启动Hotplug功能,首先需要打开服务器产品说明书,看主板是否支持Hotplug功能。接着需要和IT运维了解硬盘上运行的OS是否支持Hotplug(Linux kernel >= 2.4.6支持。官宣)。然后需要一套机制实现用户态和内核态Hotplug事件的通信以及处理。那么有没有一个公用开源库、或者通用软件框架Framework可以提供这样的服务,使得开发者不需要关注硬件驱动和操作系统细节,只要调用一两个API接口就能轻松实现Hotplug呢?看来万事具备,只欠DPDK。

PART 01

首先看DPDK都具备哪些充分条件:

1.支持各种总线结构的 PMD,包括OFED、IGB_UIO/VFIO PCI, Hyper-V/VMbus等

2.有Ethdev, Crypto, Compress, Event 各种Device Class Interfaces.

3.支持Advance的Device Syntax ,譬如bus=pci,id=BDF/class=eth,…/driver=virtio,…(18.11)

4.提供Blacklist/Whitelist配置, dynamic policy API for device management 在计划中

5.提供Device plug in and plug out的 相应APIs。(17.08)

6.Failsafe Driver(17.08), Uevent Monitor(18.05), Hotplug Handler(18.11).

注:此文仅讨论device hotplug,对于memory的hotplug(18.05),以及multi-process hotplug(18.11) 不在本文讨论的范畴,后续会另有专题,敬请期待。

PART 02

接着看,DPDK的工作线程 data path 数据快道专注于数据面性能,在设备被拔出的极端情况下,交给控制主线程control path 来接管,合情合理。所以条件充分且必要,Hotplug可以用在DPDK里面实现动态设备管理。

以下将展开介绍DPDK Hotplug。

目前Hotplug Framework在DPDK中的框架图:

众所周知,Hotplug分为热插和热拔,即Hotplug add 与 Hotplug remove两种情况。那么在DPDK里面处理Hotplug的流程大致是这样的:

Hotplugadd的流程:

->Uevent(add)

->hotplughandle and RTE_DEV_EVENT_ADD notify

->applicationcalls rte_eal_hotplug_add

->PMDprobe ports

->PMDcalls rte_eth_dev_probing_finish

->RTE_ETH_EVENT_NEW

->applicationget new ports

Hotplugremove的流程:

->Uevent(remove) or req notify(for vfio)

->hot-unplughandle and RTE_DEV_EVENT_REMOVE notify

->applicationcalls rte_eal_hotplug_remove

->PMDcalls rte_eth_dev_removing

->RTE_ETH_EVENT_DESTROY

->applicationcalls rte_eth_dev_close

PART 03

把以上流程拆分出几个主要部分放大来看:

1.首先,如何运用 uevent monitor 来监听device hotplug事件

由于Hotplug的本身行为特殊性,使得无法通过一般的设备驱动程序提供的接口ioctl 或者write/read fd 的方式去完成用户空间的程序与设备通信。 所以可以利用 linux 特有的 netlink 通信机制以及uevent设备模型事件,netlink本身具备诸多优良特性,比方说多播、异步以及标准的socket api 的良好开发体验,可以实现对Hotplug事件的监测,uevent也是Linux专有机制,freeBSD目前并不支持。

以linux kernel 4.17.0的include/linux/kobject.h文件为例,主要关注ADD和REMOVE两个event:

在DPDK 18.11 的 lib/librte_eal/linuxapp/eal/eal_dev.c文件中,建立socket fd 作事件监听。

在Linux kernel的drivers/vfio/pci/vfio_pci_private.h头文件中,vfio_pci_device 结构体中的req_trigger定义了对应的eventfd的内容。

为req notify建立eventfd 的代码路径在DPDK18.11的Drivers/bus/pci/linux/pci_vfio.c.

2.然后 对hotplug事件的处理和应用上告

由于在hotplug remove过程中程序对设备有效地址的无效读写会产生failure进而导致程序异常,而hotplug add事件不会产生failure, 所以对于hot-unplug的handler这里面主要涉及sigbus handler和hot-unplug failure handler两个处理。

对于control path,实现事件监听然后按序处理,但是对于per core per pooling thread的data path数据快道,其通过MMIO/DMA与设备通信,其与设备的通信速度远远快于control path。所以会存在这种情况,即hotplug事件在control path里面还没有处理完,快道并不知情从而继续对已经被kernel宣布无效的设备进行非法读写。为了解决这个问题,需要引入sigbus handler去截获非法事件以做相应处理,防止程序异常退出。
由于linux kernel 对hot-unplug的处理在igb_uio pci以及vfio pci不尽相同,vfio的机制是当hot-unplug 发生,kernel会先通过一个特殊的设备请求事件,通知user space释放资源以归还控制权给kernel,然后才删除设备;igb_uio则截然相反,当hot-unplug发生,kernel会直接删除设备,然后才通过uevent 告知user space.所以dpdk hot-unplug handler对于这两种情况需要分别实现两套不同机制。
如下图:

通过源码解释几个主要实现部分:

总的来说,我们需要处理两种hotplug hardware event (uevent和vfio req)和一种sigbus software事件的注册。

Igb_uio的uev handler 注册的是RTE_INTR_HANDLE_DEV_EVENT事件:

Vfio的req handler注册的是RTE_INTR_HANDLE_VFIO_REQ事件:

Sigbus的handler的注册的是SA_SIGINFO事件, 此处需要改变进程接到信号后的行为,需要使用sigaction注册自定义的sigbus_handler。

在sigbus_handler里面将对generic的sigbuserror以及因hotplug 产生的特殊sigbuserror进行区别处理。当sigbus_handler被sigbus事件触发时,利用siginfo_t结构体中的si_addr获取产生fault事故的memory地址,然后检索其是否落位于设备的BARs空间,从而对定位的设备进行hot-unplug handler的内存读写保护处理。如果是generic的sigbus error 则恢复generic sigbushandler 并直接异常退出。

如下是对igb_uiopci bus和vfio pci bus两种不同总线下hot-unplug的处理。

在igb_uio PCI bus的hot-unplug hanlder的处理,就是上文提到的内存读写保护,通过把设备的BARs(MMIO或者IO Port)空间重新remap 到一段新的anonymous的fake内存,使得后续的设备读写不会产生因为hot-unplug原因导致的sigbus error,保证control patch顺利安全的释放设备,避免了进程异常终止。

而对于vfiopci的hot-unplug的处理则不尽相同,需要启动requestirq的监测。当hot-unplug 发生,kernel 发送信令呼叫设备控制权, user space接到信令先做设备释放,然后kernel轮询监测到设备已经被释放后再删除设备。(linux kernel >= 4.0.0 支持vfio req notify)

PART 04

接下来我们看:

rte_eal_hotplug_add与 rte_eal_hotplug_remove这两个api用来将device attach到bus上,或者从bus上detach出来。这两个函数未来将会直接被rte_dev_probe和rte_dev_remove取代,device的管理将由dpdk全部接管,从而无需将相关接口暴露给到app。

关于 pci bus的scan和probe device的相关流程和策略,不在此文展开,感兴趣的同学可以下载源代码自行研究。代码往往是比文字更好的诠释语言。

然后是PMD对端口的probe和remove的过程,最后整个hotplug通路全部完成。

以下提供简单的demo以供参考,其目的是演示在一个qemu/kvm- VM的环境里,热插拔一个通过SR-IOV 来做passthough 的 NIC 对于正在收发包工作中的testpmd产生的影响。

System environment:

Host kernel: Linux 4.17.0-041700rc1-generic

VM kernel: Linux ubuntu 4.10.0-28-generic

QEMU emulator: 2.5.0

DPDK: 18.11

NIC: ixgbe or i40e nic or other(pci uio nic)

Step:

Host:

1. Bind port 0 to vfio-pci

modprobe vfio_pci

echo 1> /sys/bus/pci/devices/0000:81:00.0/sriov_numvfs

./usertools/dpdk-devbind.py -b vfio-pci 81:10.0

2. start qemu s

taskset -c 12-21 qemu-system-x86_64

-enable-kvm -m 8192 -smp cores=10,sockets=1 -cpuhost -name dpdk1-vm1

-monitor stdio

-drive file=/home/vm/ubuntu-14.10.0.img

-device vfio-pci,host=0000:81:10.0,id=dev1

-netdevtap,id=ipvm1,ifname=tap5,=/etc/qemu-ifup -device

rtl8139,netdev=ipvm1,id=net0,mac=00:00:00:00:00:01

-localtime -vnc :2

VM and Qemu:

1. VM: Bind port 0 to vfio-pci

./usertools/dpdk-devbind.py -b vfio-pci 00:03.0

2. VM: Start testpmd and enable hotplug feature

./x86_64-native-linuxapp-gcc/app/testpmd -c f-n 4 — -i –hot-plug

3. testpmd>set fwd txonly

4. testpmd>start

5. Qemu: remove device for unplug:

(qemu) device_del dev1

6.Qemu: add device for plug:

(qemu) device_addvfio-pci,host=0000:81:10.0,id=dev1

7. Bind port 0 to vfio-pci:

./usertools/dpdk-devbind.py -b vfio-pci 00:03.0

8. testpmd>stop

9. testpmd>port attach 0000: 00:03.0

10. testpmd>port start all

11. testpmd>start

可以看到,当热插拔NIC,正在收发包工作中的testpmd不会异常退出,且能正常detach设备或者attach 设备并重新开始进行网络包的收发工作。

到这里,整个一套DPDK hotplug的动态设备管理方案已经呈现。那么,除了这些还有哪些实际应用场景或工作负载可以用到这一机制呢?

DPDK Hotplug的应用场景当然不止这些,DPDK Framework中各个多样化的功能模块也许比我们想象的更加强大。

除了热干面和热狗,还有一桌满汉全席等着Hotplug去带盐……

比如,为了在hotplug的过程中进一步保障data path数据快道也不间断工作,可以通过Hotplug + Failsafe PMD来实现网络设备恢复。

再拓展开来,对于软件定义网络和网络功能虚拟化下的应用负载,可以通过Hotplug+ Failsafe PMD + Virtio + Qemu/KVM 实现基于SR-IOV的 VM 热迁移。如下图所示:

微软在这方面是先行者与主推手,其Hyper-V与Live migration 在云计算领域已经是标杆性的广泛应用,而另一山头基于KVM的虚拟化也在业界不断崛起,对于 Linux/KVM 以及SR-IOV的方案还有很大探索与发展空间可以留给开发者继续研究。

当然, Hotplug 动态设备管理机制的一些方面还需要不断完善。

譬如,设备和端口在一对多的情况下的设备移除问题,kerneldriver自动绑定的问题,还有uio kernel driver的knownissue,Hotplug 部分在整个live-migration中的性能贡献等问题都亟待探索和解决。这些问题一部分已经划入后续release的plan,另外一些改进工作将结合工作负载或应用需求、kernel的动态演进以及DPDK框架的不断进化做继续讨论和更迭完善。

文章转载自DPDK与SPDK开源社区公众号

暂无评论

发表评论