1 /*
2 * qemu_hostdev.c: QEMU hostdev management
3 *
4 * Copyright (C) 2006-2007, 2009-2014 Red Hat, Inc.
5 * Copyright (C) 2006 Daniel P. Berrange
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library. If not, see
19 * <http://www.gnu.org/licenses/>.
20 */
21
22 #include <config.h>
23
24 #include <fcntl.h>
25 #include <sys/ioctl.h>
26
27 #include "qemu_hostdev.h"
28 #include "qemu_domain.h"
29 #include "virlog.h"
30 #include "virerror.h"
31 #include "viralloc.h"
32 #include "virpci.h"
33 #include "virusb.h"
34 #include "virscsi.h"
35 #include "virnetdev.h"
36 #include "virfile.h"
37 #include "virhostdev.h"
38 #include "virutil.h"
39
40 #define VIR_FROM_THIS VIR_FROM_QEMU
41
42 VIR_LOG_INIT("qemu.qemu_hostdev");
43
44
45 int
qemuHostdevUpdateActivePCIDevices(virQEMUDriver * driver,virDomainDef * def)46 qemuHostdevUpdateActivePCIDevices(virQEMUDriver *driver,
47 virDomainDef *def)
48 {
49 virHostdevManager *mgr = driver->hostdevMgr;
50
51 if (!def->nhostdevs)
52 return 0;
53
54 return virHostdevUpdateActivePCIDevices(mgr, def->hostdevs, def->nhostdevs,
55 QEMU_DRIVER_NAME, def->name);
56 }
57
58 int
qemuHostdevUpdateActiveUSBDevices(virQEMUDriver * driver,virDomainDef * def)59 qemuHostdevUpdateActiveUSBDevices(virQEMUDriver *driver,
60 virDomainDef *def)
61 {
62 virHostdevManager *mgr = driver->hostdevMgr;
63
64 if (!def->nhostdevs)
65 return 0;
66
67 return virHostdevUpdateActiveUSBDevices(mgr, def->hostdevs, def->nhostdevs,
68 QEMU_DRIVER_NAME, def->name);
69 }
70
71 int
qemuHostdevUpdateActiveSCSIDevices(virQEMUDriver * driver,virDomainDef * def)72 qemuHostdevUpdateActiveSCSIDevices(virQEMUDriver *driver,
73 virDomainDef *def)
74 {
75 virHostdevManager *mgr = driver->hostdevMgr;
76
77 if (!def->nhostdevs)
78 return 0;
79
80 return virHostdevUpdateActiveSCSIDevices(mgr, def->hostdevs, def->nhostdevs,
81 QEMU_DRIVER_NAME, def->name);
82 }
83
84
85 int
qemuHostdevUpdateActiveMediatedDevices(virQEMUDriver * driver,virDomainDef * def)86 qemuHostdevUpdateActiveMediatedDevices(virQEMUDriver *driver,
87 virDomainDef *def)
88 {
89 virHostdevManager *mgr = driver->hostdevMgr;
90
91 if (!def->nhostdevs)
92 return 0;
93
94 return virHostdevUpdateActiveMediatedDevices(mgr, def->hostdevs,
95 def->nhostdevs,
96 QEMU_DRIVER_NAME, def->name);
97 }
98
99
100 int
qemuHostdevUpdateActiveNVMeDisks(virQEMUDriver * driver,virDomainDef * def)101 qemuHostdevUpdateActiveNVMeDisks(virQEMUDriver *driver,
102 virDomainDef *def)
103 {
104 return virHostdevUpdateActiveNVMeDevices(driver->hostdevMgr,
105 QEMU_DRIVER_NAME,
106 def->name,
107 def->disks,
108 def->ndisks);
109 }
110
111
112 int
qemuHostdevUpdateActiveDomainDevices(virQEMUDriver * driver,virDomainDef * def)113 qemuHostdevUpdateActiveDomainDevices(virQEMUDriver *driver,
114 virDomainDef *def)
115 {
116 if (!def->nhostdevs && !def->ndisks)
117 return 0;
118
119 if (qemuHostdevUpdateActiveNVMeDisks(driver, def) < 0)
120 return -1;
121
122 if (qemuHostdevUpdateActivePCIDevices(driver, def) < 0)
123 return -1;
124
125 if (qemuHostdevUpdateActiveUSBDevices(driver, def) < 0)
126 return -1;
127
128 if (qemuHostdevUpdateActiveSCSIDevices(driver, def) < 0)
129 return -1;
130
131 if (qemuHostdevUpdateActiveMediatedDevices(driver, def) < 0)
132 return -1;
133
134 return 0;
135 }
136
137
138 bool
qemuHostdevNeedsVFIO(const virDomainHostdevDef * hostdev)139 qemuHostdevNeedsVFIO(const virDomainHostdevDef *hostdev)
140 {
141 return virHostdevIsVFIODevice(hostdev) ||
142 virHostdevIsMdevDevice(hostdev);
143 }
144
145
146 bool
qemuHostdevHostSupportsPassthroughVFIO(void)147 qemuHostdevHostSupportsPassthroughVFIO(void)
148 {
149 /* condition 1 - host has IOMMU */
150 if (!virHostHasIOMMU())
151 return false;
152
153 /* condition 2 - /dev/vfio/vfio exists */
154 if (!virFileExists(QEMU_DEV_VFIO))
155 return false;
156
157 return true;
158 }
159
160
161 static bool
qemuHostdevPreparePCIDevicesCheckSupport(virDomainHostdevDef ** hostdevs,size_t nhostdevs,virQEMUCaps * qemuCaps)162 qemuHostdevPreparePCIDevicesCheckSupport(virDomainHostdevDef **hostdevs,
163 size_t nhostdevs,
164 virQEMUCaps *qemuCaps)
165 {
166 bool supportsPassthroughVFIO = qemuHostdevHostSupportsPassthroughVFIO();
167 size_t i;
168
169 /* assign defaults for hostdev passthrough */
170 for (i = 0; i < nhostdevs; i++) {
171 virDomainHostdevDef *hostdev = hostdevs[i];
172 int *backend = &hostdev->source.subsys.u.pci.backend;
173
174 if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
175 continue;
176 if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
177 continue;
178
179 switch ((virDomainHostdevSubsysPCIBackendType)*backend) {
180 case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT:
181 if (supportsPassthroughVFIO &&
182 virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VFIO_PCI)) {
183 *backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO;
184 } else {
185 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
186 _("host doesn't support passthrough of "
187 "host PCI devices"));
188 return false;
189 }
190
191 break;
192
193 case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO:
194 if (!supportsPassthroughVFIO) {
195 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
196 _("host doesn't support VFIO PCI passthrough"));
197 return false;
198 }
199 break;
200
201 case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM:
202 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
203 _("host doesn't support legacy PCI passthrough"));
204 return false;
205
206 case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_XEN:
207 case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_TYPE_LAST:
208 break;
209 }
210 }
211
212 return true;
213 }
214
215 int
qemuHostdevPrepareOneNVMeDisk(virQEMUDriver * driver,const char * name,virStorageSource * src)216 qemuHostdevPrepareOneNVMeDisk(virQEMUDriver *driver,
217 const char *name,
218 virStorageSource *src)
219 {
220 return virHostdevPrepareOneNVMeDevice(driver->hostdevMgr,
221 QEMU_DRIVER_NAME,
222 name,
223 src);
224 }
225
226 int
qemuHostdevPrepareNVMeDisks(virQEMUDriver * driver,const char * name,virDomainDiskDef ** disks,size_t ndisks)227 qemuHostdevPrepareNVMeDisks(virQEMUDriver *driver,
228 const char *name,
229 virDomainDiskDef **disks,
230 size_t ndisks)
231 {
232 return virHostdevPrepareNVMeDevices(driver->hostdevMgr,
233 QEMU_DRIVER_NAME,
234 name, disks, ndisks);
235 }
236
237 int
qemuHostdevPreparePCIDevices(virQEMUDriver * driver,const char * name,const unsigned char * uuid,virDomainHostdevDef ** hostdevs,int nhostdevs,virQEMUCaps * qemuCaps,unsigned int flags)238 qemuHostdevPreparePCIDevices(virQEMUDriver *driver,
239 const char *name,
240 const unsigned char *uuid,
241 virDomainHostdevDef **hostdevs,
242 int nhostdevs,
243 virQEMUCaps *qemuCaps,
244 unsigned int flags)
245 {
246 virHostdevManager *hostdev_mgr = driver->hostdevMgr;
247
248 if (!qemuHostdevPreparePCIDevicesCheckSupport(hostdevs, nhostdevs, qemuCaps))
249 return -1;
250
251 return virHostdevPreparePCIDevices(hostdev_mgr, QEMU_DRIVER_NAME,
252 name, uuid, hostdevs,
253 nhostdevs, flags);
254 }
255
256 int
qemuHostdevPrepareUSBDevices(virQEMUDriver * driver,const char * name,virDomainHostdevDef ** hostdevs,int nhostdevs,unsigned int flags)257 qemuHostdevPrepareUSBDevices(virQEMUDriver *driver,
258 const char *name,
259 virDomainHostdevDef **hostdevs,
260 int nhostdevs,
261 unsigned int flags)
262 {
263 virHostdevManager *hostdev_mgr = driver->hostdevMgr;
264
265 return virHostdevPrepareUSBDevices(hostdev_mgr, QEMU_DRIVER_NAME, name,
266 hostdevs, nhostdevs, flags);
267 }
268
269 int
qemuHostdevPrepareSCSIDevices(virQEMUDriver * driver,const char * name,virDomainHostdevDef ** hostdevs,int nhostdevs)270 qemuHostdevPrepareSCSIDevices(virQEMUDriver *driver,
271 const char *name,
272 virDomainHostdevDef **hostdevs,
273 int nhostdevs)
274 {
275 size_t i;
276 virHostdevManager *hostdev_mgr = driver->hostdevMgr;
277
278 /* Loop 1: Add the shared scsi host device to shared device
279 * table.
280 */
281 for (i = 0; i < nhostdevs; i++) {
282 virDomainDeviceDef dev;
283
284 if (!virHostdevIsSCSIDevice(hostdevs[i]))
285 continue;
286
287 dev.type = VIR_DOMAIN_DEVICE_HOSTDEV;
288 dev.data.hostdev = hostdevs[i];
289
290 if (qemuAddSharedDevice(driver, &dev, name) < 0)
291 return -1;
292
293 if (qemuSetUnprivSGIO(&dev) < 0)
294 return -1;
295 }
296
297 return virHostdevPrepareSCSIDevices(hostdev_mgr, QEMU_DRIVER_NAME,
298 name, hostdevs, nhostdevs);
299 }
300
301 int
qemuHostdevPrepareSCSIVHostDevices(virQEMUDriver * driver,const char * name,virDomainHostdevDef ** hostdevs,int nhostdevs)302 qemuHostdevPrepareSCSIVHostDevices(virQEMUDriver *driver,
303 const char *name,
304 virDomainHostdevDef **hostdevs,
305 int nhostdevs)
306 {
307 virHostdevManager *hostdev_mgr = driver->hostdevMgr;
308
309 return virHostdevPrepareSCSIVHostDevices(hostdev_mgr, QEMU_DRIVER_NAME,
310 name, hostdevs, nhostdevs);
311 }
312
313 int
qemuHostdevPrepareMediatedDevices(virQEMUDriver * driver,const char * name,virDomainHostdevDef ** hostdevs,int nhostdevs)314 qemuHostdevPrepareMediatedDevices(virQEMUDriver *driver,
315 const char *name,
316 virDomainHostdevDef **hostdevs,
317 int nhostdevs)
318 {
319 virHostdevManager *hostdev_mgr = driver->hostdevMgr;
320 bool supportsVFIO;
321 size_t i;
322
323 /* Checking for VFIO only is fine with mdev, as IOMMU isolation is achieved
324 * by the physical parent device.
325 */
326 supportsVFIO = virFileExists(QEMU_DEV_VFIO);
327
328 for (i = 0; i < nhostdevs; i++) {
329 if (virHostdevIsMdevDevice(hostdevs[i])) {
330 if (!supportsVFIO) {
331 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
332 _("Mediated host device assignment requires "
333 "VFIO support"));
334 return -1;
335 }
336 break;
337 }
338 }
339
340 return virHostdevPrepareMediatedDevices(hostdev_mgr, QEMU_DRIVER_NAME,
341 name, hostdevs, nhostdevs);
342 }
343
344 int
qemuHostdevPrepareDomainDevices(virQEMUDriver * driver,virDomainDef * def,virQEMUCaps * qemuCaps,unsigned int flags)345 qemuHostdevPrepareDomainDevices(virQEMUDriver *driver,
346 virDomainDef *def,
347 virQEMUCaps *qemuCaps,
348 unsigned int flags)
349 {
350 if (!def->nhostdevs && !def->ndisks)
351 return 0;
352
353 if (qemuHostdevPrepareNVMeDisks(driver, def->name, def->disks, def->ndisks) < 0)
354 return -1;
355
356 if (qemuHostdevPreparePCIDevices(driver, def->name, def->uuid,
357 def->hostdevs, def->nhostdevs,
358 qemuCaps, flags) < 0)
359 return -1;
360
361 if (qemuHostdevPrepareUSBDevices(driver, def->name,
362 def->hostdevs, def->nhostdevs, flags) < 0)
363 return -1;
364
365 if (qemuHostdevPrepareSCSIDevices(driver, def->name,
366 def->hostdevs, def->nhostdevs) < 0)
367 return -1;
368
369 if (qemuHostdevPrepareSCSIVHostDevices(driver, def->name,
370 def->hostdevs, def->nhostdevs) < 0)
371 return -1;
372
373 if (qemuHostdevPrepareMediatedDevices(driver, def->name,
374 def->hostdevs, def->nhostdevs) < 0)
375 return -1;
376
377 return 0;
378 }
379
380 void
qemuHostdevReAttachOneNVMeDisk(virQEMUDriver * driver,const char * name,virStorageSource * src)381 qemuHostdevReAttachOneNVMeDisk(virQEMUDriver *driver,
382 const char *name,
383 virStorageSource *src)
384 {
385 virHostdevReAttachOneNVMeDevice(driver->hostdevMgr,
386 QEMU_DRIVER_NAME,
387 name,
388 src);
389 }
390
391 void
qemuHostdevReAttachNVMeDisks(virQEMUDriver * driver,const char * name,virDomainDiskDef ** disks,size_t ndisks)392 qemuHostdevReAttachNVMeDisks(virQEMUDriver *driver,
393 const char *name,
394 virDomainDiskDef **disks,
395 size_t ndisks)
396 {
397 virHostdevReAttachNVMeDevices(driver->hostdevMgr,
398 QEMU_DRIVER_NAME,
399 name, disks, ndisks);
400 }
401
402 void
qemuHostdevReAttachPCIDevices(virQEMUDriver * driver,const char * name,virDomainHostdevDef ** hostdevs,int nhostdevs)403 qemuHostdevReAttachPCIDevices(virQEMUDriver *driver,
404 const char *name,
405 virDomainHostdevDef **hostdevs,
406 int nhostdevs)
407 {
408 virHostdevManager *hostdev_mgr = driver->hostdevMgr;
409
410 virHostdevReAttachPCIDevices(hostdev_mgr, QEMU_DRIVER_NAME, name,
411 hostdevs, nhostdevs);
412 }
413
414 void
qemuHostdevReAttachUSBDevices(virQEMUDriver * driver,const char * name,virDomainHostdevDef ** hostdevs,int nhostdevs)415 qemuHostdevReAttachUSBDevices(virQEMUDriver *driver,
416 const char *name,
417 virDomainHostdevDef **hostdevs,
418 int nhostdevs)
419 {
420 virHostdevManager *hostdev_mgr = driver->hostdevMgr;
421
422 virHostdevReAttachUSBDevices(hostdev_mgr, QEMU_DRIVER_NAME,
423 name, hostdevs, nhostdevs);
424 }
425
426 void
qemuHostdevReAttachSCSIDevices(virQEMUDriver * driver,const char * name,virDomainHostdevDef ** hostdevs,int nhostdevs)427 qemuHostdevReAttachSCSIDevices(virQEMUDriver *driver,
428 const char *name,
429 virDomainHostdevDef **hostdevs,
430 int nhostdevs)
431 {
432 size_t i;
433 virHostdevManager *hostdev_mgr = driver->hostdevMgr;
434
435 for (i = 0; i < nhostdevs; i++) {
436 virDomainHostdevDef *hostdev = hostdevs[i];
437 virDomainDeviceDef dev;
438
439 dev.type = VIR_DOMAIN_DEVICE_HOSTDEV;
440 dev.data.hostdev = hostdev;
441
442 ignore_value(qemuRemoveSharedDevice(driver, &dev, name));
443 }
444
445 virHostdevReAttachSCSIDevices(hostdev_mgr, QEMU_DRIVER_NAME,
446 name, hostdevs, nhostdevs);
447 }
448
449 void
qemuHostdevReAttachSCSIVHostDevices(virQEMUDriver * driver,const char * name,virDomainHostdevDef ** hostdevs,int nhostdevs)450 qemuHostdevReAttachSCSIVHostDevices(virQEMUDriver *driver,
451 const char *name,
452 virDomainHostdevDef **hostdevs,
453 int nhostdevs)
454 {
455 virHostdevManager *hostdev_mgr = driver->hostdevMgr;
456
457 virHostdevReAttachSCSIVHostDevices(hostdev_mgr, QEMU_DRIVER_NAME,
458 name, hostdevs, nhostdevs);
459 }
460
461 void
qemuHostdevReAttachMediatedDevices(virQEMUDriver * driver,const char * name,virDomainHostdevDef ** hostdevs,int nhostdevs)462 qemuHostdevReAttachMediatedDevices(virQEMUDriver *driver,
463 const char *name,
464 virDomainHostdevDef **hostdevs,
465 int nhostdevs)
466 {
467 virHostdevManager *hostdev_mgr = driver->hostdevMgr;
468
469 virHostdevReAttachMediatedDevices(hostdev_mgr, QEMU_DRIVER_NAME,
470 name, hostdevs, nhostdevs);
471 }
472
473 void
qemuHostdevReAttachDomainDevices(virQEMUDriver * driver,virDomainDef * def)474 qemuHostdevReAttachDomainDevices(virQEMUDriver *driver,
475 virDomainDef *def)
476 {
477 if (!def->nhostdevs && !def->ndisks)
478 return;
479
480 qemuHostdevReAttachNVMeDisks(driver, def->name, def->disks,
481 def->ndisks);
482
483 qemuHostdevReAttachPCIDevices(driver, def->name, def->hostdevs,
484 def->nhostdevs);
485
486 qemuHostdevReAttachUSBDevices(driver, def->name, def->hostdevs,
487 def->nhostdevs);
488
489 qemuHostdevReAttachSCSIDevices(driver, def->name, def->hostdevs,
490 def->nhostdevs);
491
492 qemuHostdevReAttachSCSIVHostDevices(driver, def->name, def->hostdevs,
493 def->nhostdevs);
494
495 qemuHostdevReAttachMediatedDevices(driver, def->name, def->hostdevs,
496 def->nhostdevs);
497 }
498