qemu 线程 vhost

news2024/11/19 15:24:53
[root@localhost cloud_images]# lsmod | grep vhost_net
vhost_net             262144  0 
vhost                 262144  1 vhost_net
tap                   262144  1 vhost_net
tun                   262144  2 vhost_net
[root@localhost cloud_images]#
vhost-net网卡的后端默认使用linux的虚拟网桥tap设备qemu和虚拟机内部使用virtio-net虚拟网卡。

步骤1: 创建linux网桥和tap设备(对于fedora,centos,redhat等默认有创建好的虚拟网卡)

brctl addbr virbr0

brctl stp virbr0 on

ip tuntap add name virbr0-nic mode tap

ip link set dev virbr0-nic up

步骤二:将host网卡添加到virbr0的一个port,并把ip配置给virbr0

brctl addif virbr0 eth0

brctl addif virbr0 virbr0-nic

dhclient virbr0

步骤三:用命令行起一个虚拟机

sudo x86_64-softmmu/qemu-system-x86_64 --enable-kvm -m 5120 -drive file=/home/fang/vm/centos.img,if=virtio -net nic,model=virtio -net tap,ifname=virbr0-nic,script=no -vnc :0

用vhost_net后端驱动

前面提到virtio在宿主机中的后端处理程序(backend)一般是由用户空间的QEMU提供的,然而如果对于网络IO请求的后端处理能够在在内核空间来完成,则效率会更高,会提高网络吞吐量和减少网络延迟。在比较新的内核中有一个叫做“vhost-net”的驱动模块,它是作为一个内核级别的后端处理程序,将virtio-net的后端处理任务放到内核空间中执行,从而提高效率

在第4章介绍“使用网桥模式”的网络配置时,有几个选项和virtio相关的,这里也介绍一下。

-net tap,[,vnet_hdr=on|off][,vhost=on|off][,vhostfd=h][,vhostforce=on|off]

vnet_hdr =on|off

设置是否打开TAP设备的“IFF_VNET_HDR”标识。“vnet_hdr=off”表示关闭这个标识;“vnet_hdr=on”则强制开启这个标识,如果没有这个标识的支持,则会触发错误。IFF_VNET_HDR是tun/tap的一个标识,打开它则允许发送或接受大数据包时仅仅做部分的校验和检查。打开这个标识,可以提高virtio_net驱动的吞吐量。

vhost=on|off

设置是否开启vhost-net这个内核空间的后端处理驱动,它只对使用MIS-X[5]中断方式的virtio客户机有效。

vhostforce=on|off

设置是否强制使用vhost作为非MSI-X中断方式的Virtio客户机的后端处理程序。

vhostfs=h

设置为去连接一个已经打开的vhost网络设备。

用如下的命令行启动一个客户机,就在客户机中使用virtio-net作为前端驱动程序,而后端处理程序则使用vhost-net(当然需要当前宿主机内核支持vhost-net模块)。

[root@jay-linux kvm_demo]# qemu-system-x86_64 rhel6u3.img -smp 2 -m 1024 -net nic,model=virtio,macaddr=00:16:3e:22:22:22 -net tap,vnet_hdr=on,vhost=on

VNC server running on ::1:5900'

qemu-system-aarch64: network script /usr/local/bin/../etc/qemu-ifup failed with status 256

[root@localhost cloud_images]# cat qemu-ifup 
#!/bin/sh
set -x

switch=virbr0 

if [ -n "$1" ];then
    ip tuntap add $1 mode tap user `whoami`
    ip link set $1 up
    sleep 0.5s
    ip link set $1 master $switch
    exit 0
else
    echo "Error: no interface specified"
    exit 1
fi
qemu-system-aarch64  -name vm2 -daemonize \
  -enable-kvm -M virt -cpu host -smp 2 -m 4096 \
  -object memory-backend-file,id=mem,size=4096M,mem-path=/mnt/huge,share=on \
  -numa node,memdev=mem -mem-prealloc \
  -global virtio-blk-device.scsi=off \
  -device virtio-scsi-device,id=scsi \
  -kernel vmlinuz-4.18 --append "console=ttyAMA0  root=UUID=6a09973e-e8fd-4a6d-a8c0-1deb9556f477 iommu=pt intel_iommu=on iommu.passthrough=1" \
  -initrd initramfs-4.18 \
 -drive file=vhuser-test1.qcow2  \
 -serial telnet:localhost:4322,server,nowait \
 -monitor telnet:localhost:4321,server,nowait \
 -net nic,model=virtio,macaddr=00:16:3e:22:22:22 -net tap,id=hostnet1,script=qemu-ifup,vnet_hdr=on,vhost=on \
 -vnc :10

当给一个Qemu进程传递了参数-netdev tap,vhost=on 的时候,QEMU会通过调用几个ioctl命令对这个文件描述符进行一些初始化的工作,然后进行特性的协商,从而宿主机跟客户机的vhost-net driver建立关系。 QEMU代码调用如下:

vhost_net_init -> vhost_dev_init -> vhost_net_ack_features

+ switch=virbr0
+ '[' -n tap0 ']'
++ whoami
+ ip tuntap add tap0 mode tap user root
ioctl(TUNSETIFF): Device or resource busy
+ ip link set tap0 up
+ sleep 0.5s
+ ip link set tap0 master virbr0
+ exit 0

[root@localhost cloud_images]# brctl show
bridge name     bridge id               STP enabled     interfaces
virbr0          8000.5254000d3f71       yes             enp125s0f1
                                                        tap0
                                                        virbr0-nic

