vlambda博客
学习文章列表

linux虚拟网络设备--虚拟机网卡和linux bridge上tap设备的关系(六)

1. 虚拟机进程

使用ps –ef |grepkvm可以看到虚拟机进程信息如下:
/usr/libexec/qemu-kvm -nameinstance-0000001d -S -machine pc-i440fx-rhel7.1.0,accel=kvm,usb=off -cpuBroadwell,+abm,+pdpe1gb,+hypervisor,+rdrand,+f16c,+osxsave,+vmx,+ss,+ds,+vme -m64 -realtime mlock=off -smp 1,sockets=1,cores=1,threads=1 -uuid 687fd29c-13c2-433b-941c-2414da556bdb-smbios type=1,manufacturer=Fedora Project,product=OpenStackNova,version=12.0.0-1.el7,serial=a373d218-fea2-4c1c-b255-26714654fdbe,uuid=687fd29c-13c2-433b-941c-2414da556bdb,family=VirtualMachine -no-user-config -nodefaults -chardevsocket,id=charmonitor,path=/var/lib/libvirt/qemu/instance-0000001d.monitor,server,nowait-mon chardev=charmonitor,id=monitor,mode=control -rtc base=utc,driftfix=slew-global kvm-pit.lost_tick_policy=discard -no-hpet -no-shutdown -boot strict=on-device ich9-usb-ehci1,id=usb,bus=pci.0,addr=0x5.0x7 -deviceich9-usb-uhci1,masterbus=usb.0,firstport=0,bus=pci.0,multifunction=on,addr=0x5-device ich9-usb-uhci2,masterbus=usb.0,firstport=2,bus=pci.0,addr=0x5.0x1-device ich9-usb-uhci3,masterbus=usb.0,firstport=4,bus=pci.0,addr=0x5.0x2-device virtio-serial-pci,id=virtio-serial0,bus=pci.0,addr=0x6 -drivefile=rbd:vms/687fd29c-13c2-433b-941c-2414da556bdb_disk:id=cinder:key=AQBqCA9X18xZOxAAWVDkhAOsKZIQY6oAf9cjlg==:auth_supported=cephx;none:mon_host=192.168.44.130:6789,if=none,id=drive-virtio-disk0,format=raw,cache=none-devicevirtio-blk-pci,scsi=off,bus=pci.0,addr=0x7,drive=drive-virtio-disk0,id=virtio-disk0,bootindex=1-drivefile=rbd:vms/687fd29c-13c2-433b-941c-2414da556bdb_disk.config:id=cinder:key=AQBqCA9X18xZOxAAWVDkhAOsKZIQY6oAf9cjlg==:auth_supported=cephx;none:mon_host=192.168.44.130:6789,if=none,id=drive-ide0-1-1,readonly=on,format=raw,cache=none-device ide-cd,bus=ide.1,unit=1,drive=drive-ide0-1-1,id=ide0-1-1 -netdev tap,fd=25,id=hostnet0,vhost=on,vhostfd=26 -device virtio-net-pci,netdev=hostnet0,id=net0 ,mac=fa:16:3e:36:c0:a7,bus=pci.0,addr=0x3-chardevfile,id=charserial0,path=/var/lib/nova/instances/687fd29c-13c2-433b-941c-2414da556bdb/console.log-device isa-serial,chardev=charserial0,id=serial0 -chardev pty,id=charserial1-device isa-serial,chardev=charserial1,id=serial1 -chardevspicevmc,id=charchannel0,name=vdagent -devicevirtserialport,bus=virtio-serial0.0,nr=1,chardev=charchannel0,id=channel0,name=com.redhat.spice.0-chardev socket,id=charchannel1,path=/var/lib/libvirt/qemu/org.qemu.guest_agent.0.instance-0000001d.sock,server,nowait-devicevirtserialport,bus=virtio-serial0.0,nr=2,chardev=charchannel1,id=channel1,name=org.qemu.guest_agent.0-device usb-tablet,id=input0 -vnc 0.0.0.0:0 -k en-us -spiceport=5901,addr=0.0.0.0,disable-ticketing,disable-copy-paste,disable-agent-file-xfer,seamless-migration=on-k en-us -deviceqxl-vga,id=video0,ram_size=67108864,vram_size=67108864,vgamem_mb=16,bus=pci.0,addr=0x2-device AC97,id=sound0,bus=pci.0,addr=0x4 -devicevirtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x8 -msg timestamp=on

关注其中的网卡配置参数:

  • 从HOST角度:

    -netdev tap

    ,fd=25,

    id=hostnet0,vhost=on

    ,vhostfd=26

  • 从GUEST角度:

    -devicevirtio-net-pci,netdev=hostnet0,id=net0

    ,mac=fa:16:3e:36:c0:a7,bus=pci.0,addr=0x3

可以看到,host上使用tap类型的网卡,开启了vhost-net技术。

vhost-net技术是在半虚拟化技术virtio上提出的,而virtio则是基于全虚拟化技术而言的。所以在了解vhost-net技术之前,需要先了解一下tun/tap工作原理、全虚拟化技术、virtio技术。

2. Tap/Tun工作原理

TUN/TAP虚拟网络设备的原理比较简单,他在Linux内核中添加了一个TUN/TAP虚拟网络设备的驱动程序和一个与之相关连的字符设备/dev/net/tun,字符设备tun作为用户空间和内核空间交换数据的接口。用户空间的应用程序可以通过这个设备文件来和内核中的驱动程序进行交互,其操作方式和普通的文件操作无异。当内核将数据包发送到虚拟网络设备时,数据包被保存在设备相关的一个队列中,直到用户空间程序通过打开的字符设备tun的描述符读取时,它才会被拷贝到用户空间的缓冲区中,其效果就相当于,数据包直接发送到了用户空间。通过系统调用write发送数据包时其原理与此类似。

