查看: 81|回复: 5

网络虚拟化之virtio-net和vhost

[复制链接]

4

主题

10

帖子

15

积分

新手上路

Rank: 1

积分
15
发表于 2022-12-9 20:35:09 | 显示全部楼层 |阅读模式
前面的文章以Type-1型的Acrn hypervisor为例,简要介绍了virtio的基础机制。作为para virtualization一个事实上的通用标准,其具体的应用包括块设备、网络设备,以及文件系统等的虚拟化实现。本文将结合基于x86体系的QEMU-KVM,来讲解virtio在网卡虚拟化方面的几种实现方式。
在virtio协议中,host端提供对设备的emulation,guest端负责对设备的驱动,host和guest的关系就是device和driver的关系。我们通常使用读写寄存器的方式,来实现对physical device的控制和驱动,但对于virtio中的emulated device,使用的则是以virtqueue形式组织的内存。
这是因为以寄存器形式访问物理设备是很快速的,使用内存的话还需要DMA的传输,但emulated device不同,它本身就是内存中的一块区域,一板一眼地模拟物理设备的寄存器反倒低效而麻烦。
当guest中的driver试图访问host中的device时,会通过一定的方式触发vm-exit,从non-root模式的ring 0/3切换到root模式的ring 0,即从guest kernel“陷”入host kernel。如果host kernel不能对这个设备进行emulate,就转给host上的userspace(root模式的ring 3)。



图片来源于 《深度探索Linux系统虚拟化》

用户态实现的Vhost-User

具体到virtio中的网络设备,guest端的driver被称作"virtio-net",而在host端,早期的经典实现是使用功能丰富的QEMU,即由host端的用户态程序来提供设备的emulation,称为"vhost-user"。
ioeventfd
当guest向virtqueue上写入数据完成后,需要通知host端来获取这部分数据(术语叫"kick"),通知的方式是访问一段设定的MMIO区域(但没有真正分配内存),以触发EPT violation/misconfig(类似于page fault),进而形成vm-exit,这种vm-exit会交由host上的KVM内核模块负责处理。
KVM在这里相当于一个代理,它需要进一步通知到用户态的QEMU,为了减小开销,采用的notify方式是相对轻量级的"eventfd"。eventfd可理解为把一个事件抽象为文件(不要和epoll搞混了),其本质上是一个wait queue,因此可用做进程间的通信和同步。
struct eventfd_ctx {
    wait_queue_head_t wqh;
    __u64 count;
}QEMU进程申请eventfd后,会在其对应的wait queue上轮询等待,当KVM收到guest端的kick,就更新这个eventfd的"count"值,以唤醒QEMU。
为了将guest访问的MMIO区域和一个eventfd关联起来,KVM设计了一个名为"ioeventfd"的数据结构:
struct _ioeventfd {
    u64 addr;
    int length;
    struct eventfd_ctx  *eventfd;
    struct kvm_io_device dev;
}
用一句话概括这个数据结构的功能就是:将guest对内存的写操作转换成对"kvm_io_device"的写操作,进而转换成对eventfd的写操作。


【irqfd】
那当QEMU向virtqueue上写入数据后,又怎么返过来通知到guest呢?还是离不开KVM这个二传手。只不过这次KVM使用的数据结构是"irqfd",同前面介绍的ioeventfd类似,它也是基于Linux中的eventfd来扩展实现的。



图片来源见文末链接

内核态实现的Vhost-Net

既然负责中转的KVM位于host kernel,如果可以减少到host userspace转一圈的次数,岂不是可以提高这个模拟网卡的数据吞吐量?没错,"vhost-net"就是这样一种在host kernel直接emulate网卡设备的内核模块。
vhost-net也是遵守virtio协议规范的,因此对于guest driver来说,原来怎么和QEMU交互的,现在就怎么和vhost-net交互,不需要什么修改。对于KVM,之前和QEMU之间使用ioeventfd和irqfd,现在和vhost-net同样如此。
对应一个由QEMU指导创建的guest VM,vhost-net会生成一个名为"vhost-[pid]"的内核worker线程,这里的"pid"即QEMU进程(也称作"hypervisor process")的PID,该内核线程替代了QEMU的等待轮询工作。


同KVM一样,vhost-net不能单独使用,而是必须搭配QEMU,因为一些配置信息,还是需要从用户态的QEMU给出。同QEMU操作KVM的方式类似,vhost-net也是暴露出"/dev/vhost-net"的文件接口,然后QEMU通过框框一顿ioctl()操作,来实现控制的目的。
因此,在vhost-net作为网卡emluation的实现中,QEMU负责control plane部分,而vhost-net负责的则是data plane:




图片来源见文末链接

硬件实现的vDPA

从QEMU/vhost-user到vhost-net,data plane的工作已经由用户态转移到了内核态,在一定程度上提高了效率,但软件层面的这种优化,终究还是比不过在硬件层面的offload。
随着Intel VT-d技术里传统的SR-IOV演进到后来的Scalable IOV,硬件pass through技术日臻完善,但是它们和virito这种“半虚拟化”方案走的是两条路子,那名字里带个"virt"的virtio就彻底和硬件加速无缘了吗,性能的升级只能就此止步了吗?
不再virt的virtio
不,谁说硬件的实现就不能符合virtio的标准,不过这中间需要一个牵线搭桥的,vDPA承担的正是这样一个角色。


满足对virtio data plane兼容性的设备可被称为"vDPA device",但不同的设备厂商在control plane部分的实现往往存在差异。vDPA对此的解决办法是:vendor的control plane的驱动需要包含一个vDPA的add-on,然后通过vDPA driver,将其转化成virtio形式的control plane。

参考:

  • Virtio Spec Overview
  • virtio的eventfd机制浅析
  • KVM MMIO implementation
  • Redhat - introduction-virtio-networking-and-vhost-net

原创文章,转载请注明出处。
回复

使用道具 举报

3

主题

7

帖子

11

积分

新手上路

Rank: 1

积分
11
发表于 2022-12-9 20:36:02 | 显示全部楼层
请教一下,在最后利用vDPA对virtio-net的卸载相比于直接VF直通到虚拟机有什么优势呢?优点是可以在VM里统一抽象不同厂家不同的硬件设备么?
回复

使用道具 举报

2

主题

6

帖子

10

积分

新手上路

Rank: 1

积分
10
发表于 2022-12-9 20:36:21 | 显示全部楼层
还能接受内核监管,在HA等方面有用
回复

使用道具 举报

3

主题

9

帖子

12

积分

新手上路

Rank: 1

积分
12
发表于 2022-12-9 20:37:05 | 显示全部楼层
第一种传统的方式应该不叫vhost-user吧 ,vhost-user应该是配合ovs那种形态的。
回复

使用道具 举报

0

主题

4

帖子

0

积分

新手上路

Rank: 1

积分
0
发表于 2022-12-9 20:37:32 | 显示全部楼层
一样的
回复

使用道具 举报

2

主题

7

帖子

11

积分

新手上路

Rank: 1

积分
11
发表于 2022-12-9 20:38:02 | 显示全部楼层
请教一下,ovs/dpdk是怎样的模型呢?
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表