[root@localhost cloud_images]# ps -elf | grep vhost
7 S root      49044      1  9  80   0 - 88035 poll_s 21:56 ?        00:00:11 qemu-system-aarch64 -name vm2 -daemonize -enable-kvm -M virt -cpu host -smp 2 -m 4096 -object memory-backend-file,id=mem,size=4096M,mem-path=/mnt/huge,share=on -numa node,memdev=mem -mem-prealloc -global virtio-blk-device.scsi=off -device virtio-scsi-device,id=scsi -kernel vmlinuz-4.18 --append console=ttyAMA0  root=UUID=6a09973e-e8fd-4a6d-a8c0-1deb9556f477 iommu=pt intel_iommu=on iommu.passthrough=1 -initrd initramfs-4.18 -drive file=vhuser-test1.qcow2 -serial telnet:localhost:4322,server,nowait -monitor telnet:localhost:4321,server,nowait -net nic,model=virtio,macaddr=00:16:3e:22:22:22 -net tap,id=hostnet1,script=qemu-ifup,vnet_hdr=on,vhost=on -vnc :10
1 S root      49065      2  0  80   0 -     0 vhost_ 21:56 ?        00:00:00 [vhost-49044]

[root@localhost ~]# cat /proc/49065/stack 
[<ffff000008085ed4>] __switch_to+0x8c/0xa8
[<ffff000001e507d8>] vhost_worker+0x148/0x170 [vhost]
[<ffff0000080f8638>] kthread+0x10c/0x138
[<ffff000008084f54>] ret_from_fork+0x10/0x18
[<ffffffffffffffff>] 0xffffffffffffffff
[root@localhost ~]# 

- To get qemu vcpu thread id
# ps -eLo ruser,pid,ppid,lwp,args | grep qemu-kvm | grep -v grep

- To get vhost thread id
# ps -eaf |grep vhost-$pid_of_qemu-kvm |grep -v grep

[root@localhost cloud_images]# ps -eLo ruser,pid,ppid,lwp,args | grep qemu-system-aarch64  | grep vhost |  grep -v grep | wc -l
20

