(KVM连载) 5.1.4 使用virtio_net (半虚拟化网卡)

5.1.4 使用virtio_net

1. 配置和使用virtio_net

在选择KVM中的网络设备时,一般来说优先选择半虚拟化的网络设备而不是纯软件模拟的设备,使用virtio_net半虚拟化驱动,可以提高网络吞吐量(thoughput)和降低网络延迟(latency),从而让客户机中网络达到几乎和原生网卡差不多的性能。

virtio_net的使用,需要两部分的支持,在宿主机中的QEMU工具的支持和客户机中virtio_net驱动的支持。较新的qemu-kvm都对virtio网卡设备的支持,且较新的流行Linux发行版中都已经将virtio_net作为模块编译到系统之中了,所以使用起来还是比较方便的。

可以通过如下几个步骤来使用virtio_net。

1. 检查QEMU是否支持virtio类型的网卡

[root@jay-linux kvm_demo]# qemu-system-x86_64 -net nic,model=?

qemu: Supported NIC models: ne2k_pci,i82551,i82557b,i82559er,rtl8139,e1000,pcnet,virtio

从输出信息中支持网卡类型可知,当前qemu-kvm支持virtio网卡模型。

2. 启动客户机时,指定分配virtio网卡设备。

[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

VNC server running on ::1:5900'

3. 在客户机中查看virtio网卡的使用情况。

[root@kvm-guest ~]# grep VIRTIO_ /boot/config-2.6.32-279.el6.x86_64

CONFIG_VIRTIO_BLK=m

CONFIG_VIRTIO_NET=m

CONFIG_VIRTIO_CONSOLE=m

CONFIG_VIRTIO_RING=m

CONFIG_VIRTIO_PCI=m

CONFIG_VIRTIO_BALLOON=m

[root@kvm-guest ~]# lspci

00:00.0 Host bridge: Intel Corporation 440FX - 82441FX PMC [Natoma] (rev 02)

00:01.0 ISA bridge: Intel Corporation 82371SB PIIX3 ISA [Natoma/Triton II]

00:01.1 IDE interface: Intel Corporation 82371SB PIIX3 IDE [Natoma/Triton II]

00:01.3 Bridge: Intel Corporation 82371AB/EB/MB PIIX4 ACPI (rev 03)

00:02.0 VGA compatible controller: Cirrus Logic GD 5446

00:03.0 Ethernet controller: Red Hat, Inc Virtio network device

[root@kvm-guest ~]# lspci -vv -s 00:03.0

00:03.0 Ethernet controller: Red Hat, Inc Virtio network device

Subsystem: Red Hat, Inc Device 0001

Physical Slot: 3

Control: I/O+ Mem+ BusMaster- SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx+

Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-

Interrupt: pin A routed to IRQ 11

Region 0: I/O ports at c000 [size=32]

Region 1: Memory at febf1000 (32-bit, non-prefetchable) [size=4K]

Expansion ROM at febe0000 [disabled] [size=64K]

Capabilities: [40] MSI-X: Enable+ Count=3 Masked-

Vector table: BAR=1 offset=00000000

PBA: BAR=1 offset=00000800

Kernel driver in use: virtio-pci

Kernel modules: virtio_pci

[root@kvm-guest ~]# lsmod | grep virtio

virtio_net             16760  0

virtio_pci              7113  0

virtio_ring             7729  2 virtio_net,virtio_pci

virtio                  4890  2 virtio_net,virtio_pci

[root@kvm-guest ~]# ethtool -i eth1

driver: virtio_net

version:

firmware-version:

bus-info: virtio0

[root@kvm-guest ~]# ifconfig eth1

eth1      Link encap:Ethernet  HWaddr 00:16:3E:22:22:22

inet addr:192.168.156.200  Bcast:192.168.255.255  Mask:255.255.0.0

inet6 addr: fe80::216:3eff:fe22:2222/64 Scope:Link

UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

RX packets:500 errors:0 dropped:0 overruns:0 frame:0

TX packets:103 errors:0 dropped:0 overruns:0 carrier:0

collisions:0 txqueuelen:1000

RX bytes:65854 (64.3 KiB)  TX bytes:19057 (18.6 KiB)

[root@kvm-guest ~]# ping 192.168.199.98 -c 1

PING 192.168.199.98 (192.168.199.98) 56(84) bytes of data.

64 bytes from 192.168.199.98: icmp_seq=1 ttl=64 time=0.313 ms

 

--- 192.168.199.98 ping statistics ---

1 packets transmitted, 1 received, 0% packet loss, time 0ms

rtt min/avg/max/mdev = 0.313/0.313/0.313/0.000 ms

根据上面输出信息可知,网络接口eth1使用了virtio_net驱动,且当前网络连接正常工作。如果启动Windows客户机使用virtio类型的网卡,则在Windows客户机的“设备管理器”中看到一个名为“Red Hat VirtIO Ethernet Adapter”的设备即是客户机中的网卡。

2. 宿主机中TSO和GSO的设置

据Redhat的文档[3]介绍,如果你在使用半虚拟化网络驱动(即virtio_net)时依然得到较低的性能,可以检查宿主机系统中对GSO和TSO[4]特性的设置。关闭GSO和TSO可以使半虚拟化网络驱动的性能得到更加优化。

如下的命令可以检查宿主机中GSO和TSO的设置,其中eth0是建立bridge供客户机使用的网络接口。

[root@jay-linux ~]# brctl show

bridge name     bridge id               STP enabled     interfaces

br0             8000.001320fb4fa8       yes             eth0

tap0

[root@jay-linux ~]# ethtool -k eth0

Offload parameters for eth0:

rx-checksumming: on

tx-checksumming: on

scatter-gather: on

tcp-segmentation-offload: on           #这个就是TSO的状态

udp-fragmentation-offload: off

generic-segmentation-offload: on      #这是GSO的状态

generic-receive-offload: on

large-receive-offload: off

通过如下命令可以关闭其GSO和TSO功能。

[root@jay-linux ~]# ethtool -K eth0 gso off

[root@jay-linux ~]# ethtool -K eth0 tso off

[root@jay-linux ~]# ethtool -k eth0

Offload parameters for eth0:

rx-checksumming: on

tx-checksumming: on

scatter-gather: on

tcp-segmentation-offload: off

udp-fragmentation-offload: off

generic-segmentation-offload: off

generic-receive-offload: on

large-receive-offload: off

3. 用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'

启动后,检查客户机网络,应该是可以正常连接的。

而在宿主机中,可以查看vhost-net的使用情况,如下。

[root@jay-linux kvm_demo]# grep VHOST /boot/config-3.5.0

CONFIG_VHOST_NET=m

[root@jay-linux kvm_demo]# lsmod | grep vhost

vhost_net              17161  1

tun                    13220  3 vhost_net

[root@jay-linux kvm_demo]# rmmod vhost-net

ERROR: Module vhost_net is in use

可见,宿主机中内核将vhost-net编译为module,此时vhost-net模块处于使用中状态(试图删除它时即报告了一个“在使用中”的错误)。

一般来说,使用vhost-net作为后端处理驱动可以提高网络的性能。不过,对于一些网络负载类型使用vhost-net作为后端,却可能使其性能不升反降。特别是从宿主机到其中的客户机之间的UDP流量,如果客户机处理接受数据的速度比宿主机发送的速度要慢,这时就容易出现性能下降。在这种情况下,使用vhost-net将会是UDP socket的接受缓冲区更快地溢出,从而导致更多的数据包丢失。故这种情况下,不使用vhost-net,让传输速度稍微慢一点,反而会提高整体的性能。

使用qemu-kvm命令行,加上“vhost=off”(或没有vhost选项)就会不使用vhost-net,而在使用libvirt时,需要对客户机的配置的XML文件中的网络配置部分进行如下的配置,指定后端驱动的名称为“qemu”(而不是“vhost”)。

<interface type="network">

...

<model type="virtio"/>

<driver name="qemu"/>

...

</interface>

master

Stay hungry, stay foolish.

4 Comments

  1. smiler 你好,请问一个问题。back-end driver 是由qemu提供,如果自己想开发一个qemu 没有提供驱动的网卡的的驱动的话,该怎么办呢?比如模仿qemu-kvm 中的e1000 或者 rtl8139 的驱动写一个加入到qemu-kvm 源码中,按照你之前提供的编译方式编译码?

    • Hi, 你可以参考hw/rtl8139.c 或者 e1000.c 的实现吧。还需要修改pci.c文件和编译配置项(x86_64-softmmu/config-devices.mak),也需要./pc-bios/pxe-rtl8139.rom 这样的网卡ROM文件。按照我提供的方式编译即可(注意把自己的新网卡设备编译进去)。我没这样实际做过,可能不完全准确。

  2. 你好请教一个问题,ethtool -i eth1 在相同配置的kvm上分别执行,输出不一样

    driver: virtio_net
    version:
    firmware-version:
    bus-info: virtio0
    supports-statistics: no
    supports-test: no
    supports-eeprom-access: no
    supports-register-dump: no
    supports-priv-flags: no

    driver: virtio_net
    version: 1.0.0
    firmware-version:
    bus-info: 0000:00:03.0
    supports-statistics: no
    supports-test: no
    supports-eeprom-access: no
    supports-register-dump: no
    supports-priv-flags: no

    都是virtio_net,一个现实出pci接口 一个显示virtio0

    • 1. 再次确认启动kvm虚拟机的配置是否一样
      2. 看下两个虚拟化操作系统的版本是否一样
      3. lspci | grep virtio 看看

发表评论

邮箱地址不会被公开。 必填项已用*标注

*