Add missing libxml2-tools dependency
[archive/platform/upstream/libvirt.git] / tests / vircgrouptest.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: Daniel P. Berrange <berrange@redhat.com>
19  */
20
21 #include <config.h>
22
23 #include "testutils.h"
24
25 #ifdef __linux__
26
27 # include <stdlib.h>
28
29 # define __VIR_CGROUP_ALLOW_INCLUDE_PRIV_H__
30 # include "vircgrouppriv.h"
31 # include "virstring.h"
32 # include "virerror.h"
33 # include "virlog.h"
34 # include "virfile.h"
35 # include "testutilslxc.h"
36 # include "nodeinfo.h"
37
38 # define VIR_FROM_THIS VIR_FROM_NONE
39
40 VIR_LOG_INIT("tests.cgrouptest");
41
42 static int validateCgroup(virCgroupPtr cgroup,
43                           const char *expectPath,
44                           const char **expectMountPoint,
45                           const char **expectLinkPoint,
46                           const char **expectPlacement)
47 {
48     size_t i;
49
50     if (STRNEQ(cgroup->path, expectPath)) {
51         fprintf(stderr, "Wrong path '%s', expected '%s'\n",
52                 cgroup->path, expectPath);
53         return -1;
54     }
55
56     for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) {
57         if (STRNEQ_NULLABLE(expectMountPoint[i],
58                             cgroup->controllers[i].mountPoint)) {
59             fprintf(stderr, "Wrong mount '%s', expected '%s' for '%s'\n",
60                     cgroup->controllers[i].mountPoint,
61                     expectMountPoint[i],
62                     virCgroupControllerTypeToString(i));
63             return -1;
64         }
65         if (STRNEQ_NULLABLE(expectLinkPoint[i],
66                             cgroup->controllers[i].linkPoint)) {
67             fprintf(stderr, "Wrong link '%s', expected '%s' for '%s'\n",
68                     cgroup->controllers[i].linkPoint,
69                     expectLinkPoint[i],
70                     virCgroupControllerTypeToString(i));
71             return -1;
72         }
73         if (STRNEQ_NULLABLE(expectPlacement[i],
74                             cgroup->controllers[i].placement)) {
75             fprintf(stderr, "Wrong placement '%s', expected '%s' for '%s'\n",
76                     cgroup->controllers[i].placement,
77                     expectPlacement[i],
78                     virCgroupControllerTypeToString(i));
79             return -1;
80         }
81     }
82
83     return 0;
84 }
85
86 const char *mountsSmall[VIR_CGROUP_CONTROLLER_LAST] = {
87     [VIR_CGROUP_CONTROLLER_CPU] = "/not/really/sys/fs/cgroup/cpu,cpuacct",
88     [VIR_CGROUP_CONTROLLER_CPUACCT] = "/not/really/sys/fs/cgroup/cpu,cpuacct",
89     [VIR_CGROUP_CONTROLLER_CPUSET] = NULL,
90     [VIR_CGROUP_CONTROLLER_MEMORY] = "/not/really/sys/fs/cgroup/memory",
91     [VIR_CGROUP_CONTROLLER_DEVICES] = NULL,
92     [VIR_CGROUP_CONTROLLER_FREEZER] = NULL,
93     [VIR_CGROUP_CONTROLLER_BLKIO] = NULL,
94     [VIR_CGROUP_CONTROLLER_SYSTEMD] = NULL,
95 };
96 const char *mountsFull[VIR_CGROUP_CONTROLLER_LAST] = {
97     [VIR_CGROUP_CONTROLLER_CPU] = "/not/really/sys/fs/cgroup/cpu,cpuacct",
98     [VIR_CGROUP_CONTROLLER_CPUACCT] = "/not/really/sys/fs/cgroup/cpu,cpuacct",
99     [VIR_CGROUP_CONTROLLER_CPUSET] = "/not/really/sys/fs/cgroup/cpuset",
100     [VIR_CGROUP_CONTROLLER_MEMORY] = "/not/really/sys/fs/cgroup/memory",
101     [VIR_CGROUP_CONTROLLER_DEVICES] = NULL,
102     [VIR_CGROUP_CONTROLLER_FREEZER] = "/not/really/sys/fs/cgroup/freezer",
103     [VIR_CGROUP_CONTROLLER_BLKIO] = "/not/really/sys/fs/cgroup/blkio",
104     [VIR_CGROUP_CONTROLLER_SYSTEMD] = "/not/really/sys/fs/cgroup/systemd",
105 };
106 const char *mountsAllInOne[VIR_CGROUP_CONTROLLER_LAST] = {
107     [VIR_CGROUP_CONTROLLER_CPU] = "/not/really/sys/fs/cgroup",
108     [VIR_CGROUP_CONTROLLER_CPUACCT] = "/not/really/sys/fs/cgroup",
109     [VIR_CGROUP_CONTROLLER_CPUSET] = "/not/really/sys/fs/cgroup",
110     [VIR_CGROUP_CONTROLLER_MEMORY] = "/not/really/sys/fs/cgroup",
111     [VIR_CGROUP_CONTROLLER_DEVICES] = "/not/really/sys/fs/cgroup",
112     [VIR_CGROUP_CONTROLLER_FREEZER] = NULL,
113     [VIR_CGROUP_CONTROLLER_BLKIO] = "/not/really/sys/fs/cgroup",
114     [VIR_CGROUP_CONTROLLER_SYSTEMD] = NULL,
115 };
116 const char *mountsLogind[VIR_CGROUP_CONTROLLER_LAST] = {
117     [VIR_CGROUP_CONTROLLER_CPU] = NULL,
118     [VIR_CGROUP_CONTROLLER_CPUACCT] = NULL,
119     [VIR_CGROUP_CONTROLLER_CPUSET] = NULL,
120     [VIR_CGROUP_CONTROLLER_MEMORY] = NULL,
121     [VIR_CGROUP_CONTROLLER_DEVICES] = NULL,
122     [VIR_CGROUP_CONTROLLER_FREEZER] = NULL,
123     [VIR_CGROUP_CONTROLLER_BLKIO] = NULL,
124     [VIR_CGROUP_CONTROLLER_SYSTEMD] = "/not/really/sys/fs/cgroup/systemd",
125 };
126
127 const char *links[VIR_CGROUP_CONTROLLER_LAST] = {
128     [VIR_CGROUP_CONTROLLER_CPU] = "/not/really/sys/fs/cgroup/cpu",
129     [VIR_CGROUP_CONTROLLER_CPUACCT] = "/not/really/sys/fs/cgroup/cpuacct",
130     [VIR_CGROUP_CONTROLLER_CPUSET] = NULL,
131     [VIR_CGROUP_CONTROLLER_MEMORY] = NULL,
132     [VIR_CGROUP_CONTROLLER_DEVICES] = NULL,
133     [VIR_CGROUP_CONTROLLER_FREEZER] = NULL,
134     [VIR_CGROUP_CONTROLLER_BLKIO] = NULL,
135     [VIR_CGROUP_CONTROLLER_SYSTEMD] = NULL,
136 };
137
138 const char *linksAllInOne[VIR_CGROUP_CONTROLLER_LAST] = {
139     [VIR_CGROUP_CONTROLLER_CPU] = NULL,
140     [VIR_CGROUP_CONTROLLER_CPUACCT] = NULL,
141     [VIR_CGROUP_CONTROLLER_CPUSET] = NULL,
142     [VIR_CGROUP_CONTROLLER_MEMORY] = NULL,
143     [VIR_CGROUP_CONTROLLER_DEVICES] = NULL,
144     [VIR_CGROUP_CONTROLLER_FREEZER] = NULL,
145     [VIR_CGROUP_CONTROLLER_BLKIO] = NULL,
146     [VIR_CGROUP_CONTROLLER_SYSTEMD] = NULL,
147 };
148
149 const char *linksLogind[VIR_CGROUP_CONTROLLER_LAST] = {
150     [VIR_CGROUP_CONTROLLER_CPU] = NULL,
151     [VIR_CGROUP_CONTROLLER_CPUACCT] = NULL,
152     [VIR_CGROUP_CONTROLLER_CPUSET] = NULL,
153     [VIR_CGROUP_CONTROLLER_MEMORY] = NULL,
154     [VIR_CGROUP_CONTROLLER_DEVICES] = NULL,
155     [VIR_CGROUP_CONTROLLER_FREEZER] = NULL,
156     [VIR_CGROUP_CONTROLLER_BLKIO] = NULL,
157     [VIR_CGROUP_CONTROLLER_SYSTEMD] = NULL,
158 };
159
160
161 static int testCgroupNewForSelf(const void *args ATTRIBUTE_UNUSED)
162 {
163     virCgroupPtr cgroup = NULL;
164     int ret = -1;
165     const char *placement[VIR_CGROUP_CONTROLLER_LAST] = {
166         [VIR_CGROUP_CONTROLLER_CPU] = "/system",
167         [VIR_CGROUP_CONTROLLER_CPUACCT] = "/system",
168         [VIR_CGROUP_CONTROLLER_CPUSET] = "/",
169         [VIR_CGROUP_CONTROLLER_MEMORY] = "/",
170         [VIR_CGROUP_CONTROLLER_DEVICES] = NULL,
171         [VIR_CGROUP_CONTROLLER_FREEZER] = "/",
172         [VIR_CGROUP_CONTROLLER_BLKIO] = "/",
173         [VIR_CGROUP_CONTROLLER_SYSTEMD] = "/user/berrange/123",
174     };
175
176     if (virCgroupNewSelf(&cgroup) < 0) {
177         fprintf(stderr, "Cannot create cgroup for self\n");
178         goto cleanup;
179     }
180
181     ret = validateCgroup(cgroup, "", mountsFull, links, placement);
182
183  cleanup:
184     virCgroupFree(&cgroup);
185     return ret;
186 }
187
188
189 # define ENSURE_ERRNO(en)                                           \
190     do {                                                            \
191     if (!virLastErrorIsSystemErrno(en)) {                           \
192         virErrorPtr err = virGetLastError();                        \
193         fprintf(stderr, "Did not get " #en " error code: %d:%d\n",  \
194                 err ? err->code : 0, err ? err->int1 : 0);          \
195         goto cleanup;                                               \
196     } } while (0)
197
198     /* Asking for impossible combination since CPU is co-mounted */
199
200
201 static int testCgroupNewForPartition(const void *args ATTRIBUTE_UNUSED)
202 {
203     virCgroupPtr cgroup = NULL;
204     int ret = -1;
205     int rv;
206     const char *placementSmall[VIR_CGROUP_CONTROLLER_LAST] = {
207         [VIR_CGROUP_CONTROLLER_CPU] = "/virtualmachines.partition",
208         [VIR_CGROUP_CONTROLLER_CPUACCT] = "/virtualmachines.partition",
209         [VIR_CGROUP_CONTROLLER_CPUSET] = NULL,
210         [VIR_CGROUP_CONTROLLER_MEMORY] = "/virtualmachines.partition",
211         [VIR_CGROUP_CONTROLLER_DEVICES] = NULL,
212         [VIR_CGROUP_CONTROLLER_FREEZER] = NULL,
213         [VIR_CGROUP_CONTROLLER_BLKIO] = NULL,
214         [VIR_CGROUP_CONTROLLER_SYSTEMD] = NULL,
215     };
216     const char *placementFull[VIR_CGROUP_CONTROLLER_LAST] = {
217         [VIR_CGROUP_CONTROLLER_CPU] = "/virtualmachines.partition",
218         [VIR_CGROUP_CONTROLLER_CPUACCT] = "/virtualmachines.partition",
219         [VIR_CGROUP_CONTROLLER_CPUSET] = "/virtualmachines.partition",
220         [VIR_CGROUP_CONTROLLER_MEMORY] = "/virtualmachines.partition",
221         [VIR_CGROUP_CONTROLLER_DEVICES] = NULL,
222         [VIR_CGROUP_CONTROLLER_FREEZER] = "/virtualmachines.partition",
223         [VIR_CGROUP_CONTROLLER_BLKIO] = "/virtualmachines.partition",
224         [VIR_CGROUP_CONTROLLER_SYSTEMD] = "/user/berrange/123",
225     };
226
227     if ((rv = virCgroupNewPartition("/virtualmachines", false, -1, &cgroup)) != -1) {
228         fprintf(stderr, "Unexpected found /virtualmachines cgroup: %d\n", -rv);
229         goto cleanup;
230     }
231     ENSURE_ERRNO(ENOENT);
232
233     /* Asking for impossible combination since CPU is co-mounted */
234     if ((rv = virCgroupNewPartition("/virtualmachines", true,
235                                     (1 << VIR_CGROUP_CONTROLLER_CPU),
236                                     &cgroup)) != -1) {
237         fprintf(stderr, "Should not have created /virtualmachines cgroup: %d\n", -rv);
238         goto cleanup;
239     }
240     ENSURE_ERRNO(EINVAL);
241
242     /* Asking for impossible combination since devices is not mounted */
243     if ((rv = virCgroupNewPartition("/virtualmachines", true,
244                                     (1 << VIR_CGROUP_CONTROLLER_DEVICES),
245                                     &cgroup)) != -1) {
246         fprintf(stderr, "Should not have created /virtualmachines cgroup: %d\n", -rv);
247         goto cleanup;
248     }
249     ENSURE_ERRNO(ENXIO);
250
251     /* Asking for small combination since devices is not mounted */
252     if ((rv = virCgroupNewPartition("/virtualmachines", true,
253                                     (1 << VIR_CGROUP_CONTROLLER_CPU) |
254                                     (1 << VIR_CGROUP_CONTROLLER_CPUACCT) |
255                                     (1 << VIR_CGROUP_CONTROLLER_MEMORY),
256                                     &cgroup)) != 0) {
257         fprintf(stderr, "Cannot create /virtualmachines cgroup: %d\n", -rv);
258         goto cleanup;
259     }
260     ret = validateCgroup(cgroup, "/virtualmachines.partition", mountsSmall, links, placementSmall);
261     virCgroupFree(&cgroup);
262
263     if ((rv = virCgroupNewPartition("/virtualmachines", true, -1, &cgroup)) != 0) {
264         fprintf(stderr, "Cannot create /virtualmachines cgroup: %d\n", -rv);
265         goto cleanup;
266     }
267     ret = validateCgroup(cgroup, "/virtualmachines.partition", mountsFull, links, placementFull);
268
269  cleanup:
270     virCgroupFree(&cgroup);
271     return ret;
272 }
273
274
275 static int testCgroupNewForPartitionNested(const void *args ATTRIBUTE_UNUSED)
276 {
277     virCgroupPtr cgroup = NULL;
278     int ret = -1;
279     int rv;
280     const char *placementFull[VIR_CGROUP_CONTROLLER_LAST] = {
281         [VIR_CGROUP_CONTROLLER_CPU] = "/deployment.partition/production.partition",
282         [VIR_CGROUP_CONTROLLER_CPUACCT] = "/deployment.partition/production.partition",
283         [VIR_CGROUP_CONTROLLER_CPUSET] = "/deployment.partition/production.partition",
284         [VIR_CGROUP_CONTROLLER_MEMORY] = "/deployment.partition/production.partition",
285         [VIR_CGROUP_CONTROLLER_DEVICES] = NULL,
286         [VIR_CGROUP_CONTROLLER_FREEZER] = "/deployment.partition/production.partition",
287         [VIR_CGROUP_CONTROLLER_BLKIO] = "/deployment.partition/production.partition",
288         [VIR_CGROUP_CONTROLLER_SYSTEMD] = "/user/berrange/123",
289     };
290
291     if ((rv = virCgroupNewPartition("/deployment/production", false, -1, &cgroup)) != -1) {
292         fprintf(stderr, "Unexpected found /deployment/production cgroup: %d\n", -rv);
293         goto cleanup;
294     }
295     ENSURE_ERRNO(ENOENT);
296
297     /* Should not work, since we require /deployment to be pre-created */
298     if ((rv = virCgroupNewPartition("/deployment/production", true, -1, &cgroup)) != -1) {
299         fprintf(stderr, "Unexpected created /deployment/production cgroup: %d\n", -rv);
300         goto cleanup;
301     }
302     ENSURE_ERRNO(ENOENT);
303
304     if ((rv = virCgroupNewPartition("/deployment", true, -1, &cgroup)) != 0) {
305         fprintf(stderr, "Failed to create /deployment cgroup: %d\n", -rv);
306         goto cleanup;
307     }
308
309     /* Should now work */
310     if ((rv = virCgroupNewPartition("/deployment/production", true, -1, &cgroup)) != 0) {
311         fprintf(stderr, "Failed to create /deployment/production cgroup: %d\n", -rv);
312         goto cleanup;
313     }
314
315     ret = validateCgroup(cgroup, "/deployment.partition/production.partition",
316                          mountsFull, links, placementFull);
317
318  cleanup:
319     virCgroupFree(&cgroup);
320     return ret;
321 }
322
323
324 static int testCgroupNewForPartitionNestedDeep(const void *args ATTRIBUTE_UNUSED)
325 {
326     virCgroupPtr cgroup = NULL;
327     int ret = -1;
328     int rv;
329     const char *placementFull[VIR_CGROUP_CONTROLLER_LAST] = {
330         [VIR_CGROUP_CONTROLLER_CPU] = "/user/berrange.user/production.partition",
331         [VIR_CGROUP_CONTROLLER_CPUACCT] = "/user/berrange.user/production.partition",
332         [VIR_CGROUP_CONTROLLER_CPUSET] = "/user/berrange.user/production.partition",
333         [VIR_CGROUP_CONTROLLER_MEMORY] = "/user/berrange.user/production.partition",
334         [VIR_CGROUP_CONTROLLER_DEVICES] = NULL,
335         [VIR_CGROUP_CONTROLLER_FREEZER] = "/user/berrange.user/production.partition",
336         [VIR_CGROUP_CONTROLLER_BLKIO] = "/user/berrange.user/production.partition",
337         [VIR_CGROUP_CONTROLLER_SYSTEMD] = "/user/berrange/123",
338     };
339
340     if ((rv = virCgroupNewPartition("/user/berrange.user/production", false, -1, &cgroup)) != -1) {
341         fprintf(stderr, "Unexpected found /user/berrange.user/production cgroup: %d\n", -rv);
342         goto cleanup;
343     }
344     ENSURE_ERRNO(ENOENT);
345
346     /* Should not work, since we require /user/berrange.user to be pre-created */
347     if ((rv = virCgroupNewPartition("/user/berrange.user/production", true, -1, &cgroup)) != -1) {
348         fprintf(stderr, "Unexpected created /user/berrange.user/production cgroup: %d\n", -rv);
349         goto cleanup;
350     }
351     ENSURE_ERRNO(ENOENT);
352
353     if ((rv = virCgroupNewPartition("/user", true, -1, &cgroup)) != 0) {
354         fprintf(stderr, "Failed to create /user/berrange.user cgroup: %d\n", -rv);
355         goto cleanup;
356     }
357
358     if ((rv = virCgroupNewPartition("/user/berrange.user", true, -1, &cgroup)) != 0) {
359         fprintf(stderr, "Failed to create /user/berrange.user cgroup: %d\n", -rv);
360         goto cleanup;
361     }
362
363     /* Should now work */
364     if ((rv = virCgroupNewPartition("/user/berrange.user/production", true, -1, &cgroup)) != 0) {
365         fprintf(stderr, "Failed to create /user/berrange.user/production cgroup: %d\n", -rv);
366         goto cleanup;
367     }
368
369     ret = validateCgroup(cgroup, "/user/berrange.user/production.partition",
370                          mountsFull, links, placementFull);
371
372  cleanup:
373     virCgroupFree(&cgroup);
374     return ret;
375 }
376
377
378
379 static int testCgroupNewForPartitionDomain(const void *args ATTRIBUTE_UNUSED)
380 {
381     virCgroupPtr partitioncgroup = NULL;
382     virCgroupPtr domaincgroup = NULL;
383     int ret = -1;
384     int rv;
385     const char *placement[VIR_CGROUP_CONTROLLER_LAST] = {
386         [VIR_CGROUP_CONTROLLER_CPU] = "/production.partition/foo.libvirt-lxc",
387         [VIR_CGROUP_CONTROLLER_CPUACCT] = "/production.partition/foo.libvirt-lxc",
388         [VIR_CGROUP_CONTROLLER_CPUSET] = "/production.partition/foo.libvirt-lxc",
389         [VIR_CGROUP_CONTROLLER_MEMORY] = "/production.partition/foo.libvirt-lxc",
390         [VIR_CGROUP_CONTROLLER_DEVICES] = NULL,
391         [VIR_CGROUP_CONTROLLER_FREEZER] = "/production.partition/foo.libvirt-lxc",
392         [VIR_CGROUP_CONTROLLER_BLKIO] = "/production.partition/foo.libvirt-lxc",
393         [VIR_CGROUP_CONTROLLER_SYSTEMD] = "/user/berrange/123",
394     };
395
396     if ((rv = virCgroupNewPartition("/production", true, -1, &partitioncgroup)) != 0) {
397         fprintf(stderr, "Failed to create /production cgroup: %d\n", -rv);
398         goto cleanup;
399     }
400
401     if ((rv = virCgroupNewDomainPartition(partitioncgroup, "lxc", "foo", true, &domaincgroup)) != 0) {
402         fprintf(stderr, "Cannot create LXC cgroup: %d\n", -rv);
403         goto cleanup;
404     }
405
406     ret = validateCgroup(domaincgroup, "/production.partition/foo.libvirt-lxc", mountsFull, links, placement);
407
408  cleanup:
409     virCgroupFree(&partitioncgroup);
410     virCgroupFree(&domaincgroup);
411     return ret;
412 }
413
414 static int testCgroupNewForPartitionDomainEscaped(const void *args ATTRIBUTE_UNUSED)
415 {
416     virCgroupPtr partitioncgroup1 = NULL;
417     virCgroupPtr partitioncgroup2 = NULL;
418     virCgroupPtr partitioncgroup3 = NULL;
419     virCgroupPtr domaincgroup = NULL;
420     int ret = -1;
421     int rv;
422     const char *placement[VIR_CGROUP_CONTROLLER_LAST] = {
423         [VIR_CGROUP_CONTROLLER_CPU] = "/_cgroup.evil/net_cls.evil/__evil.evil/_cpu.foo.libvirt-lxc",
424         [VIR_CGROUP_CONTROLLER_CPUACCT] = "/_cgroup.evil/net_cls.evil/__evil.evil/_cpu.foo.libvirt-lxc",
425         [VIR_CGROUP_CONTROLLER_CPUSET] = "/_cgroup.evil/net_cls.evil/__evil.evil/_cpu.foo.libvirt-lxc",
426         [VIR_CGROUP_CONTROLLER_MEMORY] = "/_cgroup.evil/net_cls.evil/__evil.evil/_cpu.foo.libvirt-lxc",
427         [VIR_CGROUP_CONTROLLER_DEVICES] = NULL,
428         [VIR_CGROUP_CONTROLLER_FREEZER] = "/_cgroup.evil/net_cls.evil/__evil.evil/_cpu.foo.libvirt-lxc",
429         [VIR_CGROUP_CONTROLLER_BLKIO] = "/_cgroup.evil/net_cls.evil/__evil.evil/_cpu.foo.libvirt-lxc",
430         [VIR_CGROUP_CONTROLLER_SYSTEMD] = "/user/berrange/123",
431     };
432
433     if ((rv = virCgroupNewPartition("/cgroup.evil", true, -1, &partitioncgroup1)) != 0) {
434         fprintf(stderr, "Failed to create /cgroup.evil cgroup: %d\n", -rv);
435         goto cleanup;
436     }
437
438     if ((rv = virCgroupNewPartition("/cgroup.evil/net_cls.evil", true, -1, &partitioncgroup2)) != 0) {
439         fprintf(stderr, "Failed to create /cgroup.evil/cpu.evil cgroup: %d\n", -rv);
440         goto cleanup;
441     }
442
443     if ((rv = virCgroupNewPartition("/cgroup.evil/net_cls.evil/_evil.evil", true, -1, &partitioncgroup3)) != 0) {
444         fprintf(stderr, "Failed to create /cgroup.evil cgroup: %d\n", -rv);
445         goto cleanup;
446     }
447
448     if ((rv = virCgroupNewDomainPartition(partitioncgroup3, "lxc", "cpu.foo", true, &domaincgroup)) != 0) {
449         fprintf(stderr, "Cannot create LXC cgroup: %d\n", -rv);
450         goto cleanup;
451     }
452
453     /* NB we're not expecting 'net_cls.evil' to be escaped,
454      * since our fake /proc/cgroups pretends this controller
455      * isn't compiled into the kernel
456      */
457     ret = validateCgroup(domaincgroup, "/_cgroup.evil/net_cls.evil/__evil.evil/_cpu.foo.libvirt-lxc", mountsFull, links, placement);
458
459  cleanup:
460     virCgroupFree(&partitioncgroup3);
461     virCgroupFree(&partitioncgroup2);
462     virCgroupFree(&partitioncgroup1);
463     virCgroupFree(&domaincgroup);
464     return ret;
465 }
466
467 static int testCgroupNewForSelfAllInOne(const void *args ATTRIBUTE_UNUSED)
468 {
469     virCgroupPtr cgroup = NULL;
470     int ret = -1;
471     const char *placement[VIR_CGROUP_CONTROLLER_LAST] = {
472         [VIR_CGROUP_CONTROLLER_CPU] = "/",
473         [VIR_CGROUP_CONTROLLER_CPUACCT] = "/",
474         [VIR_CGROUP_CONTROLLER_CPUSET] = "/",
475         [VIR_CGROUP_CONTROLLER_MEMORY] = "/",
476         [VIR_CGROUP_CONTROLLER_DEVICES] = "/",
477         [VIR_CGROUP_CONTROLLER_FREEZER] = NULL,
478         [VIR_CGROUP_CONTROLLER_BLKIO] = "/",
479     };
480
481     if (virCgroupNewSelf(&cgroup) < 0) {
482         fprintf(stderr, "Cannot create cgroup for self\n");
483         goto cleanup;
484     }
485
486     ret = validateCgroup(cgroup, "", mountsAllInOne, linksAllInOne, placement);
487
488  cleanup:
489     virCgroupFree(&cgroup);
490     return ret;
491 }
492
493
494 static int testCgroupNewForSelfLogind(const void *args ATTRIBUTE_UNUSED)
495 {
496     virCgroupPtr cgroup = NULL;
497     int ret = -1;
498     const char *placement[VIR_CGROUP_CONTROLLER_LAST] = {
499         [VIR_CGROUP_CONTROLLER_CPU] = NULL,
500         [VIR_CGROUP_CONTROLLER_CPUACCT] = NULL,
501         [VIR_CGROUP_CONTROLLER_CPUSET] = NULL,
502         [VIR_CGROUP_CONTROLLER_MEMORY] = NULL,
503         [VIR_CGROUP_CONTROLLER_DEVICES] = NULL,
504         [VIR_CGROUP_CONTROLLER_FREEZER] = NULL,
505         [VIR_CGROUP_CONTROLLER_BLKIO] = NULL,
506         [VIR_CGROUP_CONTROLLER_SYSTEMD] = "/",
507     };
508
509     if (virCgroupNewSelf(&cgroup) < 0) {
510         fprintf(stderr, "Cannot create cgroup for self\n");
511         goto cleanup;
512     }
513
514     ret = validateCgroup(cgroup, "", mountsLogind, linksLogind, placement);
515
516  cleanup:
517     virCgroupFree(&cgroup);
518     return ret;
519 }
520
521
522 static int testCgroupAvailable(const void *args)
523 {
524     bool got = virCgroupAvailable();
525     bool want = args == (void*)0x1;
526
527     if (got != want) {
528         fprintf(stderr, "Expected cgroup %savailable, but state was wrong\n",
529                 want ? "" : "not ");
530         return -1;
531     }
532
533     return 0;
534 }
535
536 static int testCgroupGetPercpuStats(const void *args ATTRIBUTE_UNUSED)
537 {
538     virCgroupPtr cgroup = NULL;
539     size_t i;
540     int rv, ret = -1;
541     virTypedParameter params[2];
542
543     // TODO: mock nodeGetCPUCount() as well & check 2nd cpu, too
544     unsigned long long expected[] = {
545         1413142688153030ULL
546     };
547
548     if ((rv = virCgroupNewPartition("/virtualmachines", true,
549                                     (1 << VIR_CGROUP_CONTROLLER_CPU) |
550                                     (1 << VIR_CGROUP_CONTROLLER_CPUACCT),
551                                     &cgroup)) < 0) {
552         fprintf(stderr, "Could not create /virtualmachines cgroup: %d\n", -rv);
553         goto cleanup;
554     }
555
556     if (nodeGetCPUCount() < 1) {
557         fprintf(stderr, "Unexpected: nodeGetCPUCount() yields: %d\n", nodeGetCPUCount());
558         goto cleanup;
559     }
560
561     if ((rv = virCgroupGetPercpuStats(cgroup,
562                                       params,
563                                       2, 0, 1, 0)) < 0) {
564         fprintf(stderr, "Failed call to virCgroupGetPercpuStats for /virtualmachines cgroup: %d\n", -rv);
565         goto cleanup;
566     }
567
568     for (i = 0; i < ARRAY_CARDINALITY(expected); i++) {
569         if (!STREQ(params[i].field, VIR_DOMAIN_CPU_STATS_CPUTIME)) {
570             fprintf(stderr,
571                     "Wrong parameter name value from virCgroupGetPercpuStats (is: %s)\n",
572                     params[i].field);
573             goto cleanup;
574         }
575
576         if (params[i].type != VIR_TYPED_PARAM_ULLONG) {
577             fprintf(stderr,
578                     "Wrong parameter value type from virCgroupGetPercpuStats (is: %d)\n",
579                     params[i].type);
580             goto cleanup;
581         }
582
583         if (params[i].value.ul != expected[i]) {
584             fprintf(stderr,
585                     "Wrong value from virCgroupGetMemoryUsage (expected %llu)\n",
586                     params[i].value.ul);
587             goto cleanup;
588         }
589     }
590
591     ret = 0;
592
593  cleanup:
594     virCgroupFree(&cgroup);
595     return ret;
596 }
597
598 static int testCgroupGetMemoryUsage(const void *args ATTRIBUTE_UNUSED)
599 {
600     virCgroupPtr cgroup = NULL;
601     int rv, ret = -1;
602     unsigned long kb;
603
604     if ((rv = virCgroupNewPartition("/virtualmachines", true,
605                                     (1 << VIR_CGROUP_CONTROLLER_MEMORY),
606                                     &cgroup)) < 0) {
607         fprintf(stderr, "Could not create /virtualmachines cgroup: %d\n", -rv);
608         goto cleanup;
609     }
610
611     if ((rv = virCgroupGetMemoryUsage(cgroup, &kb)) < 0) {
612         fprintf(stderr, "Could not retrieve GetMemoryUsage for /virtualmachines cgroup: %d\n", -rv);
613         goto cleanup;
614     }
615
616     if (kb != 1421212UL) {
617         fprintf(stderr,
618                 "Wrong value from virCgroupGetMemoryUsage (expected %ld)\n",
619                 1421212UL);
620         goto cleanup;
621     }
622
623     ret = 0;
624
625  cleanup:
626     virCgroupFree(&cgroup);
627     return ret;
628 }
629
630 static int testCgroupGetBlkioIoServiced(const void *args ATTRIBUTE_UNUSED)
631 {
632     virCgroupPtr cgroup = NULL;
633     size_t i;
634     int rv, ret = -1;
635
636     const long long expected_values[] = {
637         119084214273ULL,
638         822880960513ULL,
639         9665167,
640         73283807
641     };
642     const char* names[] = {
643         "bytes read",
644         "bytes written",
645         "requests read",
646         "requests written"
647     };
648     long long values[ARRAY_CARDINALITY(expected_values)];
649
650     if ((rv = virCgroupNewPartition("/virtualmachines", true,
651                                     (1 << VIR_CGROUP_CONTROLLER_BLKIO),
652                                     &cgroup)) < 0) {
653         fprintf(stderr, "Could not create /virtualmachines cgroup: %d\n", -rv);
654         goto cleanup;
655     }
656
657     if ((rv = virCgroupGetBlkioIoServiced(cgroup,
658                                           values, &values[1],
659                                           &values[2], &values[3])) < 0) {
660         fprintf(stderr, "Could not retrieve BlkioIoServiced for /virtualmachines cgroup: %d\n", -rv);
661         goto cleanup;
662     }
663
664     for (i = 0; i < ARRAY_CARDINALITY(expected_values); i++) {
665         if (expected_values[i] != values[i]) {
666             fprintf(stderr,
667                     "Wrong value for %s from virCgroupBlkioIoServiced (expected %lld)\n",
668                     names[i], expected_values[i]);
669             goto cleanup;
670         }
671     }
672
673     ret = 0;
674
675  cleanup:
676     virCgroupFree(&cgroup);
677     return ret;
678 }
679
680 static int testCgroupGetBlkioIoDeviceServiced(const void *args ATTRIBUTE_UNUSED)
681 {
682     virCgroupPtr cgroup = NULL;
683     size_t i;
684     int rv, ret = -1;
685     const long long expected_values0[] = {
686         59542107136ULL,
687         411440480256ULL,
688         4832583,
689         36641903
690     };
691     const long long expected_values1[] = {
692         59542107137ULL,
693         411440480257ULL,
694         4832584,
695         36641904
696     };
697     const char* names[] = {
698         "bytes read",
699         "bytes written",
700         "requests read",
701         "requests written"
702     };
703     long long values[ARRAY_CARDINALITY(expected_values0)];
704
705     if ((rv = virCgroupNewPartition("/virtualmachines", true,
706                                     (1 << VIR_CGROUP_CONTROLLER_BLKIO),
707                                     &cgroup)) < 0) {
708         fprintf(stderr, "Could not create /virtualmachines cgroup: %d\n", -rv);
709         goto cleanup;
710     }
711
712     if ((rv = virCgroupGetBlkioIoDeviceServiced(cgroup,
713                                                 FAKEDEVDIR0,
714                                                 values, &values[1],
715                                                 &values[2], &values[3])) < 0) {
716         fprintf(stderr, "Could not retrieve BlkioIoDeviceServiced for /virtualmachines cgroup: %d\n", -rv);
717         goto cleanup;
718     }
719
720     for (i = 0; i < ARRAY_CARDINALITY(expected_values0); i++) {
721         if (expected_values0[i] != values[i]) {
722             fprintf(stderr,
723                     "Wrong value for %s from virCgroupGetBlkioIoDeviceServiced (expected %lld)\n",
724                     names[i], expected_values0[i]);
725             goto cleanup;
726         }
727     }
728
729     if ((rv = virCgroupGetBlkioIoDeviceServiced(cgroup,
730                                                 FAKEDEVDIR1,
731                                                 values, &values[1],
732                                                 &values[2], &values[3])) < 0) {
733         fprintf(stderr, "Could not retrieve BlkioIoDeviceServiced for /virtualmachines cgroup: %d\n", -rv);
734         goto cleanup;
735     }
736
737     for (i = 0; i < ARRAY_CARDINALITY(expected_values1); i++) {
738         if (expected_values1[i] != values[i]) {
739             fprintf(stderr,
740                     "Wrong value for %s from virCgroupGetBlkioIoDeviceServiced (expected %lld)\n",
741                     names[i], expected_values1[i]);
742             goto cleanup;
743         }
744     }
745
746     ret = 0;
747
748  cleanup:
749     virCgroupFree(&cgroup);
750     return ret;
751 }
752
753 # define FAKESYSFSDIRTEMPLATE abs_builddir "/fakesysfsdir-XXXXXX"
754
755 static int
756 mymain(void)
757 {
758     int ret = 0;
759     char *fakesysfsdir;
760
761     if (VIR_STRDUP_QUIET(fakesysfsdir, FAKESYSFSDIRTEMPLATE) < 0) {
762         fprintf(stderr, "Out of memory\n");
763         abort();
764     }
765
766     if (!mkdtemp(fakesysfsdir)) {
767         fprintf(stderr, "Cannot create fakesysfsdir");
768         abort();
769     }
770
771     setenv("LIBVIRT_FAKE_SYSFS_DIR", fakesysfsdir, 1);
772
773     if (virtTestRun("New cgroup for self", testCgroupNewForSelf, NULL) < 0)
774         ret = -1;
775
776     if (virtTestRun("New cgroup for partition", testCgroupNewForPartition, NULL) < 0)
777         ret = -1;
778
779     if (virtTestRun("New cgroup for partition nested", testCgroupNewForPartitionNested, NULL) < 0)
780         ret = -1;
781
782     if (virtTestRun("New cgroup for partition nested deeply", testCgroupNewForPartitionNestedDeep, NULL) < 0)
783         ret = -1;
784
785     if (virtTestRun("New cgroup for domain partition", testCgroupNewForPartitionDomain, NULL) < 0)
786         ret = -1;
787
788     if (virtTestRun("New cgroup for domain partition escaped", testCgroupNewForPartitionDomainEscaped, NULL) < 0)
789         ret = -1;
790
791     if (virtTestRun("Cgroup available", testCgroupAvailable, (void*)0x1) < 0)
792         ret = -1;
793
794     if (virtTestRun("virCgroupGetBlkioIoServiced works", testCgroupGetBlkioIoServiced, NULL) < 0)
795         ret = -1;
796
797     if (virtTestRun("virCgroupGetBlkioIoDeviceServiced works", testCgroupGetBlkioIoDeviceServiced, NULL) < 0)
798         ret = -1;
799
800     if (virtTestRun("virCgroupGetMemoryUsage works", testCgroupGetMemoryUsage, NULL) < 0)
801         ret = -1;
802
803     if (virtTestRun("virCgroupGetPercpuStats works", testCgroupGetPercpuStats, NULL) < 0)
804         ret = -1;
805
806     setenv("VIR_CGROUP_MOCK_MODE", "allinone", 1);
807     if (virtTestRun("New cgroup for self (allinone)", testCgroupNewForSelfAllInOne, NULL) < 0)
808         ret = -1;
809     if (virtTestRun("Cgroup available", testCgroupAvailable, (void*)0x1) < 0)
810         ret = -1;
811     unsetenv("VIR_CGROUP_MOCK_MODE");
812
813     setenv("VIR_CGROUP_MOCK_MODE", "logind", 1);
814     if (virtTestRun("New cgroup for self (logind)", testCgroupNewForSelfLogind, NULL) < 0)
815         ret = -1;
816     if (virtTestRun("Cgroup available", testCgroupAvailable, (void*)0x0) < 0)
817         ret = -1;
818     unsetenv("VIR_CGROUP_MOCK_MODE");
819
820     if (getenv("LIBVIRT_SKIP_CLEANUP") == NULL)
821         virFileDeleteTree(fakesysfsdir);
822
823     VIR_FREE(fakesysfsdir);
824
825     return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
826 }
827
828 VIRT_TEST_MAIN_PRELOAD(mymain, abs_builddir "/.libs/vircgroupmock.so")
829
830 #else
831 int
832 main(void)
833 {
834     return EXIT_AM_SKIP;
835 }
836 #endif