[root@localhost cloud_images]# ps -eLo ruser,pid,ppid,lwp,args | grep qemu-system-aarch64  | grep -v grep
root      48617      1  48617 qemu-system-aarch64 -name vm2 -daemonize -enable-kvm -M virt -cpu host -smp 16 -m 4096 -object memory-backend-file,id=mem,size=4096M,mem-path=/mnt/huge,share=on -numa node,memdev=mem -mem-prealloc -drive file=vhuser-test1.qcow2 -global virtio-blk-device.scsi=off -device virtio-scsi-device,id=scsi -kernel vmlinuz-4.18 --append console=ttyAMA0  root=UUID=6a09973e-e8fd-4a6d-a8c0-1deb9556f477 iommu=pt intel_iommu=on iommu.passthrough=1 -initrd initramfs-4.18 -serial telnet:localhost:4322,server,nowait -monitor telnet:localhost:4321,server,nowait -chardev socket,id=char0,path=/tmp/vhost1,server -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce -device virtio-net-pci,netdev=netdev0,mac=52:54:00:00:00:01,mrg_rxbuf=on,rx_queue_size=256,tx_queue_size=256 -vnc :10
root      48617      1  48618 qemu-system-aarch64 -name vm2 -daemonize -enable-kvm -M virt -cpu host -smp 16 -m 4096 -object memory-backend-file,id=mem,size=4096M,mem-path=/mnt/huge,share=on -numa node,memdev=mem -mem-prealloc -drive file=vhuser-test1.qcow2 -global virtio-blk-device.scsi=off -device virtio-scsi-device,id=scsi -kernel vmlinuz-4.18 --append console=ttyAMA0  root=UUID=6a09973e-e8fd-4a6d-a8c0-1deb9556f477 iommu=pt intel_iommu=on iommu.passthrough=1 -initrd initramfs-4.18 -serial telnet:localhost:4322,server,nowait -monitor telnet:localhost:4321,server,nowait -chardev socket,id=char0,path=/tmp/vhost1,server -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce -device virtio-net-pci,netdev=netdev0,mac=52:54:00:00:00:01,mrg_rxbuf=on,rx_queue_size=256,tx_queue_size=256 -vnc :10
root      48617      1  48619 qemu-system-aarch64 -name vm2 -daemonize -enable-kvm -M virt -cpu host -smp 16 -m 4096 -object memory-backend-file,id=mem,size=4096M,mem-path=/mnt/huge,share=on -numa node,memdev=mem -mem-prealloc -drive file=vhuser-test1.qcow2 -global virtio-blk-device.scsi=off -device virtio-scsi-device,id=scsi -kernel vmlinuz-4.18 --append console=ttyAMA0  root=UUID=6a09973e-e8fd-4a6d-a8c0-1deb9556f477 iommu=pt intel_iommu=on iommu.passthrough=1 -initrd initramfs-4.18 -serial telnet:localhost:4322,server,nowait -monitor telnet:localhost:4321,server,nowait -chardev socket,id=char0,path=/tmp/vhost1,server -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce -device virtio-net-pci,netdev=netdev0,mac=52:54:00:00:00:01,mrg_rxbuf=on,rx_queue_size=256,tx_queue_size=256 -vnc :10
root      48617      1  48672 qemu-system-aarch64 -name vm2 -daemonize -enable-kvm -M virt -cpu host -smp 16 -m 4096 -object memory-backend-file,id=mem,size=4096M,mem-path=/mnt/huge,share=on -numa node,memdev=mem -mem-prealloc -drive file=vhuser-test1.qcow2 -global virtio-blk-device.scsi=off -device virtio-scsi-device,id=scsi -kernel vmlinuz-4.18 --append console=ttyAMA0  root=UUID=6a09973e-e8fd-4a6d-a8c0-1deb9556f477 iommu=pt intel_iommu=on iommu.passthrough=1 -initrd initramfs-4.18 -serial telnet:localhost:4322,server,nowait -monitor telnet:localhost:4321,server,nowait -chardev socket,id=char0,path=/tmp/vhost1,server -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce -device virtio-net-pci,netdev=netdev0,mac=52:54:00:00:00:01,mrg_rxbuf=on,rx_queue_size=256,tx_queue_size=256 -vnc :10
root      48617      1  48674 qemu-system-aarch64 -name vm2 -daemonize -enable-kvm -M virt -cpu host -smp 16 -m 4096 -object memory-backend-file,id=mem,size=4096M,mem-path=/mnt/huge,share=on -numa node,memdev=mem -mem-prealloc -drive file=vhuser-test1.qcow2 -global virtio-blk-device.scsi=off -device virtio-scsi-device,id=scsi -kernel vmlinuz-4.18 --append console=ttyAMA0  root=UUID=6a09973e-e8fd-4a6d-a8c0-1deb9556f477 iommu=pt intel_iommu=on iommu.passthrough=1 -initrd initramfs-4.18 -serial telnet:localhost:4322,server,nowait -monitor telnet:localhost:4321,server,nowait -chardev socket,id=char0,path=/tmp/vhost1,server -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce -device virtio-net-pci,netdev=netdev0,mac=52:54:00:00:00:01,mrg_rxbuf=on,rx_queue_size=256,tx_queue_size=256 -vnc :10
root      48617      1  48676 qemu-system-aarch64 -name vm2 -daemonize -enable-kvm -M virt -cpu host -smp 16 -m 4096 -object memory-backend-file,id=mem,size=4096M,mem-path=/mnt/huge,share=on -numa node,memdev=mem -mem-prealloc -drive file=vhuser-test1.qcow2 -global virtio-blk-device.scsi=off -device virtio-scsi-device,id=scsi -kernel vmlinuz-4.18 --append console=ttyAMA0  root=UUID=6a09973e-e8fd-4a6d-a8c0-1deb9556f477 iommu=pt intel_iommu=on iommu.passthrough=1 -initrd initramfs-4.18 -serial telnet:localhost:4322,server,nowait -monitor telnet:localhost:4321,server,nowait -chardev socket,id=char0,path=/tmp/vhost1,server -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce -device virtio-net-pci,netdev=netdev0,mac=52:54:00:00:00:01,mrg_rxbuf=on,rx_queue_size=256,tx_queue_size=256 -vnc :10
root      48617      1  48677 qemu-system-aarch64 -name vm2 -daemonize -enable-kvm -M virt -cpu host -smp 16 -m 4096 -object memory-backend-file,id=mem,size=4096M,mem-path=/mnt/huge,share=on -numa node,memdev=mem -mem-prealloc -drive file=vhuser-test1.qcow2 -global virtio-blk-device.scsi=off -device virtio-scsi-device,id=scsi -kernel vmlinuz-4.18 --append console=ttyAMA0  root=UUID=6a09973e-e8fd-4a6d-a8c0-1deb9556f477 iommu=pt intel_iommu=on iommu.passthrough=1 -initrd initramfs-4.18 -serial telnet:localhost:4322,server,nowait -monitor telnet:localhost:4321,server,nowait -chardev socket,id=char0,path=/tmp/vhost1,server -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce -device virtio-net-pci,netdev=netdev0,mac=52:54:00:00:00:01,mrg_rxbuf=on,rx_queue_size=256,tx_queue_size=256 -vnc :10
root      48617      1  48678 qemu-system-aarch64 -name vm2 -daemonize -enable-kvm -M virt -cpu host -smp 16 -m 4096 -object memory-backend-file,id=mem,size=4096M,mem-path=/mnt/huge,share=on -numa node,memdev=mem -mem-prealloc -drive file=vhuser-test1.qcow2 -global virtio-blk-device.scsi=off -device virtio-scsi-device,id=scsi -kernel vmlinuz-4.18 --append console=ttyAMA0  root=UUID=6a09973e-e8fd-4a6d-a8c0-1deb9556f477 iommu=pt intel_iommu=on iommu.passthrough=1 -initrd initramfs-4.18 -serial telnet:localhost:4322,server,nowait -monitor telnet:localhost:4321,server,nowait -chardev socket,id=char0,path=/tmp/vhost1,server -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce -device virtio-net-pci,netdev=netdev0,mac=52:54:00:00:00:01,mrg_rxbuf=on,rx_queue_size=256,tx_queue_size=256 -vnc :10
root      48617      1  48679 qemu-system-aarch64 -name vm2 -daemonize -enable-kvm -M virt -cpu host -smp 16 -m 4096 -object memory-backend-file,id=mem,size=4096M,mem-path=/mnt/huge,share=on -numa node,memdev=mem -mem-prealloc -drive file=vhuser-test1.qcow2 -global virtio-blk-device.scsi=off -device virtio-scsi-device,id=scsi -kernel vmlinuz-4.18 --append console=ttyAMA0  root=UUID=6a09973e-e8fd-4a6d-a8c0-1deb9556f477 iommu=pt intel_iommu=on iommu.passthrough=1 -initrd initramfs-4.18 -serial telnet:localhost:4322,server,nowait -monitor telnet:localhost:4321,server,nowait -chardev socket,id=char0,path=/tmp/vhost1,server -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce -device virtio-net-pci,netdev=netdev0,mac=52:54:00:00:00:01,mrg_rxbuf=on,rx_queue_size=256,tx_queue_size=256 -vnc :10
root      48617      1  48680 qemu-system-aarch64 -name vm2 -daemonize -enable-kvm -M virt -cpu host -smp 16 -m 4096 -object memory-backend-file,id=mem,size=4096M,mem-path=/mnt/huge,share=on -numa node,memdev=mem -mem-prealloc -drive file=vhuser-test1.qcow2 -global virtio-blk-device.scsi=off -device virtio-scsi-device,id=scsi -kernel vmlinuz-4.18 --append console=ttyAMA0  root=UUID=6a09973e-e8fd-4a6d-a8c0-1deb9556f477 iommu=pt intel_iommu=on iommu.passthrough=1 -initrd initramfs-4.18 -serial telnet:localhost:4322,server,nowait -monitor telnet:localhost:4321,server,nowait -chardev socket,id=char0,path=/tmp/vhost1,server -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce -device virtio-net-pci,netdev=netdev0,mac=52:54:00:00:00:01,mrg_rxbuf=on,rx_queue_size=256,tx_queue_size=256 -vnc :10
root      48617      1  48681 qemu-system-aarch64 -name vm2 -daemonize -enable-kvm -M virt -cpu host -smp 16 -m 4096 -object memory-backend-file,id=mem,size=4096M,mem-path=/mnt/huge,share=on -numa node,memdev=mem -mem-prealloc -drive file=vhuser-test1.qcow2 -global virtio-blk-device.scsi=off -device virtio-scsi-device,id=scsi -kernel vmlinuz-4.18 --append console=ttyAMA0  root=UUID=6a09973e-e8fd-4a6d-a8c0-1deb9556f477 iommu=pt intel_iommu=on iommu.passthrough=1 -initrd initramfs-4.18 -serial telnet:localhost:4322,server,nowait -monitor telnet:localhost:4321,server,nowait -chardev socket,id=char0,path=/tmp/vhost1,server -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce -device virtio-net-pci,netdev=netdev0,mac=52:54:00:00:00:01,mrg_rxbuf=on,rx_queue_size=256,tx_queue_size=256 -vnc :10
root      48617      1  48682 qemu-system-aarch64 -name vm2 -daemonize -enable-kvm -M virt -cpu host -smp 16 -m 4096 -object memory-backend-file,id=mem,size=4096M,mem-path=/mnt/huge,share=on -numa node,memdev=mem -mem-prealloc -drive file=vhuser-test1.qcow2 -global virtio-blk-device.scsi=off -device virtio-scsi-device,id=scsi -kernel vmlinuz-4.18 --append console=ttyAMA0  root=UUID=6a09973e-e8fd-4a6d-a8c0-1deb9556f477 iommu=pt intel_iommu=on iommu.passthrough=1 -initrd initramfs-4.18 -serial telnet:localhost:4322,server,nowait -monitor telnet:localhost:4321,server,nowait -chardev socket,id=char0,path=/tmp/vhost1,server -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce -device virtio-net-pci,netdev=netdev0,mac=52:54:00:00:00:01,mrg_rxbuf=on,rx_queue_size=256,tx_queue_size=256 -vnc :10
root      48617      1  48683 qemu-system-aarch64 -name vm2 -daemonize -enable-kvm -M virt -cpu host -smp 16 -m 4096 -object memory-backend-file,id=mem,size=4096M,mem-path=/mnt/huge,share=on -numa node,memdev=mem -mem-prealloc -drive file=vhuser-test1.qcow2 -global virtio-blk-device.scsi=off -device virtio-scsi-device,id=scsi -kernel vmlinuz-4.18 --append console=ttyAMA0  root=UUID=6a09973e-e8fd-4a6d-a8c0-1deb9556f477 iommu=pt intel_iommu=on iommu.passthrough=1 -initrd initramfs-4.18 -serial telnet:localhost:4322,server,nowait -monitor telnet:localhost:4321,server,nowait -chardev socket,id=char0,path=/tmp/vhost1,server -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce -device virtio-net-pci,netdev=netdev0,mac=52:54:00:00:00:01,mrg_rxbuf=on,rx_queue_size=256,tx_queue_size=256 -vnc :10
root      48617      1  48684 qemu-system-aarch64 -name vm2 -daemonize -enable-kvm -M virt -cpu host -smp 16 -m 4096 -object memory-backend-file,id=mem,size=4096M,mem-path=/mnt/huge,share=on -numa node,memdev=mem -mem-prealloc -drive file=vhuser-test1.qcow2 -global virtio-blk-device.scsi=off -device virtio-scsi-device,id=scsi -kernel vmlinuz-4.18 --append console=ttyAMA0  root=UUID=6a09973e-e8fd-4a6d-a8c0-1deb9556f477 iommu=pt intel_iommu=on iommu.passthrough=1 -initrd initramfs-4.18 -serial telnet:localhost:4322,server,nowait -monitor telnet:localhost:4321,server,nowait -chardev socket,id=char0,path=/tmp/vhost1,server -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce -device virtio-net-pci,netdev=netdev0,mac=52:54:00:00:00:01,mrg_rxbuf=on,rx_queue_size=256,tx_queue_size=256 -vnc :10
root      48617      1  48685 qemu-system-aarch64 -name vm2 -daemonize -enable-kvm -M virt -cpu host -smp 16 -m 4096 -object memory-backend-file,id=mem,size=4096M,mem-path=/mnt/huge,share=on -numa node,memdev=mem -mem-prealloc -drive file=vhuser-test1.qcow2 -global virtio-blk-device.scsi=off -device virtio-scsi-device,id=scsi -kernel vmlinuz-4.18 --append console=ttyAMA0  root=UUID=6a09973e-e8fd-4a6d-a8c0-1deb9556f477 iommu=pt intel_iommu=on iommu.passthrough=1 -initrd initramfs-4.18 -serial telnet:localhost:4322,server,nowait -monitor telnet:localhost:4321,server,nowait -chardev socket,id=char0,path=/tmp/vhost1,server -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce -device virtio-net-pci,netdev=netdev0,mac=52:54:00:00:00:01,mrg_rxbuf=on,rx_queue_size=256,tx_queue_size=256 -vnc :10
root      48617      1  48686 qemu-system-aarch64 -name vm2 -daemonize -enable-kvm -M virt -cpu host -smp 16 -m 4096 -object memory-backend-file,id=mem,size=4096M,mem-path=/mnt/huge,share=on -numa node,memdev=mem -mem-prealloc -drive file=vhuser-test1.qcow2 -global virtio-blk-device.scsi=off -device virtio-scsi-device,id=scsi -kernel vmlinuz-4.18 --append console=ttyAMA0  root=UUID=6a09973e-e8fd-4a6d-a8c0-1deb9556f477 iommu=pt intel_iommu=on iommu.passthrough=1 -initrd initramfs-4.18 -serial telnet:localhost:4322,server,nowait -monitor telnet:localhost:4321,server,nowait -chardev socket,id=char0,path=/tmp/vhost1,server -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce -device virtio-net-pci,netdev=netdev0,mac=52:54:00:00:00:01,mrg_rxbuf=on,rx_queue_size=256,tx_queue_size=256 -vnc :10
root      48617      1  48687 qemu-system-aarch64 -name vm2 -daemonize -enable-kvm -M virt -cpu host -smp 16 -m 4096 -object memory-backend-file,id=mem,size=4096M,mem-path=/mnt/huge,share=on -numa node,memdev=mem -mem-prealloc -drive file=vhuser-test1.qcow2 -global virtio-blk-device.scsi=off -device virtio-scsi-device,id=scsi -kernel vmlinuz-4.18 --append console=ttyAMA0  root=UUID=6a09973e-e8fd-4a6d-a8c0-1deb9556f477 iommu=pt intel_iommu=on iommu.passthrough=1 -initrd initramfs-4.18 -serial telnet:localhost:4322,server,nowait -monitor telnet:localhost:4321,server,nowait -chardev socket,id=char0,path=/tmp/vhost1,server -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce -device virtio-net-pci,netdev=netdev0,mac=52:54:00:00:00:01,mrg_rxbuf=on,rx_queue_size=256,tx_queue_size=256 -vnc :10
root      48617      1  48688 qemu-system-aarch64 -name vm2 -daemonize -enable-kvm -M virt -cpu host -smp 16 -m 4096 -object memory-backend-file,id=mem,size=4096M,mem-path=/mnt/huge,share=on -numa node,memdev=mem -mem-prealloc -drive file=vhuser-test1.qcow2 -global virtio-blk-device.scsi=off -device virtio-scsi-device,id=scsi -kernel vmlinuz-4.18 --append console=ttyAMA0  root=UUID=6a09973e-e8fd-4a6d-a8c0-1deb9556f477 iommu=pt intel_iommu=on iommu.passthrough=1 -initrd initramfs-4.18 -serial telnet:localhost:4322,server,nowait -monitor telnet:localhost:4321,server,nowait -chardev socket,id=char0,path=/tmp/vhost1,server -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce -device virtio-net-pci,netdev=netdev0,mac=52:54:00:00:00:01,mrg_rxbuf=on,rx_queue_size=256,tx_queue_size=256 -vnc :10
root      48617      1  48689 qemu-system-aarch64 -name vm2 -daemonize -enable-kvm -M virt -cpu host -smp 16 -m 4096 -object memory-backend-file,id=mem,size=4096M,mem-path=/mnt/huge,share=on -numa node,memdev=mem -mem-prealloc -drive file=vhuser-test1.qcow2 -global virtio-blk-device.scsi=off -device virtio-scsi-device,id=scsi -kernel vmlinuz-4.18 --append console=ttyAMA0  root=UUID=6a09973e-e8fd-4a6d-a8c0-1deb9556f477 iommu=pt intel_iommu=on iommu.passthrough=1 -initrd initramfs-4.18 -serial telnet:localhost:4322,server,nowait -monitor telnet:localhost:4321,server,nowait -chardev socket,id=char0,path=/tmp/vhost1,server -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce -device virtio-net-pci,netdev=netdev0,mac=52:54:00:00:00:01,mrg_rxbuf=on,rx_queue_size=256,tx_queue_size=256 -vnc :10
root      48617      1  48690 qemu-system-aarch64 -name vm2 -daemonize -enable-kvm -M virt -cpu host -smp 16 -m 4096 -object memory-backend-file,id=mem,size=4096M,mem-path=/mnt/huge,share=on -numa node,memdev=mem -mem-prealloc -drive file=vhuser-test1.qcow2 -global virtio-blk-device.scsi=off -device virtio-scsi-device,id=scsi -kernel vmlinuz-4.18 --append console=ttyAMA0  root=UUID=6a09973e-e8fd-4a6d-a8c0-1deb9556f477 iommu=pt intel_iommu=on iommu.passthrough=1 -initrd initramfs-4.18 -serial telnet:localhost:4322,server,nowait -monitor telnet:localhost:4321,server,nowait -chardev socket,id=char0,path=/tmp/vhost1,server -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce -device virtio-net-pci,netdev=netdev0,mac=52:54:00:00:00:01,mrg_rxbuf=on,rx_queue_size=256,tx_queue_size=256 -vnc :10
root      48617      1  48782 qemu-system-aarch64 -name vm2 -daemonize -enable-kvm -M virt -cpu host -smp 16 -m 4096 -object memory-backend-file,id=mem,size=4096M,mem-path=/mnt/huge,share=on -numa node,memdev=mem -mem-prealloc -drive file=vhuser-test1.qcow2 -global virtio-blk-device.scsi=off -device virtio-scsi-device,id=scsi -kernel vmlinuz-4.18 --append console=ttyAMA0  root=UUID=6a09973e-e8fd-4a6d-a8c0-1deb9556f477 iommu=pt intel_iommu=on iommu.passthrough=1 -initrd initramfs-4.18 -serial telnet:localhost:4322,server,nowait -monitor telnet:localhost:4321,server,nowait -chardev socket,id=char0,path=/tmp/vhost1,server -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce -device virtio-net-pci,netdev=netdev0,mac=52:54:00:00:00:01,mrg_rxbuf=on,rx_queue_size=256,tx_queue_size=256 -vnc :10

