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

Reply via email to