从结构上来说,Tun/tap驱动并不单纯是实现网卡驱动,同时它还实现了字符设备驱动部分。以字符设备的方式连接用户态和核心态。下面是示意图:

Tun/tap 驱动程序中包含两个部分,一部分是字符设备驱动,还有一部分是网卡驱动部分。利用网卡驱动部分接收来自TCP/IP协议栈的网络分包并发送或者反过来将接收到的网络分包传给协议栈处理,而字符驱动部分则将网络分包在内核与用户态之间传送,模拟物理链路的数据接收和发送。Tun/tap驱动很好的实现了两种驱动的结合。

3. Tap/Tun Device在libvirt中的应用

  • 将guest system的网络和host system的网络连在一起。

  • 通过TUN/TAP adapter,会生成一个在host system上的虚拟网卡tap

  • tun建立了point to point的网络设备,使得guest system的网卡和tap虚拟网卡成为一对

  • 从而guest system的所有网络包,host system都能收到。

Tun/tap驱动程序中包含两个部分,一部分是字符设备驱动,还有一部分是网卡驱动部分
linux虚拟网络设备--虚拟机网卡和linux bridge上tap设备的关系(六)

  • 虚拟机将网络包通过字符设备写入/dev/net/tun(Host上);

  • 字符设备驱动将数据包写入虚拟网卡驱动;

  • 虚拟网卡驱动将包通过TCP/IP协议栈写给Host上的虚拟网卡tap0;

  • 在HOST上通过路由规则(通过网桥(东西向流量)、网桥和路由器(南北向流量)),包从eth0出去。

4. Linux全虚拟机网络桥接模型

KVM 客户机网络连接有两种方式:

用户网络(User Networking):让虚拟机访问主机、互联网或本地网络上的资源的简单方法,但是不能从网络或其他的客户机访问客户机,性能上也需要大的调整。NAT方式。

虚拟网桥(Virtual Bridge):这种方式要比用户网络复杂一些,但是设置好后客户机与互联网,客户机与主机之间的通信都很容易。Bridge方式。

Bridge方式即虚拟网桥的网络连接方式,是客户机和子网里面的机器能够互相通信。可以使虚拟机成为网络中具有独立IP的主机。桥接网络(也叫物理设备共享)被用作把一个物理设备复制到一台虚拟机。网桥多用作高级设置,特别是主机多个网络接口的情况。

linux虚拟网络设备--虚拟机网卡和linux bridge上tap设备的关系(六)
在Linux中的虚拟机的网卡都包含前半段和后半段,前半段在虚拟机上,后半段在宿主机上。上图eth0为虚拟机上的网卡,对应的后半段为vnet0,vnet0为tap设备。在虚拟机上所有发往eth0的数据就直接发往vnet0了,也可以将vnet0看作一块网卡。

当响应报文到达物理机上的eth0时如何判断此响应报文是发给虚拟机的还是物理机自己的?

5. Qemu全虚拟化网桥模式下的VM的收发包的流程

linux虚拟网络设备--虚拟机网卡和linux bridge上tap设备的关系(六)
如图中所示,红色箭头表示数据报文的入方向,步骤:

  1. 网络数据从 Host 上的物理网卡接收,到达网桥;

  2. 由于 eth0 与 tap1 均加入网桥中,根据二层转发原则,br0 将数据从tap1 口转发出去,即数据由 Tap设备接收;

  3. Tap 设备通知对应的 fd 数据可读; fd 的读动作通过 tap

  4. 设备的字符设备驱动将数据拷贝到用户空间,完成数据报文的前端接收。

6. 准虚拟化(Para-virtualizaiton) I/O 驱动 virtio

KVM/QEMU 的 vitio 实现采用在 Guest OS 内核中安装前端驱动 (Front-end driver)和在 QEMU 中实现后端驱动(Back-end)的方式。前后端驱动通过 vring 直接通信,这就绕过了经过 KVM 内核模块的过程,达到提高 I/O 性能的目的。纯软件模拟的设备和 Virtio 设备的区别:virtio 省去了纯模拟模式下的异常捕获环节,Guest OS 可以和 QEMU 的I/O 模块直接通信。Vitio需要让客户机知道自己运行在虚拟化环境中。

使用Virtio的完整虚拟机I/O流程:
linux虚拟网络设备--虚拟机网卡和linux bridge上tap设备的关系(六)
Host 数据发到 Guest:

  1. KVM 通过中断的方式通知 QEMU 去获取数据,放到 virtio queue 中

  2. KVM 再通知 Guest 去 virtio queue 中取数据。

7. Vhost-net驱动

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

virtio-net 和 vhost-net的比较:

备注:当客户机通过DMA (Direct Memory Access)访问大块I/O时,QEMU 模拟程序将不会把结果放进共享页中,而是通过内存映射的方式将结果直接写到客户机的内存中,然后通知KVM模块告诉客户机DMA操作已经完成。

8. 结论:

综上,虚拟机网卡eth0存在于虚拟机上(即guest),网桥tap设备则存在于宿主机(即host)上,是两个设备。这两个设备是一对设备,同时出现、同时消失,组合在一起完成虚拟机和外部的通信。两个设备通过host上的/dev/net/tun设备、内核网卡驱动、共享队列实现数据包的通信。

原文链接:https://blog.csdn.net/xiakewudi/article/details/76851076