什么是 vhost

vhost 是 virtio 的一种后端实现方案,在 virtio 简介中,我们已经提到 virtio 是一种半虚拟化的实现方案,需要虚拟机端和主机端都提供驱动才能完成通信,通常,virtio 主机端的驱动是实现在用户空间的 qemu 中,而 vhost 是实现在内核中,是内核的一个模块 vhost-net.ko。为什么要实现在内核中,有什么好处呢,请接着往下看。

为什么要用 vhost

在 virtio 的机制中,guest 与 用户空间的 Hypervisor 通信,会造成多次的数据拷贝和 CPU 特权级的上下文切换。例如 guest 发包给外部网络,首先,guest 需要切换到 host kernel,然后 host kernel 会切换到 qemu 来处理 guest 的请求, Hypervisor 通过系统调用将数据包发送到外部网络后,会切换回 host kernel , 最后再切换回 guest。这样漫长的路径无疑会带来性能上的损失。

vhost 正是在这样的背景下提出的一种改善方案,它是位于 host kernel 的一个模块,用于和 guest 直接通信,数据交换直接在 guest 和 host kernel 之间通过 virtqueue 来进行,qemu 不参与通信,但也没有完全退出舞台,它还要负责一些控制层面的事情,比如和 KVM 之间的控制指令的下发等。

