Package ganeti :: Package hypervisor :: Package hv_kvm :: Module netdev
[hide private]
[frames] | no frames]

Source Code for Module ganeti.hypervisor.hv_kvm.netdev

  1  # 
  2  # 
  3   
  4  # Copyright (C) 2014 Google Inc. 
  5  # All rights reserved. 
  6  # 
  7  # Redistribution and use in source and binary forms, with or without 
  8  # modification, are permitted provided that the following conditions are 
  9  # met: 
 10  # 
 11  # 1. Redistributions of source code must retain the above copyright notice, 
 12  # this list of conditions and the following disclaimer. 
 13  # 
 14  # 2. Redistributions in binary form must reproduce the above copyright 
 15  # notice, this list of conditions and the following disclaimer in the 
 16  # documentation and/or other materials provided with the distribution. 
 17  # 
 18  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 
 19  # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 
 20  # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
 21  # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
 22  # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
 23  # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
 24  # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
 25  # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
 26  # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
 27  # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
 28  # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 29   
 30   
 31  """KVM hypervisor tap device helpers 
 32   
 33  """ 
 34   
 35  import os 
 36  import logging 
 37  import struct 
 38  import fcntl 
 39   
 40  from ganeti import errors 
 41   
 42   
 43  # TUN/TAP driver constants, taken from <linux/if_tun.h> 
 44  # They are architecture-independent and already hardcoded in qemu-kvm source, 
 45  # so we can safely include them here. 
 46  TUNSETIFF = 0x400454ca 
 47  TUNGETIFF = 0x800454d2 
 48  TUNGETFEATURES = 0x800454cf 
 49  IFF_TAP = 0x0002 
 50  IFF_NO_PI = 0x1000 
 51  IFF_ONE_QUEUE = 0x2000 
 52  IFF_VNET_HDR = 0x4000 
 53  IFF_MULTI_QUEUE = 0x0100 
 54   
 55   
56 -def _GetTunFeatures(fd, _ioctl=fcntl.ioctl):
57 """Retrieves supported TUN features from file descriptor. 58 59 @see: L{_ProbeTapVnetHdr} 60 61 """ 62 req = struct.pack("I", 0) 63 try: 64 buf = _ioctl(fd, TUNGETFEATURES, req) 65 except EnvironmentError, err: 66 logging.warning("ioctl(TUNGETFEATURES) failed: %s", err) 67 return None 68 else: 69 (flags, ) = struct.unpack("I", buf) 70 return flags
71 72
73 -def _ProbeTapVnetHdr(fd, _features_fn=_GetTunFeatures):
74 """Check whether to enable the IFF_VNET_HDR flag. 75 76 To do this, _all_ of the following conditions must be met: 77 1. TUNGETFEATURES ioctl() *must* be implemented 78 2. TUNGETFEATURES ioctl() result *must* contain the IFF_VNET_HDR flag 79 3. TUNGETIFF ioctl() *must* be implemented; reading the kernel code in 80 drivers/net/tun.c there is no way to test this until after the tap device 81 has been created using TUNSETIFF, and there is no way to change the 82 IFF_VNET_HDR flag after creating the interface, catch-22! However both 83 TUNGETIFF and TUNGETFEATURES were introduced in kernel version 2.6.27, 84 thus we can expect TUNGETIFF to be present if TUNGETFEATURES is. 85 86 @type fd: int 87 @param fd: the file descriptor of /dev/net/tun 88 89 """ 90 flags = _features_fn(fd) 91 92 if flags is None: 93 # Not supported 94 return False 95 96 result = bool(flags & IFF_VNET_HDR) 97 98 if not result: 99 logging.warning("Kernel does not support IFF_VNET_HDR, not enabling") 100 101 return result
102 103
104 -def _ProbeTapMqVirtioNet(fd, _features_fn=_GetTunFeatures):
105 """Check whether to enable the IFF_MULTI_QUEUE flag. 106 107 This flag was introduced in Linux kernel 3.8. 108 109 @type fd: int 110 @param fd: the file descriptor of /dev/net/tun 111 112 """ 113 flags = _features_fn(fd) 114 115 if flags is None: 116 # Not supported 117 return False 118 119 result = bool(flags & IFF_MULTI_QUEUE) 120 121 if not result: 122 logging.warning("Kernel does not support IFF_MULTI_QUEUE, not enabling") 123 124 return result
125 126
127 -def OpenTap(vnet_hdr=True, virtio_net_queues=1, name=""):
128 """Open a new tap device and return its file descriptor. 129 130 This is intended to be used by a qemu-type hypervisor together with the -net 131 tap,fd=<fd> or -net tap,fds=x:y:...:z command line parameter. 132 133 @type vnet_hdr: boolean 134 @param vnet_hdr: Enable the VNET Header 135 136 @type virtio_net_queues: int 137 @param virtio_net_queues: Set number of tap queues but not more than 8, 138 queues only work with virtio-net device; 139 disabled by default (one queue). 140 141 @type name: string 142 @param name: name for the TAP interface being created; if an empty 143 string is passed, the OS will generate a unique name 144 145 @return: (ifname, [tapfds]) 146 @rtype: tuple 147 148 """ 149 tapfds = [] 150 151 for _ in range(virtio_net_queues): 152 try: 153 tapfd = os.open("/dev/net/tun", os.O_RDWR) 154 except EnvironmentError: 155 raise errors.HypervisorError("Failed to open /dev/net/tun") 156 157 flags = IFF_TAP | IFF_NO_PI 158 159 if vnet_hdr and _ProbeTapVnetHdr(tapfd): 160 flags |= IFF_VNET_HDR 161 162 # Check if it's ok to enable IFF_MULTI_QUEUE 163 if virtio_net_queues > 1 and _ProbeTapMqVirtioNet(tapfd): 164 flags |= IFF_MULTI_QUEUE 165 else: 166 flags |= IFF_ONE_QUEUE 167 168 # The struct ifreq ioctl request (see netdevice(7)) 169 ifr = struct.pack("16sh", name, flags) 170 171 try: 172 res = fcntl.ioctl(tapfd, TUNSETIFF, ifr) 173 except EnvironmentError, err: 174 raise errors.HypervisorError("Failed to allocate a new TAP device: %s" % 175 err) 176 177 tapfds.append(tapfd) 178 179 # Get the interface name from the ioctl 180 ifname = struct.unpack("16sh", res)[0].strip("\x00") 181 182 return (ifname, tapfds)
183