Merge lp:~qrilka/ubuntu/precise/libvirt/libvirt-fix-1092826 into lp:ubuntu/precise/libvirt
- Precise (12.04)
- libvirt-fix-1092826
- Merge into precise
Status: | Work in progress |
---|---|
Proposed branch: | lp:~qrilka/ubuntu/precise/libvirt/libvirt-fix-1092826 |
Merge into: | lp:ubuntu/precise/libvirt |
Diff against target: |
20791 lines (+20549/-6) 28 files modified
.pc/.quilt_patches (+1/-0) .pc/.quilt_series (+1/-0) .pc/applied-patches (+2/-0) .pc/ubuntu/qemu-warn-on-pc-0.12.patch/src/qemu/qemu_command.c (+7527/-0) .pc/ubuntu/qemu-warn-on-pc-0.12.patch/src/qemu/qemu_driver.c (+11642/-0) .pc/ubuntu/storage-fix-a-potential-crash-when-creating-vol-object/src/storage/storage_backend_logical.c (+827/-0) debian/README.Debian (+20/-0) debian/apparmor/libvirt-qemu (+3/-0) debian/apparmor/usr.sbin.libvirtd (+1/-0) debian/changelog (+48/-0) debian/control (+1/-1) debian/libvirt-bin.apport (+1/-1) debian/libvirt-bin.dirs (+1/-0) debian/libvirt-bin.dnsmasq (+4/-0) debian/libvirt-bin.install (+2/-1) debian/libvirt-bin.manpages (+1/-0) debian/libvirt-bin.postinst (+3/-0) debian/libvirt-bin.postrm (+4/-0) debian/libvirt-migrate-qemu-machinetype (+196/-0) debian/libvirt-migrate-qemu-machinetype.1 (+78/-0) debian/patches/fix-poll.patch (+77/-0) debian/patches/series (+3/-0) debian/patches/ubuntu/qemu-warn-on-pc-0.12.patch (+44/-0) debian/patches/ubuntu/storage-fix-a-potential-crash-when-creating-vol-object (+38/-0) debian/rules (+6/-1) src/qemu/qemu_command.c (+7/-1) src/qemu/qemu_driver.c (+8/-0) src/storage/storage_backend_logical.c (+3/-1) |
To merge this branch: | bzr merge lp:~qrilka/ubuntu/precise/libvirt/libvirt-fix-1092826 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jamie Strandboge | Needs Fixing | ||
Ubuntu branches | Pending | ||
Review via email: mp+141163@code.launchpad.net |
Commit message
Description of the change
Fix for LP: #1092826
Jamie Strandboge (jdstrand) wrote : | # |
Also:
* the version '0.9.8-
Unmerged revisions
- 211. By Kirill Zaborsky
-
adds proper handling for EINTR signal (LP: #1092826)
- 210. By Serge Hallyn
-
* storage-
fix-a-potential -crash- when-creating- vol-object: avoid a crash
on bad free() on error lvm storage. (LP: #1035320)
* add pm-utils as suggests to avoid log spamming with messages about
pm-is-supported not being found. (LP: #994476) - 209. By Serge Hallyn
-
debian/
apparmor/ libvirt- qemu: add ceph.conf (LP: #1026404) - 208. By Serge Hallyn
-
* debian/
libvirt- bin.install, debian/rules: name the apport file
source_libvirt. py, not source_ libvirt- bin.py. (LP: #1007405)
* install /etc/dnsmasq.d/libvirt to configure system wide dnsmasq to not
listen on the libvirt bridge. (Following Stéphane's lxc example)
(LP: #928524) (LP: #231060)
- postinst: restart dnsmasq; postrm: remove dnsmasq.d/libvirt file and
restart dnsmasq; rules, libvirt-bin.dirs and libvirt-bin.install:
install new debian/libvirt- bin.dnsmasq file.
* Warn user about bad pc-0.12 machine type, and help user transition.
(LP: #1001625)
- qemu-warn-on-pc-0. 12.patch: When defining or starting a VM which uses the
pc-0.12 machine type, warn in libvirtd.log.
- debian/libvirt- migrate- qemu-machinetyp e: automatically migrate QEMU VMs
to newest machine type. This is not done automatically as there will
be some users who have good reason to stay with pc-0.12. - 207. By Serge Hallyn
-
debian/
apparmor/ usr.sbin. libvirtd: allow execution of /lib/udev/scsi_id
(LP: #992378)
Preview Diff
1 | === added file '.pc/.quilt_patches' | |||
2 | --- .pc/.quilt_patches 1970-01-01 00:00:00 +0000 | |||
3 | +++ .pc/.quilt_patches 2012-12-22 20:09:19 +0000 | |||
4 | @@ -0,0 +1,1 @@ | |||
5 | 1 | debian/patches | ||
6 | 0 | 2 | ||
7 | === added file '.pc/.quilt_series' | |||
8 | --- .pc/.quilt_series 1970-01-01 00:00:00 +0000 | |||
9 | +++ .pc/.quilt_series 2012-12-22 20:09:19 +0000 | |||
10 | @@ -0,0 +1,1 @@ | |||
11 | 1 | series | ||
12 | 0 | 2 | ||
13 | === modified file '.pc/applied-patches' | |||
14 | --- .pc/applied-patches 2012-04-05 11:43:15 +0000 | |||
15 | +++ .pc/applied-patches 2012-12-22 20:09:19 +0000 | |||
16 | @@ -34,3 +34,5 @@ | |||
17 | 34 | ubuntu/9024-qemu-allow-snapshotting-of-sheepdog-and-rbd-disks.patch | 34 | ubuntu/9024-qemu-allow-snapshotting-of-sheepdog-and-rbd-disks.patch |
18 | 35 | ubuntu/9025-qemu-change-rbd-auth_supported-separation-character-.patch | 35 | ubuntu/9025-qemu-change-rbd-auth_supported-separation-character-.patch |
19 | 36 | ubuntu/xen-config-no-vfb-for-hvm.patch | 36 | ubuntu/xen-config-no-vfb-for-hvm.patch |
20 | 37 | ubuntu/qemu-warn-on-pc-0.12.patch | ||
21 | 38 | ubuntu/storage-fix-a-potential-crash-when-creating-vol-object | ||
22 | 37 | 39 | ||
23 | === added directory '.pc/ubuntu/qemu-warn-on-pc-0.12.patch' | |||
24 | === added directory '.pc/ubuntu/qemu-warn-on-pc-0.12.patch/src' | |||
25 | === added directory '.pc/ubuntu/qemu-warn-on-pc-0.12.patch/src/qemu' | |||
26 | === added file '.pc/ubuntu/qemu-warn-on-pc-0.12.patch/src/qemu/qemu_command.c' | |||
27 | --- .pc/ubuntu/qemu-warn-on-pc-0.12.patch/src/qemu/qemu_command.c 1970-01-01 00:00:00 +0000 | |||
28 | +++ .pc/ubuntu/qemu-warn-on-pc-0.12.patch/src/qemu/qemu_command.c 2012-12-22 20:09:19 +0000 | |||
29 | @@ -0,0 +1,7527 @@ | |||
30 | 1 | /* | ||
31 | 2 | * qemu_command.c: QEMU command generation | ||
32 | 3 | * | ||
33 | 4 | * Copyright (C) 2006-2011 Red Hat, Inc. | ||
34 | 5 | * Copyright (C) 2006 Daniel P. Berrange | ||
35 | 6 | * | ||
36 | 7 | * This library is free software; you can redistribute it and/or | ||
37 | 8 | * modify it under the terms of the GNU Lesser General Public | ||
38 | 9 | * License as published by the Free Software Foundation; either | ||
39 | 10 | * version 2.1 of the License, or (at your option) any later version. | ||
40 | 11 | * | ||
41 | 12 | * This library is distributed in the hope that it will be useful, | ||
42 | 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
43 | 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
44 | 15 | * Lesser General Public License for more details. | ||
45 | 16 | * | ||
46 | 17 | * You should have received a copy of the GNU Lesser General Public | ||
47 | 18 | * License along with this library; if not, write to the Free Software | ||
48 | 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
49 | 20 | * | ||
50 | 21 | * Author: Daniel P. Berrange <berrange@redhat.com> | ||
51 | 22 | */ | ||
52 | 23 | |||
53 | 24 | #include <config.h> | ||
54 | 25 | |||
55 | 26 | #include "qemu_command.h" | ||
56 | 27 | #include "qemu_capabilities.h" | ||
57 | 28 | #include "qemu_bridge_filter.h" | ||
58 | 29 | #include "cpu/cpu.h" | ||
59 | 30 | #include "memory.h" | ||
60 | 31 | #include "logging.h" | ||
61 | 32 | #include "virterror_internal.h" | ||
62 | 33 | #include "util.h" | ||
63 | 34 | #include "virfile.h" | ||
64 | 35 | #include "uuid.h" | ||
65 | 36 | #include "c-ctype.h" | ||
66 | 37 | #include "domain_nwfilter.h" | ||
67 | 38 | #include "domain_audit.h" | ||
68 | 39 | #include "domain_conf.h" | ||
69 | 40 | #include "network/bridge_driver.h" | ||
70 | 41 | #include "virnetdevtap.h" | ||
71 | 42 | #include "base64.h" | ||
72 | 43 | |||
73 | 44 | #include <sys/utsname.h> | ||
74 | 45 | #include <sys/stat.h> | ||
75 | 46 | #include <fcntl.h> | ||
76 | 47 | |||
77 | 48 | #define VIR_FROM_THIS VIR_FROM_QEMU | ||
78 | 49 | |||
79 | 50 | |||
80 | 51 | VIR_ENUM_DECL(virDomainDiskQEMUBus) | ||
81 | 52 | VIR_ENUM_IMPL(virDomainDiskQEMUBus, VIR_DOMAIN_DISK_BUS_LAST, | ||
82 | 53 | "ide", | ||
83 | 54 | "floppy", | ||
84 | 55 | "scsi", | ||
85 | 56 | "virtio", | ||
86 | 57 | "xen", | ||
87 | 58 | "usb", | ||
88 | 59 | "uml", | ||
89 | 60 | "sata") | ||
90 | 61 | |||
91 | 62 | |||
92 | 63 | VIR_ENUM_DECL(qemuDiskCacheV1) | ||
93 | 64 | VIR_ENUM_DECL(qemuDiskCacheV2) | ||
94 | 65 | |||
95 | 66 | VIR_ENUM_IMPL(qemuDiskCacheV1, VIR_DOMAIN_DISK_CACHE_LAST, | ||
96 | 67 | "default", | ||
97 | 68 | "off", | ||
98 | 69 | "off", /* writethrough not supported, so for safety, disable */ | ||
99 | 70 | "on", /* Old 'on' was equivalent to 'writeback' */ | ||
100 | 71 | "off", /* directsync not supported, for safety, disable */ | ||
101 | 72 | "off"); /* unsafe not supported, for safety, disable */ | ||
102 | 73 | |||
103 | 74 | VIR_ENUM_IMPL(qemuDiskCacheV2, VIR_DOMAIN_DISK_CACHE_LAST, | ||
104 | 75 | "default", | ||
105 | 76 | "none", | ||
106 | 77 | "writethrough", | ||
107 | 78 | "writeback", | ||
108 | 79 | "directsync", | ||
109 | 80 | "unsafe"); | ||
110 | 81 | |||
111 | 82 | VIR_ENUM_DECL(qemuVideo) | ||
112 | 83 | |||
113 | 84 | VIR_ENUM_IMPL(qemuVideo, VIR_DOMAIN_VIDEO_TYPE_LAST, | ||
114 | 85 | "std", | ||
115 | 86 | "cirrus", | ||
116 | 87 | "vmware", | ||
117 | 88 | "", /* no arg needed for xen */ | ||
118 | 89 | "", /* don't support vbox */ | ||
119 | 90 | "qxl"); | ||
120 | 91 | |||
121 | 92 | VIR_ENUM_DECL(qemuControllerModelUSB) | ||
122 | 93 | |||
123 | 94 | VIR_ENUM_IMPL(qemuControllerModelUSB, VIR_DOMAIN_CONTROLLER_MODEL_USB_LAST, | ||
124 | 95 | "piix3-usb-uhci", | ||
125 | 96 | "piix4-usb-uhci", | ||
126 | 97 | "usb-ehci", | ||
127 | 98 | "ich9-usb-ehci1", | ||
128 | 99 | "ich9-usb-uhci1", | ||
129 | 100 | "ich9-usb-uhci2", | ||
130 | 101 | "ich9-usb-uhci3", | ||
131 | 102 | "vt82c686b-usb-uhci", | ||
132 | 103 | "pci-ohci"); | ||
133 | 104 | |||
134 | 105 | VIR_ENUM_DECL(qemuDomainFSDriver) | ||
135 | 106 | VIR_ENUM_IMPL(qemuDomainFSDriver, VIR_DOMAIN_FS_DRIVER_TYPE_LAST, | ||
136 | 107 | "local", | ||
137 | 108 | "local", | ||
138 | 109 | "handle"); | ||
139 | 110 | |||
140 | 111 | |||
141 | 112 | static void | ||
142 | 113 | uname_normalize (struct utsname *ut) | ||
143 | 114 | { | ||
144 | 115 | uname(ut); | ||
145 | 116 | |||
146 | 117 | /* Map i386, i486, i586 to i686. */ | ||
147 | 118 | if (ut->machine[0] == 'i' && | ||
148 | 119 | ut->machine[1] != '\0' && | ||
149 | 120 | ut->machine[2] == '8' && | ||
150 | 121 | ut->machine[3] == '6' && | ||
151 | 122 | ut->machine[4] == '\0') | ||
152 | 123 | ut->machine[1] = '6'; | ||
153 | 124 | } | ||
154 | 125 | |||
155 | 126 | |||
156 | 127 | /** | ||
157 | 128 | * qemuPhysIfaceConnect: | ||
158 | 129 | * @def: the definition of the VM (needed by 802.1Qbh and audit) | ||
159 | 130 | * @driver: pointer to the qemud_driver | ||
160 | 131 | * @net: pointer to he VM's interface description with direct device type | ||
161 | 132 | * @qemuCaps: flags for qemu | ||
162 | 133 | * @vmop: VM operation type | ||
163 | 134 | * | ||
164 | 135 | * Returns a filedescriptor on success or -1 in case of error. | ||
165 | 136 | */ | ||
166 | 137 | int | ||
167 | 138 | qemuPhysIfaceConnect(virDomainDefPtr def, | ||
168 | 139 | struct qemud_driver *driver, | ||
169 | 140 | virDomainNetDefPtr net, | ||
170 | 141 | virBitmapPtr qemuCaps, | ||
171 | 142 | enum virNetDevVPortProfileOp vmop) | ||
172 | 143 | { | ||
173 | 144 | int rc; | ||
174 | 145 | char *res_ifname = NULL; | ||
175 | 146 | int vnet_hdr = 0; | ||
176 | 147 | |||
177 | 148 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_VNET_HDR) && | ||
178 | 149 | net->model && STREQ(net->model, "virtio")) | ||
179 | 150 | vnet_hdr = 1; | ||
180 | 151 | |||
181 | 152 | rc = virNetDevMacVLanCreateWithVPortProfile( | ||
182 | 153 | net->ifname, net->mac, | ||
183 | 154 | virDomainNetGetActualDirectDev(net), | ||
184 | 155 | virDomainNetGetActualDirectMode(net), | ||
185 | 156 | true, vnet_hdr, def->uuid, | ||
186 | 157 | virDomainNetGetActualDirectVirtPortProfile(net), | ||
187 | 158 | &res_ifname, | ||
188 | 159 | vmop, driver->stateDir, | ||
189 | 160 | virDomainNetGetActualBandwidth(net)); | ||
190 | 161 | if (rc >= 0) { | ||
191 | 162 | virDomainAuditNetDevice(def, net, res_ifname, true); | ||
192 | 163 | VIR_FREE(net->ifname); | ||
193 | 164 | net->ifname = res_ifname; | ||
194 | 165 | } | ||
195 | 166 | |||
196 | 167 | return rc; | ||
197 | 168 | } | ||
198 | 169 | |||
199 | 170 | |||
200 | 171 | int | ||
201 | 172 | qemuNetworkIfaceConnect(virDomainDefPtr def, | ||
202 | 173 | virConnectPtr conn, | ||
203 | 174 | struct qemud_driver *driver, | ||
204 | 175 | virDomainNetDefPtr net, | ||
205 | 176 | virBitmapPtr qemuCaps) | ||
206 | 177 | { | ||
207 | 178 | char *brname = NULL; | ||
208 | 179 | int err; | ||
209 | 180 | int tapfd = -1; | ||
210 | 181 | int vnet_hdr = 0; | ||
211 | 182 | bool template_ifname = false; | ||
212 | 183 | unsigned char tapmac[VIR_MAC_BUFLEN]; | ||
213 | 184 | int actualType = virDomainNetGetActualType(net); | ||
214 | 185 | |||
215 | 186 | if (actualType == VIR_DOMAIN_NET_TYPE_NETWORK) { | ||
216 | 187 | int active, fail = 0; | ||
217 | 188 | virErrorPtr errobj; | ||
218 | 189 | virNetworkPtr network = virNetworkLookupByName(conn, | ||
219 | 190 | net->data.network.name); | ||
220 | 191 | if (!network) | ||
221 | 192 | return -1; | ||
222 | 193 | |||
223 | 194 | active = virNetworkIsActive(network); | ||
224 | 195 | if (active != 1) { | ||
225 | 196 | fail = 1; | ||
226 | 197 | |||
227 | 198 | if (active == 0) | ||
228 | 199 | qemuReportError(VIR_ERR_INTERNAL_ERROR, | ||
229 | 200 | _("Network '%s' is not active."), | ||
230 | 201 | net->data.network.name); | ||
231 | 202 | } | ||
232 | 203 | |||
233 | 204 | if (!fail) { | ||
234 | 205 | brname = virNetworkGetBridgeName(network); | ||
235 | 206 | if (brname == NULL) | ||
236 | 207 | fail = 1; | ||
237 | 208 | } | ||
238 | 209 | |||
239 | 210 | /* Make sure any above failure is preserved */ | ||
240 | 211 | errobj = virSaveLastError(); | ||
241 | 212 | virNetworkFree(network); | ||
242 | 213 | virSetError(errobj); | ||
243 | 214 | virFreeError(errobj); | ||
244 | 215 | |||
245 | 216 | if (fail) | ||
246 | 217 | return -1; | ||
247 | 218 | |||
248 | 219 | } else if (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) { | ||
249 | 220 | if (!(brname = strdup(virDomainNetGetActualBridgeName(net)))) { | ||
250 | 221 | virReportOOMError(); | ||
251 | 222 | return -1; | ||
252 | 223 | } | ||
253 | 224 | } else { | ||
254 | 225 | qemuReportError(VIR_ERR_INTERNAL_ERROR, | ||
255 | 226 | _("Network type %d is not supported"), | ||
256 | 227 | virDomainNetGetActualType(net)); | ||
257 | 228 | return -1; | ||
258 | 229 | } | ||
259 | 230 | |||
260 | 231 | if (!net->ifname || | ||
261 | 232 | STRPREFIX(net->ifname, VIR_NET_GENERATED_PREFIX) || | ||
262 | 233 | strchr(net->ifname, '%')) { | ||
263 | 234 | VIR_FREE(net->ifname); | ||
264 | 235 | if (!(net->ifname = strdup(VIR_NET_GENERATED_PREFIX "%d"))) { | ||
265 | 236 | virReportOOMError(); | ||
266 | 237 | goto cleanup; | ||
267 | 238 | } | ||
268 | 239 | /* avoid exposing vnet%d in getXMLDesc or error outputs */ | ||
269 | 240 | template_ifname = true; | ||
270 | 241 | } | ||
271 | 242 | |||
272 | 243 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_VNET_HDR) && | ||
273 | 244 | net->model && STREQ(net->model, "virtio")) | ||
274 | 245 | vnet_hdr = 1; | ||
275 | 246 | |||
276 | 247 | memcpy(tapmac, net->mac, VIR_MAC_BUFLEN); | ||
277 | 248 | tapmac[0] = 0xFE; /* Discourage bridge from using TAP dev MAC */ | ||
278 | 249 | err = virNetDevTapCreateInBridgePort(brname, &net->ifname, tapmac, | ||
279 | 250 | vnet_hdr, true, &tapfd); | ||
280 | 251 | virDomainAuditNetDevice(def, net, "/dev/net/tun", tapfd >= 0); | ||
281 | 252 | if (err < 0) { | ||
282 | 253 | if (template_ifname) | ||
283 | 254 | VIR_FREE(net->ifname); | ||
284 | 255 | tapfd = -1; | ||
285 | 256 | } | ||
286 | 257 | |||
287 | 258 | if (driver->macFilter) { | ||
288 | 259 | if ((err = networkAllowMacOnPort(driver, net->ifname, net->mac))) { | ||
289 | 260 | virReportSystemError(err, | ||
290 | 261 | _("failed to add ebtables rule to allow MAC address on '%s'"), | ||
291 | 262 | net->ifname); | ||
292 | 263 | } | ||
293 | 264 | } | ||
294 | 265 | |||
295 | 266 | if (tapfd >= 0 && | ||
296 | 267 | virNetDevBandwidthSet(net->ifname, | ||
297 | 268 | virDomainNetGetActualBandwidth(net)) < 0) { | ||
298 | 269 | qemuReportError(VIR_ERR_INTERNAL_ERROR, | ||
299 | 270 | _("cannot set bandwidth limits on %s"), | ||
300 | 271 | net->ifname); | ||
301 | 272 | VIR_FORCE_CLOSE(tapfd); | ||
302 | 273 | goto cleanup; | ||
303 | 274 | } | ||
304 | 275 | |||
305 | 276 | if (tapfd >= 0) { | ||
306 | 277 | if ((net->filter) && (net->ifname)) { | ||
307 | 278 | err = virDomainConfNWFilterInstantiate(conn, net); | ||
308 | 279 | if (err) | ||
309 | 280 | VIR_FORCE_CLOSE(tapfd); | ||
310 | 281 | } | ||
311 | 282 | } | ||
312 | 283 | |||
313 | 284 | cleanup: | ||
314 | 285 | VIR_FREE(brname); | ||
315 | 286 | |||
316 | 287 | return tapfd; | ||
317 | 288 | } | ||
318 | 289 | |||
319 | 290 | |||
320 | 291 | int | ||
321 | 292 | qemuOpenVhostNet(virDomainDefPtr def, | ||
322 | 293 | virDomainNetDefPtr net, | ||
323 | 294 | virBitmapPtr qemuCaps, | ||
324 | 295 | int *vhostfd) | ||
325 | 296 | { | ||
326 | 297 | *vhostfd = -1; /* assume we won't use vhost */ | ||
327 | 298 | |||
328 | 299 | /* If the config says explicitly to not use vhost, return now */ | ||
329 | 300 | if (net->driver.virtio.name == VIR_DOMAIN_NET_BACKEND_TYPE_QEMU) { | ||
330 | 301 | return 0; | ||
331 | 302 | } | ||
332 | 303 | |||
333 | 304 | /* If qemu doesn't support vhost-net mode (including the -netdev command | ||
334 | 305 | * option), don't try to open the device. | ||
335 | 306 | */ | ||
336 | 307 | if (!(qemuCapsGet(qemuCaps, QEMU_CAPS_VHOST_NET) && | ||
337 | 308 | qemuCapsGet(qemuCaps, QEMU_CAPS_NETDEV) && | ||
338 | 309 | qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE))) { | ||
339 | 310 | if (net->driver.virtio.name == VIR_DOMAIN_NET_BACKEND_TYPE_VHOST) { | ||
340 | 311 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, | ||
341 | 312 | "%s", _("vhost-net is not supported with " | ||
342 | 313 | "this QEMU binary")); | ||
343 | 314 | return -1; | ||
344 | 315 | } | ||
345 | 316 | return 0; | ||
346 | 317 | } | ||
347 | 318 | |||
348 | 319 | /* If the nic model isn't virtio, don't try to open. */ | ||
349 | 320 | if (!(net->model && STREQ(net->model, "virtio"))) { | ||
350 | 321 | if (net->driver.virtio.name == VIR_DOMAIN_NET_BACKEND_TYPE_VHOST) { | ||
351 | 322 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, | ||
352 | 323 | "%s", _("vhost-net is only supported for " | ||
353 | 324 | "virtio network interfaces")); | ||
354 | 325 | return -1; | ||
355 | 326 | } | ||
356 | 327 | return 0; | ||
357 | 328 | } | ||
358 | 329 | |||
359 | 330 | *vhostfd = open("/dev/vhost-net", O_RDWR); | ||
360 | 331 | virDomainAuditNetDevice(def, net, "/dev/vhost-net", *vhostfd >= 0); | ||
361 | 332 | |||
362 | 333 | /* If the config says explicitly to use vhost and we couldn't open it, | ||
363 | 334 | * report an error. | ||
364 | 335 | */ | ||
365 | 336 | if ((*vhostfd < 0) && | ||
366 | 337 | (net->driver.virtio.name == VIR_DOMAIN_NET_BACKEND_TYPE_VHOST)) { | ||
367 | 338 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, | ||
368 | 339 | "%s", _("vhost-net was requested for an interface, " | ||
369 | 340 | "but is unavailable")); | ||
370 | 341 | return -1; | ||
371 | 342 | } | ||
372 | 343 | return 0; | ||
373 | 344 | } | ||
374 | 345 | |||
375 | 346 | |||
376 | 347 | static int qemuDomainDeviceAliasIndex(virDomainDeviceInfoPtr info, | ||
377 | 348 | const char *prefix) | ||
378 | 349 | { | ||
379 | 350 | int idx; | ||
380 | 351 | |||
381 | 352 | if (!info->alias) | ||
382 | 353 | return -1; | ||
383 | 354 | if (!STRPREFIX(info->alias, prefix)) | ||
384 | 355 | return -1; | ||
385 | 356 | |||
386 | 357 | if (virStrToLong_i(info->alias + strlen(prefix), NULL, 10, &idx) < 0) | ||
387 | 358 | return -1; | ||
388 | 359 | |||
389 | 360 | return idx; | ||
390 | 361 | } | ||
391 | 362 | |||
392 | 363 | |||
393 | 364 | int qemuDomainNetVLAN(virDomainNetDefPtr def) | ||
394 | 365 | { | ||
395 | 366 | return qemuDomainDeviceAliasIndex(&def->info, "net"); | ||
396 | 367 | } | ||
397 | 368 | |||
398 | 369 | |||
399 | 370 | /* Names used before -drive existed */ | ||
400 | 371 | static int qemuAssignDeviceDiskAliasLegacy(virDomainDiskDefPtr disk) | ||
401 | 372 | { | ||
402 | 373 | char *dev_name; | ||
403 | 374 | |||
404 | 375 | if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM && | ||
405 | 376 | STREQ(disk->dst, "hdc")) | ||
406 | 377 | dev_name = strdup("cdrom"); | ||
407 | 378 | else | ||
408 | 379 | dev_name = strdup(disk->dst); | ||
409 | 380 | |||
410 | 381 | if (!dev_name) { | ||
411 | 382 | virReportOOMError(); | ||
412 | 383 | return -1; | ||
413 | 384 | } | ||
414 | 385 | |||
415 | 386 | disk->info.alias = dev_name; | ||
416 | 387 | return 0; | ||
417 | 388 | } | ||
418 | 389 | |||
419 | 390 | |||
420 | 391 | char *qemuDeviceDriveHostAlias(virDomainDiskDefPtr disk, | ||
421 | 392 | virBitmapPtr qemuCaps) | ||
422 | 393 | { | ||
423 | 394 | char *ret; | ||
424 | 395 | |||
425 | 396 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) { | ||
426 | 397 | if (virAsprintf(&ret, "%s%s", QEMU_DRIVE_HOST_PREFIX, disk->info.alias) < 0) { | ||
427 | 398 | virReportOOMError(); | ||
428 | 399 | return NULL; | ||
429 | 400 | } | ||
430 | 401 | } else { | ||
431 | 402 | if (!(ret = strdup(disk->info.alias))) { | ||
432 | 403 | virReportOOMError(); | ||
433 | 404 | return NULL; | ||
434 | 405 | } | ||
435 | 406 | } | ||
436 | 407 | return ret; | ||
437 | 408 | } | ||
438 | 409 | |||
439 | 410 | |||
440 | 411 | /* Names used before -drive supported the id= option */ | ||
441 | 412 | static int qemuAssignDeviceDiskAliasFixed(virDomainDiskDefPtr disk) | ||
442 | 413 | { | ||
443 | 414 | int busid, devid; | ||
444 | 415 | int ret; | ||
445 | 416 | char *dev_name; | ||
446 | 417 | |||
447 | 418 | if (virDiskNameToBusDeviceIndex(disk, &busid, &devid) < 0) { | ||
448 | 419 | qemuReportError(VIR_ERR_INTERNAL_ERROR, | ||
449 | 420 | _("cannot convert disk '%s' to bus/device index"), | ||
450 | 421 | disk->dst); | ||
451 | 422 | return -1; | ||
452 | 423 | } | ||
453 | 424 | |||
454 | 425 | switch (disk->bus) { | ||
455 | 426 | case VIR_DOMAIN_DISK_BUS_IDE: | ||
456 | 427 | if (disk->device== VIR_DOMAIN_DISK_DEVICE_DISK) | ||
457 | 428 | ret = virAsprintf(&dev_name, "ide%d-hd%d", busid, devid); | ||
458 | 429 | else | ||
459 | 430 | ret = virAsprintf(&dev_name, "ide%d-cd%d", busid, devid); | ||
460 | 431 | break; | ||
461 | 432 | case VIR_DOMAIN_DISK_BUS_SCSI: | ||
462 | 433 | if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) | ||
463 | 434 | ret = virAsprintf(&dev_name, "scsi%d-hd%d", busid, devid); | ||
464 | 435 | else | ||
465 | 436 | ret = virAsprintf(&dev_name, "scsi%d-cd%d", busid, devid); | ||
466 | 437 | break; | ||
467 | 438 | case VIR_DOMAIN_DISK_BUS_FDC: | ||
468 | 439 | ret = virAsprintf(&dev_name, "floppy%d", devid); | ||
469 | 440 | break; | ||
470 | 441 | case VIR_DOMAIN_DISK_BUS_VIRTIO: | ||
471 | 442 | ret = virAsprintf(&dev_name, "virtio%d", devid); | ||
472 | 443 | break; | ||
473 | 444 | case VIR_DOMAIN_DISK_BUS_XEN: | ||
474 | 445 | ret = virAsprintf(&dev_name, "xenblk%d", devid); | ||
475 | 446 | break; | ||
476 | 447 | default: | ||
477 | 448 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, | ||
478 | 449 | _("Unsupported disk name mapping for bus '%s'"), | ||
479 | 450 | virDomainDiskBusTypeToString(disk->bus)); | ||
480 | 451 | return -1; | ||
481 | 452 | } | ||
482 | 453 | |||
483 | 454 | if (ret == -1) { | ||
484 | 455 | virReportOOMError(); | ||
485 | 456 | return -1; | ||
486 | 457 | } | ||
487 | 458 | |||
488 | 459 | disk->info.alias = dev_name; | ||
489 | 460 | |||
490 | 461 | return 0; | ||
491 | 462 | } | ||
492 | 463 | |||
493 | 464 | |||
494 | 465 | /* Our custom -drive naming scheme used with id= */ | ||
495 | 466 | static int qemuAssignDeviceDiskAliasCustom(virDomainDiskDefPtr disk) | ||
496 | 467 | { | ||
497 | 468 | const char *prefix = virDomainDiskBusTypeToString(disk->bus); | ||
498 | 469 | if (disk->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) { | ||
499 | 470 | if (virAsprintf(&disk->info.alias, "%s%d-%d-%d", prefix, | ||
500 | 471 | disk->info.addr.drive.controller, | ||
501 | 472 | disk->info.addr.drive.bus, | ||
502 | 473 | disk->info.addr.drive.unit) < 0) | ||
503 | 474 | goto no_memory; | ||
504 | 475 | } else { | ||
505 | 476 | int idx = virDiskNameToIndex(disk->dst); | ||
506 | 477 | if (virAsprintf(&disk->info.alias, "%s-disk%d", prefix, idx) < 0) | ||
507 | 478 | goto no_memory; | ||
508 | 479 | } | ||
509 | 480 | |||
510 | 481 | return 0; | ||
511 | 482 | |||
512 | 483 | no_memory: | ||
513 | 484 | virReportOOMError(); | ||
514 | 485 | return -1; | ||
515 | 486 | } | ||
516 | 487 | |||
517 | 488 | |||
518 | 489 | int | ||
519 | 490 | qemuAssignDeviceDiskAlias(virDomainDiskDefPtr def, virBitmapPtr qemuCaps) | ||
520 | 491 | { | ||
521 | 492 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_DRIVE)) { | ||
522 | 493 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) | ||
523 | 494 | return qemuAssignDeviceDiskAliasCustom(def); | ||
524 | 495 | else | ||
525 | 496 | return qemuAssignDeviceDiskAliasFixed(def); | ||
526 | 497 | } else { | ||
527 | 498 | return qemuAssignDeviceDiskAliasLegacy(def); | ||
528 | 499 | } | ||
529 | 500 | } | ||
530 | 501 | |||
531 | 502 | |||
532 | 503 | int | ||
533 | 504 | qemuAssignDeviceNetAlias(virDomainDefPtr def, virDomainNetDefPtr net, int idx) | ||
534 | 505 | { | ||
535 | 506 | if (idx == -1) { | ||
536 | 507 | int i; | ||
537 | 508 | idx = 0; | ||
538 | 509 | for (i = 0 ; i < def->nnets ; i++) { | ||
539 | 510 | int thisidx; | ||
540 | 511 | if ((thisidx = qemuDomainDeviceAliasIndex(&def->nets[i]->info, "net")) < 0) { | ||
541 | 512 | qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", | ||
542 | 513 | _("Unable to determine device index for network device")); | ||
543 | 514 | return -1; | ||
544 | 515 | } | ||
545 | 516 | if (thisidx >= idx) | ||
546 | 517 | idx = thisidx + 1; | ||
547 | 518 | } | ||
548 | 519 | } | ||
549 | 520 | |||
550 | 521 | if (virAsprintf(&net->info.alias, "net%d", idx) < 0) { | ||
551 | 522 | virReportOOMError(); | ||
552 | 523 | return -1; | ||
553 | 524 | } | ||
554 | 525 | |||
555 | 526 | return 0; | ||
556 | 527 | } | ||
557 | 528 | |||
558 | 529 | |||
559 | 530 | int | ||
560 | 531 | qemuAssignDeviceHostdevAlias(virDomainDefPtr def, virDomainHostdevDefPtr hostdev, int idx) | ||
561 | 532 | { | ||
562 | 533 | if (idx == -1) { | ||
563 | 534 | int i; | ||
564 | 535 | idx = 0; | ||
565 | 536 | for (i = 0 ; i < def->nhostdevs ; i++) { | ||
566 | 537 | int thisidx; | ||
567 | 538 | if ((thisidx = qemuDomainDeviceAliasIndex(&def->hostdevs[i]->info, "hostdev")) < 0) { | ||
568 | 539 | qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", | ||
569 | 540 | _("Unable to determine device index for hostdev device")); | ||
570 | 541 | return -1; | ||
571 | 542 | } | ||
572 | 543 | if (thisidx >= idx) | ||
573 | 544 | idx = thisidx + 1; | ||
574 | 545 | } | ||
575 | 546 | } | ||
576 | 547 | |||
577 | 548 | if (virAsprintf(&hostdev->info.alias, "hostdev%d", idx) < 0) { | ||
578 | 549 | virReportOOMError(); | ||
579 | 550 | return -1; | ||
580 | 551 | } | ||
581 | 552 | |||
582 | 553 | return 0; | ||
583 | 554 | } | ||
584 | 555 | |||
585 | 556 | |||
586 | 557 | int | ||
587 | 558 | qemuAssignDeviceRedirdevAlias(virDomainDefPtr def, virDomainRedirdevDefPtr redirdev, int idx) | ||
588 | 559 | { | ||
589 | 560 | if (idx == -1) { | ||
590 | 561 | int i; | ||
591 | 562 | idx = 0; | ||
592 | 563 | for (i = 0 ; i < def->nredirdevs ; i++) { | ||
593 | 564 | int thisidx; | ||
594 | 565 | if ((thisidx = qemuDomainDeviceAliasIndex(&def->redirdevs[i]->info, "redir")) < 0) { | ||
595 | 566 | qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", | ||
596 | 567 | _("Unable to determine device index for redirected device")); | ||
597 | 568 | return -1; | ||
598 | 569 | } | ||
599 | 570 | if (thisidx >= idx) | ||
600 | 571 | idx = thisidx + 1; | ||
601 | 572 | } | ||
602 | 573 | } | ||
603 | 574 | |||
604 | 575 | if (virAsprintf(&redirdev->info.alias, "redir%d", idx) < 0) { | ||
605 | 576 | virReportOOMError(); | ||
606 | 577 | return -1; | ||
607 | 578 | } | ||
608 | 579 | |||
609 | 580 | return 0; | ||
610 | 581 | } | ||
611 | 582 | |||
612 | 583 | |||
613 | 584 | int | ||
614 | 585 | qemuAssignDeviceControllerAlias(virDomainControllerDefPtr controller) | ||
615 | 586 | { | ||
616 | 587 | const char *prefix = virDomainControllerTypeToString(controller->type); | ||
617 | 588 | |||
618 | 589 | if (virAsprintf(&controller->info.alias, "%s%d", prefix, | ||
619 | 590 | controller->idx) < 0) { | ||
620 | 591 | virReportOOMError(); | ||
621 | 592 | return -1; | ||
622 | 593 | } | ||
623 | 594 | |||
624 | 595 | return 0; | ||
625 | 596 | } | ||
626 | 597 | |||
627 | 598 | |||
628 | 599 | int | ||
629 | 600 | qemuAssignDeviceAliases(virDomainDefPtr def, virBitmapPtr qemuCaps) | ||
630 | 601 | { | ||
631 | 602 | int i; | ||
632 | 603 | |||
633 | 604 | for (i = 0; i < def->ndisks ; i++) { | ||
634 | 605 | if (qemuAssignDeviceDiskAlias(def->disks[i], qemuCaps) < 0) | ||
635 | 606 | return -1; | ||
636 | 607 | } | ||
637 | 608 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_NET_NAME) || | ||
638 | 609 | qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) { | ||
639 | 610 | for (i = 0; i < def->nnets ; i++) { | ||
640 | 611 | if (qemuAssignDeviceNetAlias(def, def->nets[i], i) < 0) | ||
641 | 612 | return -1; | ||
642 | 613 | } | ||
643 | 614 | } | ||
644 | 615 | |||
645 | 616 | if (!qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) | ||
646 | 617 | return 0; | ||
647 | 618 | |||
648 | 619 | for (i = 0; i < def->nfss ; i++) { | ||
649 | 620 | if (virAsprintf(&def->fss[i]->info.alias, "fs%d", i) < 0) | ||
650 | 621 | goto no_memory; | ||
651 | 622 | } | ||
652 | 623 | for (i = 0; i < def->nsounds ; i++) { | ||
653 | 624 | if (virAsprintf(&def->sounds[i]->info.alias, "sound%d", i) < 0) | ||
654 | 625 | goto no_memory; | ||
655 | 626 | } | ||
656 | 627 | for (i = 0; i < def->nhostdevs ; i++) { | ||
657 | 628 | if (qemuAssignDeviceHostdevAlias(def, def->hostdevs[i], i) < 0) | ||
658 | 629 | return -1; | ||
659 | 630 | } | ||
660 | 631 | for (i = 0; i < def->nredirdevs ; i++) { | ||
661 | 632 | if (qemuAssignDeviceRedirdevAlias(def, def->redirdevs[i], i) < 0) | ||
662 | 633 | return -1; | ||
663 | 634 | } | ||
664 | 635 | for (i = 0; i < def->nvideos ; i++) { | ||
665 | 636 | if (virAsprintf(&def->videos[i]->info.alias, "video%d", i) < 0) | ||
666 | 637 | goto no_memory; | ||
667 | 638 | } | ||
668 | 639 | for (i = 0; i < def->ncontrollers ; i++) { | ||
669 | 640 | if (qemuAssignDeviceControllerAlias(def->controllers[i]) < 0) | ||
670 | 641 | return -1; | ||
671 | 642 | } | ||
672 | 643 | for (i = 0; i < def->ninputs ; i++) { | ||
673 | 644 | if (virAsprintf(&def->inputs[i]->info.alias, "input%d", i) < 0) | ||
674 | 645 | goto no_memory; | ||
675 | 646 | } | ||
676 | 647 | for (i = 0; i < def->nparallels ; i++) { | ||
677 | 648 | if (virAsprintf(&def->parallels[i]->info.alias, "parallel%d", i) < 0) | ||
678 | 649 | goto no_memory; | ||
679 | 650 | } | ||
680 | 651 | for (i = 0; i < def->nserials ; i++) { | ||
681 | 652 | if (virAsprintf(&def->serials[i]->info.alias, "serial%d", i) < 0) | ||
682 | 653 | goto no_memory; | ||
683 | 654 | } | ||
684 | 655 | for (i = 0; i < def->nchannels ; i++) { | ||
685 | 656 | if (virAsprintf(&def->channels[i]->info.alias, "channel%d", i) < 0) | ||
686 | 657 | goto no_memory; | ||
687 | 658 | } | ||
688 | 659 | for (i = 0; i < def->nconsoles ; i++) { | ||
689 | 660 | if (virAsprintf(&def->consoles[i]->info.alias, "console%d", i) < 0) | ||
690 | 661 | goto no_memory; | ||
691 | 662 | } | ||
692 | 663 | for (i = 0; i < def->nhubs ; i++) { | ||
693 | 664 | if (virAsprintf(&def->hubs[i]->info.alias, "hub%d", i) < 0) | ||
694 | 665 | goto no_memory; | ||
695 | 666 | } | ||
696 | 667 | for (i = 0; i < def->nsmartcards ; i++) { | ||
697 | 668 | if (virAsprintf(&def->smartcards[i]->info.alias, "smartcard%d", i) < 0) | ||
698 | 669 | goto no_memory; | ||
699 | 670 | } | ||
700 | 671 | if (def->watchdog) { | ||
701 | 672 | if (virAsprintf(&def->watchdog->info.alias, "watchdog%d", 0) < 0) | ||
702 | 673 | goto no_memory; | ||
703 | 674 | } | ||
704 | 675 | if (def->memballoon) { | ||
705 | 676 | if (virAsprintf(&def->memballoon->info.alias, "balloon%d", 0) < 0) | ||
706 | 677 | goto no_memory; | ||
707 | 678 | } | ||
708 | 679 | |||
709 | 680 | return 0; | ||
710 | 681 | |||
711 | 682 | no_memory: | ||
712 | 683 | virReportOOMError(); | ||
713 | 684 | return -1; | ||
714 | 685 | } | ||
715 | 686 | |||
716 | 687 | |||
717 | 688 | #define QEMU_PCI_ADDRESS_LAST_SLOT 31 | ||
718 | 689 | #define QEMU_PCI_ADDRESS_LAST_FUNCTION 8 | ||
719 | 690 | struct _qemuDomainPCIAddressSet { | ||
720 | 691 | virHashTablePtr used; | ||
721 | 692 | int nextslot; | ||
722 | 693 | }; | ||
723 | 694 | |||
724 | 695 | |||
725 | 696 | static char *qemuPCIAddressAsString(virDomainDeviceInfoPtr dev) | ||
726 | 697 | { | ||
727 | 698 | char *addr; | ||
728 | 699 | |||
729 | 700 | if (dev->addr.pci.domain != 0 || | ||
730 | 701 | dev->addr.pci.bus != 0) { | ||
731 | 702 | qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", | ||
732 | 703 | _("Only PCI domain 0 and bus 0 are available")); | ||
733 | 704 | return NULL; | ||
734 | 705 | } | ||
735 | 706 | |||
736 | 707 | if (virAsprintf(&addr, "%d:%d:%d.%d", | ||
737 | 708 | dev->addr.pci.domain, | ||
738 | 709 | dev->addr.pci.bus, | ||
739 | 710 | dev->addr.pci.slot, | ||
740 | 711 | dev->addr.pci.function) < 0) { | ||
741 | 712 | virReportOOMError(); | ||
742 | 713 | return NULL; | ||
743 | 714 | } | ||
744 | 715 | return addr; | ||
745 | 716 | } | ||
746 | 717 | |||
747 | 718 | |||
748 | 719 | static int qemuCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED, | ||
749 | 720 | virDomainDeviceInfoPtr dev, | ||
750 | 721 | void *opaque) | ||
751 | 722 | { | ||
752 | 723 | int ret = -1; | ||
753 | 724 | char *addr = NULL; | ||
754 | 725 | qemuDomainPCIAddressSetPtr addrs = opaque; | ||
755 | 726 | |||
756 | 727 | if (dev->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) | ||
757 | 728 | return 0; | ||
758 | 729 | |||
759 | 730 | addr = qemuPCIAddressAsString(dev); | ||
760 | 731 | if (!addr) | ||
761 | 732 | goto cleanup; | ||
762 | 733 | |||
763 | 734 | if (virHashLookup(addrs->used, addr)) { | ||
764 | 735 | if (dev->addr.pci.function != 0) { | ||
765 | 736 | qemuReportError(VIR_ERR_XML_ERROR, | ||
766 | 737 | _("Attempted double use of PCI Address '%s' " | ||
767 | 738 | "(may need \"multifunction='on'\" for device on function 0"), | ||
768 | 739 | addr); | ||
769 | 740 | } else { | ||
770 | 741 | qemuReportError(VIR_ERR_XML_ERROR, | ||
771 | 742 | _("Attempted double use of PCI Address '%s'"), addr); | ||
772 | 743 | } | ||
773 | 744 | goto cleanup; | ||
774 | 745 | } | ||
775 | 746 | |||
776 | 747 | VIR_DEBUG("Remembering PCI addr %s", addr); | ||
777 | 748 | if (virHashAddEntry(addrs->used, addr, addr) < 0) | ||
778 | 749 | goto cleanup; | ||
779 | 750 | addr = NULL; | ||
780 | 751 | |||
781 | 752 | if ((dev->addr.pci.function == 0) && | ||
782 | 753 | (dev->addr.pci.multi != VIR_DOMAIN_DEVICE_ADDRESS_PCI_MULTI_ON)) { | ||
783 | 754 | /* a function 0 w/o multifunction=on must reserve the entire slot */ | ||
784 | 755 | int function; | ||
785 | 756 | virDomainDeviceInfo temp_dev = *dev; | ||
786 | 757 | |||
787 | 758 | for (function = 1; function < QEMU_PCI_ADDRESS_LAST_FUNCTION; function++) { | ||
788 | 759 | temp_dev.addr.pci.function = function; | ||
789 | 760 | addr = qemuPCIAddressAsString(&temp_dev); | ||
790 | 761 | if (!addr) | ||
791 | 762 | goto cleanup; | ||
792 | 763 | |||
793 | 764 | if (virHashLookup(addrs->used, addr)) { | ||
794 | 765 | qemuReportError(VIR_ERR_XML_ERROR, | ||
795 | 766 | _("Attempted double use of PCI Address '%s'" | ||
796 | 767 | "(need \"multifunction='off'\" for device on function 0)"), | ||
797 | 768 | addr); | ||
798 | 769 | goto cleanup; | ||
799 | 770 | } | ||
800 | 771 | |||
801 | 772 | VIR_DEBUG("Remembering PCI addr %s (multifunction=off for function 0)", addr); | ||
802 | 773 | if (virHashAddEntry(addrs->used, addr, addr)) | ||
803 | 774 | goto cleanup; | ||
804 | 775 | addr = NULL; | ||
805 | 776 | } | ||
806 | 777 | } | ||
807 | 778 | ret = 0; | ||
808 | 779 | cleanup: | ||
809 | 780 | VIR_FREE(addr); | ||
810 | 781 | return ret; | ||
811 | 782 | } | ||
812 | 783 | |||
813 | 784 | |||
814 | 785 | int | ||
815 | 786 | qemuDomainAssignPCIAddresses(virDomainDefPtr def) | ||
816 | 787 | { | ||
817 | 788 | int ret = -1; | ||
818 | 789 | virBitmapPtr qemuCaps = NULL; | ||
819 | 790 | qemuDomainPCIAddressSetPtr addrs = NULL; | ||
820 | 791 | |||
821 | 792 | if (qemuCapsExtractVersionInfo(def->emulator, def->os.arch, | ||
822 | 793 | NULL, | ||
823 | 794 | &qemuCaps) < 0) | ||
824 | 795 | goto cleanup; | ||
825 | 796 | |||
826 | 797 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) { | ||
827 | 798 | if (!(addrs = qemuDomainPCIAddressSetCreate(def))) | ||
828 | 799 | goto cleanup; | ||
829 | 800 | |||
830 | 801 | if (qemuAssignDevicePCISlots(def, addrs) < 0) | ||
831 | 802 | goto cleanup; | ||
832 | 803 | } | ||
833 | 804 | |||
834 | 805 | ret = 0; | ||
835 | 806 | |||
836 | 807 | cleanup: | ||
837 | 808 | qemuCapsFree(qemuCaps); | ||
838 | 809 | qemuDomainPCIAddressSetFree(addrs); | ||
839 | 810 | |||
840 | 811 | return ret; | ||
841 | 812 | } | ||
842 | 813 | |||
843 | 814 | |||
844 | 815 | static void | ||
845 | 816 | qemuDomainPCIAddressSetFreeEntry(void *payload, | ||
846 | 817 | const void *name ATTRIBUTE_UNUSED) | ||
847 | 818 | { | ||
848 | 819 | VIR_FREE(payload); | ||
849 | 820 | } | ||
850 | 821 | |||
851 | 822 | qemuDomainPCIAddressSetPtr qemuDomainPCIAddressSetCreate(virDomainDefPtr def) | ||
852 | 823 | { | ||
853 | 824 | qemuDomainPCIAddressSetPtr addrs; | ||
854 | 825 | |||
855 | 826 | if (VIR_ALLOC(addrs) < 0) | ||
856 | 827 | goto no_memory; | ||
857 | 828 | |||
858 | 829 | if (!(addrs->used = virHashCreate(10, qemuDomainPCIAddressSetFreeEntry))) | ||
859 | 830 | goto error; | ||
860 | 831 | |||
861 | 832 | if (virDomainDeviceInfoIterate(def, qemuCollectPCIAddress, addrs) < 0) | ||
862 | 833 | goto error; | ||
863 | 834 | |||
864 | 835 | return addrs; | ||
865 | 836 | |||
866 | 837 | no_memory: | ||
867 | 838 | virReportOOMError(); | ||
868 | 839 | error: | ||
869 | 840 | qemuDomainPCIAddressSetFree(addrs); | ||
870 | 841 | return NULL; | ||
871 | 842 | } | ||
872 | 843 | |||
873 | 844 | /* check whether the slot is used by the other device | ||
874 | 845 | * Return 0 if the slot is not used by the other device, or -1 if the slot | ||
875 | 846 | * is used by the other device. | ||
876 | 847 | */ | ||
877 | 848 | static int qemuDomainPCIAddressCheckSlot(qemuDomainPCIAddressSetPtr addrs, | ||
878 | 849 | virDomainDeviceInfoPtr dev) | ||
879 | 850 | { | ||
880 | 851 | char *addr; | ||
881 | 852 | virDomainDeviceInfo temp_dev; | ||
882 | 853 | int function; | ||
883 | 854 | |||
884 | 855 | temp_dev = *dev; | ||
885 | 856 | for (function = 0; function < QEMU_PCI_ADDRESS_LAST_FUNCTION; function++) { | ||
886 | 857 | temp_dev.addr.pci.function = function; | ||
887 | 858 | addr = qemuPCIAddressAsString(&temp_dev); | ||
888 | 859 | if (!addr) | ||
889 | 860 | return -1; | ||
890 | 861 | |||
891 | 862 | if (virHashLookup(addrs->used, addr)) { | ||
892 | 863 | VIR_FREE(addr); | ||
893 | 864 | return -1; | ||
894 | 865 | } | ||
895 | 866 | |||
896 | 867 | VIR_FREE(addr); | ||
897 | 868 | } | ||
898 | 869 | |||
899 | 870 | return 0; | ||
900 | 871 | } | ||
901 | 872 | |||
902 | 873 | int qemuDomainPCIAddressReserveAddr(qemuDomainPCIAddressSetPtr addrs, | ||
903 | 874 | virDomainDeviceInfoPtr dev) | ||
904 | 875 | { | ||
905 | 876 | char *addr; | ||
906 | 877 | |||
907 | 878 | addr = qemuPCIAddressAsString(dev); | ||
908 | 879 | if (!addr) | ||
909 | 880 | return -1; | ||
910 | 881 | |||
911 | 882 | VIR_DEBUG("Reserving PCI addr %s", addr); | ||
912 | 883 | |||
913 | 884 | if (virHashLookup(addrs->used, addr)) { | ||
914 | 885 | qemuReportError(VIR_ERR_INTERNAL_ERROR, | ||
915 | 886 | _("unable to reserve PCI address %s"), addr); | ||
916 | 887 | VIR_FREE(addr); | ||
917 | 888 | return -1; | ||
918 | 889 | } | ||
919 | 890 | |||
920 | 891 | if (virHashAddEntry(addrs->used, addr, addr)) { | ||
921 | 892 | VIR_FREE(addr); | ||
922 | 893 | return -1; | ||
923 | 894 | } | ||
924 | 895 | |||
925 | 896 | if (dev->addr.pci.slot > addrs->nextslot) { | ||
926 | 897 | addrs->nextslot = dev->addr.pci.slot + 1; | ||
927 | 898 | if (QEMU_PCI_ADDRESS_LAST_SLOT < addrs->nextslot) | ||
928 | 899 | addrs->nextslot = 0; | ||
929 | 900 | } | ||
930 | 901 | |||
931 | 902 | return 0; | ||
932 | 903 | } | ||
933 | 904 | |||
934 | 905 | int qemuDomainPCIAddressReserveFunction(qemuDomainPCIAddressSetPtr addrs, | ||
935 | 906 | int slot, int function) | ||
936 | 907 | { | ||
937 | 908 | virDomainDeviceInfo dev; | ||
938 | 909 | |||
939 | 910 | dev.addr.pci.domain = 0; | ||
940 | 911 | dev.addr.pci.bus = 0; | ||
941 | 912 | dev.addr.pci.slot = slot; | ||
942 | 913 | dev.addr.pci.function = function; | ||
943 | 914 | |||
944 | 915 | return qemuDomainPCIAddressReserveAddr(addrs, &dev); | ||
945 | 916 | } | ||
946 | 917 | |||
947 | 918 | int qemuDomainPCIAddressReserveSlot(qemuDomainPCIAddressSetPtr addrs, | ||
948 | 919 | int slot) | ||
949 | 920 | { | ||
950 | 921 | int function; | ||
951 | 922 | |||
952 | 923 | for (function = 0; function < QEMU_PCI_ADDRESS_LAST_FUNCTION; function++) { | ||
953 | 924 | if (qemuDomainPCIAddressReserveFunction(addrs, slot, function) < 0) | ||
954 | 925 | goto cleanup; | ||
955 | 926 | } | ||
956 | 927 | |||
957 | 928 | return 0; | ||
958 | 929 | |||
959 | 930 | cleanup: | ||
960 | 931 | for (function--; function >= 0; function--) { | ||
961 | 932 | qemuDomainPCIAddressReleaseFunction(addrs, slot, function); | ||
962 | 933 | } | ||
963 | 934 | return -1; | ||
964 | 935 | } | ||
965 | 936 | |||
966 | 937 | int qemuDomainPCIAddressEnsureAddr(qemuDomainPCIAddressSetPtr addrs, | ||
967 | 938 | virDomainDeviceInfoPtr dev) | ||
968 | 939 | { | ||
969 | 940 | int ret = 0; | ||
970 | 941 | if (dev->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) { | ||
971 | 942 | /* We do not support hotplug multi-function PCI device now, so we should | ||
972 | 943 | * reserve the whole slot. The function of the PCI device must be 0. | ||
973 | 944 | */ | ||
974 | 945 | if (dev->addr.pci.function != 0) { | ||
975 | 946 | qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", | ||
976 | 947 | _("Only PCI device addresses with function=0" | ||
977 | 948 | " are supported")); | ||
978 | 949 | return -1; | ||
979 | 950 | } | ||
980 | 951 | |||
981 | 952 | ret = qemuDomainPCIAddressReserveSlot(addrs, dev->addr.pci.slot); | ||
982 | 953 | } else { | ||
983 | 954 | ret = qemuDomainPCIAddressSetNextAddr(addrs, dev); | ||
984 | 955 | } | ||
985 | 956 | return ret; | ||
986 | 957 | } | ||
987 | 958 | |||
988 | 959 | |||
989 | 960 | int qemuDomainPCIAddressReleaseAddr(qemuDomainPCIAddressSetPtr addrs, | ||
990 | 961 | virDomainDeviceInfoPtr dev) | ||
991 | 962 | { | ||
992 | 963 | char *addr; | ||
993 | 964 | int ret; | ||
994 | 965 | |||
995 | 966 | addr = qemuPCIAddressAsString(dev); | ||
996 | 967 | if (!addr) | ||
997 | 968 | return -1; | ||
998 | 969 | |||
999 | 970 | ret = virHashRemoveEntry(addrs->used, addr); | ||
1000 | 971 | |||
1001 | 972 | VIR_FREE(addr); | ||
1002 | 973 | |||
1003 | 974 | return ret; | ||
1004 | 975 | } | ||
1005 | 976 | |||
1006 | 977 | int qemuDomainPCIAddressReleaseFunction(qemuDomainPCIAddressSetPtr addrs, | ||
1007 | 978 | int slot, int function) | ||
1008 | 979 | { | ||
1009 | 980 | virDomainDeviceInfo dev; | ||
1010 | 981 | |||
1011 | 982 | dev.addr.pci.domain = 0; | ||
1012 | 983 | dev.addr.pci.bus = 0; | ||
1013 | 984 | dev.addr.pci.slot = slot; | ||
1014 | 985 | dev.addr.pci.function = function; | ||
1015 | 986 | |||
1016 | 987 | return qemuDomainPCIAddressReleaseAddr(addrs, &dev); | ||
1017 | 988 | } | ||
1018 | 989 | |||
1019 | 990 | int qemuDomainPCIAddressReleaseSlot(qemuDomainPCIAddressSetPtr addrs, int slot) | ||
1020 | 991 | { | ||
1021 | 992 | virDomainDeviceInfo dev; | ||
1022 | 993 | char *addr; | ||
1023 | 994 | int ret = 0; | ||
1024 | 995 | unsigned int *function = &dev.addr.pci.function; | ||
1025 | 996 | |||
1026 | 997 | dev.addr.pci.domain = 0; | ||
1027 | 998 | dev.addr.pci.bus = 0; | ||
1028 | 999 | dev.addr.pci.slot = slot; | ||
1029 | 1000 | |||
1030 | 1001 | for (*function = 0; *function < QEMU_PCI_ADDRESS_LAST_FUNCTION; (*function)++) { | ||
1031 | 1002 | addr = qemuPCIAddressAsString(&dev); | ||
1032 | 1003 | if (!addr) | ||
1033 | 1004 | return -1; | ||
1034 | 1005 | |||
1035 | 1006 | if (!virHashLookup(addrs->used, addr)) { | ||
1036 | 1007 | VIR_FREE(addr); | ||
1037 | 1008 | continue; | ||
1038 | 1009 | } | ||
1039 | 1010 | |||
1040 | 1011 | VIR_FREE(addr); | ||
1041 | 1012 | |||
1042 | 1013 | if (qemuDomainPCIAddressReleaseFunction(addrs, slot, *function) < 0) | ||
1043 | 1014 | ret = -1; | ||
1044 | 1015 | } | ||
1045 | 1016 | |||
1046 | 1017 | return ret; | ||
1047 | 1018 | } | ||
1048 | 1019 | |||
1049 | 1020 | void qemuDomainPCIAddressSetFree(qemuDomainPCIAddressSetPtr addrs) | ||
1050 | 1021 | { | ||
1051 | 1022 | if (!addrs) | ||
1052 | 1023 | return; | ||
1053 | 1024 | |||
1054 | 1025 | virHashFree(addrs->used); | ||
1055 | 1026 | VIR_FREE(addrs); | ||
1056 | 1027 | } | ||
1057 | 1028 | |||
1058 | 1029 | |||
1059 | 1030 | int qemuDomainPCIAddressSetNextAddr(qemuDomainPCIAddressSetPtr addrs, | ||
1060 | 1031 | virDomainDeviceInfoPtr dev) | ||
1061 | 1032 | { | ||
1062 | 1033 | int i; | ||
1063 | 1034 | int iteration; | ||
1064 | 1035 | |||
1065 | 1036 | for (i = addrs->nextslot, iteration = 0; | ||
1066 | 1037 | iteration <= QEMU_PCI_ADDRESS_LAST_SLOT; i++, iteration++) { | ||
1067 | 1038 | virDomainDeviceInfo maybe; | ||
1068 | 1039 | char *addr; | ||
1069 | 1040 | |||
1070 | 1041 | if (QEMU_PCI_ADDRESS_LAST_SLOT < i) | ||
1071 | 1042 | i = 0; | ||
1072 | 1043 | memset(&maybe, 0, sizeof(maybe)); | ||
1073 | 1044 | maybe.addr.pci.domain = 0; | ||
1074 | 1045 | maybe.addr.pci.bus = 0; | ||
1075 | 1046 | maybe.addr.pci.slot = i; | ||
1076 | 1047 | maybe.addr.pci.function = 0; | ||
1077 | 1048 | |||
1078 | 1049 | if (!(addr = qemuPCIAddressAsString(&maybe))) | ||
1079 | 1050 | return -1; | ||
1080 | 1051 | |||
1081 | 1052 | if (qemuDomainPCIAddressCheckSlot(addrs, &maybe) < 0) { | ||
1082 | 1053 | VIR_DEBUG("PCI addr %s already in use", addr); | ||
1083 | 1054 | VIR_FREE(addr); | ||
1084 | 1055 | continue; | ||
1085 | 1056 | } | ||
1086 | 1057 | |||
1087 | 1058 | VIR_DEBUG("Allocating PCI addr %s", addr); | ||
1088 | 1059 | VIR_FREE(addr); | ||
1089 | 1060 | |||
1090 | 1061 | if (qemuDomainPCIAddressReserveSlot(addrs, i) < 0) | ||
1091 | 1062 | return -1; | ||
1092 | 1063 | |||
1093 | 1064 | dev->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; | ||
1094 | 1065 | dev->addr.pci = maybe.addr.pci; | ||
1095 | 1066 | |||
1096 | 1067 | addrs->nextslot = i + 1; | ||
1097 | 1068 | if (QEMU_PCI_ADDRESS_LAST_SLOT < addrs->nextslot) | ||
1098 | 1069 | addrs->nextslot = 0; | ||
1099 | 1070 | |||
1100 | 1071 | return 0; | ||
1101 | 1072 | } | ||
1102 | 1073 | |||
1103 | 1074 | qemuReportError(VIR_ERR_INTERNAL_ERROR, | ||
1104 | 1075 | "%s", _("No more available PCI addresses")); | ||
1105 | 1076 | return -1; | ||
1106 | 1077 | } | ||
1107 | 1078 | |||
1108 | 1079 | /* | ||
1109 | 1080 | * This assigns static PCI slots to all configured devices. | ||
1110 | 1081 | * The ordering here is chosen to match the ordering used | ||
1111 | 1082 | * with old QEMU < 0.12, so that if a user updates a QEMU | ||
1112 | 1083 | * host from old QEMU to QEMU >= 0.12, their guests should | ||
1113 | 1084 | * get PCI addresses in the same order as before. | ||
1114 | 1085 | * | ||
1115 | 1086 | * NB, if they previously hotplugged devices then all bets | ||
1116 | 1087 | * are off. Hotplug for old QEMU was unfixably broken wrt | ||
1117 | 1088 | * to stable PCI addressing. | ||
1118 | 1089 | * | ||
1119 | 1090 | * Order is: | ||
1120 | 1091 | * | ||
1121 | 1092 | * - Host bridge (slot 0) | ||
1122 | 1093 | * - PIIX3 ISA bridge, IDE controller, something else unknown, USB controller (slot 1) | ||
1123 | 1094 | * - Video (slot 2) | ||
1124 | 1095 | * | ||
1125 | 1096 | * Incrementally assign slots from 3 onwards: | ||
1126 | 1097 | * | ||
1127 | 1098 | * - Net | ||
1128 | 1099 | * - Sound | ||
1129 | 1100 | * - SCSI controllers | ||
1130 | 1101 | * - VirtIO block | ||
1131 | 1102 | * - VirtIO balloon | ||
1132 | 1103 | * - Host device passthrough | ||
1133 | 1104 | * - Watchdog (not IB700) | ||
1134 | 1105 | * | ||
1135 | 1106 | * Prior to this function being invoked, qemuCollectPCIAddress() will have | ||
1136 | 1107 | * added all existing PCI addresses from the 'def' to 'addrs'. Thus this | ||
1137 | 1108 | * function must only try to reserve addresses if info.type == NONE and | ||
1138 | 1109 | * skip over info.type == PCI | ||
1139 | 1110 | */ | ||
1140 | 1111 | int | ||
1141 | 1112 | qemuAssignDevicePCISlots(virDomainDefPtr def, qemuDomainPCIAddressSetPtr addrs) | ||
1142 | 1113 | { | ||
1143 | 1114 | int i; | ||
1144 | 1115 | bool reservedIDE = false; | ||
1145 | 1116 | bool reservedUSB = false; | ||
1146 | 1117 | bool reservedVGA = false; | ||
1147 | 1118 | int function; | ||
1148 | 1119 | |||
1149 | 1120 | /* Host bridge */ | ||
1150 | 1121 | if (qemuDomainPCIAddressReserveSlot(addrs, 0) < 0) | ||
1151 | 1122 | goto error; | ||
1152 | 1123 | |||
1153 | 1124 | /* Verify that first IDE and USB controllers (if any) is on the PIIX3, fn 1 */ | ||
1154 | 1125 | for (i = 0; i < def->ncontrollers ; i++) { | ||
1155 | 1126 | /* First IDE controller lives on the PIIX3 at slot=1, function=1 */ | ||
1156 | 1127 | if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_IDE && | ||
1157 | 1128 | def->controllers[i]->idx == 0) { | ||
1158 | 1129 | if (def->controllers[i]->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) { | ||
1159 | 1130 | if (def->controllers[i]->info.addr.pci.domain != 0 || | ||
1160 | 1131 | def->controllers[i]->info.addr.pci.bus != 0 || | ||
1161 | 1132 | def->controllers[i]->info.addr.pci.slot != 1 || | ||
1162 | 1133 | def->controllers[i]->info.addr.pci.function != 1) { | ||
1163 | 1134 | qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", | ||
1164 | 1135 | _("Primary IDE controller must have PCI address 0:0:1.1")); | ||
1165 | 1136 | goto error; | ||
1166 | 1137 | } | ||
1167 | 1138 | /* If TYPE==PCI, then qemuCollectPCIAddress() function | ||
1168 | 1139 | * has already reserved the address, so we must skip */ | ||
1169 | 1140 | reservedIDE = true; | ||
1170 | 1141 | } else { | ||
1171 | 1142 | def->controllers[i]->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; | ||
1172 | 1143 | def->controllers[i]->info.addr.pci.domain = 0; | ||
1173 | 1144 | def->controllers[i]->info.addr.pci.bus = 0; | ||
1174 | 1145 | def->controllers[i]->info.addr.pci.slot = 1; | ||
1175 | 1146 | def->controllers[i]->info.addr.pci.function = 1; | ||
1176 | 1147 | } | ||
1177 | 1148 | } else if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_USB && | ||
1178 | 1149 | def->controllers[i]->idx == 0 && | ||
1179 | 1150 | (def->controllers[i]->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX3_UHCI || | ||
1180 | 1151 | def->controllers[i]->model == -1)) { | ||
1181 | 1152 | if (def->controllers[i]->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) { | ||
1182 | 1153 | if (def->controllers[i]->info.addr.pci.domain != 0 || | ||
1183 | 1154 | def->controllers[i]->info.addr.pci.bus != 0 || | ||
1184 | 1155 | def->controllers[i]->info.addr.pci.slot != 1 || | ||
1185 | 1156 | def->controllers[i]->info.addr.pci.function != 2) { | ||
1186 | 1157 | qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", | ||
1187 | 1158 | _("PIIX3 USB controller must have PCI address 0:0:1.2")); | ||
1188 | 1159 | goto error; | ||
1189 | 1160 | } | ||
1190 | 1161 | reservedUSB = true; | ||
1191 | 1162 | } else { | ||
1192 | 1163 | def->controllers[i]->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; | ||
1193 | 1164 | def->controllers[i]->info.addr.pci.domain = 0; | ||
1194 | 1165 | def->controllers[i]->info.addr.pci.bus = 0; | ||
1195 | 1166 | def->controllers[i]->info.addr.pci.slot = 1; | ||
1196 | 1167 | def->controllers[i]->info.addr.pci.function = 2; | ||
1197 | 1168 | } | ||
1198 | 1169 | } | ||
1199 | 1170 | } | ||
1200 | 1171 | |||
1201 | 1172 | /* PIIX3 (ISA bridge, IDE controller, something else unknown, USB controller) | ||
1202 | 1173 | * hardcoded slot=1, multifunction device | ||
1203 | 1174 | */ | ||
1204 | 1175 | for (function = 0; function < QEMU_PCI_ADDRESS_LAST_FUNCTION; function++) { | ||
1205 | 1176 | if ((function == 1 && reservedIDE) || | ||
1206 | 1177 | (function == 2 && reservedUSB)) | ||
1207 | 1178 | /* we have reserved this pci address */ | ||
1208 | 1179 | continue; | ||
1209 | 1180 | |||
1210 | 1181 | if (qemuDomainPCIAddressReserveFunction(addrs, 1, function) < 0) | ||
1211 | 1182 | goto error; | ||
1212 | 1183 | } | ||
1213 | 1184 | |||
1214 | 1185 | /* First VGA is hardcoded slot=2 */ | ||
1215 | 1186 | if (def->nvideos > 0) { | ||
1216 | 1187 | if (def->videos[0]->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) { | ||
1217 | 1188 | if (def->videos[0]->info.addr.pci.domain != 0 || | ||
1218 | 1189 | def->videos[0]->info.addr.pci.bus != 0 || | ||
1219 | 1190 | def->videos[0]->info.addr.pci.slot != 2 || | ||
1220 | 1191 | def->videos[0]->info.addr.pci.function != 0) { | ||
1221 | 1192 | qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", | ||
1222 | 1193 | _("Primary video card must have PCI address 0:0:2.0")); | ||
1223 | 1194 | goto error; | ||
1224 | 1195 | } | ||
1225 | 1196 | /* If TYPE==PCI, then qemuCollectPCIAddress() function | ||
1226 | 1197 | * has already reserved the address, so we must skip */ | ||
1227 | 1198 | reservedVGA = true; | ||
1228 | 1199 | } else { | ||
1229 | 1200 | def->videos[0]->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; | ||
1230 | 1201 | def->videos[0]->info.addr.pci.domain = 0; | ||
1231 | 1202 | def->videos[0]->info.addr.pci.bus = 0; | ||
1232 | 1203 | def->videos[0]->info.addr.pci.slot = 2; | ||
1233 | 1204 | def->videos[0]->info.addr.pci.function = 0; | ||
1234 | 1205 | } | ||
1235 | 1206 | } | ||
1236 | 1207 | |||
1237 | 1208 | if (!reservedVGA | ||
1238 | 1209 | && qemuDomainPCIAddressReserveSlot(addrs, 2) < 0) | ||
1239 | 1210 | goto error; | ||
1240 | 1211 | |||
1241 | 1212 | for (i = 0; i < def->nfss ; i++) { | ||
1242 | 1213 | if (def->fss[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) | ||
1243 | 1214 | continue; | ||
1244 | 1215 | |||
1245 | 1216 | /* Only support VirtIO-9p-pci so far. If that changes, | ||
1246 | 1217 | * we might need to skip devices here */ | ||
1247 | 1218 | if (qemuDomainPCIAddressSetNextAddr(addrs, &def->fss[i]->info) < 0) | ||
1248 | 1219 | goto error; | ||
1249 | 1220 | } | ||
1250 | 1221 | |||
1251 | 1222 | /* Network interfaces */ | ||
1252 | 1223 | for (i = 0; i < def->nnets ; i++) { | ||
1253 | 1224 | if (def->nets[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) | ||
1254 | 1225 | continue; | ||
1255 | 1226 | if (qemuDomainPCIAddressSetNextAddr(addrs, &def->nets[i]->info) < 0) | ||
1256 | 1227 | goto error; | ||
1257 | 1228 | } | ||
1258 | 1229 | |||
1259 | 1230 | /* Sound cards */ | ||
1260 | 1231 | for (i = 0; i < def->nsounds ; i++) { | ||
1261 | 1232 | if (def->sounds[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) | ||
1262 | 1233 | continue; | ||
1263 | 1234 | /* Skip ISA sound card, and PCSPK */ | ||
1264 | 1235 | if (def->sounds[i]->model == VIR_DOMAIN_SOUND_MODEL_SB16 || | ||
1265 | 1236 | def->sounds[i]->model == VIR_DOMAIN_SOUND_MODEL_PCSPK) | ||
1266 | 1237 | continue; | ||
1267 | 1238 | |||
1268 | 1239 | if (qemuDomainPCIAddressSetNextAddr(addrs, &def->sounds[i]->info) < 0) | ||
1269 | 1240 | goto error; | ||
1270 | 1241 | } | ||
1271 | 1242 | |||
1272 | 1243 | /* Disk controllers (SCSI only for now) */ | ||
1273 | 1244 | for (i = 0; i < def->ncontrollers ; i++) { | ||
1274 | 1245 | /* FDC lives behind the ISA bridge; CCID is a usb device */ | ||
1275 | 1246 | if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_FDC || | ||
1276 | 1247 | def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_CCID) | ||
1277 | 1248 | continue; | ||
1278 | 1249 | |||
1279 | 1250 | /* First IDE controller lives on the PIIX3 at slot=1, function=1, | ||
1280 | 1251 | dealt with earlier on*/ | ||
1281 | 1252 | if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_IDE && | ||
1282 | 1253 | def->controllers[i]->idx == 0) | ||
1283 | 1254 | continue; | ||
1284 | 1255 | |||
1285 | 1256 | if (def->controllers[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) | ||
1286 | 1257 | continue; | ||
1287 | 1258 | if (qemuDomainPCIAddressSetNextAddr(addrs, &def->controllers[i]->info) < 0) | ||
1288 | 1259 | goto error; | ||
1289 | 1260 | } | ||
1290 | 1261 | |||
1291 | 1262 | /* Disks (VirtIO only for now) */ | ||
1292 | 1263 | for (i = 0; i < def->ndisks ; i++) { | ||
1293 | 1264 | /* Only VirtIO disks use PCI addrs */ | ||
1294 | 1265 | if (def->disks[i]->bus != VIR_DOMAIN_DISK_BUS_VIRTIO) | ||
1295 | 1266 | continue; | ||
1296 | 1267 | |||
1297 | 1268 | if (def->disks[i]->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) | ||
1298 | 1269 | continue; | ||
1299 | 1270 | |||
1300 | 1271 | if (def->disks[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) { | ||
1301 | 1272 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, | ||
1302 | 1273 | _("virtio only support device address type 'PCI'")); | ||
1303 | 1274 | goto error; | ||
1304 | 1275 | } | ||
1305 | 1276 | |||
1306 | 1277 | if (qemuDomainPCIAddressSetNextAddr(addrs, &def->disks[i]->info) < 0) | ||
1307 | 1278 | goto error; | ||
1308 | 1279 | } | ||
1309 | 1280 | |||
1310 | 1281 | /* Host PCI devices */ | ||
1311 | 1282 | for (i = 0; i < def->nhostdevs ; i++) { | ||
1312 | 1283 | if (def->hostdevs[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) | ||
1313 | 1284 | continue; | ||
1314 | 1285 | if (def->hostdevs[i]->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS || | ||
1315 | 1286 | def->hostdevs[i]->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) | ||
1316 | 1287 | continue; | ||
1317 | 1288 | |||
1318 | 1289 | if (qemuDomainPCIAddressSetNextAddr(addrs, &def->hostdevs[i]->info) < 0) | ||
1319 | 1290 | goto error; | ||
1320 | 1291 | } | ||
1321 | 1292 | |||
1322 | 1293 | /* VirtIO balloon */ | ||
1323 | 1294 | if (def->memballoon && | ||
1324 | 1295 | def->memballoon->model == VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO && | ||
1325 | 1296 | def->memballoon->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) { | ||
1326 | 1297 | if (qemuDomainPCIAddressSetNextAddr(addrs, &def->memballoon->info) < 0) | ||
1327 | 1298 | goto error; | ||
1328 | 1299 | } | ||
1329 | 1300 | |||
1330 | 1301 | /* A watchdog - skip IB700, it is not a PCI device */ | ||
1331 | 1302 | if (def->watchdog && | ||
1332 | 1303 | def->watchdog->model != VIR_DOMAIN_WATCHDOG_MODEL_IB700 && | ||
1333 | 1304 | def->watchdog->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) { | ||
1334 | 1305 | if (qemuDomainPCIAddressSetNextAddr(addrs, &def->watchdog->info) < 0) | ||
1335 | 1306 | goto error; | ||
1336 | 1307 | } | ||
1337 | 1308 | |||
1338 | 1309 | /* Further non-primary video cards */ | ||
1339 | 1310 | for (i = 1; i < def->nvideos ; i++) { | ||
1340 | 1311 | if (def->videos[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) | ||
1341 | 1312 | continue; | ||
1342 | 1313 | if (qemuDomainPCIAddressSetNextAddr(addrs, &def->videos[i]->info) < 0) | ||
1343 | 1314 | goto error; | ||
1344 | 1315 | } | ||
1345 | 1316 | for (i = 0; i < def->ninputs ; i++) { | ||
1346 | 1317 | /* Nada - none are PCI based (yet) */ | ||
1347 | 1318 | } | ||
1348 | 1319 | for (i = 0; i < def->nparallels ; i++) { | ||
1349 | 1320 | /* Nada - none are PCI based (yet) */ | ||
1350 | 1321 | } | ||
1351 | 1322 | for (i = 0; i < def->nserials ; i++) { | ||
1352 | 1323 | /* Nada - none are PCI based (yet) */ | ||
1353 | 1324 | } | ||
1354 | 1325 | for (i = 0; i < def->nchannels ; i++) { | ||
1355 | 1326 | /* Nada - none are PCI based (yet) */ | ||
1356 | 1327 | } | ||
1357 | 1328 | for (i = 0; i < def->nhubs ; i++) { | ||
1358 | 1329 | /* Nada - none are PCI based (yet) */ | ||
1359 | 1330 | } | ||
1360 | 1331 | |||
1361 | 1332 | return 0; | ||
1362 | 1333 | |||
1363 | 1334 | error: | ||
1364 | 1335 | return -1; | ||
1365 | 1336 | } | ||
1366 | 1337 | |||
1367 | 1338 | static void | ||
1368 | 1339 | qemuUsbId(virBufferPtr buf, int idx) | ||
1369 | 1340 | { | ||
1370 | 1341 | if (idx == 0) | ||
1371 | 1342 | virBufferAsprintf(buf, "usb"); | ||
1372 | 1343 | else | ||
1373 | 1344 | virBufferAsprintf(buf, "usb%d", idx); | ||
1374 | 1345 | } | ||
1375 | 1346 | |||
1376 | 1347 | static int | ||
1377 | 1348 | qemuBuildDeviceAddressStr(virBufferPtr buf, | ||
1378 | 1349 | virDomainDeviceInfoPtr info, | ||
1379 | 1350 | virBitmapPtr qemuCaps) | ||
1380 | 1351 | { | ||
1381 | 1352 | if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) { | ||
1382 | 1353 | if (info->addr.pci.domain != 0) { | ||
1383 | 1354 | qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", | ||
1384 | 1355 | _("Only PCI device addresses with domain=0 are supported")); | ||
1385 | 1356 | return -1; | ||
1386 | 1357 | } | ||
1387 | 1358 | if (info->addr.pci.bus != 0) { | ||
1388 | 1359 | qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", | ||
1389 | 1360 | _("Only PCI device addresses with bus=0 are supported")); | ||
1390 | 1361 | return -1; | ||
1391 | 1362 | } | ||
1392 | 1363 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_PCI_MULTIFUNCTION)) { | ||
1393 | 1364 | if (info->addr.pci.function > 7) { | ||
1394 | 1365 | qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", | ||
1395 | 1366 | _("The function of PCI device addresses must " | ||
1396 | 1367 | "less than 8")); | ||
1397 | 1368 | return -1; | ||
1398 | 1369 | } | ||
1399 | 1370 | } else { | ||
1400 | 1371 | if (info->addr.pci.function != 0) { | ||
1401 | 1372 | qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", | ||
1402 | 1373 | _("Only PCI device addresses with function=0 " | ||
1403 | 1374 | "are supported with this QEMU binary")); | ||
1404 | 1375 | return -1; | ||
1405 | 1376 | } | ||
1406 | 1377 | if (info->addr.pci.multi == VIR_DOMAIN_DEVICE_ADDRESS_PCI_MULTI_ON) { | ||
1407 | 1378 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", | ||
1408 | 1379 | _("'multifunction=on' is not supported with " | ||
1409 | 1380 | "this QEMU binary")); | ||
1410 | 1381 | return -1; | ||
1411 | 1382 | } | ||
1412 | 1383 | } | ||
1413 | 1384 | |||
1414 | 1385 | /* XXX | ||
1415 | 1386 | * When QEMU grows support for > 1 PCI bus, then pci.0 changes | ||
1416 | 1387 | * to pci.1, pci.2, etc | ||
1417 | 1388 | * When QEMU grows support for > 1 PCI domain, then pci.0 change | ||
1418 | 1389 | * to pciNN.0 where NN is the domain number | ||
1419 | 1390 | */ | ||
1420 | 1391 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_PCI_MULTIBUS)) | ||
1421 | 1392 | virBufferAsprintf(buf, ",bus=pci.0"); | ||
1422 | 1393 | else | ||
1423 | 1394 | virBufferAsprintf(buf, ",bus=pci"); | ||
1424 | 1395 | if (info->addr.pci.multi == VIR_DOMAIN_DEVICE_ADDRESS_PCI_MULTI_ON) | ||
1425 | 1396 | virBufferAddLit(buf, ",multifunction=on"); | ||
1426 | 1397 | else if (info->addr.pci.multi == VIR_DOMAIN_DEVICE_ADDRESS_PCI_MULTI_OFF) | ||
1427 | 1398 | virBufferAddLit(buf, ",multifunction=off"); | ||
1428 | 1399 | virBufferAsprintf(buf, ",addr=0x%x", info->addr.pci.slot); | ||
1429 | 1400 | if (info->addr.pci.function != 0) | ||
1430 | 1401 | virBufferAsprintf(buf, ".0x%x", info->addr.pci.function); | ||
1431 | 1402 | } else if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB) { | ||
1432 | 1403 | virBufferAsprintf(buf, ",bus="); | ||
1433 | 1404 | qemuUsbId(buf, info->addr.usb.bus); | ||
1434 | 1405 | virBufferAsprintf(buf, ".0,port=%s", info->addr.usb.port); | ||
1435 | 1406 | } | ||
1436 | 1407 | |||
1437 | 1408 | return 0; | ||
1438 | 1409 | } | ||
1439 | 1410 | |||
1440 | 1411 | static int | ||
1441 | 1412 | qemuBuildIoEventFdStr(virBufferPtr buf, | ||
1442 | 1413 | enum virDomainIoEventFd use, | ||
1443 | 1414 | virBitmapPtr qemuCaps) | ||
1444 | 1415 | { | ||
1445 | 1416 | if (use && qemuCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_IOEVENTFD)) | ||
1446 | 1417 | virBufferAsprintf(buf, ",ioeventfd=%s", | ||
1447 | 1418 | virDomainIoEventFdTypeToString(use)); | ||
1448 | 1419 | return 0; | ||
1449 | 1420 | } | ||
1450 | 1421 | |||
1451 | 1422 | #define QEMU_SERIAL_PARAM_ACCEPTED_CHARS \ | ||
1452 | 1423 | "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_" | ||
1453 | 1424 | |||
1454 | 1425 | static int | ||
1455 | 1426 | qemuSafeSerialParamValue(const char *value) | ||
1456 | 1427 | { | ||
1457 | 1428 | if (strspn(value, QEMU_SERIAL_PARAM_ACCEPTED_CHARS) != strlen (value)) { | ||
1458 | 1429 | qemuReportError(VIR_ERR_INTERNAL_ERROR, | ||
1459 | 1430 | _("driver serial '%s' contains unsafe characters"), | ||
1460 | 1431 | value); | ||
1461 | 1432 | return -1; | ||
1462 | 1433 | } | ||
1463 | 1434 | |||
1464 | 1435 | return 0; | ||
1465 | 1436 | } | ||
1466 | 1437 | |||
1467 | 1438 | static int | ||
1468 | 1439 | qemuBuildRBDString(virConnectPtr conn, | ||
1469 | 1440 | virDomainDiskDefPtr disk, | ||
1470 | 1441 | virBufferPtr opt) | ||
1471 | 1442 | { | ||
1472 | 1443 | int i, ret = 0; | ||
1473 | 1444 | virSecretPtr sec = NULL; | ||
1474 | 1445 | char *secret = NULL; | ||
1475 | 1446 | size_t secret_size; | ||
1476 | 1447 | |||
1477 | 1448 | virBufferAsprintf(opt, "rbd:%s", disk->src); | ||
1478 | 1449 | if (disk->auth.username) { | ||
1479 | 1450 | virBufferEscape(opt, ":", ":id=%s", disk->auth.username); | ||
1480 | 1451 | /* look up secret */ | ||
1481 | 1452 | switch (disk->auth.secretType) { | ||
1482 | 1453 | case VIR_DOMAIN_DISK_SECRET_TYPE_UUID: | ||
1483 | 1454 | sec = virSecretLookupByUUID(conn, | ||
1484 | 1455 | disk->auth.secret.uuid); | ||
1485 | 1456 | break; | ||
1486 | 1457 | case VIR_DOMAIN_DISK_SECRET_TYPE_USAGE: | ||
1487 | 1458 | sec = virSecretLookupByUsage(conn, | ||
1488 | 1459 | VIR_SECRET_USAGE_TYPE_CEPH, | ||
1489 | 1460 | disk->auth.secret.usage); | ||
1490 | 1461 | break; | ||
1491 | 1462 | } | ||
1492 | 1463 | |||
1493 | 1464 | if (sec) { | ||
1494 | 1465 | char *base64 = NULL; | ||
1495 | 1466 | |||
1496 | 1467 | secret = (char *)conn->secretDriver->getValue(sec, &secret_size, 0, | ||
1497 | 1468 | VIR_SECRET_GET_VALUE_INTERNAL_CALL); | ||
1498 | 1469 | if (secret == NULL) { | ||
1499 | 1470 | qemuReportError(VIR_ERR_INTERNAL_ERROR, | ||
1500 | 1471 | _("could not get the value of the secret for username %s"), | ||
1501 | 1472 | disk->auth.username); | ||
1502 | 1473 | goto error; | ||
1503 | 1474 | } | ||
1504 | 1475 | /* qemu/librbd wants it base64 encoded */ | ||
1505 | 1476 | base64_encode_alloc(secret, secret_size, &base64); | ||
1506 | 1477 | if (!base64) { | ||
1507 | 1478 | virReportOOMError(); | ||
1508 | 1479 | goto error; | ||
1509 | 1480 | } | ||
1510 | 1481 | virBufferEscape(opt, ":;", ":key=%s:auth_supported=cephx\\;none", | ||
1511 | 1482 | base64); | ||
1512 | 1483 | VIR_FREE(base64); | ||
1513 | 1484 | } else { | ||
1514 | 1485 | qemuReportError(VIR_ERR_INTERNAL_ERROR, | ||
1515 | 1486 | _("rbd username '%s' specified but secret not found"), | ||
1516 | 1487 | disk->auth.username); | ||
1517 | 1488 | goto error; | ||
1518 | 1489 | } | ||
1519 | 1490 | } | ||
1520 | 1491 | |||
1521 | 1492 | if (disk->nhosts > 0) { | ||
1522 | 1493 | virBufferAddLit(opt, ":mon_host="); | ||
1523 | 1494 | for (i = 0; i < disk->nhosts; ++i) { | ||
1524 | 1495 | if (i) { | ||
1525 | 1496 | virBufferAddLit(opt, "\\;"); | ||
1526 | 1497 | } | ||
1527 | 1498 | if (disk->hosts[i].port) { | ||
1528 | 1499 | virBufferAsprintf(opt, "%s\\:%s", | ||
1529 | 1500 | disk->hosts[i].name, | ||
1530 | 1501 | disk->hosts[i].port); | ||
1531 | 1502 | } else { | ||
1532 | 1503 | virBufferAsprintf(opt, "%s", disk->hosts[i].name); | ||
1533 | 1504 | } | ||
1534 | 1505 | } | ||
1535 | 1506 | } | ||
1536 | 1507 | |||
1537 | 1508 | cleanup: | ||
1538 | 1509 | VIR_FREE(secret); | ||
1539 | 1510 | if (sec) | ||
1540 | 1511 | virUnrefSecret(sec); | ||
1541 | 1512 | |||
1542 | 1513 | return ret; | ||
1543 | 1514 | |||
1544 | 1515 | error: | ||
1545 | 1516 | ret = -1; | ||
1546 | 1517 | goto cleanup; | ||
1547 | 1518 | } | ||
1548 | 1519 | |||
1549 | 1520 | static int qemuAddRBDHost(virDomainDiskDefPtr disk, char *hostport) | ||
1550 | 1521 | { | ||
1551 | 1522 | char *port; | ||
1552 | 1523 | |||
1553 | 1524 | disk->nhosts++; | ||
1554 | 1525 | if (VIR_REALLOC_N(disk->hosts, disk->nhosts) < 0) | ||
1555 | 1526 | goto no_memory; | ||
1556 | 1527 | |||
1557 | 1528 | port = strstr(hostport, "\\:"); | ||
1558 | 1529 | if (port) { | ||
1559 | 1530 | *port = '\0'; | ||
1560 | 1531 | port += 2; | ||
1561 | 1532 | disk->hosts[disk->nhosts-1].port = strdup(port); | ||
1562 | 1533 | if (!disk->hosts[disk->nhosts-1].port) | ||
1563 | 1534 | goto no_memory; | ||
1564 | 1535 | } else { | ||
1565 | 1536 | disk->hosts[disk->nhosts-1].port = strdup("6789"); | ||
1566 | 1537 | if (!disk->hosts[disk->nhosts-1].port) | ||
1567 | 1538 | goto no_memory; | ||
1568 | 1539 | } | ||
1569 | 1540 | disk->hosts[disk->nhosts-1].name = strdup(hostport); | ||
1570 | 1541 | if (!disk->hosts[disk->nhosts-1].name) | ||
1571 | 1542 | goto no_memory; | ||
1572 | 1543 | return 0; | ||
1573 | 1544 | |||
1574 | 1545 | no_memory: | ||
1575 | 1546 | virReportOOMError(); | ||
1576 | 1547 | VIR_FREE(disk->hosts[disk->nhosts-1].port); | ||
1577 | 1548 | VIR_FREE(disk->hosts[disk->nhosts-1].name); | ||
1578 | 1549 | return -1; | ||
1579 | 1550 | } | ||
1580 | 1551 | |||
1581 | 1552 | /* disk->src initially has everything after the rbd: prefix */ | ||
1582 | 1553 | static int qemuParseRBDString(virDomainDiskDefPtr disk) | ||
1583 | 1554 | { | ||
1584 | 1555 | char *options = NULL; | ||
1585 | 1556 | char *p, *e, *next; | ||
1586 | 1557 | |||
1587 | 1558 | p = strchr(disk->src, ':'); | ||
1588 | 1559 | if (p) { | ||
1589 | 1560 | options = strdup(p + 1); | ||
1590 | 1561 | if (!options) | ||
1591 | 1562 | goto no_memory; | ||
1592 | 1563 | *p = '\0'; | ||
1593 | 1564 | } | ||
1594 | 1565 | |||
1595 | 1566 | /* options */ | ||
1596 | 1567 | if (!options) | ||
1597 | 1568 | return 0; /* all done */ | ||
1598 | 1569 | |||
1599 | 1570 | p = options; | ||
1600 | 1571 | while (*p) { | ||
1601 | 1572 | /* find : delimiter or end of string */ | ||
1602 | 1573 | for (e = p; *e && *e != ':'; ++e) { | ||
1603 | 1574 | if (*e == '\\') { | ||
1604 | 1575 | e++; | ||
1605 | 1576 | if (*e == '\0') | ||
1606 | 1577 | break; | ||
1607 | 1578 | } | ||
1608 | 1579 | } | ||
1609 | 1580 | if (*e == '\0') { | ||
1610 | 1581 | next = e; /* last kv pair */ | ||
1611 | 1582 | } else { | ||
1612 | 1583 | next = e + 1; | ||
1613 | 1584 | *e = '\0'; | ||
1614 | 1585 | } | ||
1615 | 1586 | |||
1616 | 1587 | if (STRPREFIX(p, "id=")) { | ||
1617 | 1588 | disk->auth.username = strdup(p + strlen("id=")); | ||
1618 | 1589 | if (!disk->auth.username) | ||
1619 | 1590 | goto no_memory; | ||
1620 | 1591 | } | ||
1621 | 1592 | if (STRPREFIX(p, "mon_host=")) { | ||
1622 | 1593 | char *h, *sep; | ||
1623 | 1594 | |||
1624 | 1595 | h = p + strlen("mon_host="); | ||
1625 | 1596 | while (h < e) { | ||
1626 | 1597 | for (sep = h; sep < e; ++sep) { | ||
1627 | 1598 | if (*sep == '\\' && (sep[1] == ',' || | ||
1628 | 1599 | sep[1] == ';' || | ||
1629 | 1600 | sep[1] == ' ')) { | ||
1630 | 1601 | *sep = '\0'; | ||
1631 | 1602 | sep += 2; | ||
1632 | 1603 | break; | ||
1633 | 1604 | } | ||
1634 | 1605 | } | ||
1635 | 1606 | if (qemuAddRBDHost(disk, h) < 0) { | ||
1636 | 1607 | return -1; | ||
1637 | 1608 | } | ||
1638 | 1609 | h = sep; | ||
1639 | 1610 | } | ||
1640 | 1611 | } | ||
1641 | 1612 | |||
1642 | 1613 | p = next; | ||
1643 | 1614 | } | ||
1644 | 1615 | return 0; | ||
1645 | 1616 | |||
1646 | 1617 | no_memory: | ||
1647 | 1618 | virReportOOMError(); | ||
1648 | 1619 | return -1; | ||
1649 | 1620 | } | ||
1650 | 1621 | |||
1651 | 1622 | char * | ||
1652 | 1623 | qemuBuildDriveStr(virConnectPtr conn ATTRIBUTE_UNUSED, | ||
1653 | 1624 | virDomainDiskDefPtr disk, | ||
1654 | 1625 | bool bootable, | ||
1655 | 1626 | virBitmapPtr qemuCaps) | ||
1656 | 1627 | { | ||
1657 | 1628 | virBuffer opt = VIR_BUFFER_INITIALIZER; | ||
1658 | 1629 | const char *bus = virDomainDiskQEMUBusTypeToString(disk->bus); | ||
1659 | 1630 | int idx = virDiskNameToIndex(disk->dst); | ||
1660 | 1631 | int busid = -1, unitid = -1; | ||
1661 | 1632 | |||
1662 | 1633 | if (idx < 0) { | ||
1663 | 1634 | qemuReportError(VIR_ERR_INTERNAL_ERROR, | ||
1664 | 1635 | _("unsupported disk type '%s'"), disk->dst); | ||
1665 | 1636 | goto error; | ||
1666 | 1637 | } | ||
1667 | 1638 | |||
1668 | 1639 | switch (disk->bus) { | ||
1669 | 1640 | case VIR_DOMAIN_DISK_BUS_SCSI: | ||
1670 | 1641 | if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) { | ||
1671 | 1642 | qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", | ||
1672 | 1643 | _("unexpected address type for scsi disk")); | ||
1673 | 1644 | goto error; | ||
1674 | 1645 | } | ||
1675 | 1646 | |||
1676 | 1647 | /* Setting bus= attr for SCSI drives, causes a controller | ||
1677 | 1648 | * to be created. Yes this is slightly odd. It is not possible | ||
1678 | 1649 | * to have > 1 bus on a SCSI controller (yet). */ | ||
1679 | 1650 | if (disk->info.addr.drive.bus != 0) { | ||
1680 | 1651 | qemuReportError(VIR_ERR_INTERNAL_ERROR, | ||
1681 | 1652 | "%s", _("SCSI controller only supports 1 bus")); | ||
1682 | 1653 | goto error; | ||
1683 | 1654 | } | ||
1684 | 1655 | busid = disk->info.addr.drive.controller; | ||
1685 | 1656 | unitid = disk->info.addr.drive.unit; | ||
1686 | 1657 | break; | ||
1687 | 1658 | |||
1688 | 1659 | case VIR_DOMAIN_DISK_BUS_IDE: | ||
1689 | 1660 | if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) { | ||
1690 | 1661 | qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", | ||
1691 | 1662 | _("unexpected address type for ide disk")); | ||
1692 | 1663 | goto error; | ||
1693 | 1664 | } | ||
1694 | 1665 | /* We can only have 1 IDE controller (currently) */ | ||
1695 | 1666 | if (disk->info.addr.drive.controller != 0) { | ||
1696 | 1667 | qemuReportError(VIR_ERR_INTERNAL_ERROR, | ||
1697 | 1668 | _("Only 1 %s controller is supported"), bus); | ||
1698 | 1669 | goto error; | ||
1699 | 1670 | } | ||
1700 | 1671 | busid = disk->info.addr.drive.bus; | ||
1701 | 1672 | unitid = disk->info.addr.drive.unit; | ||
1702 | 1673 | break; | ||
1703 | 1674 | |||
1704 | 1675 | case VIR_DOMAIN_DISK_BUS_FDC: | ||
1705 | 1676 | if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) { | ||
1706 | 1677 | qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", | ||
1707 | 1678 | _("unexpected address type for fdc disk")); | ||
1708 | 1679 | goto error; | ||
1709 | 1680 | } | ||
1710 | 1681 | /* We can only have 1 FDC controller (currently) */ | ||
1711 | 1682 | if (disk->info.addr.drive.controller != 0) { | ||
1712 | 1683 | qemuReportError(VIR_ERR_INTERNAL_ERROR, | ||
1713 | 1684 | _("Only 1 %s controller is supported"), bus); | ||
1714 | 1685 | goto error; | ||
1715 | 1686 | } | ||
1716 | 1687 | /* We can only have 1 FDC bus (currently) */ | ||
1717 | 1688 | if (disk->info.addr.drive.bus != 0) { | ||
1718 | 1689 | qemuReportError(VIR_ERR_INTERNAL_ERROR, | ||
1719 | 1690 | _("Only 1 %s bus is supported"), bus); | ||
1720 | 1691 | goto error; | ||
1721 | 1692 | } | ||
1722 | 1693 | unitid = disk->info.addr.drive.unit; | ||
1723 | 1694 | |||
1724 | 1695 | break; | ||
1725 | 1696 | |||
1726 | 1697 | case VIR_DOMAIN_DISK_BUS_VIRTIO: | ||
1727 | 1698 | /* Each virtio drive is a separate PCI device, no unit/busid or index */ | ||
1728 | 1699 | idx = -1; | ||
1729 | 1700 | break; | ||
1730 | 1701 | |||
1731 | 1702 | case VIR_DOMAIN_DISK_BUS_XEN: | ||
1732 | 1703 | /* Xen has no address type currently, so assign based on index */ | ||
1733 | 1704 | break; | ||
1734 | 1705 | } | ||
1735 | 1706 | |||
1736 | 1707 | /* disk->src is NULL when we use nbd disks */ | ||
1737 | 1708 | if (disk->src || (disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK && | ||
1738 | 1709 | disk->protocol == VIR_DOMAIN_DISK_PROTOCOL_NBD)) { | ||
1739 | 1710 | if (disk->type == VIR_DOMAIN_DISK_TYPE_DIR) { | ||
1740 | 1711 | /* QEMU only supports magic FAT format for now */ | ||
1741 | 1712 | if (disk->driverType && | ||
1742 | 1713 | STRNEQ(disk->driverType, "fat")) { | ||
1743 | 1714 | qemuReportError(VIR_ERR_INTERNAL_ERROR, | ||
1744 | 1715 | _("unsupported disk driver type for '%s'"), | ||
1745 | 1716 | disk->driverType); | ||
1746 | 1717 | goto error; | ||
1747 | 1718 | } | ||
1748 | 1719 | if (!disk->readonly) { | ||
1749 | 1720 | qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", | ||
1750 | 1721 | _("cannot create virtual FAT disks in read-write mode")); | ||
1751 | 1722 | goto error; | ||
1752 | 1723 | } | ||
1753 | 1724 | if (disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) | ||
1754 | 1725 | virBufferAsprintf(&opt, "file=fat:floppy:%s,", disk->src); | ||
1755 | 1726 | else | ||
1756 | 1727 | virBufferAsprintf(&opt, "file=fat:%s,", disk->src); | ||
1757 | 1728 | } else if (disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK) { | ||
1758 | 1729 | switch (disk->protocol) { | ||
1759 | 1730 | case VIR_DOMAIN_DISK_PROTOCOL_NBD: | ||
1760 | 1731 | if (disk->nhosts != 1) { | ||
1761 | 1732 | qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", | ||
1762 | 1733 | _("NBD accepts only one host")); | ||
1763 | 1734 | goto error; | ||
1764 | 1735 | } | ||
1765 | 1736 | virBufferAsprintf(&opt, "file=nbd:%s:%s,", | ||
1766 | 1737 | disk->hosts->name, disk->hosts->port); | ||
1767 | 1738 | break; | ||
1768 | 1739 | case VIR_DOMAIN_DISK_PROTOCOL_RBD: | ||
1769 | 1740 | virBufferAddLit(&opt, "file="); | ||
1770 | 1741 | if (qemuBuildRBDString(conn, disk, &opt) < 0) | ||
1771 | 1742 | goto error; | ||
1772 | 1743 | virBufferAddChar(&opt, ','); | ||
1773 | 1744 | break; | ||
1774 | 1745 | case VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG: | ||
1775 | 1746 | if (disk->nhosts == 0) | ||
1776 | 1747 | virBufferAsprintf(&opt, "file=sheepdog:%s,", disk->src); | ||
1777 | 1748 | else | ||
1778 | 1749 | /* only one host is supported now */ | ||
1779 | 1750 | virBufferAsprintf(&opt, "file=sheepdog:%s:%s:%s,", | ||
1780 | 1751 | disk->hosts->name, disk->hosts->port, | ||
1781 | 1752 | disk->src); | ||
1782 | 1753 | break; | ||
1783 | 1754 | } | ||
1784 | 1755 | } else { | ||
1785 | 1756 | virBufferAsprintf(&opt, "file=%s,", disk->src); | ||
1786 | 1757 | } | ||
1787 | 1758 | } | ||
1788 | 1759 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) | ||
1789 | 1760 | virBufferAddLit(&opt, "if=none"); | ||
1790 | 1761 | else | ||
1791 | 1762 | virBufferAsprintf(&opt, "if=%s", bus); | ||
1792 | 1763 | |||
1793 | 1764 | if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) | ||
1794 | 1765 | virBufferAddLit(&opt, ",media=cdrom"); | ||
1795 | 1766 | |||
1796 | 1767 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) { | ||
1797 | 1768 | virBufferAsprintf(&opt, ",id=%s%s", QEMU_DRIVE_HOST_PREFIX, disk->info.alias); | ||
1798 | 1769 | } else { | ||
1799 | 1770 | if (busid == -1 && unitid == -1) { | ||
1800 | 1771 | if (idx != -1) | ||
1801 | 1772 | virBufferAsprintf(&opt, ",index=%d", idx); | ||
1802 | 1773 | } else { | ||
1803 | 1774 | if (busid != -1) | ||
1804 | 1775 | virBufferAsprintf(&opt, ",bus=%d", busid); | ||
1805 | 1776 | if (unitid != -1) | ||
1806 | 1777 | virBufferAsprintf(&opt, ",unit=%d", unitid); | ||
1807 | 1778 | } | ||
1808 | 1779 | } | ||
1809 | 1780 | if (bootable && | ||
1810 | 1781 | qemuCapsGet(qemuCaps, QEMU_CAPS_DRIVE_BOOT) && | ||
1811 | 1782 | disk->device == VIR_DOMAIN_DISK_DEVICE_DISK && | ||
1812 | 1783 | disk->bus != VIR_DOMAIN_DISK_BUS_IDE) | ||
1813 | 1784 | virBufferAddLit(&opt, ",boot=on"); | ||
1814 | 1785 | if (disk->readonly && | ||
1815 | 1786 | qemuCapsGet(qemuCaps, QEMU_CAPS_DRIVE_READONLY)) | ||
1816 | 1787 | virBufferAddLit(&opt, ",readonly=on"); | ||
1817 | 1788 | if (disk->transient) { | ||
1818 | 1789 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", | ||
1819 | 1790 | _("transient disks not supported yet")); | ||
1820 | 1791 | goto error; | ||
1821 | 1792 | } | ||
1822 | 1793 | if (disk->driverType && *disk->driverType != '\0' && | ||
1823 | 1794 | disk->type != VIR_DOMAIN_DISK_TYPE_DIR && | ||
1824 | 1795 | qemuCapsGet(qemuCaps, QEMU_CAPS_DRIVE_FORMAT)) | ||
1825 | 1796 | virBufferAsprintf(&opt, ",format=%s", disk->driverType); | ||
1826 | 1797 | if (disk->serial && | ||
1827 | 1798 | qemuCapsGet(qemuCaps, QEMU_CAPS_DRIVE_SERIAL)) { | ||
1828 | 1799 | if (qemuSafeSerialParamValue(disk->serial) < 0) | ||
1829 | 1800 | goto error; | ||
1830 | 1801 | virBufferAsprintf(&opt, ",serial=%s", disk->serial); | ||
1831 | 1802 | } | ||
1832 | 1803 | |||
1833 | 1804 | if (disk->cachemode) { | ||
1834 | 1805 | const char *mode = NULL; | ||
1835 | 1806 | |||
1836 | 1807 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_DRIVE_CACHE_V2)) { | ||
1837 | 1808 | mode = qemuDiskCacheV2TypeToString(disk->cachemode); | ||
1838 | 1809 | |||
1839 | 1810 | if (disk->cachemode == VIR_DOMAIN_DISK_CACHE_DIRECTSYNC && | ||
1840 | 1811 | !qemuCapsGet(qemuCaps, QEMU_CAPS_DRIVE_CACHE_DIRECTSYNC)) { | ||
1841 | 1812 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", | ||
1842 | 1813 | _("disk cache mode 'directsync' is not " | ||
1843 | 1814 | "supported by this QEMU")); | ||
1844 | 1815 | goto error; | ||
1845 | 1816 | } else if (disk->cachemode == VIR_DOMAIN_DISK_CACHE_UNSAFE && | ||
1846 | 1817 | !qemuCapsGet(qemuCaps, QEMU_CAPS_DRIVE_CACHE_UNSAFE)) { | ||
1847 | 1818 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", | ||
1848 | 1819 | _("disk cache mode 'unsafe' is not " | ||
1849 | 1820 | "supported by this QEMU")); | ||
1850 | 1821 | goto error; | ||
1851 | 1822 | } | ||
1852 | 1823 | } else { | ||
1853 | 1824 | mode = qemuDiskCacheV1TypeToString(disk->cachemode); | ||
1854 | 1825 | } | ||
1855 | 1826 | |||
1856 | 1827 | virBufferAsprintf(&opt, ",cache=%s", mode); | ||
1857 | 1828 | } else if (disk->shared && !disk->readonly) { | ||
1858 | 1829 | virBufferAddLit(&opt, ",cache=off"); | ||
1859 | 1830 | } | ||
1860 | 1831 | |||
1861 | 1832 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_MONITOR_JSON)) { | ||
1862 | 1833 | const char *wpolicy = NULL, *rpolicy = NULL; | ||
1863 | 1834 | |||
1864 | 1835 | if (disk->error_policy) | ||
1865 | 1836 | wpolicy = virDomainDiskErrorPolicyTypeToString(disk->error_policy); | ||
1866 | 1837 | if (disk->rerror_policy) | ||
1867 | 1838 | rpolicy = virDomainDiskErrorPolicyTypeToString(disk->rerror_policy); | ||
1868 | 1839 | |||
1869 | 1840 | if (disk->error_policy == VIR_DOMAIN_DISK_ERROR_POLICY_ENOSPACE) { | ||
1870 | 1841 | /* in the case of enospace, the option is spelled | ||
1871 | 1842 | * differently in qemu, and it's only valid for werror, | ||
1872 | 1843 | * not for rerror, so leave leave rerror NULL. | ||
1873 | 1844 | */ | ||
1874 | 1845 | wpolicy = "enospc"; | ||
1875 | 1846 | } else if (!rpolicy) { | ||
1876 | 1847 | /* for other policies, rpolicy can match wpolicy */ | ||
1877 | 1848 | rpolicy = wpolicy; | ||
1878 | 1849 | } | ||
1879 | 1850 | |||
1880 | 1851 | if (wpolicy) | ||
1881 | 1852 | virBufferAsprintf(&opt, ",werror=%s", wpolicy); | ||
1882 | 1853 | if (rpolicy) | ||
1883 | 1854 | virBufferAsprintf(&opt, ",rerror=%s", rpolicy); | ||
1884 | 1855 | } | ||
1885 | 1856 | |||
1886 | 1857 | if (disk->iomode) { | ||
1887 | 1858 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_DRIVE_AIO)) { | ||
1888 | 1859 | virBufferAsprintf(&opt, ",aio=%s", | ||
1889 | 1860 | virDomainDiskIoTypeToString(disk->iomode)); | ||
1890 | 1861 | } else { | ||
1891 | 1862 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", | ||
1892 | 1863 | _("disk aio mode not supported with this " | ||
1893 | 1864 | "QEMU binary")); | ||
1894 | 1865 | goto error; | ||
1895 | 1866 | } | ||
1896 | 1867 | } | ||
1897 | 1868 | |||
1898 | 1869 | /* block I/O throttling */ | ||
1899 | 1870 | if (disk->blkdeviotune.total_bytes_sec) { | ||
1900 | 1871 | virBufferAsprintf(&opt, ",bps=%llu", | ||
1901 | 1872 | disk->blkdeviotune.total_bytes_sec); | ||
1902 | 1873 | } | ||
1903 | 1874 | |||
1904 | 1875 | if (disk->blkdeviotune.read_bytes_sec) { | ||
1905 | 1876 | virBufferAsprintf(&opt, ",bps_rd=%llu", | ||
1906 | 1877 | disk->blkdeviotune.read_bytes_sec); | ||
1907 | 1878 | } | ||
1908 | 1879 | |||
1909 | 1880 | if (disk->blkdeviotune.write_bytes_sec) { | ||
1910 | 1881 | virBufferAsprintf(&opt, ",bps_wr=%llu", | ||
1911 | 1882 | disk->blkdeviotune.write_bytes_sec); | ||
1912 | 1883 | } | ||
1913 | 1884 | |||
1914 | 1885 | if (disk->blkdeviotune.total_iops_sec) { | ||
1915 | 1886 | virBufferAsprintf(&opt, ",iops=%llu", | ||
1916 | 1887 | disk->blkdeviotune.total_iops_sec); | ||
1917 | 1888 | } | ||
1918 | 1889 | |||
1919 | 1890 | if (disk->blkdeviotune.read_iops_sec) { | ||
1920 | 1891 | virBufferAsprintf(&opt, ",iops_rd=%llu", | ||
1921 | 1892 | disk->blkdeviotune.read_iops_sec); | ||
1922 | 1893 | } | ||
1923 | 1894 | |||
1924 | 1895 | if (disk->blkdeviotune.write_iops_sec) { | ||
1925 | 1896 | virBufferAsprintf(&opt, ",iops_wr=%llu", | ||
1926 | 1897 | disk->blkdeviotune.write_iops_sec); | ||
1927 | 1898 | } | ||
1928 | 1899 | |||
1929 | 1900 | if (virBufferError(&opt)) { | ||
1930 | 1901 | virReportOOMError(); | ||
1931 | 1902 | goto error; | ||
1932 | 1903 | } | ||
1933 | 1904 | |||
1934 | 1905 | return virBufferContentAndReset(&opt); | ||
1935 | 1906 | |||
1936 | 1907 | error: | ||
1937 | 1908 | virBufferFreeAndReset(&opt); | ||
1938 | 1909 | return NULL; | ||
1939 | 1910 | } | ||
1940 | 1911 | |||
1941 | 1912 | |||
1942 | 1913 | char * | ||
1943 | 1914 | qemuBuildDriveDevStr(virDomainDiskDefPtr disk, | ||
1944 | 1915 | int bootindex, | ||
1945 | 1916 | virBitmapPtr qemuCaps) | ||
1946 | 1917 | { | ||
1947 | 1918 | virBuffer opt = VIR_BUFFER_INITIALIZER; | ||
1948 | 1919 | const char *bus = virDomainDiskQEMUBusTypeToString(disk->bus); | ||
1949 | 1920 | int idx = virDiskNameToIndex(disk->dst); | ||
1950 | 1921 | |||
1951 | 1922 | if (idx < 0) { | ||
1952 | 1923 | qemuReportError(VIR_ERR_INTERNAL_ERROR, | ||
1953 | 1924 | _("unsupported disk type '%s'"), disk->dst); | ||
1954 | 1925 | goto error; | ||
1955 | 1926 | } | ||
1956 | 1927 | |||
1957 | 1928 | switch (disk->bus) { | ||
1958 | 1929 | case VIR_DOMAIN_DISK_BUS_IDE: | ||
1959 | 1930 | virBufferAddLit(&opt, "ide-drive"); | ||
1960 | 1931 | virBufferAsprintf(&opt, ",bus=ide.%d,unit=%d", | ||
1961 | 1932 | disk->info.addr.drive.bus, | ||
1962 | 1933 | disk->info.addr.drive.unit); | ||
1963 | 1934 | break; | ||
1964 | 1935 | case VIR_DOMAIN_DISK_BUS_SCSI: | ||
1965 | 1936 | virBufferAddLit(&opt, "scsi-disk"); | ||
1966 | 1937 | virBufferAsprintf(&opt, ",bus=scsi%d.%d,scsi-id=%d", | ||
1967 | 1938 | disk->info.addr.drive.controller, | ||
1968 | 1939 | disk->info.addr.drive.bus, | ||
1969 | 1940 | disk->info.addr.drive.unit); | ||
1970 | 1941 | break; | ||
1971 | 1942 | case VIR_DOMAIN_DISK_BUS_SATA: | ||
1972 | 1943 | virBufferAddLit(&opt, "ide-drive"); | ||
1973 | 1944 | virBufferAsprintf(&opt, ",bus=ahci%d.%d", | ||
1974 | 1945 | disk->info.addr.drive.controller, | ||
1975 | 1946 | disk->info.addr.drive.unit); | ||
1976 | 1947 | break; | ||
1977 | 1948 | case VIR_DOMAIN_DISK_BUS_VIRTIO: | ||
1978 | 1949 | virBufferAddLit(&opt, "virtio-blk-pci"); | ||
1979 | 1950 | qemuBuildIoEventFdStr(&opt, disk->ioeventfd, qemuCaps); | ||
1980 | 1951 | if (disk->event_idx && | ||
1981 | 1952 | qemuCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_BLK_EVENT_IDX)) { | ||
1982 | 1953 | virBufferAsprintf(&opt, ",event_idx=%s", | ||
1983 | 1954 | virDomainVirtioEventIdxTypeToString(disk->event_idx)); | ||
1984 | 1955 | } | ||
1985 | 1956 | if (qemuBuildDeviceAddressStr(&opt, &disk->info, qemuCaps) < 0) | ||
1986 | 1957 | goto error; | ||
1987 | 1958 | break; | ||
1988 | 1959 | case VIR_DOMAIN_DISK_BUS_USB: | ||
1989 | 1960 | virBufferAddLit(&opt, "usb-storage"); | ||
1990 | 1961 | break; | ||
1991 | 1962 | default: | ||
1992 | 1963 | qemuReportError(VIR_ERR_INTERNAL_ERROR, | ||
1993 | 1964 | _("unsupported disk bus '%s' with device setup"), bus); | ||
1994 | 1965 | goto error; | ||
1995 | 1966 | } | ||
1996 | 1967 | virBufferAsprintf(&opt, ",drive=%s%s", QEMU_DRIVE_HOST_PREFIX, disk->info.alias); | ||
1997 | 1968 | virBufferAsprintf(&opt, ",id=%s", disk->info.alias); | ||
1998 | 1969 | if (bootindex && qemuCapsGet(qemuCaps, QEMU_CAPS_BOOTINDEX)) | ||
1999 | 1970 | virBufferAsprintf(&opt, ",bootindex=%d", bootindex); | ||
2000 | 1971 | |||
2001 | 1972 | if (virBufferError(&opt)) { | ||
2002 | 1973 | virReportOOMError(); | ||
2003 | 1974 | goto error; | ||
2004 | 1975 | } | ||
2005 | 1976 | |||
2006 | 1977 | return virBufferContentAndReset(&opt); | ||
2007 | 1978 | |||
2008 | 1979 | error: | ||
2009 | 1980 | virBufferFreeAndReset(&opt); | ||
2010 | 1981 | return NULL; | ||
2011 | 1982 | } | ||
2012 | 1983 | |||
2013 | 1984 | |||
2014 | 1985 | char *qemuBuildFSStr(virDomainFSDefPtr fs, | ||
2015 | 1986 | virBitmapPtr qemuCaps ATTRIBUTE_UNUSED) | ||
2016 | 1987 | { | ||
2017 | 1988 | virBuffer opt = VIR_BUFFER_INITIALIZER; | ||
2018 | 1989 | const char *driver = qemuDomainFSDriverTypeToString(fs->fsdriver); | ||
2019 | 1990 | |||
2020 | 1991 | if (fs->type != VIR_DOMAIN_FS_TYPE_MOUNT) { | ||
2021 | 1992 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", | ||
2022 | 1993 | _("only supports mount filesystem type")); | ||
2023 | 1994 | goto error; | ||
2024 | 1995 | } | ||
2025 | 1996 | |||
2026 | 1997 | if (!driver) { | ||
2027 | 1998 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", | ||
2028 | 1999 | _("Filesystem driver type not supported")); | ||
2029 | 2000 | goto error; | ||
2030 | 2001 | } | ||
2031 | 2002 | virBufferAdd(&opt, driver, -1); | ||
2032 | 2003 | |||
2033 | 2004 | if (fs->accessmode == VIR_DOMAIN_FS_ACCESSMODE_MAPPED) { | ||
2034 | 2005 | virBufferAddLit(&opt, ",security_model=mapped"); | ||
2035 | 2006 | } else if(fs->accessmode == VIR_DOMAIN_FS_ACCESSMODE_PASSTHROUGH) { | ||
2036 | 2007 | virBufferAddLit(&opt, ",security_model=passthrough"); | ||
2037 | 2008 | } else if(fs->accessmode == VIR_DOMAIN_FS_ACCESSMODE_SQUASH) { | ||
2038 | 2009 | virBufferAddLit(&opt, ",security_model=none"); | ||
2039 | 2010 | } | ||
2040 | 2011 | virBufferAsprintf(&opt, ",id=%s%s", QEMU_FSDEV_HOST_PREFIX, fs->info.alias); | ||
2041 | 2012 | virBufferAsprintf(&opt, ",path=%s", fs->src); | ||
2042 | 2013 | |||
2043 | 2014 | if (virBufferError(&opt)) { | ||
2044 | 2015 | virReportOOMError(); | ||
2045 | 2016 | goto error; | ||
2046 | 2017 | } | ||
2047 | 2018 | |||
2048 | 2019 | return virBufferContentAndReset(&opt); | ||
2049 | 2020 | |||
2050 | 2021 | error: | ||
2051 | 2022 | virBufferFreeAndReset(&opt); | ||
2052 | 2023 | return NULL; | ||
2053 | 2024 | } | ||
2054 | 2025 | |||
2055 | 2026 | |||
2056 | 2027 | char * | ||
2057 | 2028 | qemuBuildFSDevStr(virDomainFSDefPtr fs, | ||
2058 | 2029 | virBitmapPtr qemuCaps) | ||
2059 | 2030 | { | ||
2060 | 2031 | virBuffer opt = VIR_BUFFER_INITIALIZER; | ||
2061 | 2032 | |||
2062 | 2033 | if (fs->type != VIR_DOMAIN_FS_TYPE_MOUNT) { | ||
2063 | 2034 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", | ||
2064 | 2035 | _("can only passthrough directories")); | ||
2065 | 2036 | goto error; | ||
2066 | 2037 | } | ||
2067 | 2038 | |||
2068 | 2039 | virBufferAddLit(&opt, "virtio-9p-pci"); | ||
2069 | 2040 | virBufferAsprintf(&opt, ",id=%s", fs->info.alias); | ||
2070 | 2041 | virBufferAsprintf(&opt, ",fsdev=%s%s", QEMU_FSDEV_HOST_PREFIX, fs->info.alias); | ||
2071 | 2042 | virBufferAsprintf(&opt, ",mount_tag=%s", fs->dst); | ||
2072 | 2043 | |||
2073 | 2044 | if (qemuBuildDeviceAddressStr(&opt, &fs->info, qemuCaps) < 0) | ||
2074 | 2045 | goto error; | ||
2075 | 2046 | |||
2076 | 2047 | if (virBufferError(&opt)) { | ||
2077 | 2048 | virReportOOMError(); | ||
2078 | 2049 | goto error; | ||
2079 | 2050 | } | ||
2080 | 2051 | |||
2081 | 2052 | return virBufferContentAndReset(&opt); | ||
2082 | 2053 | |||
2083 | 2054 | error: | ||
2084 | 2055 | virBufferFreeAndReset(&opt); | ||
2085 | 2056 | return NULL; | ||
2086 | 2057 | } | ||
2087 | 2058 | |||
2088 | 2059 | |||
2089 | 2060 | static int | ||
2090 | 2061 | qemuControllerModelUSBToCaps(int model) | ||
2091 | 2062 | { | ||
2092 | 2063 | switch (model) { | ||
2093 | 2064 | case VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX3_UHCI: | ||
2094 | 2065 | return QEMU_CAPS_PIIX3_USB_UHCI; | ||
2095 | 2066 | case VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX4_UHCI: | ||
2096 | 2067 | return QEMU_CAPS_PIIX4_USB_UHCI; | ||
2097 | 2068 | case VIR_DOMAIN_CONTROLLER_MODEL_USB_EHCI: | ||
2098 | 2069 | return QEMU_CAPS_USB_EHCI; | ||
2099 | 2070 | case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_EHCI1: | ||
2100 | 2071 | case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI1: | ||
2101 | 2072 | case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI2: | ||
2102 | 2073 | case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI3: | ||
2103 | 2074 | return QEMU_CAPS_ICH9_USB_EHCI1; | ||
2104 | 2075 | case VIR_DOMAIN_CONTROLLER_MODEL_USB_VT82C686B_UHCI: | ||
2105 | 2076 | return QEMU_CAPS_VT82C686B_USB_UHCI; | ||
2106 | 2077 | case VIR_DOMAIN_CONTROLLER_MODEL_USB_PCI_OHCI: | ||
2107 | 2078 | return QEMU_CAPS_PCI_OHCI; | ||
2108 | 2079 | default: | ||
2109 | 2080 | return -1; | ||
2110 | 2081 | } | ||
2111 | 2082 | } | ||
2112 | 2083 | |||
2113 | 2084 | |||
2114 | 2085 | static int | ||
2115 | 2086 | qemuBuildUSBControllerDevStr(virDomainControllerDefPtr def, | ||
2116 | 2087 | virBitmapPtr qemuCaps, | ||
2117 | 2088 | virBuffer *buf) | ||
2118 | 2089 | { | ||
2119 | 2090 | const char *smodel; | ||
2120 | 2091 | int model, caps; | ||
2121 | 2092 | |||
2122 | 2093 | model = def->model; | ||
2123 | 2094 | if (model == -1) | ||
2124 | 2095 | model = VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX3_UHCI; | ||
2125 | 2096 | |||
2126 | 2097 | smodel = qemuControllerModelUSBTypeToString(model); | ||
2127 | 2098 | caps = qemuControllerModelUSBToCaps(model); | ||
2128 | 2099 | |||
2129 | 2100 | if (caps == -1 || !qemuCapsGet(qemuCaps, caps)) { | ||
2130 | 2101 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, | ||
2131 | 2102 | _("%s not supported in this QEMU binary"), smodel); | ||
2132 | 2103 | return -1; | ||
2133 | 2104 | } | ||
2134 | 2105 | |||
2135 | 2106 | virBufferAsprintf(buf, "%s", smodel); | ||
2136 | 2107 | |||
2137 | 2108 | if (def->info.mastertype == VIR_DOMAIN_CONTROLLER_MASTER_USB) { | ||
2138 | 2109 | virBufferAsprintf(buf, ",masterbus="); | ||
2139 | 2110 | qemuUsbId(buf, def->idx); | ||
2140 | 2111 | virBufferAsprintf(buf, ".0,firstport=%d", def->info.master.usb.startport); | ||
2141 | 2112 | } else { | ||
2142 | 2113 | virBufferAsprintf(buf, ",id="); | ||
2143 | 2114 | qemuUsbId(buf, def->idx); | ||
2144 | 2115 | } | ||
2145 | 2116 | |||
2146 | 2117 | return 0; | ||
2147 | 2118 | } | ||
2148 | 2119 | |||
2149 | 2120 | char * | ||
2150 | 2121 | qemuBuildControllerDevStr(virDomainControllerDefPtr def, | ||
2151 | 2122 | virBitmapPtr qemuCaps, | ||
2152 | 2123 | int *nusbcontroller) | ||
2153 | 2124 | { | ||
2154 | 2125 | virBuffer buf = VIR_BUFFER_INITIALIZER; | ||
2155 | 2126 | |||
2156 | 2127 | switch (def->type) { | ||
2157 | 2128 | case VIR_DOMAIN_CONTROLLER_TYPE_SCSI: | ||
2158 | 2129 | virBufferAddLit(&buf, "lsi"); | ||
2159 | 2130 | virBufferAsprintf(&buf, ",id=scsi%d", def->idx); | ||
2160 | 2131 | break; | ||
2161 | 2132 | |||
2162 | 2133 | case VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL: | ||
2163 | 2134 | if (def->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) { | ||
2164 | 2135 | virBufferAddLit(&buf, "virtio-serial-pci"); | ||
2165 | 2136 | } else { | ||
2166 | 2137 | virBufferAddLit(&buf, "virtio-serial"); | ||
2167 | 2138 | } | ||
2168 | 2139 | virBufferAsprintf(&buf, ",id=" QEMU_VIRTIO_SERIAL_PREFIX "%d", | ||
2169 | 2140 | def->idx); | ||
2170 | 2141 | if (def->opts.vioserial.ports != -1) { | ||
2171 | 2142 | virBufferAsprintf(&buf, ",max_ports=%d", | ||
2172 | 2143 | def->opts.vioserial.ports); | ||
2173 | 2144 | } | ||
2174 | 2145 | if (def->opts.vioserial.vectors != -1) { | ||
2175 | 2146 | virBufferAsprintf(&buf, ",vectors=%d", | ||
2176 | 2147 | def->opts.vioserial.vectors); | ||
2177 | 2148 | } | ||
2178 | 2149 | break; | ||
2179 | 2150 | |||
2180 | 2151 | case VIR_DOMAIN_CONTROLLER_TYPE_CCID: | ||
2181 | 2152 | virBufferAsprintf(&buf, "usb-ccid,id=ccid%d", def->idx); | ||
2182 | 2153 | break; | ||
2183 | 2154 | |||
2184 | 2155 | case VIR_DOMAIN_CONTROLLER_TYPE_SATA: | ||
2185 | 2156 | virBufferAsprintf(&buf, "ahci,id=ahci%d", def->idx); | ||
2186 | 2157 | break; | ||
2187 | 2158 | |||
2188 | 2159 | case VIR_DOMAIN_CONTROLLER_TYPE_USB: | ||
2189 | 2160 | if (qemuBuildUSBControllerDevStr(def, qemuCaps, &buf) == -1) | ||
2190 | 2161 | goto error; | ||
2191 | 2162 | |||
2192 | 2163 | if (nusbcontroller) | ||
2193 | 2164 | *nusbcontroller += 1; | ||
2194 | 2165 | |||
2195 | 2166 | break; | ||
2196 | 2167 | |||
2197 | 2168 | /* We always get an IDE controller, whether we want it or not. */ | ||
2198 | 2169 | case VIR_DOMAIN_CONTROLLER_TYPE_IDE: | ||
2199 | 2170 | default: | ||
2200 | 2171 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, | ||
2201 | 2172 | _("Unknown controller type: %s"), | ||
2202 | 2173 | virDomainControllerTypeToString(def->type)); | ||
2203 | 2174 | goto error; | ||
2204 | 2175 | } | ||
2205 | 2176 | |||
2206 | 2177 | if (qemuBuildDeviceAddressStr(&buf, &def->info, qemuCaps) < 0) | ||
2207 | 2178 | goto error; | ||
2208 | 2179 | |||
2209 | 2180 | if (virBufferError(&buf)) { | ||
2210 | 2181 | virReportOOMError(); | ||
2211 | 2182 | goto error; | ||
2212 | 2183 | } | ||
2213 | 2184 | |||
2214 | 2185 | return virBufferContentAndReset(&buf); | ||
2215 | 2186 | |||
2216 | 2187 | error: | ||
2217 | 2188 | virBufferFreeAndReset(&buf); | ||
2218 | 2189 | return NULL; | ||
2219 | 2190 | } | ||
2220 | 2191 | |||
2221 | 2192 | |||
2222 | 2193 | char * | ||
2223 | 2194 | qemuBuildNicStr(virDomainNetDefPtr net, | ||
2224 | 2195 | const char *prefix, | ||
2225 | 2196 | int vlan) | ||
2226 | 2197 | { | ||
2227 | 2198 | char *str; | ||
2228 | 2199 | if (virAsprintf(&str, | ||
2229 | 2200 | "%smacaddr=%02x:%02x:%02x:%02x:%02x:%02x,vlan=%d%s%s%s%s", | ||
2230 | 2201 | prefix ? prefix : "", | ||
2231 | 2202 | net->mac[0], net->mac[1], | ||
2232 | 2203 | net->mac[2], net->mac[3], | ||
2233 | 2204 | net->mac[4], net->mac[5], | ||
2234 | 2205 | vlan, | ||
2235 | 2206 | (net->model ? ",model=" : ""), | ||
2236 | 2207 | (net->model ? net->model : ""), | ||
2237 | 2208 | (net->info.alias ? ",name=" : ""), | ||
2238 | 2209 | (net->info.alias ? net->info.alias : "")) < 0) { | ||
2239 | 2210 | virReportOOMError(); | ||
2240 | 2211 | return NULL; | ||
2241 | 2212 | } | ||
2242 | 2213 | |||
2243 | 2214 | return str; | ||
2244 | 2215 | } | ||
2245 | 2216 | |||
2246 | 2217 | |||
2247 | 2218 | char * | ||
2248 | 2219 | qemuBuildNicDevStr(virDomainNetDefPtr net, | ||
2249 | 2220 | int vlan, | ||
2250 | 2221 | int bootindex, | ||
2251 | 2222 | virBitmapPtr qemuCaps) | ||
2252 | 2223 | { | ||
2253 | 2224 | virBuffer buf = VIR_BUFFER_INITIALIZER; | ||
2254 | 2225 | const char *nic; | ||
2255 | 2226 | bool usingVirtio = false; | ||
2256 | 2227 | |||
2257 | 2228 | if (!net->model) { | ||
2258 | 2229 | nic = "rtl8139"; | ||
2259 | 2230 | } else if (STREQ(net->model, "virtio")) { | ||
2260 | 2231 | nic = "virtio-net-pci"; | ||
2261 | 2232 | usingVirtio = true; | ||
2262 | 2233 | } else { | ||
2263 | 2234 | nic = net->model; | ||
2264 | 2235 | } | ||
2265 | 2236 | |||
2266 | 2237 | virBufferAdd(&buf, nic, strlen(nic)); | ||
2267 | 2238 | if (usingVirtio && net->driver.virtio.txmode) { | ||
2268 | 2239 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_TX_ALG)) { | ||
2269 | 2240 | virBufferAddLit(&buf, ",tx="); | ||
2270 | 2241 | switch (net->driver.virtio.txmode) { | ||
2271 | 2242 | case VIR_DOMAIN_NET_VIRTIO_TX_MODE_IOTHREAD: | ||
2272 | 2243 | virBufferAddLit(&buf, "bh"); | ||
2273 | 2244 | break; | ||
2274 | 2245 | |||
2275 | 2246 | case VIR_DOMAIN_NET_VIRTIO_TX_MODE_TIMER: | ||
2276 | 2247 | virBufferAddLit(&buf, "timer"); | ||
2277 | 2248 | break; | ||
2278 | 2249 | default: | ||
2279 | 2250 | /* this should never happen, if it does, we need | ||
2280 | 2251 | * to add another case to this switch. | ||
2281 | 2252 | */ | ||
2282 | 2253 | qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", | ||
2283 | 2254 | _("unrecognized virtio-net-pci 'tx' option")); | ||
2284 | 2255 | goto error; | ||
2285 | 2256 | } | ||
2286 | 2257 | } else { | ||
2287 | 2258 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", | ||
2288 | 2259 | _("virtio-net-pci 'tx' option not supported in this QEMU binary")); | ||
2289 | 2260 | goto error; | ||
2290 | 2261 | } | ||
2291 | 2262 | } | ||
2292 | 2263 | if (usingVirtio) { | ||
2293 | 2264 | qemuBuildIoEventFdStr(&buf, net->driver.virtio.ioeventfd, qemuCaps); | ||
2294 | 2265 | if (net->driver.virtio.event_idx && | ||
2295 | 2266 | qemuCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_NET_EVENT_IDX)) { | ||
2296 | 2267 | virBufferAsprintf(&buf, ",event_idx=%s", | ||
2297 | 2268 | virDomainVirtioEventIdxTypeToString(net->driver.virtio.event_idx)); | ||
2298 | 2269 | } | ||
2299 | 2270 | } | ||
2300 | 2271 | if (vlan == -1) | ||
2301 | 2272 | virBufferAsprintf(&buf, ",netdev=host%s", net->info.alias); | ||
2302 | 2273 | else | ||
2303 | 2274 | virBufferAsprintf(&buf, ",vlan=%d", vlan); | ||
2304 | 2275 | virBufferAsprintf(&buf, ",id=%s", net->info.alias); | ||
2305 | 2276 | virBufferAsprintf(&buf, ",mac=%02x:%02x:%02x:%02x:%02x:%02x", | ||
2306 | 2277 | net->mac[0], net->mac[1], | ||
2307 | 2278 | net->mac[2], net->mac[3], | ||
2308 | 2279 | net->mac[4], net->mac[5]); | ||
2309 | 2280 | if (qemuBuildDeviceAddressStr(&buf, &net->info, qemuCaps) < 0) | ||
2310 | 2281 | goto error; | ||
2311 | 2282 | if (bootindex && qemuCapsGet(qemuCaps, QEMU_CAPS_BOOTINDEX)) | ||
2312 | 2283 | virBufferAsprintf(&buf, ",bootindex=%d", bootindex); | ||
2313 | 2284 | |||
2314 | 2285 | if (virBufferError(&buf)) { | ||
2315 | 2286 | virReportOOMError(); | ||
2316 | 2287 | goto error; | ||
2317 | 2288 | } | ||
2318 | 2289 | |||
2319 | 2290 | return virBufferContentAndReset(&buf); | ||
2320 | 2291 | |||
2321 | 2292 | error: | ||
2322 | 2293 | virBufferFreeAndReset(&buf); | ||
2323 | 2294 | return NULL; | ||
2324 | 2295 | } | ||
2325 | 2296 | |||
2326 | 2297 | |||
2327 | 2298 | char * | ||
2328 | 2299 | qemuBuildHostNetStr(virDomainNetDefPtr net, | ||
2329 | 2300 | char type_sep, | ||
2330 | 2301 | int vlan, | ||
2331 | 2302 | const char *tapfd, | ||
2332 | 2303 | const char *vhostfd) | ||
2333 | 2304 | { | ||
2334 | 2305 | bool is_tap = false; | ||
2335 | 2306 | virBuffer buf = VIR_BUFFER_INITIALIZER; | ||
2336 | 2307 | |||
2337 | 2308 | switch (virDomainNetGetActualType(net)) { | ||
2338 | 2309 | case VIR_DOMAIN_NET_TYPE_NETWORK: | ||
2339 | 2310 | case VIR_DOMAIN_NET_TYPE_BRIDGE: | ||
2340 | 2311 | case VIR_DOMAIN_NET_TYPE_DIRECT: | ||
2341 | 2312 | virBufferAddLit(&buf, "tap"); | ||
2342 | 2313 | virBufferAsprintf(&buf, "%cfd=%s", type_sep, tapfd); | ||
2343 | 2314 | type_sep = ','; | ||
2344 | 2315 | is_tap = true; | ||
2345 | 2316 | break; | ||
2346 | 2317 | |||
2347 | 2318 | case VIR_DOMAIN_NET_TYPE_ETHERNET: | ||
2348 | 2319 | virBufferAddLit(&buf, "tap"); | ||
2349 | 2320 | if (net->ifname) { | ||
2350 | 2321 | virBufferAsprintf(&buf, "%cifname=%s", type_sep, net->ifname); | ||
2351 | 2322 | type_sep = ','; | ||
2352 | 2323 | } | ||
2353 | 2324 | if (net->data.ethernet.script) { | ||
2354 | 2325 | virBufferAsprintf(&buf, "%cscript=%s", type_sep, | ||
2355 | 2326 | net->data.ethernet.script); | ||
2356 | 2327 | type_sep = ','; | ||
2357 | 2328 | } | ||
2358 | 2329 | is_tap = true; | ||
2359 | 2330 | break; | ||
2360 | 2331 | |||
2361 | 2332 | case VIR_DOMAIN_NET_TYPE_CLIENT: | ||
2362 | 2333 | case VIR_DOMAIN_NET_TYPE_SERVER: | ||
2363 | 2334 | case VIR_DOMAIN_NET_TYPE_MCAST: | ||
2364 | 2335 | virBufferAddLit(&buf, "socket"); | ||
2365 | 2336 | switch (virDomainNetGetActualType(net)) { | ||
2366 | 2337 | case VIR_DOMAIN_NET_TYPE_CLIENT: | ||
2367 | 2338 | virBufferAsprintf(&buf, "%cconnect=%s:%d", | ||
2368 | 2339 | type_sep, | ||
2369 | 2340 | net->data.socket.address, | ||
2370 | 2341 | net->data.socket.port); | ||
2371 | 2342 | break; | ||
2372 | 2343 | case VIR_DOMAIN_NET_TYPE_SERVER: | ||
2373 | 2344 | virBufferAsprintf(&buf, "%clisten=%s:%d", | ||
2374 | 2345 | type_sep, | ||
2375 | 2346 | net->data.socket.address, | ||
2376 | 2347 | net->data.socket.port); | ||
2377 | 2348 | break; | ||
2378 | 2349 | case VIR_DOMAIN_NET_TYPE_MCAST: | ||
2379 | 2350 | virBufferAsprintf(&buf, "%cmcast=%s:%d", | ||
2380 | 2351 | type_sep, | ||
2381 | 2352 | net->data.socket.address, | ||
2382 | 2353 | net->data.socket.port); | ||
2383 | 2354 | break; | ||
2384 | 2355 | case VIR_DOMAIN_NET_TYPE_USER: | ||
2385 | 2356 | case VIR_DOMAIN_NET_TYPE_ETHERNET: | ||
2386 | 2357 | case VIR_DOMAIN_NET_TYPE_NETWORK: | ||
2387 | 2358 | case VIR_DOMAIN_NET_TYPE_BRIDGE: | ||
2388 | 2359 | case VIR_DOMAIN_NET_TYPE_INTERNAL: | ||
2389 | 2360 | case VIR_DOMAIN_NET_TYPE_DIRECT: | ||
2390 | 2361 | case VIR_DOMAIN_NET_TYPE_LAST: | ||
2391 | 2362 | break; | ||
2392 | 2363 | } | ||
2393 | 2364 | type_sep = ','; | ||
2394 | 2365 | break; | ||
2395 | 2366 | |||
2396 | 2367 | case VIR_DOMAIN_NET_TYPE_USER: | ||
2397 | 2368 | default: | ||
2398 | 2369 | virBufferAddLit(&buf, "user"); | ||
2399 | 2370 | break; | ||
2400 | 2371 | } | ||
2401 | 2372 | |||
2402 | 2373 | if (vlan >= 0) { | ||
2403 | 2374 | virBufferAsprintf(&buf, "%cvlan=%d", type_sep, vlan); | ||
2404 | 2375 | if (net->info.alias) | ||
2405 | 2376 | virBufferAsprintf(&buf, ",name=host%s", | ||
2406 | 2377 | net->info.alias); | ||
2407 | 2378 | } else { | ||
2408 | 2379 | virBufferAsprintf(&buf, "%cid=host%s", | ||
2409 | 2380 | type_sep, net->info.alias); | ||
2410 | 2381 | } | ||
2411 | 2382 | |||
2412 | 2383 | if (is_tap) { | ||
2413 | 2384 | if (vhostfd && *vhostfd) | ||
2414 | 2385 | virBufferAsprintf(&buf, ",vhost=on,vhostfd=%s", vhostfd); | ||
2415 | 2386 | if (net->tune.sndbuf_specified) | ||
2416 | 2387 | virBufferAsprintf(&buf, ",sndbuf=%lu", net->tune.sndbuf); | ||
2417 | 2388 | } | ||
2418 | 2389 | |||
2419 | 2390 | if (virBufferError(&buf)) { | ||
2420 | 2391 | virBufferFreeAndReset(&buf); | ||
2421 | 2392 | virReportOOMError(); | ||
2422 | 2393 | return NULL; | ||
2423 | 2394 | } | ||
2424 | 2395 | |||
2425 | 2396 | return virBufferContentAndReset(&buf); | ||
2426 | 2397 | } | ||
2427 | 2398 | |||
2428 | 2399 | |||
2429 | 2400 | char * | ||
2430 | 2401 | qemuBuildWatchdogDevStr(virDomainWatchdogDefPtr dev, | ||
2431 | 2402 | virBitmapPtr qemuCaps) | ||
2432 | 2403 | { | ||
2433 | 2404 | virBuffer buf = VIR_BUFFER_INITIALIZER; | ||
2434 | 2405 | |||
2435 | 2406 | const char *model = virDomainWatchdogModelTypeToString(dev->model); | ||
2436 | 2407 | if (!model) { | ||
2437 | 2408 | qemuReportError(VIR_ERR_INTERNAL_ERROR, | ||
2438 | 2409 | "%s", _("missing watchdog model")); | ||
2439 | 2410 | goto error; | ||
2440 | 2411 | } | ||
2441 | 2412 | |||
2442 | 2413 | virBufferAsprintf(&buf, "%s,id=%s", model, dev->info.alias); | ||
2443 | 2414 | if (qemuBuildDeviceAddressStr(&buf, &dev->info, qemuCaps) < 0) | ||
2444 | 2415 | goto error; | ||
2445 | 2416 | |||
2446 | 2417 | if (virBufferError(&buf)) { | ||
2447 | 2418 | virReportOOMError(); | ||
2448 | 2419 | goto error; | ||
2449 | 2420 | } | ||
2450 | 2421 | |||
2451 | 2422 | return virBufferContentAndReset(&buf); | ||
2452 | 2423 | |||
2453 | 2424 | error: | ||
2454 | 2425 | virBufferFreeAndReset(&buf); | ||
2455 | 2426 | return NULL; | ||
2456 | 2427 | } | ||
2457 | 2428 | |||
2458 | 2429 | |||
2459 | 2430 | char * | ||
2460 | 2431 | qemuBuildMemballoonDevStr(virDomainMemballoonDefPtr dev, | ||
2461 | 2432 | virBitmapPtr qemuCaps) | ||
2462 | 2433 | { | ||
2463 | 2434 | virBuffer buf = VIR_BUFFER_INITIALIZER; | ||
2464 | 2435 | |||
2465 | 2436 | virBufferAddLit(&buf, "virtio-balloon-pci"); | ||
2466 | 2437 | virBufferAsprintf(&buf, ",id=%s", dev->info.alias); | ||
2467 | 2438 | if (qemuBuildDeviceAddressStr(&buf, &dev->info, qemuCaps) < 0) | ||
2468 | 2439 | goto error; | ||
2469 | 2440 | |||
2470 | 2441 | if (virBufferError(&buf)) { | ||
2471 | 2442 | virReportOOMError(); | ||
2472 | 2443 | goto error; | ||
2473 | 2444 | } | ||
2474 | 2445 | |||
2475 | 2446 | return virBufferContentAndReset(&buf); | ||
2476 | 2447 | |||
2477 | 2448 | error: | ||
2478 | 2449 | virBufferFreeAndReset(&buf); | ||
2479 | 2450 | return NULL; | ||
2480 | 2451 | } | ||
2481 | 2452 | |||
2482 | 2453 | |||
2483 | 2454 | char * | ||
2484 | 2455 | qemuBuildUSBInputDevStr(virDomainInputDefPtr dev, | ||
2485 | 2456 | virBitmapPtr qemuCaps) | ||
2486 | 2457 | { | ||
2487 | 2458 | virBuffer buf = VIR_BUFFER_INITIALIZER; | ||
2488 | 2459 | |||
2489 | 2460 | virBufferAsprintf(&buf, "%s,id=%s", | ||
2490 | 2461 | dev->type == VIR_DOMAIN_INPUT_TYPE_MOUSE ? | ||
2491 | 2462 | "usb-mouse" : "usb-tablet", dev->info.alias); | ||
2492 | 2463 | |||
2493 | 2464 | if (qemuBuildDeviceAddressStr(&buf, &dev->info, qemuCaps) < 0) | ||
2494 | 2465 | goto error; | ||
2495 | 2466 | |||
2496 | 2467 | if (virBufferError(&buf)) { | ||
2497 | 2468 | virReportOOMError(); | ||
2498 | 2469 | goto error; | ||
2499 | 2470 | } | ||
2500 | 2471 | |||
2501 | 2472 | return virBufferContentAndReset(&buf); | ||
2502 | 2473 | |||
2503 | 2474 | error: | ||
2504 | 2475 | virBufferFreeAndReset(&buf); | ||
2505 | 2476 | return NULL; | ||
2506 | 2477 | } | ||
2507 | 2478 | |||
2508 | 2479 | |||
2509 | 2480 | char * | ||
2510 | 2481 | qemuBuildSoundDevStr(virDomainSoundDefPtr sound, | ||
2511 | 2482 | virBitmapPtr qemuCaps) | ||
2512 | 2483 | { | ||
2513 | 2484 | virBuffer buf = VIR_BUFFER_INITIALIZER; | ||
2514 | 2485 | const char *model = virDomainSoundModelTypeToString(sound->model); | ||
2515 | 2486 | |||
2516 | 2487 | if (!model) { | ||
2517 | 2488 | qemuReportError(VIR_ERR_INTERNAL_ERROR, | ||
2518 | 2489 | "%s", _("invalid sound model")); | ||
2519 | 2490 | goto error; | ||
2520 | 2491 | } | ||
2521 | 2492 | |||
2522 | 2493 | /* Hack for weirdly unusual devices name in QEMU */ | ||
2523 | 2494 | if (STREQ(model, "es1370")) | ||
2524 | 2495 | model = "ES1370"; | ||
2525 | 2496 | else if (STREQ(model, "ac97")) | ||
2526 | 2497 | model = "AC97"; | ||
2527 | 2498 | else if (STREQ(model, "ich6")) | ||
2528 | 2499 | model = "intel-hda"; | ||
2529 | 2500 | |||
2530 | 2501 | virBufferAsprintf(&buf, "%s,id=%s", model, sound->info.alias); | ||
2531 | 2502 | if (qemuBuildDeviceAddressStr(&buf, &sound->info, qemuCaps) < 0) | ||
2532 | 2503 | goto error; | ||
2533 | 2504 | |||
2534 | 2505 | if (virBufferError(&buf)) { | ||
2535 | 2506 | virReportOOMError(); | ||
2536 | 2507 | goto error; | ||
2537 | 2508 | } | ||
2538 | 2509 | |||
2539 | 2510 | return virBufferContentAndReset(&buf); | ||
2540 | 2511 | |||
2541 | 2512 | error: | ||
2542 | 2513 | virBufferFreeAndReset(&buf); | ||
2543 | 2514 | return NULL; | ||
2544 | 2515 | } | ||
2545 | 2516 | |||
2546 | 2517 | static char * | ||
2547 | 2518 | qemuBuildSoundCodecStr(virDomainSoundDefPtr sound, | ||
2548 | 2519 | const char *codec) | ||
2549 | 2520 | { | ||
2550 | 2521 | virBuffer buf = VIR_BUFFER_INITIALIZER; | ||
2551 | 2522 | int cad = 0; | ||
2552 | 2523 | |||
2553 | 2524 | virBufferAsprintf(&buf, "%s,id=%s-codec%d,bus=%s.0,cad=%d", | ||
2554 | 2525 | codec, sound->info.alias, cad, sound->info.alias, cad); | ||
2555 | 2526 | |||
2556 | 2527 | if (virBufferError(&buf)) { | ||
2557 | 2528 | virReportOOMError(); | ||
2558 | 2529 | goto error; | ||
2559 | 2530 | } | ||
2560 | 2531 | |||
2561 | 2532 | return virBufferContentAndReset(&buf); | ||
2562 | 2533 | |||
2563 | 2534 | error: | ||
2564 | 2535 | virBufferFreeAndReset(&buf); | ||
2565 | 2536 | return NULL; | ||
2566 | 2537 | } | ||
2567 | 2538 | |||
2568 | 2539 | static char * | ||
2569 | 2540 | qemuBuildVideoDevStr(virDomainVideoDefPtr video, | ||
2570 | 2541 | virBitmapPtr qemuCaps) | ||
2571 | 2542 | { | ||
2572 | 2543 | virBuffer buf = VIR_BUFFER_INITIALIZER; | ||
2573 | 2544 | const char *model = qemuVideoTypeToString(video->type); | ||
2574 | 2545 | |||
2575 | 2546 | if (!model) { | ||
2576 | 2547 | qemuReportError(VIR_ERR_INTERNAL_ERROR, | ||
2577 | 2548 | "%s", _("invalid video model")); | ||
2578 | 2549 | goto error; | ||
2579 | 2550 | } | ||
2580 | 2551 | |||
2581 | 2552 | virBufferAsprintf(&buf, "%s,id=%s", model, video->info.alias); | ||
2582 | 2553 | |||
2583 | 2554 | if (video->type == VIR_DOMAIN_VIDEO_TYPE_QXL) { | ||
2584 | 2555 | if (video->vram > (UINT_MAX / 1024)) { | ||
2585 | 2556 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, | ||
2586 | 2557 | _("value for 'vram' must be less than '%u'"), | ||
2587 | 2558 | UINT_MAX / 1024); | ||
2588 | 2559 | goto error; | ||
2589 | 2560 | } | ||
2590 | 2561 | |||
2591 | 2562 | /* QEMU accepts bytes for vram_size. */ | ||
2592 | 2563 | virBufferAsprintf(&buf, ",vram_size=%u", video->vram * 1024); | ||
2593 | 2564 | } | ||
2594 | 2565 | |||
2595 | 2566 | if (qemuBuildDeviceAddressStr(&buf, &video->info, qemuCaps) < 0) | ||
2596 | 2567 | goto error; | ||
2597 | 2568 | |||
2598 | 2569 | if (virBufferError(&buf)) { | ||
2599 | 2570 | virReportOOMError(); | ||
2600 | 2571 | goto error; | ||
2601 | 2572 | } | ||
2602 | 2573 | |||
2603 | 2574 | return virBufferContentAndReset(&buf); | ||
2604 | 2575 | |||
2605 | 2576 | error: | ||
2606 | 2577 | virBufferFreeAndReset(&buf); | ||
2607 | 2578 | return NULL; | ||
2608 | 2579 | } | ||
2609 | 2580 | |||
2610 | 2581 | |||
2611 | 2582 | int | ||
2612 | 2583 | qemuOpenPCIConfig(virDomainHostdevDefPtr dev) | ||
2613 | 2584 | { | ||
2614 | 2585 | char *path = NULL; | ||
2615 | 2586 | int configfd = -1; | ||
2616 | 2587 | |||
2617 | 2588 | if (virAsprintf(&path, "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/config", | ||
2618 | 2589 | dev->source.subsys.u.pci.domain, | ||
2619 | 2590 | dev->source.subsys.u.pci.bus, | ||
2620 | 2591 | dev->source.subsys.u.pci.slot, | ||
2621 | 2592 | dev->source.subsys.u.pci.function) < 0) { | ||
2622 | 2593 | virReportOOMError(); | ||
2623 | 2594 | return -1; | ||
2624 | 2595 | } | ||
2625 | 2596 | |||
2626 | 2597 | configfd = open(path, O_RDWR, 0); | ||
2627 | 2598 | |||
2628 | 2599 | if (configfd < 0) | ||
2629 | 2600 | virReportSystemError(errno, _("Failed opening %s"), path); | ||
2630 | 2601 | |||
2631 | 2602 | VIR_FREE(path); | ||
2632 | 2603 | |||
2633 | 2604 | return configfd; | ||
2634 | 2605 | } | ||
2635 | 2606 | |||
2636 | 2607 | char * | ||
2637 | 2608 | qemuBuildPCIHostdevDevStr(virDomainHostdevDefPtr dev, const char *configfd, | ||
2638 | 2609 | virBitmapPtr qemuCaps) | ||
2639 | 2610 | { | ||
2640 | 2611 | virBuffer buf = VIR_BUFFER_INITIALIZER; | ||
2641 | 2612 | |||
2642 | 2613 | virBufferAddLit(&buf, "pci-assign"); | ||
2643 | 2614 | virBufferAsprintf(&buf, ",host=%.2x:%.2x.%.1x", | ||
2644 | 2615 | dev->source.subsys.u.pci.bus, | ||
2645 | 2616 | dev->source.subsys.u.pci.slot, | ||
2646 | 2617 | dev->source.subsys.u.pci.function); | ||
2647 | 2618 | virBufferAsprintf(&buf, ",id=%s", dev->info.alias); | ||
2648 | 2619 | if (configfd && *configfd) | ||
2649 | 2620 | virBufferAsprintf(&buf, ",configfd=%s", configfd); | ||
2650 | 2621 | if (dev->bootIndex) | ||
2651 | 2622 | virBufferAsprintf(&buf, ",bootindex=%d", dev->bootIndex); | ||
2652 | 2623 | if (qemuBuildDeviceAddressStr(&buf, &dev->info, qemuCaps) < 0) | ||
2653 | 2624 | goto error; | ||
2654 | 2625 | |||
2655 | 2626 | if (dev->rombar) { | ||
2656 | 2627 | if (!qemuCapsGet(qemuCaps, QEMU_CAPS_PCI_ROMBAR)) { | ||
2657 | 2628 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, | ||
2658 | 2629 | "%s", _("rombar not supported in this QEMU binary")); | ||
2659 | 2630 | goto error; | ||
2660 | 2631 | } | ||
2661 | 2632 | |||
2662 | 2633 | switch (dev->rombar) { | ||
2663 | 2634 | case VIR_DOMAIN_PCI_ROMBAR_OFF: | ||
2664 | 2635 | virBufferAddLit(&buf, ",rombar=0"); | ||
2665 | 2636 | break; | ||
2666 | 2637 | case VIR_DOMAIN_PCI_ROMBAR_ON: | ||
2667 | 2638 | virBufferAddLit(&buf, ",rombar=1"); | ||
2668 | 2639 | break; | ||
2669 | 2640 | default: | ||
2670 | 2641 | break; | ||
2671 | 2642 | } | ||
2672 | 2643 | } | ||
2673 | 2644 | |||
2674 | 2645 | if (virBufferError(&buf)) { | ||
2675 | 2646 | virReportOOMError(); | ||
2676 | 2647 | goto error; | ||
2677 | 2648 | } | ||
2678 | 2649 | |||
2679 | 2650 | return virBufferContentAndReset(&buf); | ||
2680 | 2651 | |||
2681 | 2652 | error: | ||
2682 | 2653 | virBufferFreeAndReset(&buf); | ||
2683 | 2654 | return NULL; | ||
2684 | 2655 | } | ||
2685 | 2656 | |||
2686 | 2657 | |||
2687 | 2658 | char * | ||
2688 | 2659 | qemuBuildPCIHostdevPCIDevStr(virDomainHostdevDefPtr dev) | ||
2689 | 2660 | { | ||
2690 | 2661 | char *ret = NULL; | ||
2691 | 2662 | |||
2692 | 2663 | if (virAsprintf(&ret, "host=%.2x:%.2x.%.1x", | ||
2693 | 2664 | dev->source.subsys.u.pci.bus, | ||
2694 | 2665 | dev->source.subsys.u.pci.slot, | ||
2695 | 2666 | dev->source.subsys.u.pci.function) < 0) | ||
2696 | 2667 | virReportOOMError(); | ||
2697 | 2668 | |||
2698 | 2669 | return ret; | ||
2699 | 2670 | } | ||
2700 | 2671 | |||
2701 | 2672 | |||
2702 | 2673 | char * | ||
2703 | 2674 | qemuBuildRedirdevDevStr(virDomainRedirdevDefPtr dev, | ||
2704 | 2675 | virBitmapPtr qemuCaps) | ||
2705 | 2676 | { | ||
2706 | 2677 | virBuffer buf = VIR_BUFFER_INITIALIZER; | ||
2707 | 2678 | |||
2708 | 2679 | if (dev->bus != VIR_DOMAIN_REDIRDEV_BUS_USB) { | ||
2709 | 2680 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, | ||
2710 | 2681 | _("Redirection bus %s is not supported by QEMU"), | ||
2711 | 2682 | virDomainRedirdevBusTypeToString(dev->bus)); | ||
2712 | 2683 | goto error; | ||
2713 | 2684 | } | ||
2714 | 2685 | |||
2715 | 2686 | if (!qemuCapsGet(qemuCaps, QEMU_CAPS_USB_REDIR)) { | ||
2716 | 2687 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", | ||
2717 | 2688 | _("USB redirection is not supported " | ||
2718 | 2689 | "by this version of QEMU")); | ||
2719 | 2690 | goto error; | ||
2720 | 2691 | } | ||
2721 | 2692 | |||
2722 | 2693 | virBufferAsprintf(&buf, "usb-redir,chardev=char%s,id=%s", | ||
2723 | 2694 | dev->info.alias, | ||
2724 | 2695 | dev->info.alias); | ||
2725 | 2696 | |||
2726 | 2697 | if (qemuBuildDeviceAddressStr(&buf, &dev->info, qemuCaps) < 0) | ||
2727 | 2698 | goto error; | ||
2728 | 2699 | |||
2729 | 2700 | if (virBufferError(&buf)) { | ||
2730 | 2701 | virReportOOMError(); | ||
2731 | 2702 | goto error; | ||
2732 | 2703 | } | ||
2733 | 2704 | |||
2734 | 2705 | return virBufferContentAndReset(&buf); | ||
2735 | 2706 | |||
2736 | 2707 | error: | ||
2737 | 2708 | virBufferFreeAndReset(&buf); | ||
2738 | 2709 | return NULL; | ||
2739 | 2710 | } | ||
2740 | 2711 | |||
2741 | 2712 | char * | ||
2742 | 2713 | qemuBuildUSBHostdevDevStr(virDomainHostdevDefPtr dev, | ||
2743 | 2714 | virBitmapPtr qemuCaps) | ||
2744 | 2715 | { | ||
2745 | 2716 | virBuffer buf = VIR_BUFFER_INITIALIZER; | ||
2746 | 2717 | |||
2747 | 2718 | if (!dev->source.subsys.u.usb.bus && | ||
2748 | 2719 | !dev->source.subsys.u.usb.device) { | ||
2749 | 2720 | qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", | ||
2750 | 2721 | _("USB host device is missing bus/device information")); | ||
2751 | 2722 | return NULL; | ||
2752 | 2723 | } | ||
2753 | 2724 | |||
2754 | 2725 | virBufferAsprintf(&buf, "usb-host,hostbus=%d,hostaddr=%d,id=%s", | ||
2755 | 2726 | dev->source.subsys.u.usb.bus, | ||
2756 | 2727 | dev->source.subsys.u.usb.device, | ||
2757 | 2728 | dev->info.alias); | ||
2758 | 2729 | |||
2759 | 2730 | if (qemuBuildDeviceAddressStr(&buf, &dev->info, qemuCaps) < 0) | ||
2760 | 2731 | goto error; | ||
2761 | 2732 | |||
2762 | 2733 | if (virBufferError(&buf)) { | ||
2763 | 2734 | virReportOOMError(); | ||
2764 | 2735 | goto error; | ||
2765 | 2736 | } | ||
2766 | 2737 | |||
2767 | 2738 | return virBufferContentAndReset(&buf); | ||
2768 | 2739 | |||
2769 | 2740 | error: | ||
2770 | 2741 | virBufferFreeAndReset(&buf); | ||
2771 | 2742 | return NULL; | ||
2772 | 2743 | } | ||
2773 | 2744 | |||
2774 | 2745 | |||
2775 | 2746 | char * | ||
2776 | 2747 | qemuBuildHubDevStr(virDomainHubDefPtr dev, | ||
2777 | 2748 | virBitmapPtr qemuCaps) | ||
2778 | 2749 | { | ||
2779 | 2750 | virBuffer buf = VIR_BUFFER_INITIALIZER; | ||
2780 | 2751 | |||
2781 | 2752 | if (dev->type != VIR_DOMAIN_HUB_TYPE_USB) { | ||
2782 | 2753 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, | ||
2783 | 2754 | _("hub type %s not supported"), | ||
2784 | 2755 | virDomainHubTypeToString(dev->type)); | ||
2785 | 2756 | goto error; | ||
2786 | 2757 | } | ||
2787 | 2758 | |||
2788 | 2759 | if (!qemuCapsGet(qemuCaps, QEMU_CAPS_USB_HUB)) { | ||
2789 | 2760 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, | ||
2790 | 2761 | _("usb-hub not supported by QEMU binary")); | ||
2791 | 2762 | goto error; | ||
2792 | 2763 | } | ||
2793 | 2764 | |||
2794 | 2765 | virBufferAddLit(&buf, "usb-hub"); | ||
2795 | 2766 | virBufferAsprintf(&buf, ",id=%s", dev->info.alias); | ||
2796 | 2767 | if (qemuBuildDeviceAddressStr(&buf, &dev->info, qemuCaps) < 0) | ||
2797 | 2768 | goto error; | ||
2798 | 2769 | |||
2799 | 2770 | if (virBufferError(&buf)) { | ||
2800 | 2771 | virReportOOMError(); | ||
2801 | 2772 | goto error; | ||
2802 | 2773 | } | ||
2803 | 2774 | |||
2804 | 2775 | return virBufferContentAndReset(&buf); | ||
2805 | 2776 | |||
2806 | 2777 | error: | ||
2807 | 2778 | virBufferFreeAndReset(&buf); | ||
2808 | 2779 | return NULL; | ||
2809 | 2780 | } | ||
2810 | 2781 | |||
2811 | 2782 | |||
2812 | 2783 | char * | ||
2813 | 2784 | qemuBuildUSBHostdevUsbDevStr(virDomainHostdevDefPtr dev) | ||
2814 | 2785 | { | ||
2815 | 2786 | char *ret = NULL; | ||
2816 | 2787 | |||
2817 | 2788 | if (!dev->source.subsys.u.usb.bus && | ||
2818 | 2789 | !dev->source.subsys.u.usb.device) { | ||
2819 | 2790 | qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", | ||
2820 | 2791 | _("USB host device is missing bus/device information")); | ||
2821 | 2792 | return NULL; | ||
2822 | 2793 | } | ||
2823 | 2794 | |||
2824 | 2795 | if (virAsprintf(&ret, "host:%d.%d", | ||
2825 | 2796 | dev->source.subsys.u.usb.bus, | ||
2826 | 2797 | dev->source.subsys.u.usb.device) < 0) | ||
2827 | 2798 | virReportOOMError(); | ||
2828 | 2799 | |||
2829 | 2800 | return ret; | ||
2830 | 2801 | } | ||
2831 | 2802 | |||
2832 | 2803 | |||
2833 | 2804 | |||
2834 | 2805 | /* This function outputs a -chardev command line option which describes only the | ||
2835 | 2806 | * host side of the character device */ | ||
2836 | 2807 | static char * | ||
2837 | 2808 | qemuBuildChrChardevStr(virDomainChrSourceDefPtr dev, const char *alias, | ||
2838 | 2809 | virBitmapPtr qemuCaps) | ||
2839 | 2810 | { | ||
2840 | 2811 | virBuffer buf = VIR_BUFFER_INITIALIZER; | ||
2841 | 2812 | bool telnet; | ||
2842 | 2813 | |||
2843 | 2814 | switch(dev->type) { | ||
2844 | 2815 | case VIR_DOMAIN_CHR_TYPE_NULL: | ||
2845 | 2816 | virBufferAsprintf(&buf, "null,id=char%s", alias); | ||
2846 | 2817 | break; | ||
2847 | 2818 | |||
2848 | 2819 | case VIR_DOMAIN_CHR_TYPE_VC: | ||
2849 | 2820 | virBufferAsprintf(&buf, "vc,id=char%s", alias); | ||
2850 | 2821 | break; | ||
2851 | 2822 | |||
2852 | 2823 | case VIR_DOMAIN_CHR_TYPE_PTY: | ||
2853 | 2824 | virBufferAsprintf(&buf, "pty,id=char%s", alias); | ||
2854 | 2825 | break; | ||
2855 | 2826 | |||
2856 | 2827 | case VIR_DOMAIN_CHR_TYPE_DEV: | ||
2857 | 2828 | virBufferAsprintf(&buf, "tty,id=char%s,path=%s", alias, | ||
2858 | 2829 | dev->data.file.path); | ||
2859 | 2830 | break; | ||
2860 | 2831 | |||
2861 | 2832 | case VIR_DOMAIN_CHR_TYPE_FILE: | ||
2862 | 2833 | virBufferAsprintf(&buf, "file,id=char%s,path=%s", alias, | ||
2863 | 2834 | dev->data.file.path); | ||
2864 | 2835 | break; | ||
2865 | 2836 | |||
2866 | 2837 | case VIR_DOMAIN_CHR_TYPE_PIPE: | ||
2867 | 2838 | virBufferAsprintf(&buf, "pipe,id=char%s,path=%s", alias, | ||
2868 | 2839 | dev->data.file.path); | ||
2869 | 2840 | break; | ||
2870 | 2841 | |||
2871 | 2842 | case VIR_DOMAIN_CHR_TYPE_STDIO: | ||
2872 | 2843 | virBufferAsprintf(&buf, "stdio,id=char%s", alias); | ||
2873 | 2844 | break; | ||
2874 | 2845 | |||
2875 | 2846 | case VIR_DOMAIN_CHR_TYPE_UDP: { | ||
2876 | 2847 | const char *connectHost = dev->data.udp.connectHost; | ||
2877 | 2848 | const char *bindHost = dev->data.udp.bindHost; | ||
2878 | 2849 | const char *bindService = dev->data.udp.bindService; | ||
2879 | 2850 | |||
2880 | 2851 | if (connectHost == NULL) | ||
2881 | 2852 | connectHost = ""; | ||
2882 | 2853 | if (bindHost == NULL) | ||
2883 | 2854 | bindHost = ""; | ||
2884 | 2855 | if (bindService == NULL) | ||
2885 | 2856 | bindService = "0"; | ||
2886 | 2857 | |||
2887 | 2858 | virBufferAsprintf(&buf, | ||
2888 | 2859 | "udp,id=char%s,host=%s,port=%s,localaddr=%s," | ||
2889 | 2860 | "localport=%s", | ||
2890 | 2861 | alias, | ||
2891 | 2862 | connectHost, | ||
2892 | 2863 | dev->data.udp.connectService, | ||
2893 | 2864 | bindHost, bindService); | ||
2894 | 2865 | break; | ||
2895 | 2866 | } | ||
2896 | 2867 | case VIR_DOMAIN_CHR_TYPE_TCP: | ||
2897 | 2868 | telnet = dev->data.tcp.protocol == VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET; | ||
2898 | 2869 | virBufferAsprintf(&buf, | ||
2899 | 2870 | "socket,id=char%s,host=%s,port=%s%s%s", | ||
2900 | 2871 | alias, | ||
2901 | 2872 | dev->data.tcp.host, | ||
2902 | 2873 | dev->data.tcp.service, | ||
2903 | 2874 | telnet ? ",telnet" : "", | ||
2904 | 2875 | dev->data.tcp.listen ? ",server,nowait" : ""); | ||
2905 | 2876 | break; | ||
2906 | 2877 | |||
2907 | 2878 | case VIR_DOMAIN_CHR_TYPE_UNIX: | ||
2908 | 2879 | virBufferAsprintf(&buf, | ||
2909 | 2880 | "socket,id=char%s,path=%s%s", | ||
2910 | 2881 | alias, | ||
2911 | 2882 | dev->data.nix.path, | ||
2912 | 2883 | dev->data.nix.listen ? ",server,nowait" : ""); | ||
2913 | 2884 | break; | ||
2914 | 2885 | |||
2915 | 2886 | case VIR_DOMAIN_CHR_TYPE_SPICEVMC: | ||
2916 | 2887 | if (!qemuCapsGet(qemuCaps, QEMU_CAPS_CHARDEV_SPICEVMC)) { | ||
2917 | 2888 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, | ||
2918 | 2889 | _("spicevmc not supported in this QEMU binary")); | ||
2919 | 2890 | goto error; | ||
2920 | 2891 | } | ||
2921 | 2892 | virBufferAsprintf(&buf, "spicevmc,id=char%s,name=%s", alias, | ||
2922 | 2893 | virDomainChrSpicevmcTypeToString(dev->data.spicevmc)); | ||
2923 | 2894 | break; | ||
2924 | 2895 | |||
2925 | 2896 | default: | ||
2926 | 2897 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, | ||
2927 | 2898 | _("unsupported chardev '%s'"), | ||
2928 | 2899 | virDomainChrTypeToString(dev->type)); | ||
2929 | 2900 | goto error; | ||
2930 | 2901 | } | ||
2931 | 2902 | |||
2932 | 2903 | if (virBufferError(&buf)) { | ||
2933 | 2904 | virReportOOMError(); | ||
2934 | 2905 | goto error; | ||
2935 | 2906 | } | ||
2936 | 2907 | |||
2937 | 2908 | return virBufferContentAndReset(&buf); | ||
2938 | 2909 | |||
2939 | 2910 | error: | ||
2940 | 2911 | virBufferFreeAndReset(&buf); | ||
2941 | 2912 | return NULL; | ||
2942 | 2913 | } | ||
2943 | 2914 | |||
2944 | 2915 | |||
2945 | 2916 | static char * | ||
2946 | 2917 | qemuBuildChrArgStr(virDomainChrSourceDefPtr dev, const char *prefix) | ||
2947 | 2918 | { | ||
2948 | 2919 | virBuffer buf = VIR_BUFFER_INITIALIZER; | ||
2949 | 2920 | |||
2950 | 2921 | if (prefix) | ||
2951 | 2922 | virBufferAdd(&buf, prefix, strlen(prefix)); | ||
2952 | 2923 | |||
2953 | 2924 | switch (dev->type) { | ||
2954 | 2925 | case VIR_DOMAIN_CHR_TYPE_NULL: | ||
2955 | 2926 | virBufferAddLit(&buf, "null"); | ||
2956 | 2927 | break; | ||
2957 | 2928 | |||
2958 | 2929 | case VIR_DOMAIN_CHR_TYPE_VC: | ||
2959 | 2930 | virBufferAddLit(&buf, "vc"); | ||
2960 | 2931 | break; | ||
2961 | 2932 | |||
2962 | 2933 | case VIR_DOMAIN_CHR_TYPE_PTY: | ||
2963 | 2934 | virBufferAddLit(&buf, "pty"); | ||
2964 | 2935 | break; | ||
2965 | 2936 | |||
2966 | 2937 | case VIR_DOMAIN_CHR_TYPE_DEV: | ||
2967 | 2938 | virBufferStrcat(&buf, dev->data.file.path, NULL); | ||
2968 | 2939 | break; | ||
2969 | 2940 | |||
2970 | 2941 | case VIR_DOMAIN_CHR_TYPE_FILE: | ||
2971 | 2942 | virBufferAsprintf(&buf, "file:%s", dev->data.file.path); | ||
2972 | 2943 | break; | ||
2973 | 2944 | |||
2974 | 2945 | case VIR_DOMAIN_CHR_TYPE_PIPE: | ||
2975 | 2946 | virBufferAsprintf(&buf, "pipe:%s", dev->data.file.path); | ||
2976 | 2947 | break; | ||
2977 | 2948 | |||
2978 | 2949 | case VIR_DOMAIN_CHR_TYPE_STDIO: | ||
2979 | 2950 | virBufferAddLit(&buf, "stdio"); | ||
2980 | 2951 | break; | ||
2981 | 2952 | |||
2982 | 2953 | case VIR_DOMAIN_CHR_TYPE_UDP: { | ||
2983 | 2954 | const char *connectHost = dev->data.udp.connectHost; | ||
2984 | 2955 | const char *bindHost = dev->data.udp.bindHost; | ||
2985 | 2956 | const char *bindService = dev->data.udp.bindService; | ||
2986 | 2957 | |||
2987 | 2958 | if (connectHost == NULL) | ||
2988 | 2959 | connectHost = ""; | ||
2989 | 2960 | if (bindHost == NULL) | ||
2990 | 2961 | bindHost = ""; | ||
2991 | 2962 | if (bindService == NULL) | ||
2992 | 2963 | bindService = "0"; | ||
2993 | 2964 | |||
2994 | 2965 | virBufferAsprintf(&buf, "udp:%s:%s@%s:%s", | ||
2995 | 2966 | connectHost, | ||
2996 | 2967 | dev->data.udp.connectService, | ||
2997 | 2968 | bindHost, | ||
2998 | 2969 | bindService); | ||
2999 | 2970 | break; | ||
3000 | 2971 | } | ||
3001 | 2972 | case VIR_DOMAIN_CHR_TYPE_TCP: | ||
3002 | 2973 | if (dev->data.tcp.protocol == VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET) { | ||
3003 | 2974 | virBufferAsprintf(&buf, "telnet:%s:%s%s", | ||
3004 | 2975 | dev->data.tcp.host, | ||
3005 | 2976 | dev->data.tcp.service, | ||
3006 | 2977 | dev->data.tcp.listen ? ",server,nowait" : ""); | ||
3007 | 2978 | } else { | ||
3008 | 2979 | virBufferAsprintf(&buf, "tcp:%s:%s%s", | ||
3009 | 2980 | dev->data.tcp.host, | ||
3010 | 2981 | dev->data.tcp.service, | ||
3011 | 2982 | dev->data.tcp.listen ? ",server,nowait" : ""); | ||
3012 | 2983 | } | ||
3013 | 2984 | break; | ||
3014 | 2985 | |||
3015 | 2986 | case VIR_DOMAIN_CHR_TYPE_UNIX: | ||
3016 | 2987 | virBufferAsprintf(&buf, "unix:%s%s", | ||
3017 | 2988 | dev->data.nix.path, | ||
3018 | 2989 | dev->data.nix.listen ? ",server,nowait" : ""); | ||
3019 | 2990 | break; | ||
3020 | 2991 | } | ||
3021 | 2992 | |||
3022 | 2993 | if (virBufferError(&buf)) { | ||
3023 | 2994 | virReportOOMError(); | ||
3024 | 2995 | goto error; | ||
3025 | 2996 | } | ||
3026 | 2997 | |||
3027 | 2998 | return virBufferContentAndReset(&buf); | ||
3028 | 2999 | |||
3029 | 3000 | error: | ||
3030 | 3001 | virBufferFreeAndReset(&buf); | ||
3031 | 3002 | return NULL; | ||
3032 | 3003 | } | ||
3033 | 3004 | |||
3034 | 3005 | |||
3035 | 3006 | static char * | ||
3036 | 3007 | qemuBuildVirtioSerialPortDevStr(virDomainChrDefPtr dev, | ||
3037 | 3008 | virBitmapPtr qemuCaps) | ||
3038 | 3009 | { | ||
3039 | 3010 | virBuffer buf = VIR_BUFFER_INITIALIZER; | ||
3040 | 3011 | switch (dev->deviceType) { | ||
3041 | 3012 | case VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE: | ||
3042 | 3013 | virBufferAddLit(&buf, "virtconsole"); | ||
3043 | 3014 | break; | ||
3044 | 3015 | case VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL: | ||
3045 | 3016 | /* Legacy syntax '-device spicevmc' */ | ||
3046 | 3017 | if (dev->source.type == VIR_DOMAIN_CHR_TYPE_SPICEVMC && | ||
3047 | 3018 | qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE_SPICEVMC)) { | ||
3048 | 3019 | virBufferAddLit(&buf, "spicevmc"); | ||
3049 | 3020 | } else { | ||
3050 | 3021 | virBufferAddLit(&buf, "virtserialport"); | ||
3051 | 3022 | } | ||
3052 | 3023 | break; | ||
3053 | 3024 | default: | ||
3054 | 3025 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", | ||
3055 | 3026 | _("Cannot use virtio serial for parallel/serial devices")); | ||
3056 | 3027 | return NULL; | ||
3057 | 3028 | } | ||
3058 | 3029 | |||
3059 | 3030 | if (dev->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) { | ||
3060 | 3031 | /* Check it's a virtio-serial address */ | ||
3061 | 3032 | if (dev->info.type != | ||
3062 | 3033 | VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL) | ||
3063 | 3034 | { | ||
3064 | 3035 | qemuReportError(VIR_ERR_INTERNAL_ERROR, | ||
3065 | 3036 | "%s", _("virtio serial device has invalid address type")); | ||
3066 | 3037 | goto error; | ||
3067 | 3038 | } | ||
3068 | 3039 | |||
3069 | 3040 | virBufferAsprintf(&buf, | ||
3070 | 3041 | ",bus=" QEMU_VIRTIO_SERIAL_PREFIX "%d.%d", | ||
3071 | 3042 | dev->info.addr.vioserial.controller, | ||
3072 | 3043 | dev->info.addr.vioserial.bus); | ||
3073 | 3044 | virBufferAsprintf(&buf, | ||
3074 | 3045 | ",nr=%d", | ||
3075 | 3046 | dev->info.addr.vioserial.port); | ||
3076 | 3047 | } | ||
3077 | 3048 | |||
3078 | 3049 | if (dev->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL && | ||
3079 | 3050 | dev->source.type == VIR_DOMAIN_CHR_TYPE_SPICEVMC && | ||
3080 | 3051 | dev->target.name && | ||
3081 | 3052 | STRNEQ(dev->target.name, "com.redhat.spice.0")) { | ||
3082 | 3053 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, | ||
3083 | 3054 | _("Unsupported spicevmc target name '%s'"), | ||
3084 | 3055 | dev->target.name); | ||
3085 | 3056 | goto error; | ||
3086 | 3057 | } | ||
3087 | 3058 | |||
3088 | 3059 | if (!(dev->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL && | ||
3089 | 3060 | dev->source.type == VIR_DOMAIN_CHR_TYPE_SPICEVMC && | ||
3090 | 3061 | qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE_SPICEVMC))) { | ||
3091 | 3062 | virBufferAsprintf(&buf, ",chardev=char%s,id=%s", | ||
3092 | 3063 | dev->info.alias, dev->info.alias); | ||
3093 | 3064 | if (dev->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL && | ||
3094 | 3065 | dev->target.name) { | ||
3095 | 3066 | virBufferAsprintf(&buf, ",name=%s", dev->target.name); | ||
3096 | 3067 | } | ||
3097 | 3068 | } else { | ||
3098 | 3069 | virBufferAsprintf(&buf, ",id=%s", dev->info.alias); | ||
3099 | 3070 | } | ||
3100 | 3071 | if (virBufferError(&buf)) { | ||
3101 | 3072 | virReportOOMError(); | ||
3102 | 3073 | goto error; | ||
3103 | 3074 | } | ||
3104 | 3075 | |||
3105 | 3076 | return virBufferContentAndReset(&buf); | ||
3106 | 3077 | |||
3107 | 3078 | error: | ||
3108 | 3079 | virBufferFreeAndReset(&buf); | ||
3109 | 3080 | return NULL; | ||
3110 | 3081 | } | ||
3111 | 3082 | |||
3112 | 3083 | static char *qemuBuildSmbiosBiosStr(virSysinfoDefPtr def) | ||
3113 | 3084 | { | ||
3114 | 3085 | virBuffer buf = VIR_BUFFER_INITIALIZER; | ||
3115 | 3086 | |||
3116 | 3087 | if ((def->bios_vendor == NULL) && (def->bios_version == NULL) && | ||
3117 | 3088 | (def->bios_date == NULL) && (def->bios_release == NULL)) | ||
3118 | 3089 | return(NULL); | ||
3119 | 3090 | |||
3120 | 3091 | virBufferAddLit(&buf, "type=0"); | ||
3121 | 3092 | |||
3122 | 3093 | /* 0:Vendor */ | ||
3123 | 3094 | if (def->bios_vendor) | ||
3124 | 3095 | virBufferAsprintf(&buf, ",vendor=%s", def->bios_vendor); | ||
3125 | 3096 | /* 0:BIOS Version */ | ||
3126 | 3097 | if (def->bios_version) | ||
3127 | 3098 | virBufferAsprintf(&buf, ",version=%s", def->bios_version); | ||
3128 | 3099 | /* 0:BIOS Release Date */ | ||
3129 | 3100 | if (def->bios_date) | ||
3130 | 3101 | virBufferAsprintf(&buf, ",date=%s", def->bios_date); | ||
3131 | 3102 | /* 0:System BIOS Major Release and 0:System BIOS Minor Release */ | ||
3132 | 3103 | if (def->bios_release) | ||
3133 | 3104 | virBufferAsprintf(&buf, ",release=%s", def->bios_release); | ||
3134 | 3105 | |||
3135 | 3106 | if (virBufferError(&buf)) { | ||
3136 | 3107 | virReportOOMError(); | ||
3137 | 3108 | goto error; | ||
3138 | 3109 | } | ||
3139 | 3110 | |||
3140 | 3111 | return virBufferContentAndReset(&buf); | ||
3141 | 3112 | |||
3142 | 3113 | error: | ||
3143 | 3114 | virBufferFreeAndReset(&buf); | ||
3144 | 3115 | return(NULL); | ||
3145 | 3116 | } | ||
3146 | 3117 | |||
3147 | 3118 | static char *qemuBuildSmbiosSystemStr(virSysinfoDefPtr def, bool skip_uuid) | ||
3148 | 3119 | { | ||
3149 | 3120 | virBuffer buf = VIR_BUFFER_INITIALIZER; | ||
3150 | 3121 | |||
3151 | 3122 | if ((def->system_manufacturer == NULL) && (def->system_sku == NULL) && | ||
3152 | 3123 | (def->system_product == NULL) && (def->system_version == NULL) && | ||
3153 | 3124 | (def->system_serial == NULL) && (def->system_family == NULL) && | ||
3154 | 3125 | (def->system_uuid == NULL || skip_uuid)) | ||
3155 | 3126 | return NULL; | ||
3156 | 3127 | |||
3157 | 3128 | virBufferAddLit(&buf, "type=1"); | ||
3158 | 3129 | |||
3159 | 3130 | /* 1:Manufacturer */ | ||
3160 | 3131 | if (def->system_manufacturer) | ||
3161 | 3132 | virBufferAsprintf(&buf, ",manufacturer=%s", | ||
3162 | 3133 | def->system_manufacturer); | ||
3163 | 3134 | /* 1:Product Name */ | ||
3164 | 3135 | if (def->system_product) | ||
3165 | 3136 | virBufferAsprintf(&buf, ",product=%s", def->system_product); | ||
3166 | 3137 | /* 1:Version */ | ||
3167 | 3138 | if (def->system_version) | ||
3168 | 3139 | virBufferAsprintf(&buf, ",version=%s", def->system_version); | ||
3169 | 3140 | /* 1:Serial Number */ | ||
3170 | 3141 | if (def->system_serial) | ||
3171 | 3142 | virBufferAsprintf(&buf, ",serial=%s", def->system_serial); | ||
3172 | 3143 | /* 1:UUID */ | ||
3173 | 3144 | if (def->system_uuid && !skip_uuid) | ||
3174 | 3145 | virBufferAsprintf(&buf, ",uuid=%s", def->system_uuid); | ||
3175 | 3146 | /* 1:SKU Number */ | ||
3176 | 3147 | if (def->system_sku) | ||
3177 | 3148 | virBufferAsprintf(&buf, ",sku=%s", def->system_sku); | ||
3178 | 3149 | /* 1:Family */ | ||
3179 | 3150 | if (def->system_family) | ||
3180 | 3151 | virBufferAsprintf(&buf, ",family=%s", def->system_family); | ||
3181 | 3152 | |||
3182 | 3153 | if (virBufferError(&buf)) { | ||
3183 | 3154 | virReportOOMError(); | ||
3184 | 3155 | goto error; | ||
3185 | 3156 | } | ||
3186 | 3157 | |||
3187 | 3158 | return virBufferContentAndReset(&buf); | ||
3188 | 3159 | |||
3189 | 3160 | error: | ||
3190 | 3161 | virBufferFreeAndReset(&buf); | ||
3191 | 3162 | return(NULL); | ||
3192 | 3163 | } | ||
3193 | 3164 | |||
3194 | 3165 | static char * | ||
3195 | 3166 | qemuBuildClockArgStr(virDomainClockDefPtr def) | ||
3196 | 3167 | { | ||
3197 | 3168 | virBuffer buf = VIR_BUFFER_INITIALIZER; | ||
3198 | 3169 | |||
3199 | 3170 | switch (def->offset) { | ||
3200 | 3171 | case VIR_DOMAIN_CLOCK_OFFSET_UTC: | ||
3201 | 3172 | virBufferAddLit(&buf, "base=utc"); | ||
3202 | 3173 | break; | ||
3203 | 3174 | |||
3204 | 3175 | case VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME: | ||
3205 | 3176 | case VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE: | ||
3206 | 3177 | virBufferAddLit(&buf, "base=localtime"); | ||
3207 | 3178 | break; | ||
3208 | 3179 | |||
3209 | 3180 | case VIR_DOMAIN_CLOCK_OFFSET_VARIABLE: { | ||
3210 | 3181 | time_t now = time(NULL); | ||
3211 | 3182 | struct tm nowbits; | ||
3212 | 3183 | |||
3213 | 3184 | now += def->data.adjustment; | ||
3214 | 3185 | gmtime_r(&now, &nowbits); | ||
3215 | 3186 | |||
3216 | 3187 | virBufferAsprintf(&buf, "base=%d-%02d-%02dT%02d:%02d:%02d", | ||
3217 | 3188 | nowbits.tm_year + 1900, | ||
3218 | 3189 | nowbits.tm_mon + 1, | ||
3219 | 3190 | nowbits.tm_mday, | ||
3220 | 3191 | nowbits.tm_hour, | ||
3221 | 3192 | nowbits.tm_min, | ||
3222 | 3193 | nowbits.tm_sec); | ||
3223 | 3194 | } break; | ||
3224 | 3195 | |||
3225 | 3196 | default: | ||
3226 | 3197 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, | ||
3227 | 3198 | _("unsupported clock offset '%s'"), | ||
3228 | 3199 | virDomainClockOffsetTypeToString(def->offset)); | ||
3229 | 3200 | goto error; | ||
3230 | 3201 | } | ||
3231 | 3202 | |||
3232 | 3203 | /* Look for an 'rtc' timer element, and add in appropriate clock= and driftfix= */ | ||
3233 | 3204 | int i; | ||
3234 | 3205 | for (i = 0; i < def->ntimers; i++) { | ||
3235 | 3206 | if (def->timers[i]->name == VIR_DOMAIN_TIMER_NAME_RTC) { | ||
3236 | 3207 | switch (def->timers[i]->track) { | ||
3237 | 3208 | case -1: /* unspecified - use hypervisor default */ | ||
3238 | 3209 | break; | ||
3239 | 3210 | case VIR_DOMAIN_TIMER_TRACK_BOOT: | ||
3240 | 3211 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, | ||
3241 | 3212 | _("unsupported rtc timer track '%s'"), | ||
3242 | 3213 | virDomainTimerTrackTypeToString(def->timers[i]->track)); | ||
3243 | 3214 | goto error; | ||
3244 | 3215 | case VIR_DOMAIN_TIMER_TRACK_GUEST: | ||
3245 | 3216 | virBufferAddLit(&buf, ",clock=vm"); | ||
3246 | 3217 | break; | ||
3247 | 3218 | case VIR_DOMAIN_TIMER_TRACK_WALL: | ||
3248 | 3219 | virBufferAddLit(&buf, ",clock=host"); | ||
3249 | 3220 | break; | ||
3250 | 3221 | } | ||
3251 | 3222 | |||
3252 | 3223 | switch (def->timers[i]->tickpolicy) { | ||
3253 | 3224 | case -1: | ||
3254 | 3225 | case VIR_DOMAIN_TIMER_TICKPOLICY_DELAY: | ||
3255 | 3226 | /* This is the default - missed ticks delivered when | ||
3256 | 3227 | next scheduled, at normal rate */ | ||
3257 | 3228 | break; | ||
3258 | 3229 | case VIR_DOMAIN_TIMER_TICKPOLICY_CATCHUP: | ||
3259 | 3230 | /* deliver ticks at a faster rate until caught up */ | ||
3260 | 3231 | virBufferAddLit(&buf, ",driftfix=slew"); | ||
3261 | 3232 | break; | ||
3262 | 3233 | case VIR_DOMAIN_TIMER_TICKPOLICY_MERGE: | ||
3263 | 3234 | case VIR_DOMAIN_TIMER_TICKPOLICY_DISCARD: | ||
3264 | 3235 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, | ||
3265 | 3236 | _("unsupported rtc timer tickpolicy '%s'"), | ||
3266 | 3237 | virDomainTimerTickpolicyTypeToString(def->timers[i]->tickpolicy)); | ||
3267 | 3238 | goto error; | ||
3268 | 3239 | } | ||
3269 | 3240 | break; /* no need to check other timers - there is only one rtc */ | ||
3270 | 3241 | } | ||
3271 | 3242 | } | ||
3272 | 3243 | |||
3273 | 3244 | if (virBufferError(&buf)) { | ||
3274 | 3245 | virReportOOMError(); | ||
3275 | 3246 | goto error; | ||
3276 | 3247 | } | ||
3277 | 3248 | |||
3278 | 3249 | return virBufferContentAndReset(&buf); | ||
3279 | 3250 | |||
3280 | 3251 | error: | ||
3281 | 3252 | virBufferFreeAndReset(&buf); | ||
3282 | 3253 | return NULL; | ||
3283 | 3254 | } | ||
3284 | 3255 | |||
3285 | 3256 | |||
3286 | 3257 | static int | ||
3287 | 3258 | qemuBuildCpuArgStr(const struct qemud_driver *driver, | ||
3288 | 3259 | const virDomainDefPtr def, | ||
3289 | 3260 | const char *emulator, | ||
3290 | 3261 | virBitmapPtr qemuCaps, | ||
3291 | 3262 | const struct utsname *ut, | ||
3292 | 3263 | char **opt, | ||
3293 | 3264 | bool *hasHwVirt) | ||
3294 | 3265 | { | ||
3295 | 3266 | const virCPUDefPtr host = driver->caps->host.cpu; | ||
3296 | 3267 | virCPUDefPtr guest = NULL; | ||
3297 | 3268 | unsigned int ncpus = 0; | ||
3298 | 3269 | const char **cpus = NULL; | ||
3299 | 3270 | union cpuData *data = NULL; | ||
3300 | 3271 | int ret = -1; | ||
3301 | 3272 | virBuffer buf = VIR_BUFFER_INITIALIZER; | ||
3302 | 3273 | int i; | ||
3303 | 3274 | |||
3304 | 3275 | *hasHwVirt = false; | ||
3305 | 3276 | |||
3306 | 3277 | if (def->cpu && def->cpu->model) { | ||
3307 | 3278 | if (host && | ||
3308 | 3279 | qemuCapsProbeCPUModels(emulator, qemuCaps, host->arch, | ||
3309 | 3280 | &ncpus, &cpus) < 0) | ||
3310 | 3281 | goto cleanup; | ||
3311 | 3282 | |||
3312 | 3283 | if (!ncpus || !host) { | ||
3313 | 3284 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", | ||
3314 | 3285 | _("CPU specification not supported by hypervisor")); | ||
3315 | 3286 | goto cleanup; | ||
3316 | 3287 | } | ||
3317 | 3288 | } | ||
3318 | 3289 | |||
3319 | 3290 | if (ncpus > 0 && host) { | ||
3320 | 3291 | virCPUCompareResult cmp; | ||
3321 | 3292 | const char *preferred; | ||
3322 | 3293 | int hasSVM; | ||
3323 | 3294 | |||
3324 | 3295 | cmp = cpuGuestData(host, def->cpu, &data); | ||
3325 | 3296 | switch (cmp) { | ||
3326 | 3297 | case VIR_CPU_COMPARE_INCOMPATIBLE: | ||
3327 | 3298 | qemuReportError(VIR_ERR_INTERNAL_ERROR, | ||
3328 | 3299 | "%s", _("guest CPU is not compatible with host CPU")); | ||
3329 | 3300 | /* fall through */ | ||
3330 | 3301 | case VIR_CPU_COMPARE_ERROR: | ||
3331 | 3302 | goto cleanup; | ||
3332 | 3303 | |||
3333 | 3304 | default: | ||
3334 | 3305 | break; | ||
3335 | 3306 | } | ||
3336 | 3307 | |||
3337 | 3308 | if (VIR_ALLOC(guest) < 0 || !(guest->arch = strdup(host->arch))) | ||
3338 | 3309 | goto no_memory; | ||
3339 | 3310 | |||
3340 | 3311 | if (def->cpu->match == VIR_CPU_MATCH_MINIMUM) | ||
3341 | 3312 | preferred = host->model; | ||
3342 | 3313 | else | ||
3343 | 3314 | preferred = def->cpu->model; | ||
3344 | 3315 | |||
3345 | 3316 | guest->type = VIR_CPU_TYPE_GUEST; | ||
3346 | 3317 | if (cpuDecode(guest, data, cpus, ncpus, preferred) < 0) | ||
3347 | 3318 | goto cleanup; | ||
3348 | 3319 | |||
3349 | 3320 | /* Only 'svm' requires --enable-nesting. The nested | ||
3350 | 3321 | * 'vmx' patches now simply hook off the CPU features | ||
3351 | 3322 | */ | ||
3352 | 3323 | hasSVM = cpuHasFeature(guest->arch, data, "svm"); | ||
3353 | 3324 | if (hasSVM < 0) | ||
3354 | 3325 | goto cleanup; | ||
3355 | 3326 | *hasHwVirt = hasSVM > 0 ? true : false; | ||
3356 | 3327 | |||
3357 | 3328 | virBufferAdd(&buf, guest->model, -1); | ||
3358 | 3329 | for (i = 0; i < guest->nfeatures; i++) { | ||
3359 | 3330 | char sign; | ||
3360 | 3331 | if (guest->features[i].policy == VIR_CPU_FEATURE_DISABLE) | ||
3361 | 3332 | sign = '-'; | ||
3362 | 3333 | else | ||
3363 | 3334 | sign = '+'; | ||
3364 | 3335 | |||
3365 | 3336 | virBufferAsprintf(&buf, ",%c%s", sign, guest->features[i].name); | ||
3366 | 3337 | } | ||
3367 | 3338 | } | ||
3368 | 3339 | else { | ||
3369 | 3340 | /* | ||
3370 | 3341 | * Need to force a 32-bit guest CPU type if | ||
3371 | 3342 | * | ||
3372 | 3343 | * 1. guest OS is i686 | ||
3373 | 3344 | * 2. host OS is x86_64 | ||
3374 | 3345 | * 3. emulator is qemu-kvm or kvm | ||
3375 | 3346 | * | ||
3376 | 3347 | * Or | ||
3377 | 3348 | * | ||
3378 | 3349 | * 1. guest OS is i686 | ||
3379 | 3350 | * 2. emulator is qemu-system-x86_64 | ||
3380 | 3351 | */ | ||
3381 | 3352 | if (STREQ(def->os.arch, "i686") && | ||
3382 | 3353 | ((STREQ(ut->machine, "x86_64") && | ||
3383 | 3354 | strstr(emulator, "kvm")) || | ||
3384 | 3355 | strstr(emulator, "x86_64"))) | ||
3385 | 3356 | virBufferAddLit(&buf, "qemu32"); | ||
3386 | 3357 | } | ||
3387 | 3358 | |||
3388 | 3359 | if (virBufferError(&buf)) | ||
3389 | 3360 | goto no_memory; | ||
3390 | 3361 | |||
3391 | 3362 | *opt = virBufferContentAndReset(&buf); | ||
3392 | 3363 | |||
3393 | 3364 | ret = 0; | ||
3394 | 3365 | |||
3395 | 3366 | cleanup: | ||
3396 | 3367 | if (guest) | ||
3397 | 3368 | cpuDataFree(guest->arch, data); | ||
3398 | 3369 | virCPUDefFree(guest); | ||
3399 | 3370 | |||
3400 | 3371 | if (cpus) { | ||
3401 | 3372 | for (i = 0; i < ncpus; i++) | ||
3402 | 3373 | VIR_FREE(cpus[i]); | ||
3403 | 3374 | VIR_FREE(cpus); | ||
3404 | 3375 | } | ||
3405 | 3376 | |||
3406 | 3377 | return ret; | ||
3407 | 3378 | |||
3408 | 3379 | no_memory: | ||
3409 | 3380 | virReportOOMError(); | ||
3410 | 3381 | goto cleanup; | ||
3411 | 3382 | } | ||
3412 | 3383 | |||
3413 | 3384 | static char * | ||
3414 | 3385 | qemuBuildSmpArgStr(const virDomainDefPtr def, | ||
3415 | 3386 | virBitmapPtr qemuCaps) | ||
3416 | 3387 | { | ||
3417 | 3388 | virBuffer buf = VIR_BUFFER_INITIALIZER; | ||
3418 | 3389 | |||
3419 | 3390 | virBufferAsprintf(&buf, "%u", def->vcpus); | ||
3420 | 3391 | |||
3421 | 3392 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_SMP_TOPOLOGY)) { | ||
3422 | 3393 | if (def->vcpus != def->maxvcpus) | ||
3423 | 3394 | virBufferAsprintf(&buf, ",maxcpus=%u", def->maxvcpus); | ||
3424 | 3395 | /* sockets, cores, and threads are either all zero | ||
3425 | 3396 | * or all non-zero, thus checking one of them is enough */ | ||
3426 | 3397 | if (def->cpu && def->cpu->sockets) { | ||
3427 | 3398 | virBufferAsprintf(&buf, ",sockets=%u", def->cpu->sockets); | ||
3428 | 3399 | virBufferAsprintf(&buf, ",cores=%u", def->cpu->cores); | ||
3429 | 3400 | virBufferAsprintf(&buf, ",threads=%u", def->cpu->threads); | ||
3430 | 3401 | } | ||
3431 | 3402 | else { | ||
3432 | 3403 | virBufferAsprintf(&buf, ",sockets=%u", def->maxvcpus); | ||
3433 | 3404 | virBufferAsprintf(&buf, ",cores=%u", 1); | ||
3434 | 3405 | virBufferAsprintf(&buf, ",threads=%u", 1); | ||
3435 | 3406 | } | ||
3436 | 3407 | } else if (def->vcpus != def->maxvcpus) { | ||
3437 | 3408 | virBufferFreeAndReset(&buf); | ||
3438 | 3409 | /* FIXME - consider hot-unplugging cpus after boot for older qemu */ | ||
3439 | 3410 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", | ||
3440 | 3411 | _("setting current vcpu count less than maximum is " | ||
3441 | 3412 | "not supported with this QEMU binary")); | ||
3442 | 3413 | return NULL; | ||
3443 | 3414 | } | ||
3444 | 3415 | |||
3445 | 3416 | if (virBufferError(&buf)) { | ||
3446 | 3417 | virBufferFreeAndReset(&buf); | ||
3447 | 3418 | virReportOOMError(); | ||
3448 | 3419 | return NULL; | ||
3449 | 3420 | } | ||
3450 | 3421 | |||
3451 | 3422 | return virBufferContentAndReset(&buf); | ||
3452 | 3423 | } | ||
3453 | 3424 | |||
3454 | 3425 | static void | ||
3455 | 3426 | qemuBuildNumaCPUArgStr(char *cpumask, virBufferPtr buf) | ||
3456 | 3427 | { | ||
3457 | 3428 | int i, first, last; | ||
3458 | 3429 | int cpuSet = 0; | ||
3459 | 3430 | |||
3460 | 3431 | first = last = 0; | ||
3461 | 3432 | for (i = 0; i < VIR_DOMAIN_CPUMASK_LEN; i++) { | ||
3462 | 3433 | if (cpumask[i]) { | ||
3463 | 3434 | if (cpuSet) { | ||
3464 | 3435 | last = i; | ||
3465 | 3436 | } else { | ||
3466 | 3437 | first = last = i; | ||
3467 | 3438 | cpuSet = 1; | ||
3468 | 3439 | } | ||
3469 | 3440 | } else { | ||
3470 | 3441 | if (!cpuSet) | ||
3471 | 3442 | continue; | ||
3472 | 3443 | if (first == last) | ||
3473 | 3444 | virBufferAsprintf(buf, "%d,", first); | ||
3474 | 3445 | else | ||
3475 | 3446 | virBufferAsprintf(buf, "%d-%d,", first, last); | ||
3476 | 3447 | cpuSet = 0; | ||
3477 | 3448 | } | ||
3478 | 3449 | } | ||
3479 | 3450 | |||
3480 | 3451 | if (cpuSet) { | ||
3481 | 3452 | if (first == last) | ||
3482 | 3453 | virBufferAsprintf(buf, "%d,", first); | ||
3483 | 3454 | else | ||
3484 | 3455 | virBufferAsprintf(buf, "%d-%d,", first, last); | ||
3485 | 3456 | } | ||
3486 | 3457 | } | ||
3487 | 3458 | |||
3488 | 3459 | static int | ||
3489 | 3460 | qemuBuildNumaArgStr(const virDomainDefPtr def, virCommandPtr cmd) | ||
3490 | 3461 | { | ||
3491 | 3462 | int i; | ||
3492 | 3463 | virBuffer buf = VIR_BUFFER_INITIALIZER; | ||
3493 | 3464 | |||
3494 | 3465 | for (i = 0; i < def->cpu->ncells; i++) { | ||
3495 | 3466 | virCommandAddArg(cmd, "-numa"); | ||
3496 | 3467 | virBufferAsprintf(&buf, "node,nodeid=%d", def->cpu->cells[i].cellid); | ||
3497 | 3468 | virBufferAddLit(&buf, ",cpus="); | ||
3498 | 3469 | qemuBuildNumaCPUArgStr(def->cpu->cells[i].cpumask, &buf); | ||
3499 | 3470 | virBufferAsprintf(&buf, "mem=%d", | ||
3500 | 3471 | VIR_DIV_UP(def->cpu->cells[i].mem, 1024)); | ||
3501 | 3472 | |||
3502 | 3473 | if (virBufferError(&buf)) | ||
3503 | 3474 | goto error; | ||
3504 | 3475 | |||
3505 | 3476 | virCommandAddArgBuffer(cmd, &buf); | ||
3506 | 3477 | } | ||
3507 | 3478 | return 0; | ||
3508 | 3479 | |||
3509 | 3480 | error: | ||
3510 | 3481 | virBufferFreeAndReset(&buf); | ||
3511 | 3482 | virReportOOMError(); | ||
3512 | 3483 | return -1; | ||
3513 | 3484 | } | ||
3514 | 3485 | |||
3515 | 3486 | /* | ||
3516 | 3487 | * Constructs a argv suitable for launching qemu with config defined | ||
3517 | 3488 | * for a given virtual machine. | ||
3518 | 3489 | * | ||
3519 | 3490 | * XXX 'conn' is only required to resolve network -> bridge name | ||
3520 | 3491 | * figure out how to remove this requirement some day | ||
3521 | 3492 | */ | ||
3522 | 3493 | virCommandPtr | ||
3523 | 3494 | qemuBuildCommandLine(virConnectPtr conn, | ||
3524 | 3495 | struct qemud_driver *driver, | ||
3525 | 3496 | virDomainDefPtr def, | ||
3526 | 3497 | virDomainChrSourceDefPtr monitor_chr, | ||
3527 | 3498 | bool monitor_json, | ||
3528 | 3499 | virBitmapPtr qemuCaps, | ||
3529 | 3500 | const char *migrateFrom, | ||
3530 | 3501 | int migrateFd, | ||
3531 | 3502 | virDomainSnapshotObjPtr snapshot, | ||
3532 | 3503 | enum virNetDevVPortProfileOp vmop) | ||
3533 | 3504 | { | ||
3534 | 3505 | int i; | ||
3535 | 3506 | struct utsname ut; | ||
3536 | 3507 | int disableKQEMU = 0; | ||
3537 | 3508 | int enableKQEMU = 0; | ||
3538 | 3509 | int disableKVM = 0; | ||
3539 | 3510 | int enableKVM = 0; | ||
3540 | 3511 | const char *emulator; | ||
3541 | 3512 | char uuid[VIR_UUID_STRING_BUFLEN]; | ||
3542 | 3513 | char *cpu; | ||
3543 | 3514 | char *smp; | ||
3544 | 3515 | int last_good_net = -1; | ||
3545 | 3516 | bool hasHwVirt = false; | ||
3546 | 3517 | virCommandPtr cmd; | ||
3547 | 3518 | bool emitBootindex = false; | ||
3548 | 3519 | int usbcontroller = 0; | ||
3549 | 3520 | bool usblegacy = false; | ||
3550 | 3521 | uname_normalize(&ut); | ||
3551 | 3522 | |||
3552 | 3523 | virUUIDFormat(def->uuid, uuid); | ||
3553 | 3524 | |||
3554 | 3525 | emulator = def->emulator; | ||
3555 | 3526 | |||
3556 | 3527 | /* | ||
3557 | 3528 | * do not use boot=on for drives when not using KVM since this | ||
3558 | 3529 | * is not supported at all in upstream QEmu. | ||
3559 | 3530 | */ | ||
3560 | 3531 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_KVM) && | ||
3561 | 3532 | (def->virtType == VIR_DOMAIN_VIRT_QEMU)) | ||
3562 | 3533 | qemuCapsClear(qemuCaps, QEMU_CAPS_DRIVE_BOOT); | ||
3563 | 3534 | |||
3564 | 3535 | switch (def->virtType) { | ||
3565 | 3536 | case VIR_DOMAIN_VIRT_QEMU: | ||
3566 | 3537 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_KQEMU)) | ||
3567 | 3538 | disableKQEMU = 1; | ||
3568 | 3539 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_KVM)) | ||
3569 | 3540 | disableKVM = 1; | ||
3570 | 3541 | break; | ||
3571 | 3542 | |||
3572 | 3543 | case VIR_DOMAIN_VIRT_KQEMU: | ||
3573 | 3544 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_KVM)) | ||
3574 | 3545 | disableKVM = 1; | ||
3575 | 3546 | |||
3576 | 3547 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_ENABLE_KQEMU)) { | ||
3577 | 3548 | enableKQEMU = 1; | ||
3578 | 3549 | } else if (!qemuCapsGet(qemuCaps, QEMU_CAPS_KQEMU)) { | ||
3579 | 3550 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, | ||
3580 | 3551 | _("the QEMU binary %s does not support kqemu"), | ||
3581 | 3552 | emulator); | ||
3582 | 3553 | } | ||
3583 | 3554 | break; | ||
3584 | 3555 | |||
3585 | 3556 | case VIR_DOMAIN_VIRT_KVM: | ||
3586 | 3557 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_KQEMU)) | ||
3587 | 3558 | disableKQEMU = 1; | ||
3588 | 3559 | |||
3589 | 3560 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_ENABLE_KVM)) { | ||
3590 | 3561 | enableKVM = 1; | ||
3591 | 3562 | } else if (!qemuCapsGet(qemuCaps, QEMU_CAPS_KVM)) { | ||
3592 | 3563 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, | ||
3593 | 3564 | _("the QEMU binary %s does not support kvm"), | ||
3594 | 3565 | emulator); | ||
3595 | 3566 | } | ||
3596 | 3567 | break; | ||
3597 | 3568 | |||
3598 | 3569 | case VIR_DOMAIN_VIRT_XEN: | ||
3599 | 3570 | /* XXX better check for xenner */ | ||
3600 | 3571 | break; | ||
3601 | 3572 | |||
3602 | 3573 | default: | ||
3603 | 3574 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, | ||
3604 | 3575 | _("the QEMU binary %s does not support %s"), | ||
3605 | 3576 | emulator, virDomainVirtTypeToString(def->virtType)); | ||
3606 | 3577 | break; | ||
3607 | 3578 | } | ||
3608 | 3579 | |||
3609 | 3580 | cmd = virCommandNewArgList(emulator, "-S", NULL); | ||
3610 | 3581 | |||
3611 | 3582 | virCommandAddEnvPassCommon(cmd); | ||
3612 | 3583 | |||
3613 | 3584 | /* This should *never* be NULL, since we always provide | ||
3614 | 3585 | * a machine in the capabilities data for QEMU. So this | ||
3615 | 3586 | * check is just here as a safety in case the unexpected | ||
3616 | 3587 | * happens */ | ||
3617 | 3588 | if (def->os.machine) | ||
3618 | 3589 | virCommandAddArgList(cmd, "-M", def->os.machine, NULL); | ||
3619 | 3590 | |||
3620 | 3591 | if (qemuBuildCpuArgStr(driver, def, emulator, qemuCaps, | ||
3621 | 3592 | &ut, &cpu, &hasHwVirt) < 0) | ||
3622 | 3593 | goto error; | ||
3623 | 3594 | |||
3624 | 3595 | if (cpu) { | ||
3625 | 3596 | virCommandAddArgList(cmd, "-cpu", cpu, NULL); | ||
3626 | 3597 | VIR_FREE(cpu); | ||
3627 | 3598 | |||
3628 | 3599 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_NESTING) && | ||
3629 | 3600 | hasHwVirt) | ||
3630 | 3601 | virCommandAddArg(cmd, "-enable-nesting"); | ||
3631 | 3602 | } | ||
3632 | 3603 | |||
3633 | 3604 | if (disableKQEMU) | ||
3634 | 3605 | virCommandAddArg(cmd, "-no-kqemu"); | ||
3635 | 3606 | else if (enableKQEMU) | ||
3636 | 3607 | virCommandAddArgList(cmd, "-enable-kqemu", "-kernel-kqemu", NULL); | ||
3637 | 3608 | if (disableKVM) | ||
3638 | 3609 | virCommandAddArg(cmd, "-no-kvm"); | ||
3639 | 3610 | if (enableKVM) | ||
3640 | 3611 | virCommandAddArg(cmd, "-enable-kvm"); | ||
3641 | 3612 | |||
3642 | 3613 | /* Set '-m MB' based on maxmem, because the lower 'memory' limit | ||
3643 | 3614 | * is set post-startup using the balloon driver. If balloon driver | ||
3644 | 3615 | * is not supported, then they're out of luck anyway | ||
3645 | 3616 | */ | ||
3646 | 3617 | virCommandAddArg(cmd, "-m"); | ||
3647 | 3618 | virCommandAddArgFormat(cmd, "%lu", VIR_DIV_UP(def->mem.max_balloon, 1024)); | ||
3648 | 3619 | if (def->mem.hugepage_backed) { | ||
3649 | 3620 | if (!driver->hugetlbfs_mount) { | ||
3650 | 3621 | qemuReportError(VIR_ERR_INTERNAL_ERROR, | ||
3651 | 3622 | "%s", _("hugetlbfs filesystem is not mounted")); | ||
3652 | 3623 | goto error; | ||
3653 | 3624 | } | ||
3654 | 3625 | if (!driver->hugepage_path) { | ||
3655 | 3626 | qemuReportError(VIR_ERR_INTERNAL_ERROR, | ||
3656 | 3627 | "%s", _("hugepages are disabled by administrator config")); | ||
3657 | 3628 | goto error; | ||
3658 | 3629 | } | ||
3659 | 3630 | if (!qemuCapsGet(qemuCaps, QEMU_CAPS_MEM_PATH)) { | ||
3660 | 3631 | qemuReportError(VIR_ERR_INTERNAL_ERROR, | ||
3661 | 3632 | _("hugepage backing not supported by '%s'"), | ||
3662 | 3633 | def->emulator); | ||
3663 | 3634 | goto error; | ||
3664 | 3635 | } | ||
3665 | 3636 | virCommandAddArgList(cmd, "-mem-prealloc", "-mem-path", | ||
3666 | 3637 | driver->hugepage_path, NULL); | ||
3667 | 3638 | } | ||
3668 | 3639 | |||
3669 | 3640 | virCommandAddArg(cmd, "-smp"); | ||
3670 | 3641 | if (!(smp = qemuBuildSmpArgStr(def, qemuCaps))) | ||
3671 | 3642 | goto error; | ||
3672 | 3643 | virCommandAddArg(cmd, smp); | ||
3673 | 3644 | VIR_FREE(smp); | ||
3674 | 3645 | |||
3675 | 3646 | if (def->cpu && def->cpu->ncells) | ||
3676 | 3647 | if (qemuBuildNumaArgStr(def, cmd) < 0) | ||
3677 | 3648 | goto error; | ||
3678 | 3649 | |||
3679 | 3650 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_NAME)) { | ||
3680 | 3651 | virCommandAddArg(cmd, "-name"); | ||
3681 | 3652 | if (driver->setProcessName && | ||
3682 | 3653 | qemuCapsGet(qemuCaps, QEMU_CAPS_NAME_PROCESS)) { | ||
3683 | 3654 | virCommandAddArgFormat(cmd, "%s,process=qemu:%s", | ||
3684 | 3655 | def->name, def->name); | ||
3685 | 3656 | } else { | ||
3686 | 3657 | virCommandAddArg(cmd, def->name); | ||
3687 | 3658 | } | ||
3688 | 3659 | } | ||
3689 | 3660 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_UUID)) | ||
3690 | 3661 | virCommandAddArgList(cmd, "-uuid", uuid, NULL); | ||
3691 | 3662 | if (def->virtType == VIR_DOMAIN_VIRT_XEN || | ||
3692 | 3663 | STREQ(def->os.type, "xen") || | ||
3693 | 3664 | STREQ(def->os.type, "linux")) { | ||
3694 | 3665 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_DOMID)) { | ||
3695 | 3666 | virCommandAddArg(cmd, "-domid"); | ||
3696 | 3667 | virCommandAddArgFormat(cmd, "%d", def->id); | ||
3697 | 3668 | } else if (qemuCapsGet(qemuCaps, QEMU_CAPS_XEN_DOMID)) { | ||
3698 | 3669 | virCommandAddArg(cmd, "-xen-attach"); | ||
3699 | 3670 | virCommandAddArg(cmd, "-xen-domid"); | ||
3700 | 3671 | virCommandAddArgFormat(cmd, "%d", def->id); | ||
3701 | 3672 | } else { | ||
3702 | 3673 | qemuReportError(VIR_ERR_INTERNAL_ERROR, | ||
3703 | 3674 | _("qemu emulator '%s' does not support xen"), | ||
3704 | 3675 | def->emulator); | ||
3705 | 3676 | goto error; | ||
3706 | 3677 | } | ||
3707 | 3678 | } | ||
3708 | 3679 | |||
3709 | 3680 | if ((def->os.smbios_mode != VIR_DOMAIN_SMBIOS_NONE) && | ||
3710 | 3681 | (def->os.smbios_mode != VIR_DOMAIN_SMBIOS_EMULATE)) { | ||
3711 | 3682 | virSysinfoDefPtr source = NULL; | ||
3712 | 3683 | bool skip_uuid = false; | ||
3713 | 3684 | |||
3714 | 3685 | if (!qemuCapsGet(qemuCaps, QEMU_CAPS_SMBIOS_TYPE)) { | ||
3715 | 3686 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, | ||
3716 | 3687 | _("the QEMU binary %s does not support smbios settings"), | ||
3717 | 3688 | emulator); | ||
3718 | 3689 | goto error; | ||
3719 | 3690 | } | ||
3720 | 3691 | |||
3721 | 3692 | /* should we really error out or just warn in those cases ? */ | ||
3722 | 3693 | if (def->os.smbios_mode == VIR_DOMAIN_SMBIOS_HOST) { | ||
3723 | 3694 | if (driver->hostsysinfo == NULL) { | ||
3724 | 3695 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", | ||
3725 | 3696 | _("Host SMBIOS information is not available")); | ||
3726 | 3697 | goto error; | ||
3727 | 3698 | } | ||
3728 | 3699 | source = driver->hostsysinfo; | ||
3729 | 3700 | /* Host and guest uuid must differ, by definition of UUID. */ | ||
3730 | 3701 | skip_uuid = true; | ||
3731 | 3702 | } else if (def->os.smbios_mode == VIR_DOMAIN_SMBIOS_SYSINFO) { | ||
3732 | 3703 | if (def->sysinfo == NULL) { | ||
3733 | 3704 | qemuReportError(VIR_ERR_XML_ERROR, | ||
3734 | 3705 | _("Domain '%s' sysinfo are not available"), | ||
3735 | 3706 | def->name); | ||
3736 | 3707 | goto error; | ||
3737 | 3708 | } | ||
3738 | 3709 | source = def->sysinfo; | ||
3739 | 3710 | /* domain_conf guaranteed that system_uuid matches guest uuid. */ | ||
3740 | 3711 | } | ||
3741 | 3712 | if (source != NULL) { | ||
3742 | 3713 | char *smbioscmd; | ||
3743 | 3714 | |||
3744 | 3715 | smbioscmd = qemuBuildSmbiosBiosStr(source); | ||
3745 | 3716 | if (smbioscmd != NULL) { | ||
3746 | 3717 | virCommandAddArgList(cmd, "-smbios", smbioscmd, NULL); | ||
3747 | 3718 | VIR_FREE(smbioscmd); | ||
3748 | 3719 | } | ||
3749 | 3720 | smbioscmd = qemuBuildSmbiosSystemStr(source, skip_uuid); | ||
3750 | 3721 | if (smbioscmd != NULL) { | ||
3751 | 3722 | virCommandAddArgList(cmd, "-smbios", smbioscmd, NULL); | ||
3752 | 3723 | VIR_FREE(smbioscmd); | ||
3753 | 3724 | } | ||
3754 | 3725 | } | ||
3755 | 3726 | } | ||
3756 | 3727 | |||
3757 | 3728 | /* | ||
3758 | 3729 | * NB, -nographic *MUST* come before any serial, or monitor | ||
3759 | 3730 | * or parallel port flags due to QEMU craziness, where it | ||
3760 | 3731 | * decides to change the serial port & monitor to be on stdout | ||
3761 | 3732 | * if you ask for nographic. So we have to make sure we override | ||
3762 | 3733 | * these defaults ourselves... | ||
3763 | 3734 | */ | ||
3764 | 3735 | if (!def->graphics) | ||
3765 | 3736 | virCommandAddArg(cmd, "-nographic"); | ||
3766 | 3737 | |||
3767 | 3738 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) { | ||
3768 | 3739 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_NODEFCONFIG)) | ||
3769 | 3740 | virCommandAddArg(cmd, | ||
3770 | 3741 | "-nodefconfig"); /* Disable global config files */ | ||
3771 | 3742 | virCommandAddArg(cmd, | ||
3772 | 3743 | "-nodefaults"); /* Disable default guest devices */ | ||
3773 | 3744 | } | ||
3774 | 3745 | |||
3775 | 3746 | /* Serial graphics adapter */ | ||
3776 | 3747 | if (def->os.bios.useserial == VIR_DOMAIN_BIOS_USESERIAL_YES) { | ||
3777 | 3748 | if (!qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) { | ||
3778 | 3749 | qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", | ||
3779 | 3750 | _("qemu does not support -device")); | ||
3780 | 3751 | goto error; | ||
3781 | 3752 | } | ||
3782 | 3753 | if (!qemuCapsGet(qemuCaps, QEMU_CAPS_SGA)) { | ||
3783 | 3754 | qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", | ||
3784 | 3755 | _("qemu does not support SGA")); | ||
3785 | 3756 | goto error; | ||
3786 | 3757 | } | ||
3787 | 3758 | if (!def->nserials) { | ||
3788 | 3759 | qemuReportError(VIR_ERR_XML_ERROR, "%s", | ||
3789 | 3760 | _("need at least one serial port to use SGA")); | ||
3790 | 3761 | goto error; | ||
3791 | 3762 | } | ||
3792 | 3763 | virCommandAddArgList(cmd, "-device", "sga", NULL); | ||
3793 | 3764 | } | ||
3794 | 3765 | |||
3795 | 3766 | if (monitor_chr) { | ||
3796 | 3767 | char *chrdev; | ||
3797 | 3768 | /* Use -chardev if it's available */ | ||
3798 | 3769 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_CHARDEV)) { | ||
3799 | 3770 | |||
3800 | 3771 | virCommandAddArg(cmd, "-chardev"); | ||
3801 | 3772 | if (!(chrdev = qemuBuildChrChardevStr(monitor_chr, "monitor", | ||
3802 | 3773 | qemuCaps))) | ||
3803 | 3774 | goto error; | ||
3804 | 3775 | virCommandAddArg(cmd, chrdev); | ||
3805 | 3776 | VIR_FREE(chrdev); | ||
3806 | 3777 | |||
3807 | 3778 | virCommandAddArg(cmd, "-mon"); | ||
3808 | 3779 | virCommandAddArgFormat(cmd, | ||
3809 | 3780 | "chardev=charmonitor,id=monitor,mode=%s", | ||
3810 | 3781 | monitor_json ? "control" : "readline"); | ||
3811 | 3782 | } else { | ||
3812 | 3783 | const char *prefix = NULL; | ||
3813 | 3784 | if (monitor_json) | ||
3814 | 3785 | prefix = "control,"; | ||
3815 | 3786 | |||
3816 | 3787 | virCommandAddArg(cmd, "-monitor"); | ||
3817 | 3788 | if (!(chrdev = qemuBuildChrArgStr(monitor_chr, prefix))) | ||
3818 | 3789 | goto error; | ||
3819 | 3790 | virCommandAddArg(cmd, chrdev); | ||
3820 | 3791 | VIR_FREE(chrdev); | ||
3821 | 3792 | } | ||
3822 | 3793 | } | ||
3823 | 3794 | |||
3824 | 3795 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_RTC)) { | ||
3825 | 3796 | const char *rtcopt; | ||
3826 | 3797 | virCommandAddArg(cmd, "-rtc"); | ||
3827 | 3798 | if (!(rtcopt = qemuBuildClockArgStr(&def->clock))) | ||
3828 | 3799 | goto error; | ||
3829 | 3800 | virCommandAddArg(cmd, rtcopt); | ||
3830 | 3801 | VIR_FREE(rtcopt); | ||
3831 | 3802 | } else { | ||
3832 | 3803 | switch (def->clock.offset) { | ||
3833 | 3804 | case VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME: | ||
3834 | 3805 | case VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE: | ||
3835 | 3806 | virCommandAddArg(cmd, "-localtime"); | ||
3836 | 3807 | break; | ||
3837 | 3808 | |||
3838 | 3809 | case VIR_DOMAIN_CLOCK_OFFSET_UTC: | ||
3839 | 3810 | /* Nothing, its the default */ | ||
3840 | 3811 | break; | ||
3841 | 3812 | |||
3842 | 3813 | default: | ||
3843 | 3814 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, | ||
3844 | 3815 | _("unsupported clock offset '%s'"), | ||
3845 | 3816 | virDomainClockOffsetTypeToString(def->clock.offset)); | ||
3846 | 3817 | goto error; | ||
3847 | 3818 | } | ||
3848 | 3819 | } | ||
3849 | 3820 | if (def->clock.offset == VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE && | ||
3850 | 3821 | def->clock.data.timezone) { | ||
3851 | 3822 | virCommandAddEnvPair(cmd, "TZ", def->clock.data.timezone); | ||
3852 | 3823 | } | ||
3853 | 3824 | |||
3854 | 3825 | for (i = 0; i < def->clock.ntimers; i++) { | ||
3855 | 3826 | switch (def->clock.timers[i]->name) { | ||
3856 | 3827 | default: | ||
3857 | 3828 | case VIR_DOMAIN_TIMER_NAME_PLATFORM: | ||
3858 | 3829 | case VIR_DOMAIN_TIMER_NAME_TSC: | ||
3859 | 3830 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, | ||
3860 | 3831 | _("unsupported timer type (name) '%s'"), | ||
3861 | 3832 | virDomainTimerNameTypeToString(def->clock.timers[i]->name)); | ||
3862 | 3833 | goto error; | ||
3863 | 3834 | |||
3864 | 3835 | case VIR_DOMAIN_TIMER_NAME_RTC: | ||
3865 | 3836 | /* This has already been taken care of (in qemuBuildClockArgStr) | ||
3866 | 3837 | if QEMU_CAPS_RTC is set (mutually exclusive with | ||
3867 | 3838 | QEMUD_FLAG_RTC_TD_HACK) */ | ||
3868 | 3839 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_RTC_TD_HACK)) { | ||
3869 | 3840 | switch (def->clock.timers[i]->tickpolicy) { | ||
3870 | 3841 | case -1: | ||
3871 | 3842 | case VIR_DOMAIN_TIMER_TICKPOLICY_DELAY: | ||
3872 | 3843 | /* the default - do nothing */ | ||
3873 | 3844 | break; | ||
3874 | 3845 | case VIR_DOMAIN_TIMER_TICKPOLICY_CATCHUP: | ||
3875 | 3846 | virCommandAddArg(cmd, "-rtc-td-hack"); | ||
3876 | 3847 | break; | ||
3877 | 3848 | case VIR_DOMAIN_TIMER_TICKPOLICY_MERGE: | ||
3878 | 3849 | case VIR_DOMAIN_TIMER_TICKPOLICY_DISCARD: | ||
3879 | 3850 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, | ||
3880 | 3851 | _("unsupported rtc tickpolicy '%s'"), | ||
3881 | 3852 | virDomainTimerTickpolicyTypeToString(def->clock.timers[i]->tickpolicy)); | ||
3882 | 3853 | goto error; | ||
3883 | 3854 | } | ||
3884 | 3855 | } else if (!qemuCapsGet(qemuCaps, QEMU_CAPS_RTC) | ||
3885 | 3856 | && (def->clock.timers[i]->tickpolicy | ||
3886 | 3857 | != VIR_DOMAIN_TIMER_TICKPOLICY_DELAY) | ||
3887 | 3858 | && (def->clock.timers[i]->tickpolicy != -1)) { | ||
3888 | 3859 | /* a non-default rtc policy was given, but there is no | ||
3889 | 3860 | way to implement it in this version of qemu */ | ||
3890 | 3861 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, | ||
3891 | 3862 | _("unsupported rtc tickpolicy '%s'"), | ||
3892 | 3863 | virDomainTimerTickpolicyTypeToString(def->clock.timers[i]->tickpolicy)); | ||
3893 | 3864 | goto error; | ||
3894 | 3865 | } | ||
3895 | 3866 | break; | ||
3896 | 3867 | |||
3897 | 3868 | case VIR_DOMAIN_TIMER_NAME_PIT: | ||
3898 | 3869 | switch (def->clock.timers[i]->tickpolicy) { | ||
3899 | 3870 | case -1: | ||
3900 | 3871 | case VIR_DOMAIN_TIMER_TICKPOLICY_DELAY: | ||
3901 | 3872 | /* delay is the default if we don't have kernel | ||
3902 | 3873 | (-no-kvm-pit), otherwise, the default is catchup. */ | ||
3903 | 3874 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_NO_KVM_PIT)) | ||
3904 | 3875 | virCommandAddArg(cmd, "-no-kvm-pit-reinjection"); | ||
3905 | 3876 | break; | ||
3906 | 3877 | case VIR_DOMAIN_TIMER_TICKPOLICY_CATCHUP: | ||
3907 | 3878 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_NO_KVM_PIT)) { | ||
3908 | 3879 | /* do nothing - this is default for kvm-pit */ | ||
3909 | 3880 | } else if (qemuCapsGet(qemuCaps, QEMU_CAPS_TDF)) { | ||
3910 | 3881 | /* -tdf switches to 'catchup' with userspace pit. */ | ||
3911 | 3882 | virCommandAddArg(cmd, "-tdf"); | ||
3912 | 3883 | } else { | ||
3913 | 3884 | /* can't catchup if we have neither pit mode */ | ||
3914 | 3885 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, | ||
3915 | 3886 | _("unsupported pit tickpolicy '%s'"), | ||
3916 | 3887 | virDomainTimerTickpolicyTypeToString(def->clock.timers[i]->tickpolicy)); | ||
3917 | 3888 | goto error; | ||
3918 | 3889 | } | ||
3919 | 3890 | break; | ||
3920 | 3891 | case VIR_DOMAIN_TIMER_TICKPOLICY_MERGE: | ||
3921 | 3892 | case VIR_DOMAIN_TIMER_TICKPOLICY_DISCARD: | ||
3922 | 3893 | /* no way to support these modes for pit in qemu */ | ||
3923 | 3894 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, | ||
3924 | 3895 | _("unsupported pit tickpolicy '%s'"), | ||
3925 | 3896 | virDomainTimerTickpolicyTypeToString(def->clock.timers[i]->tickpolicy)); | ||
3926 | 3897 | goto error; | ||
3927 | 3898 | } | ||
3928 | 3899 | break; | ||
3929 | 3900 | |||
3930 | 3901 | case VIR_DOMAIN_TIMER_NAME_HPET: | ||
3931 | 3902 | /* the only meaningful attribute for hpet is "present". If | ||
3932 | 3903 | * present is -1, that means it wasn't specified, and | ||
3933 | 3904 | * should be left at the default for the | ||
3934 | 3905 | * hypervisor. "default" when -no-hpet exists is "yes", | ||
3935 | 3906 | * and when -no-hpet doesn't exist is "no". "confusing"? | ||
3936 | 3907 | * "yes"! */ | ||
3937 | 3908 | |||
3938 | 3909 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_NO_HPET)) { | ||
3939 | 3910 | if (def->clock.timers[i]->present == 0) | ||
3940 | 3911 | virCommandAddArg(cmd, "-no-hpet"); | ||
3941 | 3912 | } else { | ||
3942 | 3913 | /* no hpet timer available. The only possible action | ||
3943 | 3914 | is to raise an error if present="yes" */ | ||
3944 | 3915 | if (def->clock.timers[i]->present == 1) { | ||
3945 | 3916 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, | ||
3946 | 3917 | "%s", _("pit timer is not supported")); | ||
3947 | 3918 | } | ||
3948 | 3919 | } | ||
3949 | 3920 | break; | ||
3950 | 3921 | } | ||
3951 | 3922 | } | ||
3952 | 3923 | |||
3953 | 3924 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_NO_REBOOT) && | ||
3954 | 3925 | def->onReboot != VIR_DOMAIN_LIFECYCLE_RESTART) | ||
3955 | 3926 | virCommandAddArg(cmd, "-no-reboot"); | ||
3956 | 3927 | |||
3957 | 3928 | /* If JSON monitor is enabled, we can receive an event | ||
3958 | 3929 | * when QEMU stops. If we use no-shutdown, then we can | ||
3959 | 3930 | * watch for this event and do a soft/warm reboot. | ||
3960 | 3931 | */ | ||
3961 | 3932 | if (monitor_json && qemuCapsGet(qemuCaps, QEMU_CAPS_NO_SHUTDOWN)) | ||
3962 | 3933 | virCommandAddArg(cmd, "-no-shutdown"); | ||
3963 | 3934 | |||
3964 | 3935 | if (!(def->features & (1 << VIR_DOMAIN_FEATURE_ACPI))) | ||
3965 | 3936 | virCommandAddArg(cmd, "-no-acpi"); | ||
3966 | 3937 | |||
3967 | 3938 | if (!def->os.bootloader) { | ||
3968 | 3939 | /* | ||
3969 | 3940 | * We prefer using explicit bootindex=N parameters for predictable | ||
3970 | 3941 | * results even though domain XML doesn't use per device boot elements. | ||
3971 | 3942 | * However, we can't use bootindex if boot menu was requested. | ||
3972 | 3943 | */ | ||
3973 | 3944 | if (!def->os.nBootDevs) { | ||
3974 | 3945 | /* def->os.nBootDevs is guaranteed to be > 0 unless per-device boot | ||
3975 | 3946 | * configuration is used | ||
3976 | 3947 | */ | ||
3977 | 3948 | if (!qemuCapsGet(qemuCaps, QEMU_CAPS_BOOTINDEX)) { | ||
3978 | 3949 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", | ||
3979 | 3950 | _("hypervisor lacks deviceboot feature")); | ||
3980 | 3951 | goto error; | ||
3981 | 3952 | } | ||
3982 | 3953 | emitBootindex = true; | ||
3983 | 3954 | } else if (qemuCapsGet(qemuCaps, QEMU_CAPS_BOOTINDEX) && | ||
3984 | 3955 | (def->os.bootmenu != VIR_DOMAIN_BOOT_MENU_ENABLED || | ||
3985 | 3956 | !qemuCapsGet(qemuCaps, QEMU_CAPS_BOOT_MENU))) { | ||
3986 | 3957 | emitBootindex = true; | ||
3987 | 3958 | } | ||
3988 | 3959 | |||
3989 | 3960 | if (!emitBootindex) { | ||
3990 | 3961 | virBuffer boot_buf = VIR_BUFFER_INITIALIZER; | ||
3991 | 3962 | char boot[VIR_DOMAIN_BOOT_LAST+1]; | ||
3992 | 3963 | |||
3993 | 3964 | for (i = 0 ; i < def->os.nBootDevs ; i++) { | ||
3994 | 3965 | switch (def->os.bootDevs[i]) { | ||
3995 | 3966 | case VIR_DOMAIN_BOOT_CDROM: | ||
3996 | 3967 | boot[i] = 'd'; | ||
3997 | 3968 | break; | ||
3998 | 3969 | case VIR_DOMAIN_BOOT_FLOPPY: | ||
3999 | 3970 | boot[i] = 'a'; | ||
4000 | 3971 | break; | ||
4001 | 3972 | case VIR_DOMAIN_BOOT_DISK: | ||
4002 | 3973 | boot[i] = 'c'; | ||
4003 | 3974 | break; | ||
4004 | 3975 | case VIR_DOMAIN_BOOT_NET: | ||
4005 | 3976 | boot[i] = 'n'; | ||
4006 | 3977 | break; | ||
4007 | 3978 | default: | ||
4008 | 3979 | boot[i] = 'c'; | ||
4009 | 3980 | break; | ||
4010 | 3981 | } | ||
4011 | 3982 | } | ||
4012 | 3983 | boot[def->os.nBootDevs] = '\0'; | ||
4013 | 3984 | |||
4014 | 3985 | virCommandAddArg(cmd, "-boot"); | ||
4015 | 3986 | |||
4016 | 3987 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_BOOT_MENU) && | ||
4017 | 3988 | def->os.bootmenu != VIR_DOMAIN_BOOT_MENU_DEFAULT) { | ||
4018 | 3989 | if (def->os.bootmenu == VIR_DOMAIN_BOOT_MENU_ENABLED) | ||
4019 | 3990 | virBufferAsprintf(&boot_buf, "order=%s,menu=on", boot); | ||
4020 | 3991 | else if (def->os.bootmenu == VIR_DOMAIN_BOOT_MENU_DISABLED) | ||
4021 | 3992 | virBufferAsprintf(&boot_buf, "order=%s,menu=off", boot); | ||
4022 | 3993 | } else { | ||
4023 | 3994 | virBufferAdd(&boot_buf, boot, -1); | ||
4024 | 3995 | } | ||
4025 | 3996 | |||
4026 | 3997 | virCommandAddArgBuffer(cmd, &boot_buf); | ||
4027 | 3998 | } | ||
4028 | 3999 | |||
4029 | 4000 | if (def->os.kernel) | ||
4030 | 4001 | virCommandAddArgList(cmd, "-kernel", def->os.kernel, NULL); | ||
4031 | 4002 | if (def->os.initrd) | ||
4032 | 4003 | virCommandAddArgList(cmd, "-initrd", def->os.initrd, NULL); | ||
4033 | 4004 | if (def->os.cmdline) | ||
4034 | 4005 | virCommandAddArgList(cmd, "-append", def->os.cmdline, NULL); | ||
4035 | 4006 | } else { | ||
4036 | 4007 | virCommandAddArgList(cmd, "-bootloader", def->os.bootloader, NULL); | ||
4037 | 4008 | } | ||
4038 | 4009 | |||
4039 | 4010 | for (i = 0 ; i < def->ndisks ; i++) { | ||
4040 | 4011 | virDomainDiskDefPtr disk = def->disks[i]; | ||
4041 | 4012 | |||
4042 | 4013 | if (disk->driverName != NULL && | ||
4043 | 4014 | !STREQ(disk->driverName, "qemu")) { | ||
4044 | 4015 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, | ||
4045 | 4016 | _("unsupported driver name '%s' for disk '%s'"), | ||
4046 | 4017 | disk->driverName, disk->src); | ||
4047 | 4018 | goto error; | ||
4048 | 4019 | } | ||
4049 | 4020 | } | ||
4050 | 4021 | |||
4051 | 4022 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) { | ||
4052 | 4023 | for (i = 0 ; i < def->ncontrollers ; i++) { | ||
4053 | 4024 | virDomainControllerDefPtr cont = def->controllers[i]; | ||
4054 | 4025 | |||
4055 | 4026 | /* We don't add an explicit IDE or FD controller because the | ||
4056 | 4027 | * provided PIIX4 device already includes one. It isn't possible to | ||
4057 | 4028 | * remove the PIIX4. */ | ||
4058 | 4029 | if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_IDE || | ||
4059 | 4030 | cont->type == VIR_DOMAIN_CONTROLLER_TYPE_FDC) | ||
4060 | 4031 | continue; | ||
4061 | 4032 | |||
4062 | 4033 | /* Only recent QEMU implements a SATA (AHCI) controller */ | ||
4063 | 4034 | if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_SATA) { | ||
4064 | 4035 | if (!qemuCapsGet(qemuCaps, QEMU_CAPS_ICH9_AHCI)) { | ||
4065 | 4036 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, | ||
4066 | 4037 | "%s", _("SATA is not supported with this QEMU binary")); | ||
4067 | 4038 | goto error; | ||
4068 | 4039 | } else { | ||
4069 | 4040 | char *devstr; | ||
4070 | 4041 | |||
4071 | 4042 | virCommandAddArg(cmd, "-device"); | ||
4072 | 4043 | if (!(devstr = qemuBuildControllerDevStr(cont, qemuCaps, NULL))) | ||
4073 | 4044 | goto error; | ||
4074 | 4045 | |||
4075 | 4046 | virCommandAddArg(cmd, devstr); | ||
4076 | 4047 | VIR_FREE(devstr); | ||
4077 | 4048 | } | ||
4078 | 4049 | } else if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_USB && | ||
4079 | 4050 | def->controllers[i]->model == -1 && | ||
4080 | 4051 | !qemuCapsGet(qemuCaps, QEMU_CAPS_PIIX3_USB_UHCI)) { | ||
4081 | 4052 | if (usblegacy) { | ||
4082 | 4053 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, | ||
4083 | 4054 | _("Multiple legacy USB controller not supported")); | ||
4084 | 4055 | goto error; | ||
4085 | 4056 | } | ||
4086 | 4057 | usblegacy = true; | ||
4087 | 4058 | } else { | ||
4088 | 4059 | virCommandAddArg(cmd, "-device"); | ||
4089 | 4060 | |||
4090 | 4061 | char *devstr; | ||
4091 | 4062 | if (!(devstr = qemuBuildControllerDevStr(def->controllers[i], qemuCaps, | ||
4092 | 4063 | &usbcontroller))) | ||
4093 | 4064 | goto error; | ||
4094 | 4065 | |||
4095 | 4066 | virCommandAddArg(cmd, devstr); | ||
4096 | 4067 | VIR_FREE(devstr); | ||
4097 | 4068 | } | ||
4098 | 4069 | } | ||
4099 | 4070 | } | ||
4100 | 4071 | |||
4101 | 4072 | /* If QEMU supports -drive param instead of old -hda, -hdb, -cdrom .. */ | ||
4102 | 4073 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_DRIVE)) { | ||
4103 | 4074 | int bootCD = 0, bootFloppy = 0, bootDisk = 0; | ||
4104 | 4075 | |||
4105 | 4076 | if ((qemuCapsGet(qemuCaps, QEMU_CAPS_DRIVE_BOOT) || emitBootindex) && | ||
4106 | 4077 | !def->os.kernel) { | ||
4107 | 4078 | /* bootDevs will get translated into either bootindex=N or boot=on | ||
4108 | 4079 | * depending on what qemu supports */ | ||
4109 | 4080 | for (i = 0 ; i < def->os.nBootDevs ; i++) { | ||
4110 | 4081 | switch (def->os.bootDevs[i]) { | ||
4111 | 4082 | case VIR_DOMAIN_BOOT_CDROM: | ||
4112 | 4083 | bootCD = i + 1; | ||
4113 | 4084 | break; | ||
4114 | 4085 | case VIR_DOMAIN_BOOT_FLOPPY: | ||
4115 | 4086 | bootFloppy = i + 1; | ||
4116 | 4087 | break; | ||
4117 | 4088 | case VIR_DOMAIN_BOOT_DISK: | ||
4118 | 4089 | bootDisk = i + 1; | ||
4119 | 4090 | break; | ||
4120 | 4091 | } | ||
4121 | 4092 | } | ||
4122 | 4093 | } | ||
4123 | 4094 | |||
4124 | 4095 | for (i = 0 ; i < def->ndisks ; i++) { | ||
4125 | 4096 | char *optstr; | ||
4126 | 4097 | int bootindex = 0; | ||
4127 | 4098 | virDomainDiskDefPtr disk = def->disks[i]; | ||
4128 | 4099 | int withDeviceArg = 0; | ||
4129 | 4100 | bool deviceFlagMasked = false; | ||
4130 | 4101 | |||
4131 | 4102 | /* Unless we have -device, then USB disks need special | ||
4132 | 4103 | handling */ | ||
4133 | 4104 | if ((disk->bus == VIR_DOMAIN_DISK_BUS_USB) && | ||
4134 | 4105 | !qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) { | ||
4135 | 4106 | if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) { | ||
4136 | 4107 | virCommandAddArg(cmd, "-usbdevice"); | ||
4137 | 4108 | virCommandAddArgFormat(cmd, "disk:%s", disk->src); | ||
4138 | 4109 | } else { | ||
4139 | 4110 | qemuReportError(VIR_ERR_INTERNAL_ERROR, | ||
4140 | 4111 | _("unsupported usb disk type for '%s'"), | ||
4141 | 4112 | disk->src); | ||
4142 | 4113 | goto error; | ||
4143 | 4114 | } | ||
4144 | 4115 | continue; | ||
4145 | 4116 | } | ||
4146 | 4117 | |||
4147 | 4118 | switch (disk->device) { | ||
4148 | 4119 | case VIR_DOMAIN_DISK_DEVICE_CDROM: | ||
4149 | 4120 | bootindex = bootCD; | ||
4150 | 4121 | bootCD = 0; | ||
4151 | 4122 | break; | ||
4152 | 4123 | case VIR_DOMAIN_DISK_DEVICE_FLOPPY: | ||
4153 | 4124 | bootindex = bootFloppy; | ||
4154 | 4125 | bootFloppy = 0; | ||
4155 | 4126 | break; | ||
4156 | 4127 | case VIR_DOMAIN_DISK_DEVICE_DISK: | ||
4157 | 4128 | bootindex = bootDisk; | ||
4158 | 4129 | bootDisk = 0; | ||
4159 | 4130 | break; | ||
4160 | 4131 | } | ||
4161 | 4132 | |||
4162 | 4133 | virCommandAddArg(cmd, "-drive"); | ||
4163 | 4134 | |||
4164 | 4135 | /* Unfortunately it is not possible to use | ||
4165 | 4136 | -device for floppies, or Xen paravirt | ||
4166 | 4137 | devices. Fortunately, those don't need | ||
4167 | 4138 | static PCI addresses, so we don't really | ||
4168 | 4139 | care that we can't use -device */ | ||
4169 | 4140 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) { | ||
4170 | 4141 | if (disk->bus != VIR_DOMAIN_DISK_BUS_XEN) { | ||
4171 | 4142 | withDeviceArg = 1; | ||
4172 | 4143 | } else { | ||
4173 | 4144 | qemuCapsClear(qemuCaps, QEMU_CAPS_DEVICE); | ||
4174 | 4145 | deviceFlagMasked = true; | ||
4175 | 4146 | } | ||
4176 | 4147 | } | ||
4177 | 4148 | optstr = qemuBuildDriveStr(conn, disk, | ||
4178 | 4149 | emitBootindex ? false : !!bootindex, | ||
4179 | 4150 | qemuCaps); | ||
4180 | 4151 | if (deviceFlagMasked) | ||
4181 | 4152 | qemuCapsSet(qemuCaps, QEMU_CAPS_DEVICE); | ||
4182 | 4153 | if (!optstr) | ||
4183 | 4154 | goto error; | ||
4184 | 4155 | virCommandAddArg(cmd, optstr); | ||
4185 | 4156 | VIR_FREE(optstr); | ||
4186 | 4157 | |||
4187 | 4158 | if (!emitBootindex) | ||
4188 | 4159 | bootindex = 0; | ||
4189 | 4160 | else if (disk->bootIndex) | ||
4190 | 4161 | bootindex = disk->bootIndex; | ||
4191 | 4162 | |||
4192 | 4163 | if (withDeviceArg) { | ||
4193 | 4164 | if (disk->bus == VIR_DOMAIN_DISK_BUS_FDC) { | ||
4194 | 4165 | virCommandAddArg(cmd, "-global"); | ||
4195 | 4166 | virCommandAddArgFormat(cmd, "isa-fdc.drive%c=drive-%s", | ||
4196 | 4167 | disk->info.addr.drive.unit | ||
4197 | 4168 | ? 'B' : 'A', | ||
4198 | 4169 | disk->info.alias); | ||
4199 | 4170 | |||
4200 | 4171 | if (bootindex) { | ||
4201 | 4172 | virCommandAddArg(cmd, "-global"); | ||
4202 | 4173 | virCommandAddArgFormat(cmd, "isa-fdc.bootindex%c=%d", | ||
4203 | 4174 | disk->info.addr.drive.unit | ||
4204 | 4175 | ? 'B' : 'A', | ||
4205 | 4176 | bootindex); | ||
4206 | 4177 | } | ||
4207 | 4178 | } else { | ||
4208 | 4179 | virCommandAddArg(cmd, "-device"); | ||
4209 | 4180 | |||
4210 | 4181 | if (!(optstr = qemuBuildDriveDevStr(disk, bootindex, | ||
4211 | 4182 | qemuCaps))) | ||
4212 | 4183 | goto error; | ||
4213 | 4184 | virCommandAddArg(cmd, optstr); | ||
4214 | 4185 | VIR_FREE(optstr); | ||
4215 | 4186 | } | ||
4216 | 4187 | } | ||
4217 | 4188 | } | ||
4218 | 4189 | } else { | ||
4219 | 4190 | for (i = 0 ; i < def->ndisks ; i++) { | ||
4220 | 4191 | char dev[NAME_MAX]; | ||
4221 | 4192 | char *file; | ||
4222 | 4193 | const char *fmt; | ||
4223 | 4194 | virDomainDiskDefPtr disk = def->disks[i]; | ||
4224 | 4195 | |||
4225 | 4196 | if (disk->bus == VIR_DOMAIN_DISK_BUS_USB) { | ||
4226 | 4197 | if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) { | ||
4227 | 4198 | virCommandAddArg(cmd, "-usbdevice"); | ||
4228 | 4199 | virCommandAddArgFormat(cmd, "disk:%s", disk->src); | ||
4229 | 4200 | } else { | ||
4230 | 4201 | qemuReportError(VIR_ERR_INTERNAL_ERROR, | ||
4231 | 4202 | _("unsupported usb disk type for '%s'"), | ||
4232 | 4203 | disk->src); | ||
4233 | 4204 | goto error; | ||
4234 | 4205 | } | ||
4235 | 4206 | continue; | ||
4236 | 4207 | } | ||
4237 | 4208 | |||
4238 | 4209 | if (STREQ(disk->dst, "hdc") && | ||
4239 | 4210 | disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) { | ||
4240 | 4211 | if (disk->src) { | ||
4241 | 4212 | snprintf(dev, NAME_MAX, "-%s", "cdrom"); | ||
4242 | 4213 | } else { | ||
4243 | 4214 | continue; | ||
4244 | 4215 | } | ||
4245 | 4216 | } else { | ||
4246 | 4217 | if (STRPREFIX(disk->dst, "hd") || | ||
4247 | 4218 | STRPREFIX(disk->dst, "fd")) { | ||
4248 | 4219 | snprintf(dev, NAME_MAX, "-%s", disk->dst); | ||
4249 | 4220 | } else { | ||
4250 | 4221 | qemuReportError(VIR_ERR_INTERNAL_ERROR, | ||
4251 | 4222 | _("unsupported disk type '%s'"), disk->dst); | ||
4252 | 4223 | goto error; | ||
4253 | 4224 | } | ||
4254 | 4225 | } | ||
4255 | 4226 | |||
4256 | 4227 | if (disk->type == VIR_DOMAIN_DISK_TYPE_DIR) { | ||
4257 | 4228 | /* QEMU only supports magic FAT format for now */ | ||
4258 | 4229 | if (disk->driverType && | ||
4259 | 4230 | STRNEQ(disk->driverType, "fat")) { | ||
4260 | 4231 | qemuReportError(VIR_ERR_INTERNAL_ERROR, | ||
4261 | 4232 | _("unsupported disk driver type for '%s'"), | ||
4262 | 4233 | disk->driverType); | ||
4263 | 4234 | goto error; | ||
4264 | 4235 | } | ||
4265 | 4236 | if (!disk->readonly) { | ||
4266 | 4237 | qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", | ||
4267 | 4238 | _("cannot create virtual FAT disks in read-write mode")); | ||
4268 | 4239 | goto error; | ||
4269 | 4240 | } | ||
4270 | 4241 | if (disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) | ||
4271 | 4242 | fmt = "fat:floppy:%s"; | ||
4272 | 4243 | else | ||
4273 | 4244 | fmt = "fat:%s"; | ||
4274 | 4245 | |||
4275 | 4246 | if (virAsprintf(&file, fmt, disk->src) < 0) { | ||
4276 | 4247 | goto no_memory; | ||
4277 | 4248 | } | ||
4278 | 4249 | } else if (disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK) { | ||
4279 | 4250 | switch (disk->protocol) { | ||
4280 | 4251 | case VIR_DOMAIN_DISK_PROTOCOL_NBD: | ||
4281 | 4252 | if (disk->nhosts != 1) { | ||
4282 | 4253 | qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", | ||
4283 | 4254 | _("NBD accepts only one host")); | ||
4284 | 4255 | goto error; | ||
4285 | 4256 | } | ||
4286 | 4257 | if (virAsprintf(&file, "nbd:%s:%s,", disk->hosts->name, | ||
4287 | 4258 | disk->hosts->port) < 0) { | ||
4288 | 4259 | goto no_memory; | ||
4289 | 4260 | } | ||
4290 | 4261 | break; | ||
4291 | 4262 | case VIR_DOMAIN_DISK_PROTOCOL_RBD: | ||
4292 | 4263 | { | ||
4293 | 4264 | virBuffer opt = VIR_BUFFER_INITIALIZER; | ||
4294 | 4265 | if (qemuBuildRBDString(conn, disk, &opt) < 0) | ||
4295 | 4266 | goto error; | ||
4296 | 4267 | if (virBufferError(&opt)) { | ||
4297 | 4268 | virReportOOMError(); | ||
4298 | 4269 | goto error; | ||
4299 | 4270 | } | ||
4300 | 4271 | file = virBufferContentAndReset(&opt); | ||
4301 | 4272 | } | ||
4302 | 4273 | break; | ||
4303 | 4274 | case VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG: | ||
4304 | 4275 | if (disk->nhosts == 0) { | ||
4305 | 4276 | if (virAsprintf(&file, "sheepdog:%s,", disk->src) < 0) { | ||
4306 | 4277 | goto no_memory; | ||
4307 | 4278 | } | ||
4308 | 4279 | } else { | ||
4309 | 4280 | /* only one host is supported now */ | ||
4310 | 4281 | if (virAsprintf(&file, "sheepdog:%s:%s:%s,", | ||
4311 | 4282 | disk->hosts->name, disk->hosts->port, | ||
4312 | 4283 | disk->src) < 0) { | ||
4313 | 4284 | goto no_memory; | ||
4314 | 4285 | } | ||
4315 | 4286 | } | ||
4316 | 4287 | break; | ||
4317 | 4288 | } | ||
4318 | 4289 | } else { | ||
4319 | 4290 | if (!(file = strdup(disk->src))) { | ||
4320 | 4291 | goto no_memory; | ||
4321 | 4292 | } | ||
4322 | 4293 | } | ||
4323 | 4294 | |||
4324 | 4295 | virCommandAddArgList(cmd, dev, file, NULL); | ||
4325 | 4296 | VIR_FREE(file); | ||
4326 | 4297 | } | ||
4327 | 4298 | } | ||
4328 | 4299 | |||
4329 | 4300 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_FSDEV)) { | ||
4330 | 4301 | for (i = 0 ; i < def->nfss ; i++) { | ||
4331 | 4302 | char *optstr; | ||
4332 | 4303 | virDomainFSDefPtr fs = def->fss[i]; | ||
4333 | 4304 | |||
4334 | 4305 | virCommandAddArg(cmd, "-fsdev"); | ||
4335 | 4306 | if (!(optstr = qemuBuildFSStr(fs, qemuCaps))) | ||
4336 | 4307 | goto error; | ||
4337 | 4308 | virCommandAddArg(cmd, optstr); | ||
4338 | 4309 | VIR_FREE(optstr); | ||
4339 | 4310 | |||
4340 | 4311 | virCommandAddArg(cmd, "-device"); | ||
4341 | 4312 | if (!(optstr = qemuBuildFSDevStr(fs, qemuCaps))) | ||
4342 | 4313 | goto error; | ||
4343 | 4314 | virCommandAddArg(cmd, optstr); | ||
4344 | 4315 | VIR_FREE(optstr); | ||
4345 | 4316 | } | ||
4346 | 4317 | } else { | ||
4347 | 4318 | if (def->nfss) { | ||
4348 | 4319 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", | ||
4349 | 4320 | _("filesystem passthrough not supported by this QEMU")); | ||
4350 | 4321 | goto error; | ||
4351 | 4322 | } | ||
4352 | 4323 | } | ||
4353 | 4324 | |||
4354 | 4325 | if (!def->nnets) { | ||
4355 | 4326 | /* If we have -device, then we set -nodefault already */ | ||
4356 | 4327 | if (!qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) | ||
4357 | 4328 | virCommandAddArgList(cmd, "-net", "none", NULL); | ||
4358 | 4329 | } else { | ||
4359 | 4330 | int bootNet = 0; | ||
4360 | 4331 | |||
4361 | 4332 | if (emitBootindex) { | ||
4362 | 4333 | /* convert <boot dev='network'/> to bootindex since we didn't emit | ||
4363 | 4334 | * -boot n | ||
4364 | 4335 | */ | ||
4365 | 4336 | for (i = 0 ; i < def->os.nBootDevs ; i++) { | ||
4366 | 4337 | if (def->os.bootDevs[i] == VIR_DOMAIN_BOOT_NET) { | ||
4367 | 4338 | bootNet = i + 1; | ||
4368 | 4339 | break; | ||
4369 | 4340 | } | ||
4370 | 4341 | } | ||
4371 | 4342 | } | ||
4372 | 4343 | |||
4373 | 4344 | for (i = 0 ; i < def->nnets ; i++) { | ||
4374 | 4345 | virDomainNetDefPtr net = def->nets[i]; | ||
4375 | 4346 | char *nic, *host; | ||
4376 | 4347 | char tapfd_name[50]; | ||
4377 | 4348 | char vhostfd_name[50] = ""; | ||
4378 | 4349 | int vlan; | ||
4379 | 4350 | int bootindex = bootNet; | ||
4380 | 4351 | int actualType; | ||
4381 | 4352 | |||
4382 | 4353 | bootNet = 0; | ||
4383 | 4354 | if (!bootindex) | ||
4384 | 4355 | bootindex = net->bootIndex; | ||
4385 | 4356 | |||
4386 | 4357 | /* VLANs are not used with -netdev, so don't record them */ | ||
4387 | 4358 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_NETDEV) && | ||
4388 | 4359 | qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) | ||
4389 | 4360 | vlan = -1; | ||
4390 | 4361 | else | ||
4391 | 4362 | vlan = i; | ||
4392 | 4363 | |||
4393 | 4364 | /* If appropriate, grab a physical device from the configured | ||
4394 | 4365 | * network's pool of devices, or resolve bridge device name | ||
4395 | 4366 | * to the one defined in the network definition. | ||
4396 | 4367 | */ | ||
4397 | 4368 | if (networkAllocateActualDevice(net) < 0) | ||
4398 | 4369 | goto error; | ||
4399 | 4370 | |||
4400 | 4371 | actualType = virDomainNetGetActualType(net); | ||
4401 | 4372 | if (actualType == VIR_DOMAIN_NET_TYPE_NETWORK || | ||
4402 | 4373 | actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) { | ||
4403 | 4374 | int tapfd = qemuNetworkIfaceConnect(def, conn, driver, net, | ||
4404 | 4375 | qemuCaps); | ||
4405 | 4376 | if (tapfd < 0) | ||
4406 | 4377 | goto error; | ||
4407 | 4378 | |||
4408 | 4379 | last_good_net = i; | ||
4409 | 4380 | virCommandTransferFD(cmd, tapfd); | ||
4410 | 4381 | |||
4411 | 4382 | if (snprintf(tapfd_name, sizeof(tapfd_name), "%d", | ||
4412 | 4383 | tapfd) >= sizeof(tapfd_name)) | ||
4413 | 4384 | goto no_memory; | ||
4414 | 4385 | } else if (actualType == VIR_DOMAIN_NET_TYPE_DIRECT) { | ||
4415 | 4386 | int tapfd = qemuPhysIfaceConnect(def, driver, net, | ||
4416 | 4387 | qemuCaps, vmop); | ||
4417 | 4388 | if (tapfd < 0) | ||
4418 | 4389 | goto error; | ||
4419 | 4390 | |||
4420 | 4391 | last_good_net = i; | ||
4421 | 4392 | virCommandTransferFD(cmd, tapfd); | ||
4422 | 4393 | |||
4423 | 4394 | if (snprintf(tapfd_name, sizeof(tapfd_name), "%d", | ||
4424 | 4395 | tapfd) >= sizeof(tapfd_name)) | ||
4425 | 4396 | goto no_memory; | ||
4426 | 4397 | } | ||
4427 | 4398 | |||
4428 | 4399 | if (actualType == VIR_DOMAIN_NET_TYPE_NETWORK || | ||
4429 | 4400 | actualType == VIR_DOMAIN_NET_TYPE_BRIDGE || | ||
4430 | 4401 | actualType == VIR_DOMAIN_NET_TYPE_DIRECT) { | ||
4431 | 4402 | /* Attempt to use vhost-net mode for these types of | ||
4432 | 4403 | network device */ | ||
4433 | 4404 | int vhostfd; | ||
4434 | 4405 | |||
4435 | 4406 | if (qemuOpenVhostNet(def, net, qemuCaps, &vhostfd) < 0) | ||
4436 | 4407 | goto error; | ||
4437 | 4408 | if (vhostfd >= 0) { | ||
4438 | 4409 | virCommandTransferFD(cmd, vhostfd); | ||
4439 | 4410 | |||
4440 | 4411 | if (snprintf(vhostfd_name, sizeof(vhostfd_name), "%d", | ||
4441 | 4412 | vhostfd) >= sizeof(vhostfd_name)) | ||
4442 | 4413 | goto no_memory; | ||
4443 | 4414 | } | ||
4444 | 4415 | } | ||
4445 | 4416 | /* Possible combinations: | ||
4446 | 4417 | * | ||
4447 | 4418 | * 1. Old way: -net nic,model=e1000,vlan=1 -net tap,vlan=1 | ||
4448 | 4419 | * 2. Semi-new: -device e1000,vlan=1 -net tap,vlan=1 | ||
4449 | 4420 | * 3. Best way: -netdev type=tap,id=netdev1 -device e1000,id=netdev1 | ||
4450 | 4421 | * | ||
4451 | 4422 | * NB, no support for -netdev without use of -device | ||
4452 | 4423 | */ | ||
4453 | 4424 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_NETDEV) && | ||
4454 | 4425 | qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) { | ||
4455 | 4426 | virCommandAddArg(cmd, "-netdev"); | ||
4456 | 4427 | if (!(host = qemuBuildHostNetStr(net, ',', vlan, | ||
4457 | 4428 | tapfd_name, vhostfd_name))) | ||
4458 | 4429 | goto error; | ||
4459 | 4430 | virCommandAddArg(cmd, host); | ||
4460 | 4431 | VIR_FREE(host); | ||
4461 | 4432 | } | ||
4462 | 4433 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) { | ||
4463 | 4434 | virCommandAddArg(cmd, "-device"); | ||
4464 | 4435 | nic = qemuBuildNicDevStr(net, vlan, bootindex, qemuCaps); | ||
4465 | 4436 | if (!nic) | ||
4466 | 4437 | goto error; | ||
4467 | 4438 | virCommandAddArg(cmd, nic); | ||
4468 | 4439 | VIR_FREE(nic); | ||
4469 | 4440 | } else { | ||
4470 | 4441 | virCommandAddArg(cmd, "-net"); | ||
4471 | 4442 | if (!(nic = qemuBuildNicStr(net, "nic,", vlan))) | ||
4472 | 4443 | goto error; | ||
4473 | 4444 | virCommandAddArg(cmd, nic); | ||
4474 | 4445 | VIR_FREE(nic); | ||
4475 | 4446 | } | ||
4476 | 4447 | if (!(qemuCapsGet(qemuCaps, QEMU_CAPS_NETDEV) && | ||
4477 | 4448 | qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE))) { | ||
4478 | 4449 | virCommandAddArg(cmd, "-net"); | ||
4479 | 4450 | if (!(host = qemuBuildHostNetStr(net, ',', vlan, | ||
4480 | 4451 | tapfd_name, vhostfd_name))) | ||
4481 | 4452 | goto error; | ||
4482 | 4453 | virCommandAddArg(cmd, host); | ||
4483 | 4454 | VIR_FREE(host); | ||
4484 | 4455 | } | ||
4485 | 4456 | } | ||
4486 | 4457 | } | ||
4487 | 4458 | |||
4488 | 4459 | if (def->nsmartcards) { | ||
4489 | 4460 | /* -device usb-ccid was already emitted along with other | ||
4490 | 4461 | * controllers. For now, qemu handles only one smartcard. */ | ||
4491 | 4462 | virDomainSmartcardDefPtr smartcard = def->smartcards[0]; | ||
4492 | 4463 | char *devstr; | ||
4493 | 4464 | virBuffer opt = VIR_BUFFER_INITIALIZER; | ||
4494 | 4465 | int j; | ||
4495 | 4466 | const char *database; | ||
4496 | 4467 | |||
4497 | 4468 | if (def->nsmartcards > 1 || | ||
4498 | 4469 | smartcard->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID || | ||
4499 | 4470 | smartcard->info.addr.ccid.controller != 0 || | ||
4500 | 4471 | smartcard->info.addr.ccid.slot != 0) { | ||
4501 | 4472 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", | ||
4502 | 4473 | _("this QEMU binary lacks multiple smartcard " | ||
4503 | 4474 | "support")); | ||
4504 | 4475 | virBufferFreeAndReset(&opt); | ||
4505 | 4476 | goto error; | ||
4506 | 4477 | } | ||
4507 | 4478 | |||
4508 | 4479 | switch (smartcard->type) { | ||
4509 | 4480 | case VIR_DOMAIN_SMARTCARD_TYPE_HOST: | ||
4510 | 4481 | if (!qemuCapsGet(qemuCaps, QEMU_CAPS_CHARDEV) || | ||
4511 | 4482 | !qemuCapsGet(qemuCaps, QEMU_CAPS_CCID_EMULATED)) { | ||
4512 | 4483 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", | ||
4513 | 4484 | _("this QEMU binary lacks smartcard host " | ||
4514 | 4485 | "mode support")); | ||
4515 | 4486 | goto error; | ||
4516 | 4487 | } | ||
4517 | 4488 | |||
4518 | 4489 | virBufferAddLit(&opt, "ccid-card-emulated,backend=nss-emulated"); | ||
4519 | 4490 | break; | ||
4520 | 4491 | |||
4521 | 4492 | case VIR_DOMAIN_SMARTCARD_TYPE_HOST_CERTIFICATES: | ||
4522 | 4493 | if (!qemuCapsGet(qemuCaps, QEMU_CAPS_CHARDEV) || | ||
4523 | 4494 | !qemuCapsGet(qemuCaps, QEMU_CAPS_CCID_EMULATED)) { | ||
4524 | 4495 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", | ||
4525 | 4496 | _("this QEMU binary lacks smartcard host " | ||
4526 | 4497 | "mode support")); | ||
4527 | 4498 | goto error; | ||
4528 | 4499 | } | ||
4529 | 4500 | |||
4530 | 4501 | virBufferAddLit(&opt, "ccid-card-emulated,backend=certificates"); | ||
4531 | 4502 | for (j = 0; j < VIR_DOMAIN_SMARTCARD_NUM_CERTIFICATES; j++) { | ||
4532 | 4503 | if (strchr(smartcard->data.cert.file[j], ',')) { | ||
4533 | 4504 | virBufferFreeAndReset(&opt); | ||
4534 | 4505 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, | ||
4535 | 4506 | _("invalid certificate name: %s"), | ||
4536 | 4507 | smartcard->data.cert.file[j]); | ||
4537 | 4508 | goto error; | ||
4538 | 4509 | } | ||
4539 | 4510 | virBufferAsprintf(&opt, ",cert%d=%s", j + 1, | ||
4540 | 4511 | smartcard->data.cert.file[j]); | ||
4541 | 4512 | } | ||
4542 | 4513 | if (smartcard->data.cert.database) { | ||
4543 | 4514 | if (strchr(smartcard->data.cert.database, ',')) { | ||
4544 | 4515 | virBufferFreeAndReset(&opt); | ||
4545 | 4516 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, | ||
4546 | 4517 | _("invalid database name: %s"), | ||
4547 | 4518 | smartcard->data.cert.database); | ||
4548 | 4519 | goto error; | ||
4549 | 4520 | } | ||
4550 | 4521 | database = smartcard->data.cert.database; | ||
4551 | 4522 | } else { | ||
4552 | 4523 | database = VIR_DOMAIN_SMARTCARD_DEFAULT_DATABASE; | ||
4553 | 4524 | } | ||
4554 | 4525 | virBufferAsprintf(&opt, ",database=%s", database); | ||
4555 | 4526 | break; | ||
4556 | 4527 | |||
4557 | 4528 | case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH: | ||
4558 | 4529 | if (!qemuCapsGet(qemuCaps, QEMU_CAPS_CHARDEV) || | ||
4559 | 4530 | !qemuCapsGet(qemuCaps, QEMU_CAPS_CCID_PASSTHRU)) { | ||
4560 | 4531 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", | ||
4561 | 4532 | _("this QEMU binary lacks smartcard " | ||
4562 | 4533 | "passthrough mode support")); | ||
4563 | 4534 | goto error; | ||
4564 | 4535 | } | ||
4565 | 4536 | |||
4566 | 4537 | virCommandAddArg(cmd, "-chardev"); | ||
4567 | 4538 | if (!(devstr = qemuBuildChrChardevStr(&smartcard->data.passthru, | ||
4568 | 4539 | smartcard->info.alias, | ||
4569 | 4540 | qemuCaps))) { | ||
4570 | 4541 | virBufferFreeAndReset(&opt); | ||
4571 | 4542 | goto error; | ||
4572 | 4543 | } | ||
4573 | 4544 | virCommandAddArg(cmd, devstr); | ||
4574 | 4545 | VIR_FREE(devstr); | ||
4575 | 4546 | |||
4576 | 4547 | virBufferAsprintf(&opt, "ccid-card-passthru,chardev=char%s", | ||
4577 | 4548 | smartcard->info.alias); | ||
4578 | 4549 | break; | ||
4579 | 4550 | |||
4580 | 4551 | default: | ||
4581 | 4552 | qemuReportError(VIR_ERR_INTERNAL_ERROR, | ||
4582 | 4553 | _("unexpected smartcard type %d"), | ||
4583 | 4554 | smartcard->type); | ||
4584 | 4555 | virBufferFreeAndReset(&opt); | ||
4585 | 4556 | goto error; | ||
4586 | 4557 | } | ||
4587 | 4558 | virCommandAddArg(cmd, "-device"); | ||
4588 | 4559 | virBufferAsprintf(&opt, ",id=%s,bus=ccid0.0", smartcard->info.alias); | ||
4589 | 4560 | virCommandAddArgBuffer(cmd, &opt); | ||
4590 | 4561 | } | ||
4591 | 4562 | |||
4592 | 4563 | if (!def->nserials) { | ||
4593 | 4564 | /* If we have -device, then we set -nodefault already */ | ||
4594 | 4565 | if (!qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) | ||
4595 | 4566 | virCommandAddArgList(cmd, "-serial", "none", NULL); | ||
4596 | 4567 | } else { | ||
4597 | 4568 | for (i = 0 ; i < def->nserials ; i++) { | ||
4598 | 4569 | virDomainChrDefPtr serial = def->serials[i]; | ||
4599 | 4570 | char *devstr; | ||
4600 | 4571 | |||
4601 | 4572 | /* Use -chardev with -device if they are available */ | ||
4602 | 4573 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_CHARDEV) && | ||
4603 | 4574 | qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) { | ||
4604 | 4575 | virCommandAddArg(cmd, "-chardev"); | ||
4605 | 4576 | if (!(devstr = qemuBuildChrChardevStr(&serial->source, | ||
4606 | 4577 | serial->info.alias, | ||
4607 | 4578 | qemuCaps))) | ||
4608 | 4579 | goto error; | ||
4609 | 4580 | virCommandAddArg(cmd, devstr); | ||
4610 | 4581 | VIR_FREE(devstr); | ||
4611 | 4582 | |||
4612 | 4583 | virCommandAddArg(cmd, "-device"); | ||
4613 | 4584 | virCommandAddArgFormat(cmd, "isa-serial,chardev=char%s,id=%s", | ||
4614 | 4585 | serial->info.alias, serial->info.alias); | ||
4615 | 4586 | } else { | ||
4616 | 4587 | virCommandAddArg(cmd, "-serial"); | ||
4617 | 4588 | if (!(devstr = qemuBuildChrArgStr(&serial->source, NULL))) | ||
4618 | 4589 | goto error; | ||
4619 | 4590 | virCommandAddArg(cmd, devstr); | ||
4620 | 4591 | VIR_FREE(devstr); | ||
4621 | 4592 | } | ||
4622 | 4593 | } | ||
4623 | 4594 | } | ||
4624 | 4595 | |||
4625 | 4596 | if (!def->nparallels) { | ||
4626 | 4597 | /* If we have -device, then we set -nodefault already */ | ||
4627 | 4598 | if (!qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) | ||
4628 | 4599 | virCommandAddArgList(cmd, "-parallel", "none", NULL); | ||
4629 | 4600 | } else { | ||
4630 | 4601 | for (i = 0 ; i < def->nparallels ; i++) { | ||
4631 | 4602 | virDomainChrDefPtr parallel = def->parallels[i]; | ||
4632 | 4603 | char *devstr; | ||
4633 | 4604 | |||
4634 | 4605 | /* Use -chardev with -device if they are available */ | ||
4635 | 4606 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_CHARDEV) && | ||
4636 | 4607 | qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) { | ||
4637 | 4608 | virCommandAddArg(cmd, "-chardev"); | ||
4638 | 4609 | if (!(devstr = qemuBuildChrChardevStr(¶llel->source, | ||
4639 | 4610 | parallel->info.alias, | ||
4640 | 4611 | qemuCaps))) | ||
4641 | 4612 | goto error; | ||
4642 | 4613 | virCommandAddArg(cmd, devstr); | ||
4643 | 4614 | VIR_FREE(devstr); | ||
4644 | 4615 | |||
4645 | 4616 | virCommandAddArg(cmd, "-device"); | ||
4646 | 4617 | virCommandAddArgFormat(cmd, "isa-parallel,chardev=char%s,id=%s", | ||
4647 | 4618 | parallel->info.alias, | ||
4648 | 4619 | parallel->info.alias); | ||
4649 | 4620 | } else { | ||
4650 | 4621 | virCommandAddArg(cmd, "-parallel"); | ||
4651 | 4622 | if (!(devstr = qemuBuildChrArgStr(¶llel->source, NULL))) | ||
4652 | 4623 | goto error; | ||
4653 | 4624 | virCommandAddArg(cmd, devstr); | ||
4654 | 4625 | VIR_FREE(devstr); | ||
4655 | 4626 | } | ||
4656 | 4627 | } | ||
4657 | 4628 | } | ||
4658 | 4629 | |||
4659 | 4630 | for (i = 0 ; i < def->nchannels ; i++) { | ||
4660 | 4631 | virDomainChrDefPtr channel = def->channels[i]; | ||
4661 | 4632 | char *devstr; | ||
4662 | 4633 | char *addr; | ||
4663 | 4634 | int port; | ||
4664 | 4635 | |||
4665 | 4636 | switch(channel->targetType) { | ||
4666 | 4637 | case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_GUESTFWD: | ||
4667 | 4638 | if (!qemuCapsGet(qemuCaps, QEMU_CAPS_CHARDEV) || | ||
4668 | 4639 | !qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) { | ||
4669 | 4640 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, | ||
4670 | 4641 | "%s", _("guestfwd requires QEMU to support -chardev & -device")); | ||
4671 | 4642 | goto error; | ||
4672 | 4643 | } | ||
4673 | 4644 | |||
4674 | 4645 | virCommandAddArg(cmd, "-chardev"); | ||
4675 | 4646 | if (!(devstr = qemuBuildChrChardevStr(&channel->source, | ||
4676 | 4647 | channel->info.alias, | ||
4677 | 4648 | qemuCaps))) | ||
4678 | 4649 | goto error; | ||
4679 | 4650 | virCommandAddArg(cmd, devstr); | ||
4680 | 4651 | VIR_FREE(devstr); | ||
4681 | 4652 | |||
4682 | 4653 | addr = virSocketAddrFormat(channel->target.addr); | ||
4683 | 4654 | if (!addr) | ||
4684 | 4655 | goto error; | ||
4685 | 4656 | port = virSocketAddrGetPort(channel->target.addr); | ||
4686 | 4657 | |||
4687 | 4658 | virCommandAddArg(cmd, "-netdev"); | ||
4688 | 4659 | virCommandAddArgFormat(cmd, | ||
4689 | 4660 | "user,guestfwd=tcp:%s:%i,chardev=char%s,id=user-%s", | ||
4690 | 4661 | addr, port, channel->info.alias, | ||
4691 | 4662 | channel->info.alias); | ||
4692 | 4663 | VIR_FREE(addr); | ||
4693 | 4664 | break; | ||
4694 | 4665 | |||
4695 | 4666 | case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO: | ||
4696 | 4667 | if (!qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) { | ||
4697 | 4668 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", | ||
4698 | 4669 | _("virtio channel requires QEMU to support -device")); | ||
4699 | 4670 | goto error; | ||
4700 | 4671 | } | ||
4701 | 4672 | |||
4702 | 4673 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE_SPICEVMC) && | ||
4703 | 4674 | channel->source.type == VIR_DOMAIN_CHR_TYPE_SPICEVMC) { | ||
4704 | 4675 | /* spicevmc was originally introduced via a -device | ||
4705 | 4676 | * with a backend internal to qemu; although we prefer | ||
4706 | 4677 | * the newer -chardev interface. */ | ||
4707 | 4678 | ; | ||
4708 | 4679 | } else { | ||
4709 | 4680 | virCommandAddArg(cmd, "-chardev"); | ||
4710 | 4681 | if (!(devstr = qemuBuildChrChardevStr(&channel->source, | ||
4711 | 4682 | channel->info.alias, | ||
4712 | 4683 | qemuCaps))) | ||
4713 | 4684 | goto error; | ||
4714 | 4685 | virCommandAddArg(cmd, devstr); | ||
4715 | 4686 | VIR_FREE(devstr); | ||
4716 | 4687 | } | ||
4717 | 4688 | |||
4718 | 4689 | virCommandAddArg(cmd, "-device"); | ||
4719 | 4690 | if (!(devstr = qemuBuildVirtioSerialPortDevStr(channel, | ||
4720 | 4691 | qemuCaps))) | ||
4721 | 4692 | goto error; | ||
4722 | 4693 | virCommandAddArg(cmd, devstr); | ||
4723 | 4694 | VIR_FREE(devstr); | ||
4724 | 4695 | break; | ||
4725 | 4696 | } | ||
4726 | 4697 | } | ||
4727 | 4698 | |||
4728 | 4699 | /* Explicit console devices */ | ||
4729 | 4700 | for (i = 0 ; i < def->nconsoles ; i++) { | ||
4730 | 4701 | virDomainChrDefPtr console = def->consoles[i]; | ||
4731 | 4702 | char *devstr; | ||
4732 | 4703 | |||
4733 | 4704 | switch(console->targetType) { | ||
4734 | 4705 | case VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_VIRTIO: | ||
4735 | 4706 | if (!qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) { | ||
4736 | 4707 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", | ||
4737 | 4708 | _("virtio channel requires QEMU to support -device")); | ||
4738 | 4709 | goto error; | ||
4739 | 4710 | } | ||
4740 | 4711 | |||
4741 | 4712 | virCommandAddArg(cmd, "-chardev"); | ||
4742 | 4713 | if (!(devstr = qemuBuildChrChardevStr(&console->source, | ||
4743 | 4714 | console->info.alias, | ||
4744 | 4715 | qemuCaps))) | ||
4745 | 4716 | goto error; | ||
4746 | 4717 | virCommandAddArg(cmd, devstr); | ||
4747 | 4718 | VIR_FREE(devstr); | ||
4748 | 4719 | |||
4749 | 4720 | virCommandAddArg(cmd, "-device"); | ||
4750 | 4721 | if (!(devstr = qemuBuildVirtioSerialPortDevStr(console, | ||
4751 | 4722 | qemuCaps))) | ||
4752 | 4723 | goto error; | ||
4753 | 4724 | virCommandAddArg(cmd, devstr); | ||
4754 | 4725 | VIR_FREE(devstr); | ||
4755 | 4726 | break; | ||
4756 | 4727 | |||
4757 | 4728 | case VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL: | ||
4758 | 4729 | break; | ||
4759 | 4730 | |||
4760 | 4731 | default: | ||
4761 | 4732 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, | ||
4762 | 4733 | _("unsupported console target type %s"), | ||
4763 | 4734 | NULLSTR(virDomainChrConsoleTargetTypeToString(console->targetType))); | ||
4764 | 4735 | goto error; | ||
4765 | 4736 | } | ||
4766 | 4737 | } | ||
4767 | 4738 | |||
4768 | 4739 | if (usbcontroller == 0) | ||
4769 | 4740 | virCommandAddArg(cmd, "-usb"); | ||
4770 | 4741 | |||
4771 | 4742 | for (i = 0 ; i < def->nhubs ; i++) { | ||
4772 | 4743 | virDomainHubDefPtr hub = def->hubs[i]; | ||
4773 | 4744 | char *optstr; | ||
4774 | 4745 | |||
4775 | 4746 | virCommandAddArg(cmd, "-device"); | ||
4776 | 4747 | if (!(optstr = qemuBuildHubDevStr(hub, qemuCaps))) | ||
4777 | 4748 | goto error; | ||
4778 | 4749 | virCommandAddArg(cmd, optstr); | ||
4779 | 4750 | VIR_FREE(optstr); | ||
4780 | 4751 | } | ||
4781 | 4752 | |||
4782 | 4753 | for (i = 0 ; i < def->ninputs ; i++) { | ||
4783 | 4754 | virDomainInputDefPtr input = def->inputs[i]; | ||
4784 | 4755 | |||
4785 | 4756 | if (input->bus == VIR_DOMAIN_INPUT_BUS_USB) { | ||
4786 | 4757 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) { | ||
4787 | 4758 | char *optstr; | ||
4788 | 4759 | virCommandAddArg(cmd, "-device"); | ||
4789 | 4760 | if (!(optstr = qemuBuildUSBInputDevStr(input, qemuCaps))) | ||
4790 | 4761 | goto error; | ||
4791 | 4762 | virCommandAddArg(cmd, optstr); | ||
4792 | 4763 | VIR_FREE(optstr); | ||
4793 | 4764 | } else { | ||
4794 | 4765 | virCommandAddArgList(cmd, "-usbdevice", | ||
4795 | 4766 | input->type == VIR_DOMAIN_INPUT_TYPE_MOUSE | ||
4796 | 4767 | ? "mouse" : "tablet", NULL); | ||
4797 | 4768 | } | ||
4798 | 4769 | } | ||
4799 | 4770 | } | ||
4800 | 4771 | |||
4801 | 4772 | if (def->ngraphics > 1) { | ||
4802 | 4773 | qemuReportError(VIR_ERR_INTERNAL_ERROR, | ||
4803 | 4774 | "%s", _("only 1 graphics device is supported")); | ||
4804 | 4775 | goto error; | ||
4805 | 4776 | } | ||
4806 | 4777 | |||
4807 | 4778 | if ((def->ngraphics == 1) && | ||
4808 | 4779 | def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) { | ||
4809 | 4780 | virBuffer opt = VIR_BUFFER_INITIALIZER; | ||
4810 | 4781 | |||
4811 | 4782 | if (def->graphics[0]->data.vnc.socket || | ||
4812 | 4783 | driver->vncAutoUnixSocket) { | ||
4813 | 4784 | |||
4814 | 4785 | if (!def->graphics[0]->data.vnc.socket && | ||
4815 | 4786 | virAsprintf(&def->graphics[0]->data.vnc.socket, | ||
4816 | 4787 | "%s/%s.vnc", driver->libDir, def->name) == -1) { | ||
4817 | 4788 | goto no_memory; | ||
4818 | 4789 | } | ||
4819 | 4790 | |||
4820 | 4791 | virBufferAsprintf(&opt, "unix:%s", | ||
4821 | 4792 | def->graphics[0]->data.vnc.socket); | ||
4822 | 4793 | |||
4823 | 4794 | } else if (qemuCapsGet(qemuCaps, QEMU_CAPS_VNC_COLON)) { | ||
4824 | 4795 | const char *listenNetwork; | ||
4825 | 4796 | const char *listenAddr = NULL; | ||
4826 | 4797 | char *netAddr = NULL; | ||
4827 | 4798 | bool escapeAddr; | ||
4828 | 4799 | int ret; | ||
4829 | 4800 | |||
4830 | 4801 | switch (virDomainGraphicsListenGetType(def->graphics[0], 0)) { | ||
4831 | 4802 | case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS: | ||
4832 | 4803 | listenAddr = virDomainGraphicsListenGetAddress(def->graphics[0], 0); | ||
4833 | 4804 | break; | ||
4834 | 4805 | |||
4835 | 4806 | case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK: | ||
4836 | 4807 | listenNetwork = virDomainGraphicsListenGetNetwork(def->graphics[0], 0); | ||
4837 | 4808 | if (!listenNetwork) | ||
4838 | 4809 | break; | ||
4839 | 4810 | ret = networkGetNetworkAddress(listenNetwork, &netAddr); | ||
4840 | 4811 | if (ret <= -2) { | ||
4841 | 4812 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, | ||
4842 | 4813 | "%s", _("network-based listen not possible, " | ||
4843 | 4814 | "network driver not present")); | ||
4844 | 4815 | goto error; | ||
4845 | 4816 | } | ||
4846 | 4817 | if (ret < 0) { | ||
4847 | 4818 | qemuReportError(VIR_ERR_XML_ERROR, | ||
4848 | 4819 | _("listen network '%s' had no usable address"), | ||
4849 | 4820 | listenNetwork); | ||
4850 | 4821 | goto error; | ||
4851 | 4822 | } | ||
4852 | 4823 | listenAddr = netAddr; | ||
4853 | 4824 | /* store the address we found in the <graphics> element so it will | ||
4854 | 4825 | * show up in status. */ | ||
4855 | 4826 | if (virDomainGraphicsListenSetAddress(def->graphics[0], 0, | ||
4856 | 4827 | listenAddr, -1, false) < 0) | ||
4857 | 4828 | goto error; | ||
4858 | 4829 | break; | ||
4859 | 4830 | } | ||
4860 | 4831 | |||
4861 | 4832 | if (!listenAddr) | ||
4862 | 4833 | listenAddr = driver->vncListen; | ||
4863 | 4834 | |||
4864 | 4835 | escapeAddr = strchr(listenAddr, ':') != NULL; | ||
4865 | 4836 | if (escapeAddr) | ||
4866 | 4837 | virBufferAsprintf(&opt, "[%s]", listenAddr); | ||
4867 | 4838 | else | ||
4868 | 4839 | virBufferAdd(&opt, listenAddr, -1); | ||
4869 | 4840 | virBufferAsprintf(&opt, ":%d", | ||
4870 | 4841 | def->graphics[0]->data.vnc.port - 5900); | ||
4871 | 4842 | |||
4872 | 4843 | VIR_FREE(netAddr); | ||
4873 | 4844 | } else { | ||
4874 | 4845 | virBufferAsprintf(&opt, "%d", | ||
4875 | 4846 | def->graphics[0]->data.vnc.port - 5900); | ||
4876 | 4847 | } | ||
4877 | 4848 | |||
4878 | 4849 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_VNC_COLON)) { | ||
4879 | 4850 | if (def->graphics[0]->data.vnc.auth.passwd || | ||
4880 | 4851 | driver->vncPassword) | ||
4881 | 4852 | virBufferAddLit(&opt, ",password"); | ||
4882 | 4853 | |||
4883 | 4854 | if (driver->vncTLS) { | ||
4884 | 4855 | virBufferAddLit(&opt, ",tls"); | ||
4885 | 4856 | if (driver->vncTLSx509verify) { | ||
4886 | 4857 | virBufferAsprintf(&opt, ",x509verify=%s", | ||
4887 | 4858 | driver->vncTLSx509certdir); | ||
4888 | 4859 | } else { | ||
4889 | 4860 | virBufferAsprintf(&opt, ",x509=%s", | ||
4890 | 4861 | driver->vncTLSx509certdir); | ||
4891 | 4862 | } | ||
4892 | 4863 | } | ||
4893 | 4864 | |||
4894 | 4865 | if (driver->vncSASL) { | ||
4895 | 4866 | virBufferAddLit(&opt, ",sasl"); | ||
4896 | 4867 | |||
4897 | 4868 | if (driver->vncSASLdir) | ||
4898 | 4869 | virCommandAddEnvPair(cmd, "SASL_CONF_DIR", | ||
4899 | 4870 | driver->vncSASLdir); | ||
4900 | 4871 | |||
4901 | 4872 | /* TODO: Support ACLs later */ | ||
4902 | 4873 | } | ||
4903 | 4874 | } | ||
4904 | 4875 | |||
4905 | 4876 | virCommandAddArg(cmd, "-vnc"); | ||
4906 | 4877 | virCommandAddArgBuffer(cmd, &opt); | ||
4907 | 4878 | if (def->graphics[0]->data.vnc.keymap) { | ||
4908 | 4879 | virCommandAddArgList(cmd, "-k", def->graphics[0]->data.vnc.keymap, | ||
4909 | 4880 | NULL); | ||
4910 | 4881 | } | ||
4911 | 4882 | |||
4912 | 4883 | /* Unless user requested it, set the audio backend to none, to | ||
4913 | 4884 | * prevent it opening the host OS audio devices, since that causes | ||
4914 | 4885 | * security issues and might not work when using VNC. | ||
4915 | 4886 | */ | ||
4916 | 4887 | if (driver->vncAllowHostAudio) { | ||
4917 | 4888 | virCommandAddEnvPass(cmd, "QEMU_AUDIO_DRV"); | ||
4918 | 4889 | } else { | ||
4919 | 4890 | virCommandAddEnvString(cmd, "QEMU_AUDIO_DRV=none"); | ||
4920 | 4891 | } | ||
4921 | 4892 | } else if ((def->ngraphics == 1) && | ||
4922 | 4893 | def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) { | ||
4923 | 4894 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_0_10) && | ||
4924 | 4895 | !qemuCapsGet(qemuCaps, QEMU_CAPS_SDL)) { | ||
4925 | 4896 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, | ||
4926 | 4897 | _("sdl not supported by '%s'"), | ||
4927 | 4898 | def->emulator); | ||
4928 | 4899 | goto error; | ||
4929 | 4900 | } | ||
4930 | 4901 | |||
4931 | 4902 | if (def->graphics[0]->data.sdl.xauth) | ||
4932 | 4903 | virCommandAddEnvPair(cmd, "XAUTHORITY", | ||
4933 | 4904 | def->graphics[0]->data.sdl.xauth); | ||
4934 | 4905 | if (def->graphics[0]->data.sdl.display) | ||
4935 | 4906 | virCommandAddEnvPair(cmd, "DISPLAY", | ||
4936 | 4907 | def->graphics[0]->data.sdl.display); | ||
4937 | 4908 | if (def->graphics[0]->data.sdl.fullscreen) | ||
4938 | 4909 | virCommandAddArg(cmd, "-full-screen"); | ||
4939 | 4910 | |||
4940 | 4911 | /* If using SDL for video, then we should just let it | ||
4941 | 4912 | * use QEMU's host audio drivers, possibly SDL too | ||
4942 | 4913 | * User can set these two before starting libvirtd | ||
4943 | 4914 | */ | ||
4944 | 4915 | virCommandAddEnvPass(cmd, "QEMU_AUDIO_DRV"); | ||
4945 | 4916 | virCommandAddEnvPass(cmd, "SDL_AUDIODRIVER"); | ||
4946 | 4917 | |||
4947 | 4918 | /* New QEMU has this flag to let us explicitly ask for | ||
4948 | 4919 | * SDL graphics. This is better than relying on the | ||
4949 | 4920 | * default, since the default changes :-( */ | ||
4950 | 4921 | if (qemuCapsGet(qemuCaps, QEMU_CAPS_SDL)) | ||
4951 | 4922 | virCommandAddArg(cmd, "-sdl"); | ||
4952 | 4923 | |||
4953 | 4924 | } else if ((def->ngraphics == 1) && | ||
4954 | 4925 | def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) { | ||
4955 | 4926 | virBuffer opt = VIR_BUFFER_INITIALIZER; | ||
4956 | 4927 | const char *listenNetwork; | ||
4957 | 4928 | const char *listenAddr = NULL; | ||
4958 | 4929 | char *netAddr = NULL; | ||
4959 | 4930 | int ret; | ||
4960 | 4931 | |||
4961 | 4932 | if (!qemuCapsGet(qemuCaps, QEMU_CAPS_SPICE)) { | ||
4962 | 4933 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", | ||
4963 | 4934 | _("spice graphics are not supported with this QEMU")); | ||
4964 | 4935 | goto error; | ||
4965 | 4936 | } | ||
4966 | 4937 | |||
4967 | 4938 | virBufferAsprintf(&opt, "port=%u", def->graphics[0]->data.spice.port); | ||
4968 | 4939 | |||
4969 | 4940 | if (driver->spiceTLS && def->graphics[0]->data.spice.tlsPort != -1) | ||
4970 | 4941 | virBufferAsprintf(&opt, ",tls-port=%u", def->graphics[0]->data.spice.tlsPort); | ||
4971 | 4942 | |||
4972 | 4943 | switch (virDomainGraphicsListenGetType(def->graphics[0], 0)) { | ||
4973 | 4944 | case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS: | ||
4974 | 4945 | listenAddr = virDomainGraphicsListenGetAddress(def->graphics[0], 0); | ||
4975 | 4946 | break; | ||
4976 | 4947 | |||
4977 | 4948 | case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK: | ||
4978 | 4949 | listenNetwork = virDomainGraphicsListenGetNetwork(def->graphics[0], 0); | ||
4979 | 4950 | if (!listenNetwork) | ||
4980 | 4951 | break; | ||
4981 | 4952 | ret = networkGetNetworkAddress(listenNetwork, &netAddr); | ||
4982 | 4953 | if (ret <= -2) { | ||
4983 | 4954 | qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, | ||
4984 | 4955 | "%s", _("network-based listen not possible, " | ||
4985 | 4956 | "network driver not present")); | ||
4986 | 4957 | goto error; | ||
4987 | 4958 | } | ||
4988 | 4959 | if (ret < 0) { | ||
4989 | 4960 | qemuReportError(VIR_ERR_XML_ERROR, | ||
4990 | 4961 | _("listen network '%s' had no usable address"), | ||
4991 | 4962 | listenNetwork); | ||
4992 | 4963 | goto error; | ||
4993 | 4964 | } | ||
4994 | 4965 | listenAddr = netAddr; | ||
4995 | 4966 | /* store the address we found in the <graphics> element so it will | ||
4996 | 4967 | * show up in status. */ | ||
4997 | 4968 | if (virDomainGraphicsListenSetAddress(def->graphics[0], 0, | ||
4998 | 4969 | listenAddr, -1, false) < 0) | ||
4999 | 4970 | goto error; | ||
5000 | 4971 | break; |
Thanks for your patch! Unfortunately it cannot be incorporated into Ubuntu in its current state: patches/ fix-poll. patch does not include DEP-3 comments
* debian/
* debian/changelog should reference precise-proposed, not precise
* the patch does not apply cleanly to 0.9.8-2ubuntu17.5, the version that is currently in precise
Please feel free to make these changes and resubmit. Thanks!