vhost 的数据流程

下图左半部分是 vhost 负责将数据发往外部网络的过程, 右半部分是 vhost 大概的数据交互流程图。其中,qemu 还是需要负责 virtio 设备的适配模拟,负责用户空间某些管理控制事件的处理,而 vhost 实现较为纯净,以一个独立的模块完成 guest 和 host kernel 的数据交换过程。

vhost 与 virtio 前端的通信主要采用一种事件驱动 eventfd 的机制来实现,guest 通知 vhost 的事件要借助 kvm.ko 模块来完成,vhost 初始化期间,会启动一个工作线程 work 来监听 eventfd,一旦 guest 发出对 vhost 的 kick event,kvm.ko 触发 ioeventfd 通知到 vhost,vhost 通过 virtqueue 的 avail ring 获取数据,并设置 used ring。同样,从 vhost 工作线程向 guest 通信时,也采用同样的机制,只不过这种情况发的是一个回调的 call envent,kvm.ko 触发 irqfd 通知 guest。

总结

vhost 与 kvm 的事件通信通过 eventfd 机制来实现,主要包括两个方向的 event,一个是 guest 到 vhost 方向的 kick event,通过 ioeventfd 实现;另一个是 vhost 到 guest 方向的 call event,通过 irqfd 实现。

Vhost 概述

