Add missing libxml2-tools dependency
[archive/platform/upstream/libvirt.git] / tests / virhostdevtest.c
1 /*
2  * Copyright (C) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library.  If not, see
16  * <http://www.gnu.org/licenses/>.
17  *
18  * Author: Chunyan Liu <cyliu@suse.com>
19  */
20
21 #include <config.h>
22
23 #include "testutils.h"
24
25 #ifdef __linux__
26
27 # include <stdlib.h>
28 # include <stdio.h>
29 # include <sys/types.h>
30 # include <sys/stat.h>
31 # include <sys/ioctl.h>
32 # include <fcntl.h>
33 # include "virlog.h"
34 # include "virhostdev.h"
35
36 # define VIR_FROM_THIS VIR_FROM_NONE
37
38 VIR_LOG_INIT("tests.hostdevtest");
39
40 # define CHECK_LIST_COUNT(list, cnt)                                    \
41     if ((count = virPCIDeviceListCount(list)) != cnt) {                 \
42         virReportError(VIR_ERR_INTERNAL_ERROR,                          \
43                        "Unexpected count of items in " #list ": %d, "   \
44                        "expecting %zu", count, (size_t) cnt);           \
45         goto cleanup;                                                   \
46     }
47
48 # define TEST_STATE_DIR abs_builddir "/hostdevmgr"
49 static const char *drv_name = "test_driver";
50 static const char *dom_name = "test_domain";
51 static const unsigned char *uuid =
52             (unsigned char *)("f92360b0-2541-8791-fb32-d1f838811541");
53 static int nhostdevs = 3;
54 static virDomainHostdevDefPtr hostdevs[] = {NULL, NULL, NULL};
55 static virPCIDevicePtr dev[] = {NULL, NULL, NULL};
56 static virHostdevManagerPtr mgr = NULL;
57
58 static void
59 myCleanup(void)
60 {
61     size_t i;
62     for (i = 0; i < nhostdevs; i++) {
63          virPCIDeviceFree(dev[i]);
64          virDomainHostdevDefFree(hostdevs[i]);
65     }
66
67     if (mgr) {
68         if (mgr->stateDir && !getenv("LIBVIRT_SKIP_CLEANUP"))
69             virFileDeleteTree(mgr->stateDir);
70
71         virObjectUnref(mgr->activePCIHostdevs);
72         virObjectUnref(mgr->inactivePCIHostdevs);
73         virObjectUnref(mgr->activeUSBHostdevs);
74         VIR_FREE(mgr->stateDir);
75         VIR_FREE(mgr);
76     }
77 }
78
79 static int
80 myInit(void)
81 {
82     size_t i;
83
84     for (i = 0; i < nhostdevs; i++) {
85         virDomainHostdevSubsys subsys;
86         hostdevs[i] = virDomainHostdevDefAlloc();
87         if (!hostdevs[i])
88             goto cleanup;
89         hostdevs[i]->mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS;
90         subsys.type = VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI;
91         subsys.u.pci.addr.domain = 0;
92         subsys.u.pci.addr.bus = 0;
93         subsys.u.pci.addr.slot = i + 1;
94         subsys.u.pci.addr.function = 0;
95         subsys.u.pci.backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM;
96         hostdevs[i]->source.subsys = subsys;
97     }
98
99     for (i = 0; i < nhostdevs; i++) {
100         if (!(dev[i] = virPCIDeviceNew(0, 0, i + 1, 0)) ||
101             virPCIDeviceSetStubDriver(dev[i], "pci-stub") < 0)
102             goto cleanup;
103     }
104
105     if (VIR_ALLOC(mgr) < 0)
106         goto cleanup;
107     if ((mgr->activePCIHostdevs = virPCIDeviceListNew()) == NULL)
108         goto cleanup;
109     if ((mgr->activeUSBHostdevs = virUSBDeviceListNew()) == NULL)
110         goto cleanup;
111     if ((mgr->inactivePCIHostdevs = virPCIDeviceListNew()) == NULL)
112         goto cleanup;
113     if ((mgr->activeSCSIHostdevs = virSCSIDeviceListNew()) == NULL)
114         goto cleanup;
115     if (VIR_STRDUP(mgr->stateDir, TEST_STATE_DIR) < 0)
116         goto cleanup;
117     if (virFileMakePath(mgr->stateDir) < 0)
118         goto cleanup;
119
120     return 0;
121
122  cleanup:
123     myCleanup();
124     return -1;
125 }
126
127 # if HAVE_LINUX_KVM_H
128 #  include <linux/kvm.h>
129 static bool
130 virHostdevHostSupportsPassthroughKVM(void)
131 {
132     int kvmfd = -1;
133     bool ret = false;
134
135     if ((kvmfd = open("/dev/kvm", O_RDONLY)) < 0)
136         goto cleanup;
137
138 #  ifdef KVM_CAP_IOMMU
139     if ((ioctl(kvmfd, KVM_CHECK_EXTENSION, KVM_CAP_IOMMU)) <= 0)
140         goto cleanup;
141
142     ret = true;
143 #  endif
144
145  cleanup:
146     VIR_FORCE_CLOSE(kvmfd);
147
148     return ret;
149 }
150 # else
151 static bool
152 virHostdevHostSupportsPassthroughKVM(void)
153 {
154     return false;
155 }
156 # endif
157
158 static int
159 testVirHostdevPreparePCIHostdevs_unmanaged(const void *oaque ATTRIBUTE_UNUSED)
160 {
161     int ret = -1;
162     size_t i;
163     int count, count1, count2;
164
165     for (i = 0; i < nhostdevs; i++)
166          hostdevs[i]->managed = false;
167
168     count1 = virPCIDeviceListCount(mgr->activePCIHostdevs);
169     count2 = virPCIDeviceListCount(mgr->inactivePCIHostdevs);
170
171     /* Test normal functionality */
172     VIR_DEBUG("Test 0 hostdevs\n");
173     if (virHostdevPreparePCIDevices(mgr, drv_name, dom_name, uuid,
174                                     NULL, 0, 0) < 0)
175         goto cleanup;
176     CHECK_LIST_COUNT(mgr->activePCIHostdevs, count1);
177
178     /* Test unmanaged hostdevs */
179     VIR_DEBUG("Test >=1 unmanaged hostdevs\n");
180     if (virHostdevPreparePCIDevices(mgr, drv_name, dom_name, uuid,
181                                     hostdevs, nhostdevs, 0) < 0)
182         goto cleanup;
183     CHECK_LIST_COUNT(mgr->activePCIHostdevs, count1 + 3);
184     CHECK_LIST_COUNT(mgr->inactivePCIHostdevs, count2 - 3);
185
186     /* Test conflict */
187     count1 = virPCIDeviceListCount(mgr->activePCIHostdevs);
188     count2 = virPCIDeviceListCount(mgr->inactivePCIHostdevs);
189     VIR_DEBUG("Test: prepare same hostdevs for same driver/domain again\n");
190     if (!virHostdevPreparePCIDevices(mgr, drv_name, dom_name, uuid,
191                                      &hostdevs[0], 1, 0))
192         goto cleanup;
193     CHECK_LIST_COUNT(mgr->activePCIHostdevs, count1);
194     CHECK_LIST_COUNT(mgr->inactivePCIHostdevs, count2);
195
196     VIR_DEBUG("Test: prepare same hostdevs for same driver, diff domain again\n");
197     if (!virHostdevPreparePCIDevices(mgr, drv_name, "test_domain1", uuid,
198                                      &hostdevs[1], 1, 0))
199         goto cleanup;
200     CHECK_LIST_COUNT(mgr->activePCIHostdevs, count1);
201     CHECK_LIST_COUNT(mgr->inactivePCIHostdevs, count2);
202
203     VIR_DEBUG("Test: prepare same hostdevs for diff driver/domain again\n");
204     if (!virHostdevPreparePCIDevices(mgr, "test_driver1", dom_name, uuid,
205                                      &hostdevs[2], 1, 0))
206         goto cleanup;
207     CHECK_LIST_COUNT(mgr->activePCIHostdevs, count1);
208     CHECK_LIST_COUNT(mgr->inactivePCIHostdevs, count2);
209
210     ret = 0;
211
212  cleanup:
213     return ret;
214
215 }
216
217 static int
218 testVirHostdevReAttachPCIHostdevs_unmanaged(const void *oaque ATTRIBUTE_UNUSED)
219 {
220     int ret = -1;
221     size_t i;
222     int count, count1, count2;
223
224     for (i = 0; i < nhostdevs; i++) {
225         if (hostdevs[i]->managed != false) {
226             VIR_DEBUG("invalid test\n");
227             return -1;
228         }
229     }
230
231     count1 = virPCIDeviceListCount(mgr->activePCIHostdevs);
232     count2 = virPCIDeviceListCount(mgr->inactivePCIHostdevs);
233
234     VIR_DEBUG("Test 0 hostdevs\n");
235     virHostdevReAttachPCIDevices(mgr, drv_name, dom_name, NULL, 0, NULL);
236     CHECK_LIST_COUNT(mgr->activePCIHostdevs, count1);
237
238     VIR_DEBUG("Test >=1 unmanaged hostdevs\n");
239     virHostdevReAttachPCIDevices(mgr, drv_name, dom_name,
240                                   hostdevs, nhostdevs, NULL);
241     CHECK_LIST_COUNT(mgr->activePCIHostdevs, count1 - 3);
242     CHECK_LIST_COUNT(mgr->inactivePCIHostdevs, count2 + 3);
243
244     ret = 0;
245
246  cleanup:
247     return ret;
248
249 }
250
251 static int
252 testVirHostdevPreparePCIHostdevs_managed(const void *oaque ATTRIBUTE_UNUSED)
253 {
254     int ret = -1;
255     size_t i;
256     int count, count1;
257
258     for (i = 0; i < nhostdevs; i++)
259         hostdevs[i]->managed = true;
260
261     count1 = virPCIDeviceListCount(mgr->activePCIHostdevs);
262
263     /* Test normal functionality */
264     VIR_DEBUG("Test >=1 hostdevs\n");
265     if (virHostdevPreparePCIDevices(mgr, drv_name, dom_name, uuid,
266                                      hostdevs, nhostdevs, 0) < 0)
267         goto cleanup;
268     CHECK_LIST_COUNT(mgr->activePCIHostdevs, count1 + 3);
269
270     /* Test conflict */
271     count1 = virPCIDeviceListCount(mgr->activePCIHostdevs);
272     VIR_DEBUG("Test: prepare same hostdevs for same driver/domain again\n");
273     if (!virHostdevPreparePCIDevices(mgr, drv_name, dom_name, uuid,
274                                       &hostdevs[0], 1, 0))
275         goto cleanup;
276     CHECK_LIST_COUNT(mgr->activePCIHostdevs, count1);
277
278     VIR_DEBUG("Test: prepare same hostdevs for same driver, diff domain again\n");
279     if (!virHostdevPreparePCIDevices(mgr, drv_name, "test_domain1", uuid,
280                                       &hostdevs[1], 1, 0))
281         goto cleanup;
282     CHECK_LIST_COUNT(mgr->activePCIHostdevs, count1);
283
284     VIR_DEBUG("Test: prepare same hostdevs for diff driver/domain again\n");
285     if (!virHostdevPreparePCIDevices(mgr, "test_driver1", dom_name, uuid,
286                                       &hostdevs[2], 1, 0))
287         goto cleanup;
288     CHECK_LIST_COUNT(mgr->activePCIHostdevs, count1);
289
290     ret = 0;
291
292  cleanup:
293     return ret;
294
295 }
296
297 static int
298 testVirHostdevReAttachPCIHostdevs_managed(const void *oaque ATTRIBUTE_UNUSED)
299 {
300     int ret = -1;
301     size_t i;
302     int count, count1;
303
304     for (i = 0; i < nhostdevs; i++) {
305         if (hostdevs[i]->managed != true) {
306             VIR_DEBUG("invalid test\n");
307             return -1;
308         }
309     }
310
311     count1 = virPCIDeviceListCount(mgr->activePCIHostdevs);
312
313     VIR_DEBUG("Test 0 hostdevs\n");
314     virHostdevReAttachPCIDevices(mgr, drv_name, dom_name, NULL, 0, NULL);
315     CHECK_LIST_COUNT(mgr->activePCIHostdevs, count1);
316
317     VIR_DEBUG("Test >=1 hostdevs\n");
318     virHostdevReAttachPCIDevices(mgr, drv_name, dom_name,
319                                   hostdevs, nhostdevs, NULL);
320     CHECK_LIST_COUNT(mgr->activePCIHostdevs, count1 - 3);
321
322     ret = 0;
323
324  cleanup:
325     return ret;
326
327 }
328
329 static int
330 testVirHostdevDetachPCINodeDevice(const void *oaque ATTRIBUTE_UNUSED)
331 {
332     int ret = -1;
333     size_t i;
334     int count, count1;
335
336     for (i = 0; i < nhostdevs; i++) {
337         count1 = virPCIDeviceListCount(mgr->inactivePCIHostdevs);
338         if (virHostdevPCINodeDeviceDetach(mgr, dev[i]) < 0)
339             goto cleanup;
340         CHECK_LIST_COUNT(mgr->inactivePCIHostdevs, count1 + 1);
341     }
342
343     ret = 0;
344
345  cleanup:
346     return ret;
347 }
348 static int
349 testVirHostdevResetPCINodeDevice(const void *oaque ATTRIBUTE_UNUSED)
350 {
351     int ret = -1;
352     size_t i;
353
354     for (i = 0; i < nhostdevs; i++) {
355         if (virHostdevPCINodeDeviceReset(mgr, dev[i]) < 0)
356             goto cleanup;
357     }
358
359     ret = 0;
360
361  cleanup:
362     return ret;
363
364 }
365
366 static int
367 testVirHostdevReAttachPCINodeDevice(const void *oaque ATTRIBUTE_UNUSED)
368 {
369     int ret = -1;
370     size_t i;
371     int count, count1;
372
373     for (i = 0; i < nhostdevs; i++) {
374         count1 = virPCIDeviceListCount(mgr->inactivePCIHostdevs);
375         if (virHostdevPCINodeDeviceReAttach(mgr, dev[i]) < 0)
376             goto cleanup;
377         CHECK_LIST_COUNT(mgr->inactivePCIHostdevs, count1 - 1);
378     }
379
380     ret = 0;
381
382  cleanup:
383     return ret;
384
385 }
386
387 static int
388 testVirHostdevUpdateActivePCIHostdevs(const void *oaque ATTRIBUTE_UNUSED)
389 {
390     int ret = -1;
391     int count, count1;
392
393     count1 = virPCIDeviceListCount(mgr->activePCIHostdevs);
394
395     VIR_DEBUG("Test 0 hostdevs\n");
396     if (virHostdevUpdateActivePCIDevices(mgr, NULL, 0,
397                                          drv_name, dom_name) < 0)
398         goto cleanup;
399     CHECK_LIST_COUNT(mgr->activePCIHostdevs, count1);
400
401     VIR_DEBUG("Test >=1 hostdevs\n");
402     if (virHostdevUpdateActivePCIDevices(mgr, hostdevs, nhostdevs,
403                                          drv_name, dom_name) < 0)
404         goto cleanup;
405     CHECK_LIST_COUNT(mgr->activePCIHostdevs, count1 + 3);
406
407     ret = 0;
408
409  cleanup:
410     return ret;
411 }
412
413 # define FAKESYSFSDIRTEMPLATE abs_builddir "/fakesysfsdir-XXXXXX"
414
415 static int
416 mymain(void)
417 {
418     int ret = 0;
419     char *fakesysfsdir;
420
421     if (VIR_STRDUP_QUIET(fakesysfsdir, FAKESYSFSDIRTEMPLATE) < 0) {
422         fprintf(stderr, "Out of memory\n");
423         abort();
424     }
425
426     if (!mkdtemp(fakesysfsdir)) {
427         fprintf(stderr, "Cannot create fakesysfsdir");
428         abort();
429     }
430
431     setenv("LIBVIRT_FAKE_SYSFS_DIR", fakesysfsdir, 1);
432
433 # define DO_TEST(fnc)                                   \
434     do {                                                \
435         VIR_DEBUG("\nTesting: %s", #fnc);                 \
436         if (virtTestRun(#fnc, fnc, NULL) < 0)           \
437             ret = -1;                                   \
438     } while (0)
439
440     if (myInit() < 0)
441         fprintf(stderr, "Init data structures failed.");
442
443     DO_TEST(testVirHostdevDetachPCINodeDevice);
444     if (virHostdevHostSupportsPassthroughKVM()) {
445         /* following tests would check KVM support */
446         DO_TEST(testVirHostdevPreparePCIHostdevs_unmanaged);
447         DO_TEST(testVirHostdevReAttachPCIHostdevs_unmanaged);
448     }
449     DO_TEST(testVirHostdevResetPCINodeDevice);
450     DO_TEST(testVirHostdevReAttachPCINodeDevice);
451     if (virHostdevHostSupportsPassthroughKVM()) {
452         /* following tests would check KVM support */
453         DO_TEST(testVirHostdevPreparePCIHostdevs_managed);
454         DO_TEST(testVirHostdevReAttachPCIHostdevs_managed);
455     }
456     DO_TEST(testVirHostdevUpdateActivePCIHostdevs);
457
458     myCleanup();
459
460     if (getenv("LIBVIRT_SKIP_CLEANUP") == NULL)
461         virFileDeleteTree(fakesysfsdir);
462
463     VIR_FREE(fakesysfsdir);
464
465     return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
466 }
467
468 VIRT_TEST_MAIN_PRELOAD(mymain, abs_builddir "/.libs/virpcimock.so")
469 #else
470 int
471 main(void)
472 {
473     return EXIT_AM_SKIP;
474 }
475 #endif