On 14:55 Tue 21 Dec , Apollon Oikonomopoulos wrote: > Hi, > > On 13:31 Thu 16 Dec , Guido Trotter wrote: > > On Mon, Dec 13, 2010 at 3:21 PM, Apollon Oikonomopoulos > > <[email protected]> wrote: > > > Add two new functions, _OpenTap and _ProbeTapVnetHdr, to > > > hypervisors.hv_kvm. > > > > > > > Should they be in hv_kvm or in netutils.py? > I was thinking about that too, but chose to use hv_kvm since KVM is the > only user of this feature right now. > > > > _ProbeTapVnetHdr checks if the host side supports IFF_VNET_HDR and thus a > > > qemu-kvm instance with version >= 0.12.0 and virtio-net can leverage the > > > kernel's capabilities to perform GSO (see code comments). > > > > > > > Can you explain better in the comment what this exactly is and does? Hi,
Patch with updated commit message follows. What about the location? Should I move the functions to netutils? Thanks, Apollon -- Add two new functions, _OpenTap and _ProbeTapVnetHdr, to hypervisors.hv_kvm. _ProbeTapVnetHdr checks if the host kernel supports the virtio net header (IFF_VNET_HDR) feature. This feature allows KVM to ask the the host kernel to perform checksumming and segmentation offload of the data passing through a guest's virtio NIC, using a special header[1] prepended to data sent through the tap interface. A qemu-kvm version later than 0.12 is required for this feature to work. _OpenTap opens a new tap device suitable for use with qemu-kvm's "-net tap,fd=n" option. It also enables vnet_hdr support if requested and safe to do so. [1] struct virtio_net_hdr in include/linux/virtio_net.h Signed-off-by: Apollon Oikonomopoulos <[email protected]> --- lib/hypervisor/hv_kvm.py | 79 ++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 79 insertions(+), 0 deletions(-) diff --git a/lib/hypervisor/hv_kvm.py b/lib/hypervisor/hv_kvm.py index 46f41c5..ee895f3 100644 --- a/lib/hypervisor/hv_kvm.py +++ b/lib/hypervisor/hv_kvm.py @@ -31,6 +31,8 @@ import tempfile import time import logging import pwd +import struct +import fcntl from cStringIO import StringIO from ganeti import utils @@ -46,6 +48,83 @@ from ganeti import netutils _KVM_NETWORK_SCRIPT = constants.SYSCONFDIR + "/ganeti/kvm-vif-bridge" +# TUN/TAP driver constants, taken from <linux/if_tun.h> +# They are architecture-independent and already hardcoded in qemu-kvm source, +# so we can safely include them here. +TUNSETIFF = 0x400454ca +TUNGETIFF = 0x800454d2 +TUNGETFEATURES = 0x800454cf +IFF_TAP = 0x0002 +IFF_NO_PI = 0x1000 +IFF_VNET_HDR = 0x4000 + + +def _ProbeTapVnetHdr(fd): + """Check whether to enable the IFF_VNET_HDR flag. + + To do this, _all_ of the following conditions must be met: + 1. TUNGETFEATURES ioctl() *must* be implemented + 2. TUNGETFEATURES ioctl() result *must* contain the IFF_VNET_HDR flag + 3. TUNGETIFF ioctl() *must* be implemented; reading the kernel code in + drivers/net/tun.c there is no way to test this until after the tap device + has been created using TUNSETIFF, and there is no way to change the + IFF_VNET_HDR flag after creating the interface, catch-22! However both + TUNGETIFF and TUNGETFEATURES were introduced in kernel version 2.6.27, + thus we can expect TUNGETIFF to be present if TUNGETFEATURES is. + + @type fd: int + @param fd: the file descriptor of /dev/net/tun + + """ + req = struct.pack("I", 0) + try: + res = fcntl.ioctl(fd, TUNGETFEATURES, req) + except: + logging.warning("TUNGETFEATURES ioctl() not implemented") + return False + + tunflags = struct.unpack("I", res)[0] + if tunflags & IFF_VNET_HDR: + return True + else: + logging.warning("Host does not support IFF_VNET_HDR, not enabling") + return False + + +def _OpenTap(vnet_hdr=True): + """Open a new tap device and return its file descriptor. + + This is intended to be used by a qemu-type hypervisor together with the -net + tap,fd=<fd> command line parameter. + + @type vnet_hdr: boolean + @param vnet_hdr: Enable the VNET Header + @return: (ifname, tapfd) + @rtype: tuple + + """ + try: + tapfd = os.open("/dev/net/tun", os.O_RDWR) + except os.OSError: + raise errors.HypervisorError("Failed to open /dev/net/tun") + + flags = IFF_TAP | IFF_NO_PI + + if vnet_hdr and _ProbeTapVnetHdr(tapfd): + flags |= IFF_VNET_HDR + + # The struct ifreq ioctl request (see netdevice(7)) + ifr = struct.pack("16sh", "", flags) + + try: + res = fcntl.ioctl(tapfd, TUNSETIFF, ifr) + except: + raise errors.HypervisorError("Failed to allocate a new TAP device") + + # Get the interface name from the ioctl + ifname = struct.unpack("16sh", res)[0].strip("\x00") + return (ifname, tapfd) + def _WriteNetScript(instance, nic, index): """Write a script to connect a net interface to the proper bridge. -- 1.7.1