Linux kernel 中的vhost driver提供了KVM在kernel环境中的virtio设备的模拟。vhost把QEMU模拟设备的代码放在了linux kernel里面,所以设备模拟代码可以直接进入kernel子系统,从而不需要从用户空间通过系统调用陷入内核,减少了由于模拟IO导致的性能下降。

vhost-net是在宿主机上对vhost 网卡的模拟,同样,也有vhost-blk,对block设备的模拟,以及vhost-scsi,对scsi设备的模拟。

vhost 在kernel中的代码位于 drivers/vhost/vhost.c

Vhost 驱动模型

vhost driver创建了一个字符设备 /dev/vhost-net,这个设备可以被用户空间打开,并可以被ioctl命令操作。当给一个Qemu进程传递了参数-netdev tap,vhost=on 的时候,QEMU会通过调用几个ioctl命令对这个文件描述符进行一些初始化的工作,然后进行特性的协商,从而宿主机跟客户机的vhost-net driver建立关系。 QEMU代码调用如下:

vhost_net_init -> vhost_dev_init -> vhost_net_ack_features

在vhost_net_init中调用了 vhost_dev_init ,打开/dev/vhost-net这个设备,然后返回一个文件描述符作为vhost-net的后端, vhost_dev_init 调用的ioctl命令有

r = ioctl(hdev->control, VHOST_SET_OWNER, NULL);

Kernel 中的定义为:

1.  /* Set current process as the (exclusive) owner of this file descriptor.  This  
2.   * must be called before any other vhost command.  Further calls to  
3.   * VHOST_OWNER_SET fail until VHOST_OWNER_RESET is called. */  
4.  #define VHOST_SET_OWNER _IO(VHOST_VIRTIO, 0x01)

然后获取VHOST支持的特性

r = ioctl(hdev->control, VHOST_GET_FEATURES, &features);

同样,kernel中的定义为:

1.  /* Features bitmask for forward compatibility.  Transport bits are used for  
2.   * vhost specific features. */  
3.  #define VHOST_GET_FEATURES      _IOR(VHOST_VIRTIO, 0x00, __u64)  

QEMU中用vhost_net 这个数据结构代表打开的vhost_net 实例:

1.  struct vhost_net {  
2.      struct vhost_dev dev;  
3.      struct vhost_virtqueue vqs[2];  
4.      int backend;  
5.      NetClientState *nc;  
6.  };  

使用ioctl设置完后,QEMU注册memory_listener 回调函数:

