1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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
44
45
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
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
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
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
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
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(name="", features=None):
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 name: string
134 @param name: name for the TAP interface being created; if an empty
135 string is passed, the OS will generate a unique name
136
137 @type features: dict
138 @param features: A dict denoting whether vhost, vnet_hdr, mq
139 netdev features are enabled or not.
140
141 @return: (ifname, [tapfds], [vhostfds])
142 @rtype: tuple
143
144 """
145 tapfds = []
146 vhostfds = []
147 if features is None:
148 features = {}
149 vhost = features.get("vhost", False)
150 vnet_hdr = features.get("vnet_hdr", True)
151 _, virtio_net_queues = features.get("mq", (False, 1))
152
153 for _ in range(virtio_net_queues):
154 try:
155 tapfd = os.open("/dev/net/tun", os.O_RDWR)
156 except EnvironmentError:
157 raise errors.HypervisorError("Failed to open /dev/net/tun")
158
159 flags = IFF_TAP | IFF_NO_PI
160
161 if vnet_hdr and _ProbeTapVnetHdr(tapfd):
162 flags |= IFF_VNET_HDR
163
164
165 if virtio_net_queues > 1 and _ProbeTapMqVirtioNet(tapfd):
166 flags |= IFF_MULTI_QUEUE
167 else:
168 flags |= IFF_ONE_QUEUE
169
170
171 ifr = struct.pack("16sh", name, flags)
172
173 try:
174 res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
175 except EnvironmentError, err:
176 raise errors.HypervisorError("Failed to allocate a new TAP device: %s" %
177 err)
178
179 if vhost:
180
181
182
183
184 try:
185 vhostfd = os.open("/dev/vhost-net", os.O_RDWR)
186 vhostfds.append(vhostfd)
187 except EnvironmentError:
188 raise errors.HypervisorError("Failed to open /dev/vhost-net")
189
190 tapfds.append(tapfd)
191
192
193 ifname = struct.unpack("16sh", res)[0].strip("\x00")
194
195 return (ifname, tapfds, vhostfds)
196