[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 [] __switch_to+0x8c/0xa8 [ ] vhost_worker+0x148/0x170 [vhost] [ ] kthread+0x10c/0x138 [ ] ret_from_fork+0x10/0x18 [ ] 0xffffffffffffffff [root@localhost ~]#
- To get qemu vcpu thread id # ps -eLo