Add missing libxml2-tools dependency
[archive/platform/upstream/libvirt.git] / tests / virpcitest.c
1 /*
2  * Copyright (C) 2013, 2014 Red Hat, Inc.
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: Michal Privoznik <mprivozn@redhat.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 <fcntl.h>
32 # include <virpci.h>
33
34 # define VIR_FROM_THIS VIR_FROM_NONE
35
36 static int
37 testVirPCIDeviceCheckDriver(virPCIDevicePtr dev, const char *expected)
38 {
39     char *path = NULL;
40     char *driver = NULL;
41     int ret = -1;
42
43     if (virPCIDeviceGetDriverPathAndName(dev, &path, &driver) < 0)
44         goto cleanup;
45
46     if (STRNEQ_NULLABLE(driver, expected)) {
47         virReportError(VIR_ERR_INTERNAL_ERROR,
48                        "PCI device %s driver mismatch: %s, expecting %s",
49                        virPCIDeviceGetName(dev), NULLSTR(driver),
50                        NULLSTR(expected));
51         goto cleanup;
52     }
53
54     ret = 0;
55  cleanup:
56     VIR_FREE(path);
57     VIR_FREE(driver);
58     return ret;
59 }
60
61 static int
62 testVirPCIDeviceNew(const void *opaque ATTRIBUTE_UNUSED)
63 {
64     int ret = -1;
65     virPCIDevicePtr dev;
66     const char *devName;
67
68     if (!(dev = virPCIDeviceNew(0, 0, 0, 0)))
69         goto cleanup;
70
71     devName = virPCIDeviceGetName(dev);
72     if (STRNEQ(devName, "0000:00:00.0")) {
73         virReportError(VIR_ERR_INTERNAL_ERROR,
74                        "PCI device name mismatch: %s, expecting %s",
75                        devName, "0000:00:00.0");
76         goto cleanup;
77     }
78
79     ret = 0;
80  cleanup:
81     virPCIDeviceFree(dev);
82     return ret;
83 }
84
85 # define CHECK_LIST_COUNT(list, cnt)                                    \
86     if ((count = virPCIDeviceListCount(list)) != cnt) {                 \
87         virReportError(VIR_ERR_INTERNAL_ERROR,                          \
88                        "Unexpected count of items in " #list ": %d, "   \
89                        "expecting %zu", count, (size_t) cnt);           \
90         goto cleanup;                                                   \
91     }
92
93 static int
94 testVirPCIDeviceDetach(const void *oaque ATTRIBUTE_UNUSED)
95 {
96     int ret = -1;
97     virPCIDevicePtr dev[] = {NULL, NULL, NULL};
98     size_t i, nDev = ARRAY_CARDINALITY(dev);
99     virPCIDeviceListPtr activeDevs = NULL, inactiveDevs = NULL;
100     int count;
101
102     if (!(activeDevs = virPCIDeviceListNew()) ||
103         !(inactiveDevs = virPCIDeviceListNew()))
104         goto cleanup;
105
106     CHECK_LIST_COUNT(activeDevs, 0);
107     CHECK_LIST_COUNT(inactiveDevs, 0);
108
109     for (i = 0; i < nDev; i++) {
110         if (!(dev[i] = virPCIDeviceNew(0, 0, i + 1, 0)) ||
111             virPCIDeviceSetStubDriver(dev[i], "pci-stub") < 0)
112             goto cleanup;
113
114         if (virPCIDeviceDetach(dev[i], activeDevs, inactiveDevs) < 0)
115             goto cleanup;
116
117         if (testVirPCIDeviceCheckDriver(dev[i], "pci-stub") < 0)
118             goto cleanup;
119
120         CHECK_LIST_COUNT(activeDevs, 0);
121         CHECK_LIST_COUNT(inactiveDevs, i + 1);
122     }
123
124     ret = 0;
125  cleanup:
126     for (i = 0; i < nDev; i++)
127         virPCIDeviceFree(dev[i]);
128     virObjectUnref(activeDevs);
129     virObjectUnref(inactiveDevs);
130     return ret;
131 }
132
133 static int
134 testVirPCIDeviceReset(const void *opaque ATTRIBUTE_UNUSED)
135 {
136     int ret = -1;
137     virPCIDevicePtr dev[] = {NULL, NULL, NULL};
138     size_t i, nDev = ARRAY_CARDINALITY(dev);
139     virPCIDeviceListPtr activeDevs = NULL, inactiveDevs = NULL;
140     int count;
141
142     if (!(activeDevs = virPCIDeviceListNew()) ||
143         !(inactiveDevs = virPCIDeviceListNew()))
144         goto cleanup;
145
146     CHECK_LIST_COUNT(activeDevs, 0);
147     CHECK_LIST_COUNT(inactiveDevs, 0);
148
149     for (i = 0; i < nDev; i++) {
150         if (!(dev[i] = virPCIDeviceNew(0, 0, i + 1, 0)) ||
151             virPCIDeviceSetStubDriver(dev[i], "pci-stub") < 0)
152             goto cleanup;
153
154         if (virPCIDeviceReset(dev[i], activeDevs, inactiveDevs) < 0)
155             goto cleanup;
156     }
157
158     ret = 0;
159  cleanup:
160     for (i = 0; i < nDev; i++)
161         virPCIDeviceFree(dev[i]);
162     virObjectUnref(activeDevs);
163     virObjectUnref(inactiveDevs);
164     return ret;
165 }
166
167 static int
168 testVirPCIDeviceReattach(const void *opaque ATTRIBUTE_UNUSED)
169 {
170     int ret = -1;
171     virPCIDevicePtr dev[] = {NULL, NULL, NULL};
172     size_t i, nDev = ARRAY_CARDINALITY(dev);
173     virPCIDeviceListPtr activeDevs = NULL, inactiveDevs = NULL;
174     int count;
175
176     if (!(activeDevs = virPCIDeviceListNew()) ||
177         !(inactiveDevs = virPCIDeviceListNew()))
178         goto cleanup;
179
180     for (i = 0; i < nDev; i++) {
181         if (!(dev[i] = virPCIDeviceNew(0, 0, i + 1, 0)))
182             goto cleanup;
183
184         if (virPCIDeviceListAdd(inactiveDevs, dev[i]) < 0) {
185             virPCIDeviceFree(dev[i]);
186             goto cleanup;
187         }
188
189         CHECK_LIST_COUNT(activeDevs, 0);
190         CHECK_LIST_COUNT(inactiveDevs, i + 1);
191
192         if (virPCIDeviceSetStubDriver(dev[i], "pci-stub") < 0)
193             goto cleanup;
194     }
195
196     CHECK_LIST_COUNT(activeDevs, 0);
197     CHECK_LIST_COUNT(inactiveDevs, nDev);
198
199     for (i = 0; i < nDev; i++) {
200         if (virPCIDeviceReattach(dev[i], activeDevs, inactiveDevs) < 0)
201             goto cleanup;
202
203         CHECK_LIST_COUNT(activeDevs, 0);
204         CHECK_LIST_COUNT(inactiveDevs, nDev - i - 1);
205     }
206
207     ret = 0;
208  cleanup:
209     virObjectUnref(activeDevs);
210     virObjectUnref(inactiveDevs);
211     return ret;
212 }
213
214 struct testPCIDevData {
215     unsigned int domain;
216     unsigned int bus;
217     unsigned int slot;
218     unsigned int function;
219     const char *driver;
220 };
221
222 static int
223 testVirPCIDeviceIsAssignable(const void *opaque)
224 {
225     const struct testPCIDevData *data = opaque;
226     int ret = -1;
227     virPCIDevicePtr dev;
228
229     if (!(dev = virPCIDeviceNew(data->domain, data->bus, data->slot, data->function)))
230         goto cleanup;
231
232     if (virPCIDeviceIsAssignable(dev, true))
233         ret = 0;
234
235     virPCIDeviceFree(dev);
236  cleanup:
237     return ret;
238 }
239
240 static int
241 testVirPCIDeviceDetachSingle(const void *opaque)
242 {
243     const struct testPCIDevData *data = opaque;
244     int ret = -1;
245     virPCIDevicePtr dev;
246
247     dev = virPCIDeviceNew(data->domain, data->bus, data->slot, data->function);
248     if (!dev)
249         goto cleanup;
250
251     if (virPCIDeviceSetStubDriver(dev, "pci-stub") < 0 ||
252         virPCIDeviceDetach(dev, NULL, NULL) < 0)
253         goto cleanup;
254
255     ret = 0;
256  cleanup:
257     virPCIDeviceFree(dev);
258     return ret;
259 }
260
261 static int
262 testVirPCIDeviceDetachFail(const void *opaque)
263 {
264     const struct testPCIDevData *data = opaque;
265     int ret = -1;
266     virPCIDevicePtr dev;
267
268     dev = virPCIDeviceNew(data->domain, data->bus, data->slot, data->function);
269     if (!dev)
270         goto cleanup;
271
272     if (virPCIDeviceSetStubDriver(dev, "vfio-pci") < 0)
273         goto cleanup;
274
275     if (virPCIDeviceDetach(dev, NULL, NULL) < 0) {
276         if (virTestGetVerbose() || virTestGetDebug())
277             virDispatchError(NULL);
278         virResetLastError();
279         ret = 0;
280     } else {
281         virReportError(VIR_ERR_INTERNAL_ERROR,
282                        "Attaching device %s to %s should have failed",
283                        virPCIDeviceGetName(dev),
284                        virPCIDeviceGetStubDriver(dev));
285     }
286
287  cleanup:
288     virPCIDeviceFree(dev);
289     return ret;
290 }
291
292 static int
293 testVirPCIDeviceReattachSingle(const void *opaque)
294 {
295     const struct testPCIDevData *data = opaque;
296     int ret = -1;
297     virPCIDevicePtr dev;
298
299     dev = virPCIDeviceNew(data->domain, data->bus, data->slot, data->function);
300     if (!dev)
301         goto cleanup;
302
303     virPCIDeviceReattachInit(dev);
304     if (virPCIDeviceReattach(dev, NULL, NULL) < 0)
305         goto cleanup;
306
307     ret = 0;
308  cleanup:
309     virPCIDeviceFree(dev);
310     return ret;
311 }
312
313 static int
314 testVirPCIDeviceCheckDriverTest(const void *opaque)
315 {
316     const struct testPCIDevData *data = opaque;
317     int ret = -1;
318     virPCIDevicePtr dev;
319
320     dev = virPCIDeviceNew(data->domain, data->bus, data->slot, data->function);
321     if (!dev)
322         goto cleanup;
323
324     if (testVirPCIDeviceCheckDriver(dev, data->driver) < 0)
325         goto cleanup;
326
327     ret = 0;
328  cleanup:
329     virPCIDeviceFree(dev);
330     return ret;
331 }
332
333 static int
334 testVirPCIDeviceUnbind(const void *opaque)
335 {
336     const struct testPCIDevData *data = opaque;
337     int ret = -1;
338     virPCIDevicePtr dev;
339
340     dev = virPCIDeviceNew(data->domain, data->bus, data->slot, data->function);
341     if (!dev)
342         goto cleanup;
343
344     if (virPCIDeviceUnbind(dev, false) < 0)
345         goto cleanup;
346
347     ret = 0;
348  cleanup:
349     virPCIDeviceFree(dev);
350     return ret;
351 }
352
353 # define FAKESYSFSDIRTEMPLATE abs_builddir "/fakesysfsdir-XXXXXX"
354
355 static int
356 mymain(void)
357 {
358     int ret = 0;
359     char *fakesysfsdir;
360
361     if (VIR_STRDUP_QUIET(fakesysfsdir, FAKESYSFSDIRTEMPLATE) < 0) {
362         fprintf(stderr, "Out of memory\n");
363         abort();
364     }
365
366     if (!mkdtemp(fakesysfsdir)) {
367         fprintf(stderr, "Cannot create fakesysfsdir");
368         abort();
369     }
370
371     setenv("LIBVIRT_FAKE_SYSFS_DIR", fakesysfsdir, 1);
372
373 # define DO_TEST(fnc)                                   \
374     do {                                                \
375         if (virtTestRun(#fnc, fnc, NULL) < 0)           \
376             ret = -1;                                   \
377     } while (0)
378
379 # define DO_TEST_PCI(fnc, domain, bus, slot, function)                  \
380     do {                                                                \
381         struct testPCIDevData data = {                                  \
382             domain, bus, slot, function, NULL                           \
383         };                                                              \
384         char *label = NULL;                                             \
385         if (virAsprintf(&label, "%s(%04x:%02x:%02x.%x)",                \
386                         #fnc, domain, bus, slot, function) < 0) {       \
387             ret = -1;                                                   \
388             break;                                                      \
389         }                                                               \
390         if (virtTestRun(label, fnc, &data) < 0)                         \
391             ret = -1;                                                   \
392         VIR_FREE(label);                                                \
393     } while (0)
394
395 # define DO_TEST_PCI_DRIVER(domain, bus, slot, function, driver)        \
396     do {                                                                \
397         struct testPCIDevData data = {                                  \
398             domain, bus, slot, function, driver                         \
399         };                                                              \
400         char *label = NULL;                                             \
401         if (virAsprintf(&label, "PCI driver %04x:%02x:%02x.%x is %s",   \
402                         domain, bus, slot, function,                    \
403                         NULLSTR(driver)) < 0) {                         \
404             ret = -1;                                                   \
405             break;                                                      \
406         }                                                               \
407         if (virtTestRun(label, testVirPCIDeviceCheckDriverTest,         \
408                         &data) < 0)                                     \
409             ret = -1;                                                   \
410         VIR_FREE(label);                                                \
411     } while (0)
412
413     /* Changes made to individual devices are persistent and the
414      * tests often rely on the state set by previous tests.
415      */
416
417     DO_TEST(testVirPCIDeviceNew);
418     DO_TEST(testVirPCIDeviceDetach);
419     DO_TEST(testVirPCIDeviceReset);
420     DO_TEST(testVirPCIDeviceReattach);
421     DO_TEST_PCI(testVirPCIDeviceIsAssignable, 5, 0x90, 1, 0);
422     DO_TEST_PCI(testVirPCIDeviceIsAssignable, 1, 1, 0, 0);
423
424     DO_TEST_PCI(testVirPCIDeviceDetachFail, 0, 0x0a, 1, 0);
425
426     /* Reattach a device already bound to non-stub a driver */
427     DO_TEST_PCI_DRIVER(0, 0x0a, 1, 0, "i915");
428     DO_TEST_PCI(testVirPCIDeviceReattachSingle, 0, 0x0a, 1, 0);
429     DO_TEST_PCI_DRIVER(0, 0x0a, 1, 0, "i915");
430
431     /* Reattach an unbound device */
432     DO_TEST_PCI(testVirPCIDeviceUnbind, 0, 0x0a, 1, 0);
433     DO_TEST_PCI_DRIVER(0, 0x0a, 1, 0, NULL);
434     DO_TEST_PCI(testVirPCIDeviceReattachSingle, 0, 0x0a, 1, 0);
435     DO_TEST_PCI_DRIVER(0, 0x0a, 1, 0, "i915");
436
437     /* Detach an unbound device */
438     DO_TEST_PCI_DRIVER(0, 0x0a, 2, 0, NULL);
439     DO_TEST_PCI(testVirPCIDeviceDetachSingle, 0, 0x0a, 2, 0);
440     DO_TEST_PCI_DRIVER(0, 0x0a, 2, 0, "pci-stub");
441
442     /* Reattach an unknown unbound device */
443     DO_TEST_PCI_DRIVER(0, 0x0a, 3, 0, NULL);
444     DO_TEST_PCI(testVirPCIDeviceReattachSingle, 0, 0x0a, 3, 0);
445     DO_TEST_PCI_DRIVER(0, 0x0a, 3, 0, NULL);
446
447     if (getenv("LIBVIRT_SKIP_CLEANUP") == NULL)
448         virFileDeleteTree(fakesysfsdir);
449
450     VIR_FREE(fakesysfsdir);
451
452     return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
453 }
454
455 VIRT_TEST_MAIN_PRELOAD(mymain, abs_builddir "/.libs/virpcimock.so")
456 #else
457 int
458 main(void)
459 {
460     return EXIT_AM_SKIP;
461 }
462 #endif