Revision 199b2053 lib/hypervisor/hv_kvm.py

b/lib/hypervisor/hv_kvm.py
31 31
import time
32 32
import logging
33 33
import pwd
34
import struct
35
import fcntl
34 36
from cStringIO import StringIO
35 37

  
36 38
from ganeti import utils
......
46 48

  
47 49
_KVM_NETWORK_SCRIPT = constants.SYSCONFDIR + "/ganeti/kvm-vif-bridge"
48 50

  
51
# TUN/TAP driver constants, taken from <linux/if_tun.h>
52
# They are architecture-independent and already hardcoded in qemu-kvm source,
53
# so we can safely include them here.
54
TUNSETIFF = 0x400454ca
55
TUNGETIFF = 0x800454d2
56
TUNGETFEATURES = 0x800454cf
57
IFF_TAP = 0x0002
58
IFF_NO_PI = 0x1000
59
IFF_VNET_HDR = 0x4000
60

  
61

  
62
def _ProbeTapVnetHdr(fd):
63
  """Check whether to enable the IFF_VNET_HDR flag.
64

  
65
  To do this, _all_ of the following conditions must be met:
66
   1. TUNGETFEATURES ioctl() *must* be implemented
67
   2. TUNGETFEATURES ioctl() result *must* contain the IFF_VNET_HDR flag
68
   3. TUNGETIFF ioctl() *must* be implemented; reading the kernel code in
69
      drivers/net/tun.c there is no way to test this until after the tap device
70
      has been created using TUNSETIFF, and there is no way to change the
71
      IFF_VNET_HDR flag after creating the interface, catch-22! However both
72
      TUNGETIFF and TUNGETFEATURES were introduced in kernel version 2.6.27,
73
      thus we can expect TUNGETIFF to be present if TUNGETFEATURES is.
74

  
75
   @type fd: int
76
   @param fd: the file descriptor of /dev/net/tun
77

  
78
  """
79
  req = struct.pack("I", 0)
80
  try:
81
    res = fcntl.ioctl(fd, TUNGETFEATURES, req)
82
  except EnvironmentError:
83
    logging.warning("TUNGETFEATURES ioctl() not implemented")
84
    return False
85

  
86
  tunflags = struct.unpack("I", res)[0]
87
  if tunflags & IFF_VNET_HDR:
88
    return True
89
  else:
90
    logging.warning("Host does not support IFF_VNET_HDR, not enabling")
91
    return False
92

  
93

  
94
def _OpenTap(vnet_hdr=True):
95
  """Open a new tap device and return its file descriptor.
96

  
97
  This is intended to be used by a qemu-type hypervisor together with the -net
98
  tap,fd=<fd> command line parameter.
99

  
100
  @type vnet_hdr: boolean
101
  @param vnet_hdr: Enable the VNET Header
102
  @return: (ifname, tapfd)
103
  @rtype: tuple
104

  
105
  """
106
  try:
107
    tapfd = os.open("/dev/net/tun", os.O_RDWR)
108
  except EnvironmentError:
109
    raise errors.HypervisorError("Failed to open /dev/net/tun")
110

  
111
  flags = IFF_TAP | IFF_NO_PI
112

  
113
  if vnet_hdr and _ProbeTapVnetHdr(tapfd):
114
    flags |= IFF_VNET_HDR
115

  
116
  # The struct ifreq ioctl request (see netdevice(7))
117
  ifr = struct.pack("16sh", "", flags)
118

  
119
  try:
120
    res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
121
  except EnvironmentError:
122
    raise errors.HypervisorError("Failed to allocate a new TAP device")
123

  
124
  # Get the interface name from the ioctl
125
  ifname = struct.unpack("16sh", res)[0].strip("\x00")
126
  return (ifname, tapfd)
127

  
49 128

  
50 129
def _WriteNetScript(instance, nic, index):
51 130
  """Write a script to connect a net interface to the proper bridge.

Also available in: Unified diff