1.  hdev->memory_listener = (MemoryListener) {  
2.      .begin = vhost_begin,  
3.      .commit = vhost_commit,  
4.      .region_add = vhost_region_add,  
5.      .region_del = vhost_region_del,  
6.      .region_nop = vhost_region_nop,  
7.      .log_start = vhost_log_start,  
8.      .log_stop = vhost_log_stop,  
9.      .log_sync = vhost_log_sync,  
10.     .log_global_start = vhost_log_global_start,  
11.     .log_global_stop = vhost_log_global_stop,  
12.     .eventfd_add = vhost_eventfd_add,  
13.     .eventfd_del = vhost_eventfd_del,  
14.     .priority = 10  
15. };  

vhost_region_add 是为了将QEMU guest的地址空间映射到vhost driver

最后进行特性的协商:

1.  /* Set sane init value. Override when guest acks. */  
2.  vhost_net_ack_features(net, 0); 

与此同时,kernel中要创建一个kernel thread 用于处理I/O事件和设备的模拟。 kernel代码 drivers/vhost/vhost.c:

在vhost_dev_set_owner中,调用了这个函数用于创建worker线程(线程名字为vhost-qemu+进程pid)

Kernel 中的virtio 模拟

vhost并没有完全模拟一个pci设备,相反,它只把自己限制在对virtqueue的操作上。

worker thread 一直等待virtqueue的数据,对于vhost-net来说,当virtqueue的tx队列中有数据了,它会把数据传送到与其相关联的tap设备文件描述符上。

相反,worker thread 也要进行tap文件描述符的轮询,对于vhost-net,当tap文件描述符有数据到来时候,worker thread会被唤醒,然后将数据传送到rx队列中。

vhost的在用户空间的接口

数据已经准备好了,如何通知客户机呢?

从vhost模块的依赖性可以得知,vhost这个模块并没有依赖于kvm 模块,也就是说,理论上其他应用只要实现了和vhost接口,也可以调用vhost来进行数据传输的加速。

但也正是因为vhost跟kvm模块没什么关系,当QEMU(KVM)guest把数据放到tx队列(virtqueue)上之后,它是没有办法直接通知vhost数据准备了的。

不过,vhost 设置了一个eventfd文件描述符,这个文件描述符被前面我们提到的worker thread 监控,所以QEMU可以通过向eventfd发送消息告诉vhost数据准备好了。

QEMU的做法是这样的,在QEMU中注册一个ioeventfd,当guest 发生I/O退出了,会被KVM捕捉到,KVM向vhost发送eventfd从而告知vhost KVM guest已经准备好数据了。由于 worker thread监控这个eventfd,在收到消息后,知道guest已经把数据放到了tx队列,可以进行对戏

vhost通过发出一个guest中断,通过KVM提供的irqevent,告诉guest需要传送的buffer已经放到了rx virtqueue了,QEMU(KVM)注册这个irq PCI事件,得知内核空间的数据准备好了,调用guest驱动进行数据的读取。

所以,总的来说 vhost 实例需要知道的有三样

  • guest的内存映射,也就是virtqueue,用于数据的传输
  • qemu kick eventfd,vhost接收guest发送的消息,该消息被worker thread捕获
  • call event(irqfd)用于通知guest

以上三点在QEMU初始化的时候准备好,数据的传输只在内核空间就完成了,不需要QEMU进行干预,所以这也是为什么使用vhost进行传输数据高效的原因

(免费订阅,永久学习)学习地址: Dpdk/网络协议栈/vpp/OvS/DDos/NFV/虚拟化/高性能专家-学习视频教程-腾讯课堂

更多DPDK相关学习资料有需要的可以自行报名学习,免费订阅,永久学习,或点击这里加qun免费
领取,关注我持续更新哦! !   

原文链接

:https://www.cnblogs.com/dream397/p/13935494.html 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/29421.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[附源码]SSM计算机毕业设计基于实时定位的超市配送业务管理JAVA

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

低碳世界杂志低碳世界杂志社低碳世界编辑部2022年第7期目录

节能环保 挥发性有机物的全厂控制措施 董少军; 1-3 《低碳世界》投稿&#xff1a;cnqikantg126.com 佛山市市政排水管网通沟污泥处理处置工艺设计 张红; 4-6 “双碳”背景下海岸带地区适应气候变化评估与对策研究 王鸿浩;邬乐雅;吴晓晨;张丽佳;黄婧蓼琦;胡斐…

【毕业设计】基于情感分析的网络舆情热点分析系统

文章目录0 前言1 课题背景2 数据处理3 文本情感分析3.1 情感分析-词库搭建3.2 文本情感分析实现3.3 建立情感倾向性分析模型4 数据可视化工具4.1 django框架介绍4.2 ECharts5 Django使用echarts进行可视化展示5.1 修改setting.py连接mysql数据库5.2 导入数据5.3 使用echarts可视…

Java编程实战9:统计只差一个字符的子串数目

目录统计只差一个字符的子串数目题目示例 1示例 2示例 3示例 4提示解答解题思路完整代码统计只差一个字符的子串数目 题目 给你两个字符串 s 和 t &#xff0c;请你找出 s 中的非空子串的数目&#xff0c;这些子串满足替换 一个不同字符 以后&#xff0c;是 t 串的子串。换言…

实验1:Arduino的nRF24L01单向收发实验

实验结果: 发送端发送“Hello World”,发送成功打印1 接收端接收到“Hello World”,在串口中打印出“Hello World” OK,直接讲代码 因为我用的Arduino和nRF24L01 是用扩展板连接的,而我的嵌入式硬件开发,也就是AD实在不擅长,就不解释了 其中(9,10)CE,CSN 那么我…

通关算法题之 ⌈数组⌋ 下

二分搜索 704. 二分查找 给定一个 n 个元素有序的&#xff08;升序&#xff09;整型数组 nums 和一个目标值 target &#xff0c;写一个函数搜索 nums 中的 target&#xff0c;如果目标值存在返回下标&#xff0c;否则返回 -1。 输入: nums [-1,0,3,5,9,12], target 9 输出…

【后台技术】异步编程指北,问题和重点

导语&#xff1a;同步、异步&#xff0c;并发、并行、串行&#xff0c;这些名词在我们的开发中会经常遇到&#xff0c;这里对异步编程做一个详细的归纳总结&#xff0c;希望可以对这方面的开发有一些帮助。 内容大纲&#xff1a; 1、几个名词的概念 多任务的时候&#xff0c;…

jmeter压力测试报告

出版社智能智造测试报告 &#xff08;二期版本&#xff09; 2022年11月 目 录 1. 测试背景 1.1. 项目背景 1.2. 测试目的 1.3. 测试时间 1.4. 测试资源 1.5. 参考资料 2. 测试范围 3. 性能需求指标 3.1. 业界指标 4. 测试工具 5. 测试环境 5.1. 阿里云测试环境软…

搭建Gitlab

Gitlab是目前被广泛使用的基于git的开源代码管理平台, 基于Ruby on Rails构建, 主要针对软件开发过程中产生的代码和文档进行管理 一、搭建gitlab服务器&#xff0c;统一管理软件项目 第一步&#xff1a; 创建一个4G内存的虚拟机&#xff0c;否则很容易启动不了&#xff0c;报…

(附源码)计算机毕业设计Java“华商转转”平台的设计和实现

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; Springboot mybatis Maven Vue 等等组成&#xff0c;B/…

python常用进制转换

整数之间转换 # 1. 10 -> 16 hex(number)# 2. 10 -> 2 bin(number)# 3. 10 -> 8 oct(number)# 4. x进制 -> 10 int(Union[str, bytes, bytearray],basex) ------------------ print(int("0x16", base16)) // 22字符串转整数 # 10进制 val int(10) pri…

SPP-学习笔记

Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition SPP提出的原因 1、现有的深度卷积神经网络(spp出现之前的)需要固定大小的输入图像(例如224224)。往往需要对图片裁剪或者resize&#xff0c;导致图片信息损失或者产生几何畸变。这样可能会损…

奥比中光亮相全球1024开发者节,与科大讯飞达成战略合作

作者 | 奥比中光 编辑 | 3D视觉开发者社区 11月17日-23日&#xff0c;第五届世界声博会暨2022科大讯飞全球1024开发者节在安徽合肥举办&#xff0c;奥比中光作为3D视觉感知头部企业参展&#xff0c;并与科大讯飞达成战略合作&#xff0c;共同赋能3D视觉行业应用开发。 本次参…

如何利用现代工具来管理多项目

多项目管理是如今现代企业管理时常常遇到的一个难题。不同于单项目管理&#xff0c;多个项目同时进行管理要复杂得很多。而单纯的手工管理方式已经满足不了多管理的复杂需求&#xff0c;项目负责人想要保障在预定的时间内&#xff0c;又快又好地完成整体项目&#xff0c;便需要…

工厂模式解耦-交由spring来完成

上面两个小节一直在谈论解耦&#xff0c;从入门的多例到升级的单例BeanFactory工厂类是我们自己手工写的。 BeanFactory主要做了3件事&#xff1a; 1.读取配置文件&#xff08;可以是properties或xml类型的文件&#xff0c;示例中用的是properties文件&#xff09; 2.获取类…

OC RSA加密解密

好久好久没有更新了。。。你们等的急不急。。这不&#xff0c;我就姗姗来迟了。。。本文重点讲解一下iOS系统下的RSA加密解密问题。 一般为了安全&#xff0c;私钥是不会给前端暴露出来 的&#xff0c;只会通过私钥生成一个公开的公钥提供给外部对数据进行加密。将加密后的数据…

残差网络ResNet解读

一、残差网络的定义 残差网络的核心是解决增加深度带来的退化问题&#xff0c;这样能够通过单纯增加网络深度来提高网络性能。 残差单元以短连接的形式&#xff0c;将单元的输入直接与单元输出加在一起&#xff0c;然后再进行激活。 Weight为抽取特征的网络层 Addition时xl和…

RK3568平台开发系列讲解(视频篇)摄像头采集视频的相关配置

🚀返回专栏总目录 文章目录 一、权限配置二、配置摄像头2.1、打开摄像头2.2、预览格式2.3、预览尺寸沉淀、分享、成长,让自己和他人都能有所收获!😄 📢Android 平台的摄像头的采集核心部分都是在 Native 层构建的,所以这就会涉及 JNI 层的一些转换操作。 一、权限配置…

Linux | 进程间通信 | 匿名管道 | 命名管道 | 模拟代码实现进程通信 |

文章目录进程通信的意义匿名管道通信原理管道的访问控制进程控制管道的特点命名管道进程通信的意义 之前聊进程时&#xff0c;讲过一个性质&#xff0c;即进程具有独立性&#xff0c;两个进程之间的交互频率是比较少的。就连父子进程也只是共享代码&#xff0c;修改父子进程中…

MODBUS通信系列之数据处理

MODBUS通信专栏有详细文章讲解,这里不再赘述,大家可以自行查看。链接如下: SMART S7-200PLC MODBUS通信_RXXW_Dor的博客-CSDN博客_smart200做modbus通讯MODBUS 是 OSI 模型第 7 层上的应用层报文传输协议,它在连接至不同类型总线或网络的设备之间提供客户机/服务器通信。自…