1 /*
2 * Copyright (C) 2010-2016 Red Hat, Inc.
3 * Copyright IBM Corp. 2008
4 *
5 * lxc_driver.c: linux container driver functions
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 <sched.h>
26 #include <sys/utsname.h>
27
28 #ifdef __linux__
29 # include <sys/sysmacros.h>
30 #endif
31
32 #include <sys/stat.h>
33 #include <sys/poll.h>
34 #include <unistd.h>
35 #include <wait.h>
36
37 #include "virerror.h"
38 #include "virlog.h"
39 #include "datatypes.h"
40 #include "lxc_cgroup.h"
41 #include "lxc_conf.h"
42 #include "lxc_container.h"
43 #include "lxc_domain.h"
44 #include "lxc_driver.h"
45 #include "lxc_native.h"
46 #include "lxc_process.h"
47 #include "virnetdevbridge.h"
48 #include "virnetdevveth.h"
49 #include "virnetdevopenvswitch.h"
50 #include "virhostcpu.h"
51 #include "virhostmem.h"
52 #include "viruuid.h"
53 #include "virhook.h"
54 #include "virfile.h"
55 #include "virpidfile.h"
56 #include "virfdstream.h"
57 #include "domain_audit.h"
58 #include "domain_cgroup.h"
59 #include "domain_driver.h"
60 #include "domain_nwfilter.h"
61 #include "domain_validate.h"
62 #include "virinitctl.h"
63 #include "virnetdev.h"
64 #include "virnetdevtap.h"
65 #include "virnodesuspend.h"
66 #include "virprocess.h"
67 #include "virtime.h"
68 #include "virtypedparam.h"
69 #include "viruri.h"
70 #include "virstring.h"
71 #include "viraccessapicheck.h"
72 #include "viraccessapichecklxc.h"
73 #include "virhostdev.h"
74 #include "netdev_bandwidth_conf.h"
75 #include "virsocket.h"
76 #include "virutil.h"
77
78 #define VIR_FROM_THIS VIR_FROM_LXC
79
80 VIR_LOG_INIT("lxc.lxc_driver");
81
82 #define LXC_NB_MEM_PARAM 3
83 #define LXC_NB_DOMAIN_BLOCK_STAT_PARAM 4
84
85
86 static int lxcStateInitialize(bool privileged,
87 const char *root,
88 virStateInhibitCallback callback,
89 void *opaque);
90 static int lxcStateCleanup(void);
91 virLXCDriver *lxc_driver = NULL;
92
93
94 /**
95 * lxcDomObjFromDomain:
96 * @domain: Domain pointer that has to be looked up
97 *
98 * This function looks up @domain and returns the appropriate virDomainObj *
99 * that has to be released by calling virDomainObjEndAPI.
100 *
101 * Returns the domain object with incremented reference counter which is locked
102 * on success, NULL otherwise.
103 */
104 static virDomainObj *
lxcDomObjFromDomain(virDomainPtr domain)105 lxcDomObjFromDomain(virDomainPtr domain)
106 {
107 virDomainObj *vm;
108 virLXCDriver *driver = domain->conn->privateData;
109 char uuidstr[VIR_UUID_STRING_BUFLEN];
110
111 vm = virDomainObjListFindByUUID(driver->domains, domain->uuid);
112 if (!vm) {
113 virUUIDFormat(domain->uuid, uuidstr);
114 virReportError(VIR_ERR_NO_DOMAIN,
115 _("no domain with matching uuid '%s' (%s)"),
116 uuidstr, domain->name);
117 return NULL;
118 }
119
120 return vm;
121 }
122
123 /* Functions */
124
125 static int
lxcConnectURIProbe(char ** uri)126 lxcConnectURIProbe(char **uri)
127 {
128 if (lxc_driver == NULL)
129 return 0;
130
131 *uri = g_strdup("lxc:///system");
132 return 1;
133 }
134
135
lxcConnectOpen(virConnectPtr conn,virConnectAuthPtr auth G_GNUC_UNUSED,virConf * conf G_GNUC_UNUSED,unsigned int flags)136 static virDrvOpenStatus lxcConnectOpen(virConnectPtr conn,
137 virConnectAuthPtr auth G_GNUC_UNUSED,
138 virConf *conf G_GNUC_UNUSED,
139 unsigned int flags)
140 {
141 virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);
142
143 /* If path isn't '/' then they typoed, tell them correct path */
144 if (STRNEQ(conn->uri->path, "") &&
145 STRNEQ(conn->uri->path, "/") &&
146 STRNEQ(conn->uri->path, "/system")) {
147 virReportError(VIR_ERR_INTERNAL_ERROR,
148 _("Unexpected LXC URI path '%s', try lxc:///system"),
149 conn->uri->path);
150 return VIR_DRV_OPEN_ERROR;
151 }
152
153 /* URI was good, but driver isn't active */
154 if (lxc_driver == NULL) {
155 virReportError(VIR_ERR_INTERNAL_ERROR,
156 "%s", _("lxc state driver is not active"));
157 return VIR_DRV_OPEN_ERROR;
158 }
159
160 if (virConnectOpenEnsureACL(conn) < 0)
161 return VIR_DRV_OPEN_ERROR;
162
163 conn->privateData = lxc_driver;
164
165 return VIR_DRV_OPEN_SUCCESS;
166 }
167
lxcConnectClose(virConnectPtr conn)168 static int lxcConnectClose(virConnectPtr conn)
169 {
170 virLXCDriver *driver = conn->privateData;
171
172 virCloseCallbacksRun(driver->closeCallbacks, conn, driver->domains, driver);
173 conn->privateData = NULL;
174 return 0;
175 }
176
177
lxcConnectIsSecure(virConnectPtr conn G_GNUC_UNUSED)178 static int lxcConnectIsSecure(virConnectPtr conn G_GNUC_UNUSED)
179 {
180 /* Trivially secure, since always inside the daemon */
181 return 1;
182 }
183
184
lxcConnectIsEncrypted(virConnectPtr conn G_GNUC_UNUSED)185 static int lxcConnectIsEncrypted(virConnectPtr conn G_GNUC_UNUSED)
186 {
187 /* Not encrypted, but remote driver takes care of that */
188 return 0;
189 }
190
191
lxcConnectIsAlive(virConnectPtr conn G_GNUC_UNUSED)192 static int lxcConnectIsAlive(virConnectPtr conn G_GNUC_UNUSED)
193 {
194 return 1;
195 }
196
197
lxcConnectGetCapabilities(virConnectPtr conn)198 static char *lxcConnectGetCapabilities(virConnectPtr conn) {
199 virLXCDriver *driver = conn->privateData;
200 virCaps *caps;
201 char *xml;
202
203 if (virConnectGetCapabilitiesEnsureACL(conn) < 0)
204 return NULL;
205
206 if (!(caps = virLXCDriverGetCapabilities(driver, true)))
207 return NULL;
208
209 xml = virCapabilitiesFormatXML(caps);
210
211 virObjectUnref(caps);
212 return xml;
213 }
214
215
lxcDomainLookupByID(virConnectPtr conn,int id)216 static virDomainPtr lxcDomainLookupByID(virConnectPtr conn,
217 int id)
218 {
219 virLXCDriver *driver = conn->privateData;
220 virDomainObj *vm;
221 virDomainPtr dom = NULL;
222
223 vm = virDomainObjListFindByID(driver->domains, id);
224
225 if (!vm) {
226 virReportError(VIR_ERR_NO_DOMAIN,
227 _("No domain with matching id %d"), id);
228 goto cleanup;
229 }
230
231 if (virDomainLookupByIDEnsureACL(conn, vm->def) < 0)
232 goto cleanup;
233
234 dom = virGetDomain(conn, vm->def->name, vm->def->uuid, vm->def->id);
235
236 cleanup:
237 virDomainObjEndAPI(&vm);
238 return dom;
239 }
240
lxcDomainLookupByUUID(virConnectPtr conn,const unsigned char * uuid)241 static virDomainPtr lxcDomainLookupByUUID(virConnectPtr conn,
242 const unsigned char *uuid)
243 {
244 virLXCDriver *driver = conn->privateData;
245 virDomainObj *vm;
246 virDomainPtr dom = NULL;
247
248 vm = virDomainObjListFindByUUID(driver->domains, uuid);
249
250 if (!vm) {
251 char uuidstr[VIR_UUID_STRING_BUFLEN];
252 virUUIDFormat(uuid, uuidstr);
253 virReportError(VIR_ERR_NO_DOMAIN,
254 _("No domain with matching uuid '%s'"), uuidstr);
255 goto cleanup;
256 }
257
258 if (virDomainLookupByUUIDEnsureACL(conn, vm->def) < 0)
259 goto cleanup;
260
261 dom = virGetDomain(conn, vm->def->name, vm->def->uuid, vm->def->id);
262
263 cleanup:
264 virDomainObjEndAPI(&vm);
265 return dom;
266 }
267
lxcDomainLookupByName(virConnectPtr conn,const char * name)268 static virDomainPtr lxcDomainLookupByName(virConnectPtr conn,
269 const char *name)
270 {
271 virLXCDriver *driver = conn->privateData;
272 virDomainObj *vm;
273 virDomainPtr dom = NULL;
274
275 vm = virDomainObjListFindByName(driver->domains, name);
276 if (!vm) {
277 virReportError(VIR_ERR_NO_DOMAIN,
278 _("No domain with matching name '%s'"), name);
279 goto cleanup;
280 }
281
282 if (virDomainLookupByNameEnsureACL(conn, vm->def) < 0)
283 goto cleanup;
284
285 dom = virGetDomain(conn, vm->def->name, vm->def->uuid, vm->def->id);
286
287 cleanup:
288 virDomainObjEndAPI(&vm);
289 return dom;
290 }
291
292
lxcDomainIsActive(virDomainPtr dom)293 static int lxcDomainIsActive(virDomainPtr dom)
294 {
295 virDomainObj *obj;
296 int ret = -1;
297
298 if (!(obj = lxcDomObjFromDomain(dom)))
299 goto cleanup;
300
301 if (virDomainIsActiveEnsureACL(dom->conn, obj->def) < 0)
302 goto cleanup;
303
304 ret = virDomainObjIsActive(obj);
305
306 cleanup:
307 virDomainObjEndAPI(&obj);
308 return ret;
309 }
310
311
lxcDomainIsPersistent(virDomainPtr dom)312 static int lxcDomainIsPersistent(virDomainPtr dom)
313 {
314 virDomainObj *obj;
315 int ret = -1;
316
317 if (!(obj = lxcDomObjFromDomain(dom)))
318 goto cleanup;
319
320 if (virDomainIsPersistentEnsureACL(dom->conn, obj->def) < 0)
321 goto cleanup;
322
323 ret = obj->persistent;
324
325 cleanup:
326 virDomainObjEndAPI(&obj);
327 return ret;
328 }
329
lxcDomainIsUpdated(virDomainPtr dom)330 static int lxcDomainIsUpdated(virDomainPtr dom)
331 {
332 virDomainObj *obj;
333 int ret = -1;
334
335 if (!(obj = lxcDomObjFromDomain(dom)))
336 goto cleanup;
337
338 if (virDomainIsUpdatedEnsureACL(dom->conn, obj->def) < 0)
339 goto cleanup;
340
341 ret = obj->updated;
342
343 cleanup:
344 virDomainObjEndAPI(&obj);
345 return ret;
346 }
347
lxcConnectListDomains(virConnectPtr conn,int * ids,int nids)348 static int lxcConnectListDomains(virConnectPtr conn, int *ids, int nids)
349 {
350 virLXCDriver *driver = conn->privateData;
351
352 if (virConnectListDomainsEnsureACL(conn) < 0)
353 return -1;
354
355 return virDomainObjListGetActiveIDs(driver->domains, ids, nids,
356 virConnectListDomainsCheckACL, conn);
357 }
358
lxcConnectNumOfDomains(virConnectPtr conn)359 static int lxcConnectNumOfDomains(virConnectPtr conn)
360 {
361 virLXCDriver *driver = conn->privateData;
362
363 if (virConnectNumOfDomainsEnsureACL(conn) < 0)
364 return -1;
365
366 return virDomainObjListNumOfDomains(driver->domains, true,
367 virConnectNumOfDomainsCheckACL, conn);
368 }
369
lxcConnectListDefinedDomains(virConnectPtr conn,char ** const names,int nnames)370 static int lxcConnectListDefinedDomains(virConnectPtr conn,
371 char **const names, int nnames)
372 {
373 virLXCDriver *driver = conn->privateData;
374
375 if (virConnectListDefinedDomainsEnsureACL(conn) < 0)
376 return -1;
377
378 return virDomainObjListGetInactiveNames(driver->domains, names, nnames,
379 virConnectListDefinedDomainsCheckACL,
380 conn);
381 }
382
383
lxcConnectNumOfDefinedDomains(virConnectPtr conn)384 static int lxcConnectNumOfDefinedDomains(virConnectPtr conn)
385 {
386 virLXCDriver *driver = conn->privateData;
387
388 if (virConnectNumOfDefinedDomainsEnsureACL(conn) < 0)
389 return -1;
390
391 return virDomainObjListNumOfDomains(driver->domains, false,
392 virConnectNumOfDefinedDomainsCheckACL,
393 conn);
394 }
395
396
397
398 static virDomainPtr
lxcDomainDefineXMLFlags(virConnectPtr conn,const char * xml,unsigned int flags)399 lxcDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flags)
400 {
401 virLXCDriver *driver = conn->privateData;
402 virDomainDef *def = NULL;
403 virDomainObj *vm = NULL;
404 virDomainPtr dom = NULL;
405 virObjectEvent *event = NULL;
406 virDomainDef *oldDef = NULL;
407 virLXCDriverConfig *cfg = virLXCDriverGetConfig(driver);
408 virCaps *caps = NULL;
409 unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
410
411 virCheckFlags(VIR_DOMAIN_DEFINE_VALIDATE, NULL);
412
413 if (flags & VIR_DOMAIN_DEFINE_VALIDATE)
414 parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
415
416 if (!(caps = virLXCDriverGetCapabilities(driver, false)))
417 goto cleanup;
418
419 if (!(def = virDomainDefParseString(xml, driver->xmlopt,
420 NULL, parse_flags)))
421 goto cleanup;
422
423 if (virXMLCheckIllegalChars("name", def->name, "\n") < 0)
424 goto cleanup;
425
426 if (virDomainDefineXMLFlagsEnsureACL(conn, def) < 0)
427 goto cleanup;
428
429 if (virSecurityManagerVerify(driver->securityManager, def) < 0)
430 goto cleanup;
431
432 if ((def->nets != NULL) && !(cfg->have_netns)) {
433 virReportError(VIR_ERR_OPERATION_INVALID,
434 "%s", _("System lacks NETNS support"));
435 goto cleanup;
436 }
437
438 if (!(vm = virDomainObjListAdd(driver->domains, &def,
439 driver->xmlopt,
440 0, &oldDef)))
441 goto cleanup;
442
443 vm->persistent = 1;
444
445 if (virDomainDefSave(vm->newDef ? vm->newDef : vm->def,
446 driver->xmlopt, cfg->configDir) < 0) {
447 virDomainObjListRemove(driver->domains, vm);
448 goto cleanup;
449 }
450
451 event = virDomainEventLifecycleNewFromObj(vm,
452 VIR_DOMAIN_EVENT_DEFINED,
453 !oldDef ?
454 VIR_DOMAIN_EVENT_DEFINED_ADDED :
455 VIR_DOMAIN_EVENT_DEFINED_UPDATED);
456
457 dom = virGetDomain(conn, vm->def->name, vm->def->uuid, vm->def->id);
458
459 cleanup:
460 virDomainDefFree(def);
461 virDomainDefFree(oldDef);
462 virDomainObjEndAPI(&vm);
463 virObjectEventStateQueue(driver->domainEventState, event);
464 virObjectUnref(caps);
465 virObjectUnref(cfg);
466 return dom;
467 }
468
469 static virDomainPtr
lxcDomainDefineXML(virConnectPtr conn,const char * xml)470 lxcDomainDefineXML(virConnectPtr conn, const char *xml)
471 {
472 return lxcDomainDefineXMLFlags(conn, xml, 0);
473 }
474
lxcDomainUndefineFlags(virDomainPtr dom,unsigned int flags)475 static int lxcDomainUndefineFlags(virDomainPtr dom,
476 unsigned int flags)
477 {
478 virLXCDriver *driver = dom->conn->privateData;
479 virDomainObj *vm;
480 virObjectEvent *event = NULL;
481 int ret = -1;
482 virLXCDriverConfig *cfg = virLXCDriverGetConfig(driver);
483
484 virCheckFlags(0, -1);
485
486 if (!(vm = lxcDomObjFromDomain(dom)))
487 goto cleanup;
488
489 if (virDomainUndefineFlagsEnsureACL(dom->conn, vm->def) < 0)
490 goto cleanup;
491
492 if (!vm->persistent) {
493 virReportError(VIR_ERR_OPERATION_INVALID,
494 "%s", _("Cannot undefine transient domain"));
495 goto cleanup;
496 }
497
498 if (virDomainDeleteConfig(cfg->configDir,
499 cfg->autostartDir,
500 vm) < 0)
501 goto cleanup;
502
503 event = virDomainEventLifecycleNewFromObj(vm,
504 VIR_DOMAIN_EVENT_UNDEFINED,
505 VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
506
507 if (virDomainObjIsActive(vm))
508 vm->persistent = 0;
509 else
510 virDomainObjListRemove(driver->domains, vm);
511
512 ret = 0;
513
514 cleanup:
515 virDomainObjEndAPI(&vm);
516 virObjectEventStateQueue(driver->domainEventState, event);
517 virObjectUnref(cfg);
518 return ret;
519 }
520
lxcDomainUndefine(virDomainPtr dom)521 static int lxcDomainUndefine(virDomainPtr dom)
522 {
523 return lxcDomainUndefineFlags(dom, 0);
524 }
525
lxcDomainGetInfo(virDomainPtr dom,virDomainInfoPtr info)526 static int lxcDomainGetInfo(virDomainPtr dom,
527 virDomainInfoPtr info)
528 {
529 virDomainObj *vm;
530 int ret = -1;
531 virLXCDomainObjPrivate *priv;
532
533 if (!(vm = lxcDomObjFromDomain(dom)))
534 goto cleanup;
535
536 priv = vm->privateData;
537
538 if (virDomainGetInfoEnsureACL(dom->conn, vm->def) < 0)
539 goto cleanup;
540
541 info->state = virDomainObjGetState(vm, NULL);
542
543 if (!virDomainObjIsActive(vm)) {
544 info->cpuTime = 0;
545 info->memory = vm->def->mem.cur_balloon;
546 } else {
547 if (virCgroupGetCpuacctUsage(priv->cgroup, &(info->cpuTime)) < 0) {
548 virReportError(VIR_ERR_OPERATION_FAILED,
549 "%s", _("Cannot read cputime for domain"));
550 goto cleanup;
551 }
552 if (virCgroupGetMemoryUsage(priv->cgroup, &(info->memory)) < 0) {
553 /* Don't fail if we can't read memory usage due to a lack of
554 * kernel support */
555 if (virLastErrorIsSystemErrno(ENOENT)) {
556 virResetLastError();
557 info->memory = 0;
558 } else {
559 goto cleanup;
560 }
561 }
562 }
563
564 info->maxMem = virDomainDefGetMemoryTotal(vm->def);
565 info->nrVirtCpu = virDomainDefGetVcpus(vm->def);
566 ret = 0;
567
568 cleanup:
569 virDomainObjEndAPI(&vm);
570 return ret;
571 }
572
573 static int
lxcDomainGetState(virDomainPtr dom,int * state,int * reason,unsigned int flags)574 lxcDomainGetState(virDomainPtr dom,
575 int *state,
576 int *reason,
577 unsigned int flags)
578 {
579 virDomainObj *vm;
580 int ret = -1;
581
582 virCheckFlags(0, -1);
583
584 if (!(vm = lxcDomObjFromDomain(dom)))
585 goto cleanup;
586
587 if (virDomainGetStateEnsureACL(dom->conn, vm->def) < 0)
588 goto cleanup;
589
590 *state = virDomainObjGetState(vm, reason);
591 ret = 0;
592
593 cleanup:
594 virDomainObjEndAPI(&vm);
595 return ret;
596 }
597
lxcDomainGetOSType(virDomainPtr dom)598 static char *lxcDomainGetOSType(virDomainPtr dom)
599 {
600 virDomainObj *vm;
601 char *ret = NULL;
602
603 if (!(vm = lxcDomObjFromDomain(dom)))
604 goto cleanup;
605
606 if (virDomainGetOSTypeEnsureACL(dom->conn, vm->def) < 0)
607 goto cleanup;
608
609 ret = g_strdup(virDomainOSTypeToString(vm->def->os.type));
610
611 cleanup:
612 virDomainObjEndAPI(&vm);
613 return ret;
614 }
615
616 /* Returns max memory in kb, 0 if error */
617 static unsigned long long
lxcDomainGetMaxMemory(virDomainPtr dom)618 lxcDomainGetMaxMemory(virDomainPtr dom)
619 {
620 virDomainObj *vm;
621 unsigned long long ret = 0;
622
623 if (!(vm = lxcDomObjFromDomain(dom)))
624 goto cleanup;
625
626 if (virDomainGetMaxMemoryEnsureACL(dom->conn, vm->def) < 0)
627 goto cleanup;
628
629 ret = virDomainDefGetMemoryTotal(vm->def);
630
631 cleanup:
632 virDomainObjEndAPI(&vm);
633 return ret;
634 }
635
lxcDomainSetMemoryFlags(virDomainPtr dom,unsigned long newmem,unsigned int flags)636 static int lxcDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem,
637 unsigned int flags)
638 {
639 virDomainObj *vm;
640 virDomainDef *def = NULL;
641 virDomainDef *persistentDef = NULL;
642 int ret = -1;
643 virLXCDomainObjPrivate *priv;
644 virLXCDriver *driver = dom->conn->privateData;
645 virLXCDriverConfig *cfg = NULL;
646
647 virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
648 VIR_DOMAIN_AFFECT_CONFIG |
649 VIR_DOMAIN_MEM_MAXIMUM, -1);
650
651 if (!(vm = lxcDomObjFromDomain(dom)))
652 goto cleanup;
653
654 cfg = virLXCDriverGetConfig(driver);
655
656 priv = vm->privateData;
657
658 if (virDomainSetMemoryFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
659 goto cleanup;
660
661 if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
662 goto cleanup;
663
664 if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
665 goto endjob;
666
667 if (flags & VIR_DOMAIN_MEM_MAXIMUM) {
668 if (def) {
669 virReportError(VIR_ERR_OPERATION_INVALID, "%s",
670 _("Cannot resize the max memory "
671 "on an active domain"));
672 goto endjob;
673 }
674
675 if (persistentDef) {
676 virDomainDefSetMemoryTotal(persistentDef, newmem);
677 if (persistentDef->mem.cur_balloon > newmem)
678 persistentDef->mem.cur_balloon = newmem;
679 if (virDomainDefSave(persistentDef,
680 driver->xmlopt, cfg->configDir) < 0)
681 goto endjob;
682 }
683 } else {
684 unsigned long oldmax = 0;
685
686 if (def)
687 oldmax = virDomainDefGetMemoryTotal(def);
688 if (persistentDef) {
689 if (!oldmax || oldmax > virDomainDefGetMemoryTotal(persistentDef))
690 oldmax = virDomainDefGetMemoryTotal(persistentDef);
691 }
692
693 if (newmem > oldmax) {
694 virReportError(VIR_ERR_INVALID_ARG,
695 "%s", _("Cannot set memory higher than max memory"));
696 goto endjob;
697 }
698
699 if (def) {
700 if (virCgroupSetMemory(priv->cgroup, newmem) < 0) {
701 virReportError(VIR_ERR_OPERATION_FAILED,
702 "%s", _("Failed to set memory for domain"));
703 goto endjob;
704 }
705
706 def->mem.cur_balloon = newmem;
707 if (virDomainObjSave(vm, driver->xmlopt, cfg->stateDir) < 0)
708 goto endjob;
709 }
710
711 if (persistentDef) {
712 persistentDef->mem.cur_balloon = newmem;
713 if (virDomainDefSave(persistentDef,
714 driver->xmlopt, cfg->configDir) < 0)
715 goto endjob;
716 }
717 }
718
719 ret = 0;
720
721 endjob:
722 virLXCDomainObjEndJob(driver, vm);
723
724 cleanup:
725 virDomainObjEndAPI(&vm);
726 virObjectUnref(cfg);
727 return ret;
728 }
729
lxcDomainSetMemory(virDomainPtr dom,unsigned long newmem)730 static int lxcDomainSetMemory(virDomainPtr dom, unsigned long newmem)
731 {
732 return lxcDomainSetMemoryFlags(dom, newmem, VIR_DOMAIN_AFFECT_LIVE);
733 }
734
lxcDomainSetMaxMemory(virDomainPtr dom,unsigned long newmax)735 static int lxcDomainSetMaxMemory(virDomainPtr dom, unsigned long newmax)
736 {
737 return lxcDomainSetMemoryFlags(dom, newmax, VIR_DOMAIN_MEM_MAXIMUM);
738 }
739
740 static int
lxcDomainSetMemoryParameters(virDomainPtr dom,virTypedParameterPtr params,int nparams,unsigned int flags)741 lxcDomainSetMemoryParameters(virDomainPtr dom,
742 virTypedParameterPtr params,
743 int nparams,
744 unsigned int flags)
745 {
746 virDomainDef *def = NULL;
747 virDomainDef *persistentDef = NULL;
748 virDomainObj *vm = NULL;
749 virLXCDomainObjPrivate *priv = NULL;
750 virLXCDriverConfig *cfg = NULL;
751 virLXCDriver *driver = dom->conn->privateData;
752 int ret = -1;
753
754 virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
755 VIR_DOMAIN_AFFECT_CONFIG, -1);
756
757 if (virTypedParamsValidate(params, nparams,
758 VIR_DOMAIN_MEMORY_HARD_LIMIT,
759 VIR_TYPED_PARAM_ULLONG,
760 VIR_DOMAIN_MEMORY_SOFT_LIMIT,
761 VIR_TYPED_PARAM_ULLONG,
762 VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT,
763 VIR_TYPED_PARAM_ULLONG,
764 NULL) < 0)
765 return -1;
766
767 if (!(vm = lxcDomObjFromDomain(dom)))
768 goto cleanup;
769
770 priv = vm->privateData;
771 cfg = virLXCDriverGetConfig(driver);
772
773 if (virDomainSetMemoryParametersEnsureACL(dom->conn, vm->def, flags) < 0)
774 goto cleanup;
775
776 if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
777 goto cleanup;
778
779 /* QEMU and LXC implementation are identical */
780 if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
781 goto endjob;
782
783 if (def &&
784 !virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_MEMORY)) {
785 virReportError(VIR_ERR_OPERATION_INVALID, "%s",
786 _("cgroup memory controller is not mounted"));
787 goto endjob;
788 }
789
790 if (virDomainCgroupSetMemoryLimitParameters(priv->cgroup, vm, def,
791 persistentDef,
792 params, nparams) < 0)
793 goto endjob;
794
795 if (def &&
796 virDomainObjSave(vm, driver->xmlopt, cfg->stateDir) < 0)
797 goto endjob;
798
799 if (persistentDef &&
800 virDomainDefSave(persistentDef, driver->xmlopt, cfg->configDir) < 0)
801 goto endjob;
802 /* QEMU and LXC implementations are identical */
803
804 ret = 0;
805
806 endjob:
807 virLXCDomainObjEndJob(driver, vm);
808
809 cleanup:
810 virDomainObjEndAPI(&vm);
811 virObjectUnref(cfg);
812 return ret;
813 }
814
815 static int
lxcDomainGetMemoryParameters(virDomainPtr dom,virTypedParameterPtr params,int * nparams,unsigned int flags)816 lxcDomainGetMemoryParameters(virDomainPtr dom,
817 virTypedParameterPtr params,
818 int *nparams,
819 unsigned int flags)
820 {
821 virDomainDef *persistentDef = NULL;
822 virDomainDef *def = NULL;
823 virDomainObj *vm = NULL;
824 virLXCDomainObjPrivate *priv = NULL;
825 unsigned long long val;
826 int ret = -1;
827 size_t i;
828
829 virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
830 VIR_DOMAIN_AFFECT_CONFIG |
831 VIR_TYPED_PARAM_STRING_OKAY, -1);
832
833 /* We don't return strings, and thus trivially support this flag. */
834 flags &= ~VIR_TYPED_PARAM_STRING_OKAY;
835
836 if (!(vm = lxcDomObjFromDomain(dom)))
837 goto cleanup;
838
839 priv = vm->privateData;
840
841 if (virDomainGetMemoryParametersEnsureACL(dom->conn, vm->def) < 0)
842 goto cleanup;
843
844 if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
845 goto cleanup;
846
847 if (def &&
848 !virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_MEMORY)) {
849 virReportError(VIR_ERR_OPERATION_INVALID,
850 "%s", _("cgroup memory controller is not mounted"));
851 goto cleanup;
852 }
853
854 if ((*nparams) == 0) {
855 /* Current number of memory parameters supported by cgroups */
856 *nparams = LXC_NB_MEM_PARAM;
857 ret = 0;
858 goto cleanup;
859 }
860
861 for (i = 0; i < LXC_NB_MEM_PARAM && i < *nparams; i++) {
862 virTypedParameterPtr param = ¶ms[i];
863 val = 0;
864
865 switch (i) {
866 case 0: /* fill memory hard limit here */
867 if (persistentDef) {
868 val = persistentDef->mem.hard_limit;
869 } else if (virCgroupGetMemoryHardLimit(priv->cgroup, &val) < 0) {
870 goto cleanup;
871 }
872 if (virTypedParameterAssign(param, VIR_DOMAIN_MEMORY_HARD_LIMIT,
873 VIR_TYPED_PARAM_ULLONG, val) < 0)
874 goto cleanup;
875 break;
876 case 1: /* fill memory soft limit here */
877 if (persistentDef) {
878 val = persistentDef->mem.soft_limit;
879 } else if (virCgroupGetMemorySoftLimit(priv->cgroup, &val) < 0) {
880 goto cleanup;
881 }
882 if (virTypedParameterAssign(param, VIR_DOMAIN_MEMORY_SOFT_LIMIT,
883 VIR_TYPED_PARAM_ULLONG, val) < 0)
884 goto cleanup;
885 break;
886 case 2: /* fill swap hard limit here */
887 if (persistentDef) {
888 val = persistentDef->mem.swap_hard_limit;
889 } else if (virCgroupGetMemSwapHardLimit(priv->cgroup, &val) < 0) {
890 goto cleanup;
891 }
892 if (virTypedParameterAssign(param,
893 VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT,
894 VIR_TYPED_PARAM_ULLONG, val) < 0)
895 goto cleanup;
896 break;
897 }
898 }
899
900 if (*nparams > LXC_NB_MEM_PARAM)
901 *nparams = LXC_NB_MEM_PARAM;
902 ret = 0;
903
904 cleanup:
905 virDomainObjEndAPI(&vm);
906 return ret;
907 }
908
lxcDomainGetXMLDesc(virDomainPtr dom,unsigned int flags)909 static char *lxcDomainGetXMLDesc(virDomainPtr dom,
910 unsigned int flags)
911 {
912 virLXCDriver *driver = dom->conn->privateData;
913 virDomainObj *vm;
914 char *ret = NULL;
915
916 virCheckFlags(VIR_DOMAIN_XML_COMMON_FLAGS, NULL);
917
918 if (!(vm = lxcDomObjFromDomain(dom)))
919 goto cleanup;
920
921 if (virDomainGetXMLDescEnsureACL(dom->conn, vm->def, flags) < 0)
922 goto cleanup;
923
924 ret = virDomainDefFormat((flags & VIR_DOMAIN_XML_INACTIVE) &&
925 vm->newDef ? vm->newDef : vm->def,
926 driver->xmlopt,
927 virDomainDefFormatConvertXMLFlags(flags));
928
929 cleanup:
930 virDomainObjEndAPI(&vm);
931 return ret;
932 }
933
lxcConnectDomainXMLFromNative(virConnectPtr conn,const char * nativeFormat,const char * nativeConfig,unsigned int flags)934 static char *lxcConnectDomainXMLFromNative(virConnectPtr conn,
935 const char *nativeFormat,
936 const char *nativeConfig,
937 unsigned int flags)
938 {
939 char *xml = NULL;
940 virDomainDef *def = NULL;
941 virLXCDriver *driver = conn->privateData;
942 virCaps *caps = virLXCDriverGetCapabilities(driver, false);
943
944 virCheckFlags(0, NULL);
945
946 if (virConnectDomainXMLFromNativeEnsureACL(conn) < 0)
947 goto cleanup;
948
949 if (STRNEQ(nativeFormat, LXC_CONFIG_FORMAT)) {
950 virReportError(VIR_ERR_INVALID_ARG,
951 _("unsupported config type %s"), nativeFormat);
952 goto cleanup;
953 }
954
955 if (!(def = lxcParseConfigString(nativeConfig, caps, driver->xmlopt)))
956 goto cleanup;
957
958 xml = virDomainDefFormat(def, driver->xmlopt, 0);
959
960 cleanup:
961 virObjectUnref(caps);
962 virDomainDefFree(def);
963 return xml;
964 }
965
966 /**
967 * lxcDomainCreateWithFiles:
968 * @dom: domain to start
969 * @flags: Must be 0 for now
970 *
971 * Looks up domain and starts it.
972 *
973 * Returns 0 on success or -1 in case of error
974 */
lxcDomainCreateWithFiles(virDomainPtr dom,unsigned int nfiles,int * files,unsigned int flags)975 static int lxcDomainCreateWithFiles(virDomainPtr dom,
976 unsigned int nfiles,
977 int *files,
978 unsigned int flags)
979 {
980 virLXCDriver *driver = dom->conn->privateData;
981 virDomainObj *vm;
982 virObjectEvent *event = NULL;
983 int ret = -1;
984 virLXCDriverConfig *cfg = virLXCDriverGetConfig(driver);
985
986 virCheckFlags(VIR_DOMAIN_START_AUTODESTROY, -1);
987
988 virNWFilterReadLockFilterUpdates();
989
990 if (!(vm = lxcDomObjFromDomain(dom)))
991 goto cleanup;
992
993 if (virDomainCreateWithFilesEnsureACL(dom->conn, vm->def) < 0)
994 goto cleanup;
995
996 if ((vm->def->nets != NULL) && !(cfg->have_netns)) {
997 virReportError(VIR_ERR_OPERATION_INVALID,
998 "%s", _("System lacks NETNS support"));
999 goto cleanup;
1000 }
1001
1002 if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
1003 goto cleanup;
1004
1005 if (virDomainObjIsActive(vm)) {
1006 virReportError(VIR_ERR_OPERATION_INVALID,
1007 "%s", _("Domain is already running"));
1008 goto endjob;
1009 }
1010
1011 ret = virLXCProcessStart(dom->conn, driver, vm,
1012 nfiles, files,
1013 (flags & VIR_DOMAIN_START_AUTODESTROY),
1014 VIR_DOMAIN_RUNNING_BOOTED);
1015
1016 if (ret == 0) {
1017 event = virDomainEventLifecycleNewFromObj(vm,
1018 VIR_DOMAIN_EVENT_STARTED,
1019 VIR_DOMAIN_EVENT_STARTED_BOOTED);
1020 virDomainAuditStart(vm, "booted", true);
1021 } else {
1022 virDomainAuditStart(vm, "booted", false);
1023 }
1024
1025 endjob:
1026 virLXCDomainObjEndJob(driver, vm);
1027
1028 cleanup:
1029 virDomainObjEndAPI(&vm);
1030 virObjectEventStateQueue(driver->domainEventState, event);
1031 virObjectUnref(cfg);
1032 virNWFilterUnlockFilterUpdates();
1033 return ret;
1034 }
1035
1036 /**
1037 * lxcDomainCreate:
1038 * @dom: domain to start
1039 *
1040 * Looks up domain and starts it.
1041 *
1042 * Returns 0 on success or -1 in case of error
1043 */
lxcDomainCreate(virDomainPtr dom)1044 static int lxcDomainCreate(virDomainPtr dom)
1045 {
1046 return lxcDomainCreateWithFiles(dom, 0, NULL, 0);
1047 }
1048
1049 /**
1050 * lxcDomainCreateWithFlags:
1051 * @dom: domain to start
1052 *
1053 * Looks up domain and starts it.
1054 *
1055 * Returns 0 on success or -1 in case of error
1056 */
lxcDomainCreateWithFlags(virDomainPtr dom,unsigned int flags)1057 static int lxcDomainCreateWithFlags(virDomainPtr dom,
1058 unsigned int flags)
1059 {
1060 return lxcDomainCreateWithFiles(dom, 0, NULL, flags);
1061 }
1062
1063 /**
1064 * lxcDomainCreateXMLWithFiles:
1065 * @conn: pointer to connection
1066 * @xml: XML definition of domain
1067 * @nfiles: number of file descriptors passed
1068 * @files: list of file descriptors passed
1069 * @flags: bitwise-OR of supported virDomainCreateFlags
1070 *
1071 * Creates a domain based on xml and starts it
1072 *
1073 * Returns a new domain object or NULL in case of failure.
1074 */
1075 static virDomainPtr
lxcDomainCreateXMLWithFiles(virConnectPtr conn,const char * xml,unsigned int nfiles,int * files,unsigned int flags)1076 lxcDomainCreateXMLWithFiles(virConnectPtr conn,
1077 const char *xml,
1078 unsigned int nfiles,
1079 int *files,
1080 unsigned int flags)
1081 {
1082 virLXCDriver *driver = conn->privateData;
1083 virDomainObj *vm = NULL;
1084 virDomainDef *def = NULL;
1085 virDomainPtr dom = NULL;
1086 virObjectEvent *event = NULL;
1087 virLXCDriverConfig *cfg = virLXCDriverGetConfig(driver);
1088 virCaps *caps = NULL;
1089 unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
1090
1091 virCheckFlags(VIR_DOMAIN_START_AUTODESTROY |
1092 VIR_DOMAIN_START_VALIDATE, NULL);
1093
1094
1095 if (flags & VIR_DOMAIN_START_VALIDATE)
1096 parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
1097
1098 virNWFilterReadLockFilterUpdates();
1099
1100 if (!(caps = virLXCDriverGetCapabilities(driver, false)))
1101 goto cleanup;
1102
1103 if (!(def = virDomainDefParseString(xml, driver->xmlopt,
1104 NULL, parse_flags)))
1105 goto cleanup;
1106
1107 if (virDomainCreateXMLWithFilesEnsureACL(conn, def) < 0)
1108 goto cleanup;
1109
1110 if (virSecurityManagerVerify(driver->securityManager, def) < 0)
1111 goto cleanup;
1112
1113 if ((def->nets != NULL) && !(cfg->have_netns)) {
1114 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1115 "%s", _("System lacks NETNS support"));
1116 goto cleanup;
1117 }
1118
1119
1120 if (!(vm = virDomainObjListAdd(driver->domains, &def,
1121 driver->xmlopt,
1122 VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
1123 VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
1124 NULL)))
1125 goto cleanup;
1126
1127 if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0) {
1128 if (!vm->persistent)
1129 virDomainObjListRemove(driver->domains, vm);
1130 goto cleanup;
1131 }
1132
1133 if (virLXCProcessStart(conn, driver, vm,
1134 nfiles, files,
1135 (flags & VIR_DOMAIN_START_AUTODESTROY),
1136 VIR_DOMAIN_RUNNING_BOOTED) < 0) {
1137 virDomainAuditStart(vm, "booted", false);
1138 virLXCDomainObjEndJob(driver, vm);
1139 if (!vm->persistent)
1140 virDomainObjListRemove(driver->domains, vm);
1141 goto cleanup;
1142 }
1143
1144 event = virDomainEventLifecycleNewFromObj(vm,
1145 VIR_DOMAIN_EVENT_STARTED,
1146 VIR_DOMAIN_EVENT_STARTED_BOOTED);
1147 virDomainAuditStart(vm, "booted", true);
1148
1149 dom = virGetDomain(conn, vm->def->name, vm->def->uuid, vm->def->id);
1150
1151 virLXCDomainObjEndJob(driver, vm);
1152
1153 cleanup:
1154 virDomainDefFree(def);
1155 virDomainObjEndAPI(&vm);
1156 virObjectEventStateQueue(driver->domainEventState, event);
1157 virObjectUnref(caps);
1158 virObjectUnref(cfg);
1159 virNWFilterUnlockFilterUpdates();
1160 return dom;
1161 }
1162
1163 /**
1164 * lxcDomainCreateXML:
1165 * @conn: pointer to connection
1166 * @xml: XML definition of domain
1167 * @flags: bitwise-OR of supported virDomainCreateFlags
1168 *
1169 * Creates a domain based on xml and starts it
1170 *
1171 * Returns a new domain object or NULL in case of failure.
1172 */
1173 static virDomainPtr
lxcDomainCreateXML(virConnectPtr conn,const char * xml,unsigned int flags)1174 lxcDomainCreateXML(virConnectPtr conn,
1175 const char *xml,
1176 unsigned int flags)
1177 {
1178 return lxcDomainCreateXMLWithFiles(conn, xml, 0, NULL, flags);
1179 }
1180
1181
lxcDomainGetSecurityLabel(virDomainPtr dom,virSecurityLabelPtr seclabel)1182 static int lxcDomainGetSecurityLabel(virDomainPtr dom, virSecurityLabelPtr seclabel)
1183 {
1184 virLXCDriver *driver = dom->conn->privateData;
1185 virDomainObj *vm;
1186 int ret = -1;
1187
1188 memset(seclabel, 0, sizeof(*seclabel));
1189
1190 if (!(vm = lxcDomObjFromDomain(dom)))
1191 goto cleanup;
1192
1193 if (virDomainGetSecurityLabelEnsureACL(dom->conn, vm->def) < 0)
1194 goto cleanup;
1195
1196 /*
1197 * Theoretically, the pid can be replaced during this operation and
1198 * return the label of a different process. If atomicity is needed,
1199 * further validation will be required.
1200 *
1201 * Comment from Dan Berrange:
1202 *
1203 * Well the PID as stored in the virDomainObj *can't be changed
1204 * because you've got a locked object. The OS level PID could have
1205 * exited, though and in extreme circumstances have cycled through all
1206 * PIDs back to ours. We could sanity check that our PID still exists
1207 * after reading the label, by checking that our FD connecting to the
1208 * LXC monitor hasn't seen SIGHUP/ERR on poll().
1209 */
1210 if (virDomainObjIsActive(vm)) {
1211 virLXCDomainObjPrivate *priv = vm->privateData;
1212
1213 if (!priv->initpid) {
1214 virReportError(VIR_ERR_OPERATION_INVALID, "%s",
1215 _("Init pid is not yet available"));
1216 goto cleanup;
1217 }
1218
1219 if (virSecurityManagerGetProcessLabel(driver->securityManager,
1220 vm->def, priv->initpid,
1221 seclabel) < 0)
1222 goto cleanup;
1223 }
1224
1225 ret = 0;
1226
1227 cleanup:
1228 virDomainObjEndAPI(&vm);
1229 return ret;
1230 }
1231
lxcNodeGetSecurityModel(virConnectPtr conn,virSecurityModelPtr secmodel)1232 static int lxcNodeGetSecurityModel(virConnectPtr conn,
1233 virSecurityModelPtr secmodel)
1234 {
1235 virLXCDriver *driver = conn->privateData;
1236 virCaps *caps = NULL;
1237 int ret = 0;
1238
1239 memset(secmodel, 0, sizeof(*secmodel));
1240
1241 if (virNodeGetSecurityModelEnsureACL(conn) < 0)
1242 goto cleanup;
1243
1244 if (!(caps = virLXCDriverGetCapabilities(driver, false)))
1245 goto cleanup;
1246
1247 /* we treat no driver as success, but simply return no data in *secmodel */
1248 if (caps->host.nsecModels == 0
1249 || caps->host.secModels[0].model == NULL)
1250 goto cleanup;
1251
1252 if (virStrcpy(secmodel->model, caps->host.secModels[0].model,
1253 VIR_SECURITY_MODEL_BUFLEN) < 0) {
1254 virReportError(VIR_ERR_INTERNAL_ERROR,
1255 _("security model string exceeds max %d bytes"),
1256 VIR_SECURITY_MODEL_BUFLEN - 1);
1257 ret = -1;
1258 goto cleanup;
1259 }
1260
1261 if (virStrcpy(secmodel->doi, caps->host.secModels[0].doi,
1262 VIR_SECURITY_DOI_BUFLEN) < 0) {
1263 virReportError(VIR_ERR_INTERNAL_ERROR,
1264 _("security DOI string exceeds max %d bytes"),
1265 VIR_SECURITY_DOI_BUFLEN-1);
1266 ret = -1;
1267 goto cleanup;
1268 }
1269
1270 cleanup:
1271 virObjectUnref(caps);
1272 return ret;
1273 }
1274
1275
1276 static int
lxcConnectDomainEventRegister(virConnectPtr conn,virConnectDomainEventCallback callback,void * opaque,virFreeCallback freecb)1277 lxcConnectDomainEventRegister(virConnectPtr conn,
1278 virConnectDomainEventCallback callback,
1279 void *opaque,
1280 virFreeCallback freecb)
1281 {
1282 virLXCDriver *driver = conn->privateData;
1283
1284 if (virConnectDomainEventRegisterEnsureACL(conn) < 0)
1285 return -1;
1286
1287 if (virDomainEventStateRegister(conn,
1288 driver->domainEventState,
1289 callback, opaque, freecb) < 0)
1290 return -1;
1291
1292 return 0;
1293 }
1294
1295
1296 static int
lxcConnectDomainEventDeregister(virConnectPtr conn,virConnectDomainEventCallback callback)1297 lxcConnectDomainEventDeregister(virConnectPtr conn,
1298 virConnectDomainEventCallback callback)
1299 {
1300 virLXCDriver *driver = conn->privateData;
1301
1302 if (virConnectDomainEventDeregisterEnsureACL(conn) < 0)
1303 return -1;
1304
1305 if (virDomainEventStateDeregister(conn,
1306 driver->domainEventState,
1307 callback) < 0)
1308 return -1;
1309
1310 return 0;
1311 }
1312
1313
1314 static int
lxcConnectDomainEventRegisterAny(virConnectPtr conn,virDomainPtr dom,int eventID,virConnectDomainEventGenericCallback callback,void * opaque,virFreeCallback freecb)1315 lxcConnectDomainEventRegisterAny(virConnectPtr conn,
1316 virDomainPtr dom,
1317 int eventID,
1318 virConnectDomainEventGenericCallback callback,
1319 void *opaque,
1320 virFreeCallback freecb)
1321 {
1322 virLXCDriver *driver = conn->privateData;
1323 int ret;
1324
1325 if (virConnectDomainEventRegisterAnyEnsureACL(conn) < 0)
1326 return -1;
1327
1328 if (virDomainEventStateRegisterID(conn,
1329 driver->domainEventState,
1330 dom, eventID,
1331 callback, opaque, freecb, &ret) < 0)
1332 ret = -1;
1333
1334 return ret;
1335 }
1336
1337
1338 static int
lxcConnectDomainEventDeregisterAny(virConnectPtr conn,int callbackID)1339 lxcConnectDomainEventDeregisterAny(virConnectPtr conn,
1340 int callbackID)
1341 {
1342 virLXCDriver *driver = conn->privateData;
1343
1344 if (virConnectDomainEventDeregisterAnyEnsureACL(conn) < 0)
1345 return -1;
1346
1347 if (virObjectEventStateDeregisterID(conn,
1348 driver->domainEventState,
1349 callbackID, true) < 0)
1350 return -1;
1351
1352 return 0;
1353 }
1354
1355
1356 /**
1357 * lxcDomainDestroyFlags:
1358 * @dom: pointer to domain to destroy
1359 * @flags: extra flags; not used yet.
1360 *
1361 * Sends SIGKILL to container root process to terminate the container
1362 *
1363 * Returns 0 on success or -1 in case of error
1364 */
1365 static int
lxcDomainDestroyFlags(virDomainPtr dom,unsigned int flags)1366 lxcDomainDestroyFlags(virDomainPtr dom,
1367 unsigned int flags)
1368 {
1369 virLXCDriver *driver = dom->conn->privateData;
1370 virDomainObj *vm;
1371 virObjectEvent *event = NULL;
1372 int ret = -1;
1373 virLXCDomainObjPrivate *priv;
1374
1375 virCheckFlags(0, -1);
1376
1377 if (!(vm = lxcDomObjFromDomain(dom)))
1378 goto cleanup;
1379
1380 if (virDomainDestroyFlagsEnsureACL(dom->conn, vm->def) < 0)
1381 goto cleanup;
1382
1383 if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_DESTROY) < 0)
1384 goto cleanup;
1385
1386 if (virDomainObjCheckActive(vm) < 0)
1387 goto endjob;
1388
1389 priv = vm->privateData;
1390 ret = virLXCProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_DESTROYED);
1391 event = virDomainEventLifecycleNewFromObj(vm,
1392 VIR_DOMAIN_EVENT_STOPPED,
1393 VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
1394 priv->doneStopEvent = true;
1395 virDomainAuditStop(vm, "destroyed");
1396
1397 endjob:
1398 virLXCDomainObjEndJob(driver, vm);
1399 if (!vm->persistent)
1400 virDomainObjListRemove(driver->domains, vm);
1401
1402 cleanup:
1403 virDomainObjEndAPI(&vm);
1404 virObjectEventStateQueue(driver->domainEventState, event);
1405 return ret;
1406 }
1407
1408 /**
1409 * lxcDomainDestroy:
1410 * @dom: pointer to domain to destroy
1411 *
1412 * Sends SIGKILL to container root process to terminate the container
1413 *
1414 * Returns 0 on success or -1 in case of error
1415 */
1416 static int
lxcDomainDestroy(virDomainPtr dom)1417 lxcDomainDestroy(virDomainPtr dom)
1418 {
1419 return lxcDomainDestroyFlags(dom, 0);
1420 }
1421
lxcCheckNetNsSupport(void)1422 static int lxcCheckNetNsSupport(void)
1423 {
1424 g_autoptr(virCommand) cmd = virCommandNewArgList("ip", "link", "set", "lo",
1425 "netns", "-1", NULL);
1426 int ip_rc;
1427
1428 if (virCommandRun(cmd, &ip_rc) < 0 || ip_rc == 255)
1429 return 0;
1430
1431 if (virProcessNamespaceAvailable(VIR_PROCESS_NAMESPACE_NET) < 0)
1432 return 0;
1433
1434 return 1;
1435 }
1436
1437
1438 static virSecurityManager *
lxcSecurityInit(virLXCDriverConfig * cfg)1439 lxcSecurityInit(virLXCDriverConfig *cfg)
1440 {
1441 unsigned int flags = VIR_SECURITY_MANAGER_PRIVILEGED;
1442 virSecurityManager *mgr;
1443
1444 VIR_INFO("lxcSecurityInit %s", cfg->securityDriverName);
1445
1446 if (cfg->securityDefaultConfined)
1447 flags |= VIR_SECURITY_MANAGER_DEFAULT_CONFINED;
1448 if (cfg->securityRequireConfined)
1449 flags |= VIR_SECURITY_MANAGER_REQUIRE_CONFINED;
1450
1451 mgr = virSecurityManagerNew(cfg->securityDriverName,
1452 LXC_DRIVER_NAME, flags);
1453 if (!mgr)
1454 goto error;
1455
1456 return mgr;
1457
1458 error:
1459 VIR_ERROR(_("Failed to initialize security drivers"));
1460 virObjectUnref(mgr);
1461 return NULL;
1462 }
1463
1464
lxcStateInitialize(bool privileged,const char * root,virStateInhibitCallback callback G_GNUC_UNUSED,void * opaque G_GNUC_UNUSED)1465 static int lxcStateInitialize(bool privileged,
1466 const char *root,
1467 virStateInhibitCallback callback G_GNUC_UNUSED,
1468 void *opaque G_GNUC_UNUSED)
1469 {
1470 virLXCDriverConfig *cfg = NULL;
1471 bool autostart = true;
1472 const char *defsecmodel;
1473
1474 if (root != NULL) {
1475 virReportError(VIR_ERR_INVALID_ARG, "%s",
1476 _("Driver does not support embedded mode"));
1477 return -1;
1478 }
1479
1480 /* Check that the user is root, silently disable if not */
1481 if (!privileged) {
1482 VIR_INFO("Not running privileged, disabling driver");
1483 return VIR_DRV_STATE_INIT_SKIPPED;
1484 }
1485
1486 /* Check that this is a container enabled kernel */
1487 if (virProcessNamespaceAvailable(VIR_PROCESS_NAMESPACE_MNT |
1488 VIR_PROCESS_NAMESPACE_PID |
1489 VIR_PROCESS_NAMESPACE_UTS |
1490 VIR_PROCESS_NAMESPACE_IPC) < 0) {
1491 VIR_INFO("LXC support not available in this kernel, disabling driver");
1492 return VIR_DRV_STATE_INIT_SKIPPED;
1493 }
1494
1495 lxc_driver = g_new0(virLXCDriver, 1);
1496 lxc_driver->lockFD = -1;
1497 if (virMutexInit(&lxc_driver->lock) < 0) {
1498 g_free(lxc_driver);
1499 lxc_driver = NULL;
1500 return VIR_DRV_STATE_INIT_ERROR;
1501 }
1502
1503 if (!(lxc_driver->domains = virDomainObjListNew()))
1504 goto cleanup;
1505
1506 lxc_driver->domainEventState = virObjectEventStateNew();
1507 if (!lxc_driver->domainEventState)
1508 goto cleanup;
1509
1510 lxc_driver->hostsysinfo = virSysinfoRead();
1511
1512 if (!(lxc_driver->config = cfg = virLXCDriverConfigNew()))
1513 goto cleanup;
1514
1515 cfg->log_libvirtd = false; /* by default log to container logfile */
1516 cfg->have_netns = lxcCheckNetNsSupport();
1517
1518 /* Call function to load lxc driver configuration information */
1519 if (virLXCLoadDriverConfig(cfg, SYSCONFDIR "/libvirt/lxc.conf") < 0)
1520 goto cleanup;
1521
1522 if (!(lxc_driver->securityManager = lxcSecurityInit(cfg)))
1523 goto cleanup;
1524
1525 if (!(lxc_driver->hostdevMgr = virHostdevManagerGetDefault()))
1526 goto cleanup;
1527
1528 defsecmodel = virSecurityManagerGetModel(lxc_driver->securityManager);
1529
1530 if (!(lxc_driver->xmlopt = lxcDomainXMLConfInit(lxc_driver, defsecmodel)))
1531 goto cleanup;
1532
1533 if (!(lxc_driver->closeCallbacks = virCloseCallbacksNew()))
1534 goto cleanup;
1535
1536 if (g_mkdir_with_parents(cfg->stateDir, 0777) < 0) {
1537 virReportSystemError(errno,
1538 _("Failed to mkdir %s"),
1539 cfg->stateDir);
1540 goto cleanup;
1541 }
1542
1543 if ((lxc_driver->lockFD =
1544 virPidFileAcquire(cfg->stateDir, "driver", false, getpid())) < 0)
1545 goto cleanup;
1546
1547 /* Get all the running persistent or transient configs first */
1548 if (virDomainObjListLoadAllConfigs(lxc_driver->domains,
1549 cfg->stateDir,
1550 NULL, true,
1551 lxc_driver->xmlopt,
1552 NULL, NULL) < 0)
1553 goto cleanup;
1554
1555 virLXCProcessReconnectAll(lxc_driver, lxc_driver->domains);
1556
1557 /* Then inactive persistent configs */
1558 if (virDomainObjListLoadAllConfigs(lxc_driver->domains,
1559 cfg->configDir,
1560 cfg->autostartDir, false,
1561 lxc_driver->xmlopt,
1562 NULL, NULL) < 0)
1563 goto cleanup;
1564
1565 if (virDriverShouldAutostart(cfg->stateDir, &autostart) < 0)
1566 goto cleanup;
1567
1568 if (autostart)
1569 virLXCProcessAutostartAll(lxc_driver);
1570
1571 return VIR_DRV_STATE_INIT_COMPLETE;
1572
1573 cleanup:
1574 lxcStateCleanup();
1575 return VIR_DRV_STATE_INIT_ERROR;
1576 }
1577
lxcNotifyLoadDomain(virDomainObj * vm,int newVM,void * opaque)1578 static void lxcNotifyLoadDomain(virDomainObj *vm, int newVM, void *opaque)
1579 {
1580 virLXCDriver *driver = opaque;
1581
1582 if (newVM) {
1583 virObjectEvent *event =
1584 virDomainEventLifecycleNewFromObj(vm,
1585 VIR_DOMAIN_EVENT_DEFINED,
1586 VIR_DOMAIN_EVENT_DEFINED_ADDED);
1587 virObjectEventStateQueue(driver->domainEventState, event);
1588 }
1589 }
1590
1591 /**
1592 * lxcStateReload:
1593 *
1594 * Function to restart the LXC driver, it will recheck the configuration
1595 * files and perform autostart
1596 */
1597 static int
lxcStateReload(void)1598 lxcStateReload(void)
1599 {
1600 virLXCDriverConfig *cfg = NULL;
1601
1602 if (!lxc_driver)
1603 return 0;
1604
1605 cfg = virLXCDriverGetConfig(lxc_driver);
1606
1607 virDomainObjListLoadAllConfigs(lxc_driver->domains,
1608 cfg->configDir,
1609 cfg->autostartDir, false,
1610 lxc_driver->xmlopt,
1611 lxcNotifyLoadDomain, lxc_driver);
1612 virObjectUnref(cfg);
1613 return 0;
1614 }
1615
lxcStateCleanup(void)1616 static int lxcStateCleanup(void)
1617 {
1618 if (lxc_driver == NULL)
1619 return -1;
1620
1621 virObjectUnref(lxc_driver->domains);
1622 virObjectUnref(lxc_driver->domainEventState);
1623
1624 virObjectUnref(lxc_driver->closeCallbacks);
1625
1626 virSysinfoDefFree(lxc_driver->hostsysinfo);
1627
1628 virObjectUnref(lxc_driver->hostdevMgr);
1629 virObjectUnref(lxc_driver->caps);
1630 virObjectUnref(lxc_driver->securityManager);
1631 virObjectUnref(lxc_driver->xmlopt);
1632
1633 if (lxc_driver->lockFD != -1)
1634 virPidFileRelease(lxc_driver->config->stateDir, "driver", lxc_driver->lockFD);
1635
1636 virObjectUnref(lxc_driver->config);
1637 virMutexDestroy(&lxc_driver->lock);
1638 g_free(lxc_driver);
1639 lxc_driver = NULL;
1640
1641 return 0;
1642 }
1643
1644 static int
lxcConnectSupportsFeature(virConnectPtr conn,int feature)1645 lxcConnectSupportsFeature(virConnectPtr conn, int feature)
1646 {
1647 if (virConnectSupportsFeatureEnsureACL(conn) < 0)
1648 return -1;
1649
1650 switch ((virDrvFeature) feature) {
1651 case VIR_DRV_FEATURE_TYPED_PARAM_STRING:
1652 case VIR_DRV_FEATURE_NETWORK_UPDATE_HAS_CORRECT_ORDER:
1653 return 1;
1654 case VIR_DRV_FEATURE_FD_PASSING:
1655 case VIR_DRV_FEATURE_MIGRATE_CHANGE_PROTECTION:
1656 case VIR_DRV_FEATURE_MIGRATION_DIRECT:
1657 case VIR_DRV_FEATURE_MIGRATION_OFFLINE:
1658 case VIR_DRV_FEATURE_MIGRATION_P2P:
1659 case VIR_DRV_FEATURE_MIGRATION_PARAMS:
1660 case VIR_DRV_FEATURE_MIGRATION_V1:
1661 case VIR_DRV_FEATURE_MIGRATION_V2:
1662 case VIR_DRV_FEATURE_MIGRATION_V3:
1663 case VIR_DRV_FEATURE_PROGRAM_KEEPALIVE:
1664 case VIR_DRV_FEATURE_REMOTE:
1665 case VIR_DRV_FEATURE_REMOTE_CLOSE_CALLBACK:
1666 case VIR_DRV_FEATURE_REMOTE_EVENT_CALLBACK:
1667 case VIR_DRV_FEATURE_XML_MIGRATABLE:
1668 default:
1669 return 0;
1670 }
1671 }
1672
1673
lxcConnectGetVersion(virConnectPtr conn,unsigned long * version)1674 static int lxcConnectGetVersion(virConnectPtr conn, unsigned long *version)
1675 {
1676 struct utsname ver;
1677
1678 uname(&ver);
1679
1680 if (virConnectGetVersionEnsureACL(conn) < 0)
1681 return -1;
1682
1683 if (virParseVersionString(ver.release, version, true) < 0) {
1684 virReportError(VIR_ERR_INTERNAL_ERROR, _("Unknown release: %s"), ver.release);
1685 return -1;
1686 }
1687
1688 return 0;
1689 }
1690
1691
1692 static int
lxcDomainInterfaceAddresses(virDomainPtr dom,virDomainInterfacePtr ** ifaces,unsigned int source,unsigned int flags)1693 lxcDomainInterfaceAddresses(virDomainPtr dom,
1694 virDomainInterfacePtr **ifaces,
1695 unsigned int source,
1696 unsigned int flags)
1697 {
1698 virDomainObj *vm = NULL;
1699 int ret = -1;
1700
1701 virCheckFlags(0, -1);
1702
1703 if (!(vm = lxcDomObjFromDomain(dom)))
1704 goto cleanup;
1705
1706 if (virDomainInterfaceAddressesEnsureACL(dom->conn, vm->def, source) < 0)
1707 goto cleanup;
1708
1709 if (virDomainObjCheckActive(vm) < 0)
1710 goto cleanup;
1711
1712 switch (source) {
1713 case VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_LEASE:
1714 ret = virDomainNetDHCPInterfaces(vm->def, ifaces);
1715 break;
1716
1717 case VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_ARP:
1718 ret = virDomainNetARPInterfaces(vm->def, ifaces);
1719 break;
1720
1721 default:
1722 virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED,
1723 _("Unknown IP address data source %d"),
1724 source);
1725 break;
1726 }
1727
1728 cleanup:
1729 virDomainObjEndAPI(&vm);
1730 return ret;
1731 }
1732
1733
1734
lxcConnectGetHostname(virConnectPtr conn)1735 static char *lxcConnectGetHostname(virConnectPtr conn)
1736 {
1737 if (virConnectGetHostnameEnsureACL(conn) < 0)
1738 return NULL;
1739
1740 return virGetHostname();
1741 }
1742
1743
lxcDomainGetSchedulerType(virDomainPtr dom,int * nparams)1744 static char *lxcDomainGetSchedulerType(virDomainPtr dom,
1745 int *nparams)
1746 {
1747 char *ret = NULL;
1748 virDomainObj *vm;
1749 virLXCDomainObjPrivate *priv;
1750
1751 if (!(vm = lxcDomObjFromDomain(dom)))
1752 goto cleanup;
1753
1754 priv = vm->privateData;
1755
1756 if (virDomainGetSchedulerTypeEnsureACL(dom->conn, vm->def) < 0)
1757 goto cleanup;
1758
1759 /* Domain not running, thus no cgroups - return defaults */
1760 if (!virDomainObjIsActive(vm)) {
1761 if (nparams)
1762 *nparams = 3;
1763 ret = g_strdup("posix");
1764 goto cleanup;
1765 }
1766
1767 if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU)) {
1768 virReportError(VIR_ERR_OPERATION_INVALID,
1769 "%s", _("cgroup CPU controller is not mounted"));
1770 goto cleanup;
1771 }
1772
1773 if (nparams) {
1774 if (virCgroupSupportsCpuBW(priv->cgroup))
1775 *nparams = 3;
1776 else
1777 *nparams = 1;
1778 }
1779
1780 ret = g_strdup("posix");
1781
1782 cleanup:
1783 virDomainObjEndAPI(&vm);
1784 return ret;
1785 }
1786
1787
1788 static int
lxcGetVcpuBWLive(virCgroup * cgroup,unsigned long long * period,long long * quota)1789 lxcGetVcpuBWLive(virCgroup *cgroup, unsigned long long *period,
1790 long long *quota)
1791 {
1792 return virCgroupGetCpuPeriodQuota(cgroup, period, quota);
1793 }
1794
1795
lxcSetVcpuBWLive(virCgroup * cgroup,unsigned long long period,long long quota)1796 static int lxcSetVcpuBWLive(virCgroup *cgroup, unsigned long long period,
1797 long long quota)
1798 {
1799 return virCgroupSetupCpuPeriodQuota(cgroup, period, quota);
1800 }
1801
1802
1803 static int
lxcDomainSetSchedulerParametersFlags(virDomainPtr dom,virTypedParameterPtr params,int nparams,unsigned int flags)1804 lxcDomainSetSchedulerParametersFlags(virDomainPtr dom,
1805 virTypedParameterPtr params,
1806 int nparams,
1807 unsigned int flags)
1808 {
1809 virLXCDriver *driver = dom->conn->privateData;
1810 virCaps *caps = NULL;
1811 size_t i;
1812 virDomainObj *vm = NULL;
1813 virDomainDef *def = NULL;
1814 virDomainDef *persistentDefCopy = NULL;
1815 virDomainDef *persistentDef = NULL;
1816 int ret = -1;
1817 int rc;
1818 virLXCDomainObjPrivate *priv;
1819 virLXCDriverConfig *cfg = virLXCDriverGetConfig(driver);
1820
1821 virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
1822 VIR_DOMAIN_AFFECT_CONFIG, -1);
1823 if (virTypedParamsValidate(params, nparams,
1824 VIR_DOMAIN_SCHEDULER_CPU_SHARES,
1825 VIR_TYPED_PARAM_ULLONG,
1826 VIR_DOMAIN_SCHEDULER_VCPU_PERIOD,
1827 VIR_TYPED_PARAM_ULLONG,
1828 VIR_DOMAIN_SCHEDULER_VCPU_QUOTA,
1829 VIR_TYPED_PARAM_LLONG,
1830 NULL) < 0)
1831 return -1;
1832
1833 if (!(vm = lxcDomObjFromDomain(dom)))
1834 goto cleanup;
1835
1836 priv = vm->privateData;
1837
1838 if (virDomainSetSchedulerParametersFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
1839 goto cleanup;
1840
1841 if (!(caps = virLXCDriverGetCapabilities(driver, false)))
1842 goto cleanup;
1843
1844 if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
1845 goto cleanup;
1846
1847 if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
1848 goto endjob;
1849
1850 if (persistentDef) {
1851 /* Make a copy for updated domain. */
1852 persistentDefCopy = virDomainObjCopyPersistentDef(vm, driver->xmlopt, NULL);
1853 if (!persistentDefCopy)
1854 goto endjob;
1855 }
1856
1857 if (def) {
1858 if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU)) {
1859 virReportError(VIR_ERR_OPERATION_INVALID,
1860 "%s", _("cgroup CPU controller is not mounted"));
1861 goto endjob;
1862 }
1863 }
1864
1865 for (i = 0; i < nparams; i++) {
1866 virTypedParameterPtr param = ¶ms[i];
1867
1868 if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_CPU_SHARES)) {
1869 if (def) {
1870 if (virCgroupSetCpuShares(priv->cgroup, params[i].value.ul) < 0)
1871 goto endjob;
1872
1873 def->cputune.shares = params[i].value.ul;
1874 def->cputune.sharesSpecified = true;
1875 }
1876
1877 if (persistentDef) {
1878 persistentDefCopy->cputune.shares = params[i].value.ul;
1879 persistentDefCopy->cputune.sharesSpecified = true;
1880 }
1881 } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_VCPU_PERIOD)) {
1882 if (def) {
1883 rc = lxcSetVcpuBWLive(priv->cgroup, params[i].value.ul, 0);
1884 if (rc != 0)
1885 goto endjob;
1886
1887 if (params[i].value.ul)
1888 def->cputune.period = params[i].value.ul;
1889 }
1890
1891 if (persistentDef)
1892 persistentDefCopy->cputune.period = params[i].value.ul;
1893 } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_VCPU_QUOTA)) {
1894 if (def) {
1895 rc = lxcSetVcpuBWLive(priv->cgroup, 0, params[i].value.l);
1896 if (rc != 0)
1897 goto endjob;
1898
1899 if (params[i].value.l)
1900 def->cputune.quota = params[i].value.l;
1901 }
1902
1903 if (persistentDef)
1904 persistentDefCopy->cputune.quota = params[i].value.l;
1905 }
1906 }
1907
1908 if (virDomainObjSave(vm, driver->xmlopt, cfg->stateDir) < 0)
1909 goto endjob;
1910
1911
1912 if (persistentDef) {
1913 rc = virDomainDefSave(persistentDefCopy, driver->xmlopt,
1914 cfg->configDir);
1915 if (rc < 0)
1916 goto endjob;
1917
1918 virDomainObjAssignDef(vm, &persistentDefCopy, false, NULL);
1919 }
1920
1921 ret = 0;
1922
1923 endjob:
1924 virLXCDomainObjEndJob(driver, vm);
1925
1926 cleanup:
1927 virDomainDefFree(persistentDefCopy);
1928 virDomainObjEndAPI(&vm);
1929 virObjectUnref(caps);
1930 virObjectUnref(cfg);
1931 return ret;
1932 }
1933
1934 static int
lxcDomainSetSchedulerParameters(virDomainPtr domain,virTypedParameterPtr params,int nparams)1935 lxcDomainSetSchedulerParameters(virDomainPtr domain,
1936 virTypedParameterPtr params,
1937 int nparams)
1938 {
1939 return lxcDomainSetSchedulerParametersFlags(domain, params, nparams, 0);
1940 }
1941
1942 static int
lxcDomainGetSchedulerParametersFlags(virDomainPtr dom,virTypedParameterPtr params,int * nparams,unsigned int flags)1943 lxcDomainGetSchedulerParametersFlags(virDomainPtr dom,
1944 virTypedParameterPtr params,
1945 int *nparams,
1946 unsigned int flags)
1947 {
1948 virDomainObj *vm = NULL;
1949 virDomainDef *def;
1950 virDomainDef *persistentDef;
1951 unsigned long long shares = 0;
1952 unsigned long long period = 0;
1953 long long quota = 0;
1954 int ret = -1;
1955 int rc;
1956 bool cpu_bw_status = false;
1957 int saved_nparams = 0;
1958 virLXCDomainObjPrivate *priv;
1959
1960 virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
1961 VIR_DOMAIN_AFFECT_CONFIG |
1962 VIR_TYPED_PARAM_STRING_OKAY, -1);
1963
1964 /* We don't return strings, and thus trivially support this flag. */
1965 flags &= ~VIR_TYPED_PARAM_STRING_OKAY;
1966
1967 if (!(vm = lxcDomObjFromDomain(dom)))
1968 goto cleanup;
1969
1970 priv = vm->privateData;
1971
1972 if (virDomainGetSchedulerParametersFlagsEnsureACL(dom->conn, vm->def) < 0)
1973 goto cleanup;
1974
1975 if (*nparams > 1)
1976 cpu_bw_status = virCgroupSupportsCpuBW(priv->cgroup);
1977
1978 if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
1979 goto cleanup;
1980
1981 if (persistentDef) {
1982 shares = persistentDef->cputune.shares;
1983 if (*nparams > 1) {
1984 period = persistentDef->cputune.period;
1985 quota = persistentDef->cputune.quota;
1986 cpu_bw_status = true; /* Allow copy of data to params[] */
1987 }
1988 goto out;
1989 }
1990
1991 if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU)) {
1992 virReportError(VIR_ERR_OPERATION_INVALID,
1993 "%s", _("cgroup CPU controller is not mounted"));
1994 goto cleanup;
1995 }
1996
1997 if (virCgroupGetCpuShares(priv->cgroup, &shares) < 0)
1998 goto cleanup;
1999
2000 if (*nparams > 1 && cpu_bw_status) {
2001 rc = lxcGetVcpuBWLive(priv->cgroup, &period, "a);
2002 if (rc != 0)
2003 goto cleanup;
2004 }
2005 out:
2006 if (virTypedParameterAssign(¶ms[0], VIR_DOMAIN_SCHEDULER_CPU_SHARES,
2007 VIR_TYPED_PARAM_ULLONG, shares) < 0)
2008 goto cleanup;
2009 saved_nparams++;
2010
2011 if (cpu_bw_status) {
2012 if (*nparams > saved_nparams) {
2013 if (virTypedParameterAssign(¶ms[1],
2014 VIR_DOMAIN_SCHEDULER_VCPU_PERIOD,
2015 VIR_TYPED_PARAM_ULLONG, period) < 0)
2016 goto cleanup;
2017 saved_nparams++;
2018 }
2019
2020 if (*nparams > saved_nparams) {
2021 if (virTypedParameterAssign(¶ms[2],
2022 VIR_DOMAIN_SCHEDULER_VCPU_QUOTA,
2023 VIR_TYPED_PARAM_LLONG, quota) < 0)
2024 goto cleanup;
2025 saved_nparams++;
2026 }
2027 }
2028
2029 *nparams = saved_nparams;
2030
2031 ret = 0;
2032
2033 cleanup:
2034 virDomainObjEndAPI(&vm);
2035 return ret;
2036 }
2037
2038 static int
lxcDomainGetSchedulerParameters(virDomainPtr domain,virTypedParameterPtr params,int * nparams)2039 lxcDomainGetSchedulerParameters(virDomainPtr domain,
2040 virTypedParameterPtr params,
2041 int *nparams)
2042 {
2043 return lxcDomainGetSchedulerParametersFlags(domain, params, nparams, 0);
2044 }
2045
2046
2047 static int
lxcDomainBlockStats(virDomainPtr dom,const char * path,virDomainBlockStatsPtr stats)2048 lxcDomainBlockStats(virDomainPtr dom,
2049 const char *path,
2050 virDomainBlockStatsPtr stats)
2051 {
2052 virLXCDriver *driver = dom->conn->privateData;
2053 int ret = -1;
2054 virDomainObj *vm;
2055 virDomainDiskDef *disk = NULL;
2056 virLXCDomainObjPrivate *priv;
2057
2058 if (!(vm = lxcDomObjFromDomain(dom)))
2059 return ret;
2060
2061 priv = vm->privateData;
2062
2063 if (virDomainBlockStatsEnsureACL(dom->conn, vm->def) < 0)
2064 goto cleanup;
2065
2066 if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_QUERY) < 0)
2067 goto cleanup;
2068
2069 if (virDomainObjCheckActive(vm) < 0)
2070 goto endjob;
2071
2072 if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_BLKIO)) {
2073 virReportError(VIR_ERR_OPERATION_INVALID, "%s",
2074 _("blkio cgroup isn't mounted"));
2075 goto endjob;
2076 }
2077
2078 if (!*path) {
2079 /* empty path - return entire domain blkstats instead */
2080 ret = virCgroupGetBlkioIoServiced(priv->cgroup,
2081 &stats->rd_bytes,
2082 &stats->wr_bytes,
2083 &stats->rd_req,
2084 &stats->wr_req);
2085 goto endjob;
2086 }
2087
2088 if (!(disk = virDomainDiskByName(vm->def, path, false))) {
2089 virReportError(VIR_ERR_INVALID_ARG,
2090 _("invalid path: %s"), path);
2091 goto endjob;
2092 }
2093
2094 if (!disk->info.alias) {
2095 virReportError(VIR_ERR_INTERNAL_ERROR,
2096 _("missing disk device alias name for %s"), disk->dst);
2097 goto endjob;
2098 }
2099
2100 ret = virCgroupGetBlkioIoDeviceServiced(priv->cgroup,
2101 disk->info.alias,
2102 &stats->rd_bytes,
2103 &stats->wr_bytes,
2104 &stats->rd_req,
2105 &stats->wr_req);
2106
2107 endjob:
2108 virLXCDomainObjEndJob(driver, vm);
2109
2110 cleanup:
2111 virDomainObjEndAPI(&vm);
2112 return ret;
2113 }
2114
2115
2116 static int
lxcDomainBlockStatsFlags(virDomainPtr dom,const char * path,virTypedParameterPtr params,int * nparams,unsigned int flags)2117 lxcDomainBlockStatsFlags(virDomainPtr dom,
2118 const char * path,
2119 virTypedParameterPtr params,
2120 int * nparams,
2121 unsigned int flags)
2122 {
2123 virLXCDriver *driver = dom->conn->privateData;
2124 int tmp, ret = -1;
2125 virDomainObj *vm;
2126 virDomainDiskDef *disk = NULL;
2127 virLXCDomainObjPrivate *priv;
2128 long long rd_req, rd_bytes, wr_req, wr_bytes;
2129 virTypedParameterPtr param;
2130
2131 virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1);
2132
2133 /* We don't return strings, and thus trivially support this flag. */
2134 flags &= ~VIR_TYPED_PARAM_STRING_OKAY;
2135
2136 if (!*nparams) {
2137 *nparams = LXC_NB_DOMAIN_BLOCK_STAT_PARAM;
2138 return 0;
2139 }
2140
2141 if (!(vm = lxcDomObjFromDomain(dom)))
2142 return ret;
2143
2144 priv = vm->privateData;
2145
2146 if (virDomainBlockStatsFlagsEnsureACL(dom->conn, vm->def) < 0)
2147 goto cleanup;
2148
2149 if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_QUERY) < 0)
2150 goto cleanup;
2151
2152 if (virDomainObjCheckActive(vm) < 0)
2153 goto endjob;
2154
2155 if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_BLKIO)) {
2156 virReportError(VIR_ERR_OPERATION_INVALID, "%s",
2157 _("blkio cgroup isn't mounted"));
2158 goto endjob;
2159 }
2160
2161 if (!*path) {
2162 /* empty path - return entire domain blkstats instead */
2163 if (virCgroupGetBlkioIoServiced(priv->cgroup,
2164 &rd_bytes,
2165 &wr_bytes,
2166 &rd_req,
2167 &wr_req) < 0) {
2168 virReportError(VIR_ERR_INTERNAL_ERROR,
2169 "%s", _("domain stats query failed"));
2170 goto endjob;
2171 }
2172 } else {
2173 if (!(disk = virDomainDiskByName(vm->def, path, false))) {
2174 virReportError(VIR_ERR_INVALID_ARG,
2175 _("invalid path: %s"), path);
2176 goto endjob;
2177 }
2178
2179 if (!disk->info.alias) {
2180 virReportError(VIR_ERR_INTERNAL_ERROR,
2181 _("missing disk device alias name for %s"), disk->dst);
2182 goto endjob;
2183 }
2184
2185 if (virCgroupGetBlkioIoDeviceServiced(priv->cgroup,
2186 disk->info.alias,
2187 &rd_bytes,
2188 &wr_bytes,
2189 &rd_req,
2190 &wr_req) < 0) {
2191 virReportError(VIR_ERR_INTERNAL_ERROR,
2192 "%s", _("domain stats query failed"));
2193 goto endjob;
2194 }
2195 }
2196
2197 tmp = 0;
2198 ret = -1;
2199
2200 if (tmp < *nparams && wr_bytes != -1) {
2201 param = ¶ms[tmp];
2202 if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_WRITE_BYTES,
2203 VIR_TYPED_PARAM_LLONG, wr_bytes) < 0)
2204 goto endjob;
2205 tmp++;
2206 }
2207
2208 if (tmp < *nparams && wr_req != -1) {
2209 param = ¶ms[tmp];
2210 if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_WRITE_REQ,
2211 VIR_TYPED_PARAM_LLONG, wr_req) < 0)
2212 goto endjob;
2213 tmp++;
2214 }
2215
2216 if (tmp < *nparams && rd_bytes != -1) {
2217 param = ¶ms[tmp];
2218 if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_READ_BYTES,
2219 VIR_TYPED_PARAM_LLONG, rd_bytes) < 0)
2220 goto endjob;
2221 tmp++;
2222 }
2223
2224 if (tmp < *nparams && rd_req != -1) {
2225 param = ¶ms[tmp];
2226 if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_READ_REQ,
2227 VIR_TYPED_PARAM_LLONG, rd_req) < 0)
2228 goto endjob;
2229 tmp++;
2230 }
2231
2232 ret = 0;
2233 *nparams = tmp;
2234
2235 endjob:
2236 virLXCDomainObjEndJob(driver, vm);
2237
2238 cleanup:
2239 virDomainObjEndAPI(&vm);
2240 return ret;
2241 }
2242
2243
2244 static int
lxcDomainSetBlkioParameters(virDomainPtr dom,virTypedParameterPtr params,int nparams,unsigned int flags)2245 lxcDomainSetBlkioParameters(virDomainPtr dom,
2246 virTypedParameterPtr params,
2247 int nparams,
2248 unsigned int flags)
2249 {
2250 virLXCDriver *driver = dom->conn->privateData;
2251 virDomainObj *vm = NULL;
2252 virDomainDef *def = NULL;
2253 virDomainDef *persistentDef = NULL;
2254 int ret = -1;
2255 virLXCDriverConfig *cfg = NULL;
2256 virLXCDomainObjPrivate *priv;
2257
2258 virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
2259 VIR_DOMAIN_AFFECT_CONFIG, -1);
2260 if (virTypedParamsValidate(params, nparams,
2261 VIR_DOMAIN_BLKIO_WEIGHT,
2262 VIR_TYPED_PARAM_UINT,
2263 VIR_DOMAIN_BLKIO_DEVICE_WEIGHT,
2264 VIR_TYPED_PARAM_STRING,
2265 VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS,
2266 VIR_TYPED_PARAM_STRING,
2267 VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS,
2268 VIR_TYPED_PARAM_STRING,
2269 VIR_DOMAIN_BLKIO_DEVICE_READ_BPS,
2270 VIR_TYPED_PARAM_STRING,
2271 VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS,
2272 VIR_TYPED_PARAM_STRING,
2273 NULL) < 0)
2274 return -1;
2275
2276 if (!(vm = lxcDomObjFromDomain(dom)))
2277 return -1;
2278
2279 priv = vm->privateData;
2280 cfg = virLXCDriverGetConfig(driver);
2281
2282 if (virDomainSetBlkioParametersEnsureACL(dom->conn, vm->def, flags) < 0)
2283 goto cleanup;
2284
2285 if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
2286 goto cleanup;
2287
2288 if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
2289 goto endjob;
2290
2291 if (def) {
2292 if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_BLKIO)) {
2293 virReportError(VIR_ERR_OPERATION_INVALID, "%s",
2294 _("blkio cgroup isn't mounted"));
2295 goto endjob;
2296 }
2297 }
2298
2299 ret = 0;
2300 if (def) {
2301 ret = virDomainCgroupSetupDomainBlkioParameters(priv->cgroup, def,
2302 params, nparams);
2303 }
2304 if (ret < 0)
2305 goto endjob;
2306 if (persistentDef) {
2307 ret = virDomainDriverSetupPersistentDefBlkioParams(persistentDef,
2308 params,
2309 nparams);
2310
2311 if (virDomainDefSave(persistentDef, driver->xmlopt, cfg->configDir) < 0)
2312 ret = -1;
2313 }
2314
2315 endjob:
2316 virLXCDomainObjEndJob(driver, vm);
2317
2318 cleanup:
2319 virDomainObjEndAPI(&vm);
2320 virObjectUnref(cfg);
2321 return ret;
2322 }
2323
2324
2325 #define LXC_NB_BLKIO_PARAM 6
2326
2327 static int
lxcDomainGetBlkioParameters(virDomainPtr dom,virTypedParameterPtr params,int * nparams,unsigned int flags)2328 lxcDomainGetBlkioParameters(virDomainPtr dom,
2329 virTypedParameterPtr params,
2330 int *nparams,
2331 unsigned int flags)
2332 {
2333 virDomainObj *vm = NULL;
2334 virDomainDef *def = NULL;
2335 virDomainDef *persistentDef = NULL;
2336 int maxparams = LXC_NB_BLKIO_PARAM;
2337 unsigned int val;
2338 int ret = -1;
2339 virLXCDomainObjPrivate *priv;
2340
2341 virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
2342 VIR_DOMAIN_AFFECT_CONFIG |
2343 VIR_TYPED_PARAM_STRING_OKAY, -1);
2344
2345 /* We blindly return a string, and let libvirt.c and
2346 * remote_driver.c do the filtering on behalf of older clients
2347 * that can't parse it. */
2348 flags &= ~VIR_TYPED_PARAM_STRING_OKAY;
2349
2350 if (!(vm = lxcDomObjFromDomain(dom)))
2351 return -1;
2352
2353 priv = vm->privateData;
2354
2355 if (virDomainGetBlkioParametersEnsureACL(dom->conn, vm->def) < 0)
2356 goto cleanup;
2357
2358 if ((*nparams) == 0) {
2359 /* Current number of blkio parameters supported by cgroups */
2360 *nparams = LXC_NB_BLKIO_PARAM;
2361 ret = 0;
2362 goto cleanup;
2363 } else if (*nparams < maxparams) {
2364 maxparams = *nparams;
2365 }
2366
2367 *nparams = 0;
2368
2369 if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
2370 goto cleanup;
2371
2372 if (def) {
2373 if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_BLKIO)) {
2374 virReportError(VIR_ERR_OPERATION_INVALID, "%s",
2375 _("blkio cgroup isn't mounted"));
2376 goto cleanup;
2377 }
2378
2379 /* fill blkio weight here */
2380 if (virCgroupGetBlkioWeight(priv->cgroup, &val) < 0)
2381 goto cleanup;
2382 if (virTypedParameterAssign(&(params[(*nparams)++]),
2383 VIR_DOMAIN_BLKIO_WEIGHT,
2384 VIR_TYPED_PARAM_UINT, val) < 0)
2385 goto cleanup;
2386
2387 if (virDomainGetBlkioParametersAssignFromDef(def, params, nparams,
2388 maxparams) < 0)
2389 goto cleanup;
2390
2391 } else if (persistentDef) {
2392 /* fill blkio weight here */
2393 if (virTypedParameterAssign(&(params[(*nparams)++]),
2394 VIR_DOMAIN_BLKIO_WEIGHT,
2395 VIR_TYPED_PARAM_UINT,
2396 persistentDef->blkio.weight) < 0)
2397 goto cleanup;
2398
2399 if (virDomainGetBlkioParametersAssignFromDef(persistentDef, params,
2400 nparams, maxparams) < 0)
2401 goto cleanup;
2402 }
2403
2404 ret = 0;
2405
2406 cleanup:
2407 virDomainObjEndAPI(&vm);
2408 return ret;
2409 }
2410
2411
2412 static int
lxcDomainInterfaceStats(virDomainPtr dom,const char * device,virDomainInterfaceStatsPtr stats)2413 lxcDomainInterfaceStats(virDomainPtr dom,
2414 const char *device,
2415 virDomainInterfaceStatsPtr stats)
2416 {
2417 virDomainObj *vm;
2418 int ret = -1;
2419 virLXCDriver *driver = dom->conn->privateData;
2420 virDomainNetDef *net = NULL;
2421
2422 if (!(vm = lxcDomObjFromDomain(dom)))
2423 goto cleanup;
2424
2425 if (virDomainInterfaceStatsEnsureACL(dom->conn, vm->def) < 0)
2426 goto cleanup;
2427
2428 if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_QUERY) < 0)
2429 goto cleanup;
2430
2431 if (virDomainObjCheckActive(vm) < 0)
2432 goto endjob;
2433
2434 if (!(net = virDomainNetFind(vm->def, device)))
2435 goto endjob;
2436
2437 if (virNetDevTapInterfaceStats(net->ifname, stats,
2438 !virDomainNetTypeSharesHostView(net)) < 0)
2439 goto endjob;
2440
2441 ret = 0;
2442
2443 endjob:
2444 virLXCDomainObjEndJob(driver, vm);
2445
2446 cleanup:
2447 virDomainObjEndAPI(&vm);
2448 return ret;
2449 }
2450
2451
lxcDomainGetAutostart(virDomainPtr dom,int * autostart)2452 static int lxcDomainGetAutostart(virDomainPtr dom,
2453 int *autostart)
2454 {
2455 virDomainObj *vm;
2456 int ret = -1;
2457
2458 if (!(vm = lxcDomObjFromDomain(dom)))
2459 goto cleanup;
2460
2461 if (virDomainGetAutostartEnsureACL(dom->conn, vm->def) < 0)
2462 goto cleanup;
2463
2464 *autostart = vm->autostart;
2465 ret = 0;
2466
2467 cleanup:
2468 virDomainObjEndAPI(&vm);
2469 return ret;
2470 }
2471
lxcDomainSetAutostart(virDomainPtr dom,int autostart)2472 static int lxcDomainSetAutostart(virDomainPtr dom,
2473 int autostart)
2474 {
2475 virLXCDriver *driver = dom->conn->privateData;
2476 virDomainObj *vm;
2477 g_autofree char *configFile = NULL;
2478 g_autofree char *autostartLink = NULL;
2479 int ret = -1;
2480 virLXCDriverConfig *cfg = virLXCDriverGetConfig(driver);
2481
2482 if (!(vm = lxcDomObjFromDomain(dom)))
2483 goto cleanup;
2484
2485 if (virDomainSetAutostartEnsureACL(dom->conn, vm->def) < 0)
2486 goto cleanup;
2487
2488 if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
2489 goto cleanup;
2490
2491 if (!vm->persistent) {
2492 virReportError(VIR_ERR_OPERATION_INVALID,
2493 "%s", _("Cannot set autostart for transient domain"));
2494 goto endjob;
2495 }
2496
2497 autostart = (autostart != 0);
2498
2499 if (vm->autostart == autostart) {
2500 ret = 0;
2501 goto endjob;
2502 }
2503
2504 configFile = virDomainConfigFile(cfg->configDir,
2505 vm->def->name);
2506 if (configFile == NULL)
2507 goto endjob;
2508 autostartLink = virDomainConfigFile(cfg->autostartDir,
2509 vm->def->name);
2510 if (autostartLink == NULL)
2511 goto endjob;
2512
2513 if (autostart) {
2514 if (g_mkdir_with_parents(cfg->autostartDir, 0777) < 0) {
2515 virReportSystemError(errno,
2516 _("Cannot create autostart directory %s"),
2517 cfg->autostartDir);
2518 goto endjob;
2519 }
2520
2521 if (symlink(configFile, autostartLink) < 0) {
2522 virReportSystemError(errno,
2523 _("Failed to create symlink '%s to '%s'"),
2524 autostartLink, configFile);
2525 goto endjob;
2526 }
2527 } else {
2528 if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
2529 virReportSystemError(errno,
2530 _("Failed to delete symlink '%s'"),
2531 autostartLink);
2532 goto endjob;
2533 }
2534 }
2535
2536 vm->autostart = autostart;
2537 ret = 0;
2538
2539 endjob:
2540 virLXCDomainObjEndJob(driver, vm);
2541
2542 cleanup:
2543 virDomainObjEndAPI(&vm);
2544 virObjectUnref(cfg);
2545 return ret;
2546 }
2547
lxcFreezeContainer(virDomainObj * vm)2548 static int lxcFreezeContainer(virDomainObj *vm)
2549 {
2550 int timeout = 1000; /* In milliseconds */
2551 int check_interval = 1; /* In milliseconds */
2552 int exp = 10;
2553 int waited_time = 0;
2554 g_autofree char *state = NULL;
2555 virLXCDomainObjPrivate *priv = vm->privateData;
2556
2557 while (waited_time < timeout) {
2558 int r;
2559 /*
2560 * Writing "FROZEN" to the "freezer.state" freezes the group,
2561 * i.e., the container, temporarily transiting "FREEZING" state.
2562 * Once the freezing is completed, the state of the group transits
2563 * to "FROZEN".
2564 * (see linux-2.6/Documentation/cgroups/freezer-subsystem.txt)
2565 */
2566 r = virCgroupSetFreezerState(priv->cgroup, "FROZEN");
2567
2568 /*
2569 * Returning EBUSY explicitly indicates that the group is
2570 * being frozen but incomplete, and other errors are true
2571 * errors.
2572 */
2573 if (r < 0 && r != -EBUSY) {
2574 VIR_DEBUG("Writing freezer.state failed with errno: %d", r);
2575 goto error;
2576 }
2577 if (r == -EBUSY)
2578 VIR_DEBUG("Writing freezer.state gets EBUSY");
2579
2580 /*
2581 * Unfortunately, returning 0 (success) is likely to happen
2582 * even when the freezing has not been completed. Sometimes
2583 * the state of the group remains "FREEZING" like when
2584 * returning -EBUSY and even worse may never transit to
2585 * "FROZEN" even if writing "FROZEN" again.
2586 *
2587 * So we don't trust the return value anyway and always
2588 * decide that the freezing has been complete only with
2589 * the state actually transit to "FROZEN".
2590 */
2591 g_usleep(check_interval * 1000);
2592
2593 r = virCgroupGetFreezerState(priv->cgroup, &state);
2594
2595 if (r < 0) {
2596 VIR_DEBUG("Reading freezer.state failed with errno: %d", r);
2597 goto error;
2598 }
2599 VIR_DEBUG("Read freezer.state: %s", state);
2600
2601 if (STREQ(state, "FROZEN"))
2602 return 0;
2603
2604 waited_time += check_interval;
2605 /*
2606 * Increasing check_interval exponentially starting with
2607 * small initial value treats nicely two cases; One is
2608 * a container is under no load and waiting for long period
2609 * makes no sense. The other is under heavy load. The container
2610 * may stay longer time in FREEZING or never transit to FROZEN.
2611 * In that case, eager polling will just waste CPU time.
2612 */
2613 check_interval *= exp;
2614 }
2615 VIR_DEBUG("lxcFreezeContainer timeout");
2616 error:
2617 /*
2618 * If timeout or an error on reading the state occurs,
2619 * activate the group again and return an error.
2620 * This is likely to fall the group back again gracefully.
2621 */
2622 virCgroupSetFreezerState(priv->cgroup, "THAWED");
2623 return -1;
2624 }
2625
lxcDomainSuspend(virDomainPtr dom)2626 static int lxcDomainSuspend(virDomainPtr dom)
2627 {
2628 virLXCDriver *driver = dom->conn->privateData;
2629 virDomainObj *vm;
2630 virObjectEvent *event = NULL;
2631 int ret = -1;
2632 virLXCDriverConfig *cfg = virLXCDriverGetConfig(driver);
2633
2634 if (!(vm = lxcDomObjFromDomain(dom)))
2635 goto cleanup;
2636
2637 if (virDomainSuspendEnsureACL(dom->conn, vm->def) < 0)
2638 goto cleanup;
2639
2640 if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
2641 goto cleanup;
2642
2643 if (virDomainObjCheckActive(vm) < 0)
2644 goto endjob;
2645
2646 if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_PAUSED) {
2647 if (lxcFreezeContainer(vm) < 0) {
2648 virReportError(VIR_ERR_OPERATION_FAILED,
2649 "%s", _("Suspend operation failed"));
2650 goto endjob;
2651 }
2652 virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
2653
2654 event = virDomainEventLifecycleNewFromObj(vm,
2655 VIR_DOMAIN_EVENT_SUSPENDED,
2656 VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
2657 }
2658
2659 if (virDomainObjSave(vm, driver->xmlopt, cfg->stateDir) < 0)
2660 goto endjob;
2661 ret = 0;
2662
2663 endjob:
2664 virLXCDomainObjEndJob(driver, vm);
2665
2666 cleanup:
2667 virObjectEventStateQueue(driver->domainEventState, event);
2668 virDomainObjEndAPI(&vm);
2669 virObjectUnref(cfg);
2670 return ret;
2671 }
2672
lxcDomainResume(virDomainPtr dom)2673 static int lxcDomainResume(virDomainPtr dom)
2674 {
2675 virLXCDriver *driver = dom->conn->privateData;
2676 virDomainObj *vm;
2677 virObjectEvent *event = NULL;
2678 int ret = -1;
2679 int state;
2680 virLXCDomainObjPrivate *priv;
2681 virLXCDriverConfig *cfg = virLXCDriverGetConfig(driver);
2682
2683 if (!(vm = lxcDomObjFromDomain(dom)))
2684 goto cleanup;
2685
2686 priv = vm->privateData;
2687
2688 if (virDomainResumeEnsureACL(dom->conn, vm->def) < 0)
2689 goto cleanup;
2690
2691 if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
2692 goto cleanup;
2693
2694 if (virDomainObjCheckActive(vm) < 0)
2695 goto endjob;
2696
2697 state = virDomainObjGetState(vm, NULL);
2698 if (state == VIR_DOMAIN_RUNNING) {
2699 virReportError(VIR_ERR_OPERATION_INVALID,
2700 "%s", _("domain is already running"));
2701 goto endjob;
2702 } else if (state == VIR_DOMAIN_PAUSED) {
2703 if (virCgroupSetFreezerState(priv->cgroup, "THAWED") < 0) {
2704 virReportError(VIR_ERR_OPERATION_FAILED,
2705 "%s", _("Resume operation failed"));
2706 goto endjob;
2707 }
2708 virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
2709 VIR_DOMAIN_RUNNING_UNPAUSED);
2710
2711 event = virDomainEventLifecycleNewFromObj(vm,
2712 VIR_DOMAIN_EVENT_RESUMED,
2713 VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
2714 }
2715
2716 if (virDomainObjSave(vm, driver->xmlopt, cfg->stateDir) < 0)
2717 goto endjob;
2718 ret = 0;
2719
2720 endjob:
2721 virLXCDomainObjEndJob(driver, vm);
2722
2723 cleanup:
2724 virObjectEventStateQueue(driver->domainEventState, event);
2725 virDomainObjEndAPI(&vm);
2726 virObjectUnref(cfg);
2727 return ret;
2728 }
2729
2730 static int
lxcDomainOpenConsole(virDomainPtr dom,const char * dev_name,virStreamPtr st,unsigned int flags)2731 lxcDomainOpenConsole(virDomainPtr dom,
2732 const char *dev_name,
2733 virStreamPtr st,
2734 unsigned int flags)
2735 {
2736 virDomainObj *vm = NULL;
2737 int ret = -1;
2738 virDomainChrDef *chr = NULL;
2739 size_t i;
2740
2741 virCheckFlags(0, -1);
2742
2743 if (!(vm = lxcDomObjFromDomain(dom)))
2744 goto cleanup;
2745
2746 if (virDomainOpenConsoleEnsureACL(dom->conn, vm->def) < 0)
2747 goto cleanup;
2748
2749 if (virDomainObjCheckActive(vm) < 0)
2750 goto cleanup;
2751
2752 if (dev_name) {
2753 for (i = 0; i < vm->def->nconsoles; i++) {
2754 if (vm->def->consoles[i]->info.alias &&
2755 STREQ(vm->def->consoles[i]->info.alias, dev_name)) {
2756 chr = vm->def->consoles[i];
2757 break;
2758 }
2759 }
2760 } else {
2761 if (vm->def->nconsoles)
2762 chr = vm->def->consoles[0];
2763 else if (vm->def->nserials)
2764 chr = vm->def->serials[0];
2765 }
2766
2767 if (!chr) {
2768 virReportError(VIR_ERR_INTERNAL_ERROR,
2769 _("cannot find console device '%s'"),
2770 dev_name ? dev_name : _("default"));
2771 goto cleanup;
2772 }
2773
2774 if (chr->source->type != VIR_DOMAIN_CHR_TYPE_PTY) {
2775 virReportError(VIR_ERR_INTERNAL_ERROR,
2776 _("character device %s is not using a PTY"),
2777 dev_name ? dev_name : NULLSTR(chr->info.alias));
2778 goto cleanup;
2779 }
2780
2781 if (virFDStreamOpenFile(st, chr->source->data.file.path,
2782 0, 0, O_RDWR) < 0)
2783 goto cleanup;
2784
2785 ret = 0;
2786 cleanup:
2787 virDomainObjEndAPI(&vm);
2788 return ret;
2789 }
2790
2791
2792 static int
lxcDomainSendProcessSignal(virDomainPtr dom,long long pid_value,unsigned int signum,unsigned int flags)2793 lxcDomainSendProcessSignal(virDomainPtr dom,
2794 long long pid_value,
2795 unsigned int signum,
2796 unsigned int flags)
2797 {
2798 virLXCDriver *driver = dom->conn->privateData;
2799 virDomainObj *vm = NULL;
2800 virLXCDomainObjPrivate *priv;
2801 pid_t victim;
2802 int ret = -1;
2803
2804 virCheckFlags(0, -1);
2805
2806 if (signum >= VIR_DOMAIN_PROCESS_SIGNAL_LAST) {
2807 virReportError(VIR_ERR_INVALID_ARG,
2808 _("signum value %d is out of range"),
2809 signum);
2810 return -1;
2811 }
2812
2813 if (!(vm = lxcDomObjFromDomain(dom)))
2814 goto cleanup;
2815
2816 priv = vm->privateData;
2817
2818 if (virDomainSendProcessSignalEnsureACL(dom->conn, vm->def) < 0)
2819 goto cleanup;
2820
2821 if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
2822 goto cleanup;
2823
2824 if (virDomainObjCheckActive(vm) < 0)
2825 goto endjob;
2826
2827 /*
2828 * XXX if the kernel has /proc/$PID/ns/pid we can
2829 * switch into container namespace & that way be
2830 * able to kill any PID. Alternatively if there
2831 * is a way to find a mapping of guest<->host PIDs
2832 * we can kill that way.
2833 */
2834 if (pid_value != 1) {
2835 virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
2836 _("Only the init process may be killed"));
2837 goto endjob;
2838 }
2839
2840 if (!priv->initpid) {
2841 virReportError(VIR_ERR_OPERATION_INVALID, "%s",
2842 _("Init pid is not yet available"));
2843 goto endjob;
2844 }
2845 victim = priv->initpid;
2846
2847 /* We're relying on fact libvirt header signal numbers
2848 * are taken from Linux, to avoid mapping
2849 */
2850 if (kill(victim, signum) < 0) {
2851 virReportSystemError(errno,
2852 _("Unable to send %d signal to process %d"),
2853 signum, victim);
2854 goto endjob;
2855 }
2856
2857 ret = 0;
2858
2859 endjob:
2860 virLXCDomainObjEndJob(driver, vm);
2861
2862 cleanup:
2863 virDomainObjEndAPI(&vm);
2864 return ret;
2865 }
2866
2867
2868 static int
lxcConnectListAllDomains(virConnectPtr conn,virDomainPtr ** domains,unsigned int flags)2869 lxcConnectListAllDomains(virConnectPtr conn,
2870 virDomainPtr **domains,
2871 unsigned int flags)
2872 {
2873 virLXCDriver *driver = conn->privateData;
2874
2875 virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
2876
2877 if (virConnectListAllDomainsEnsureACL(conn) < 0)
2878 return -1;
2879
2880 return virDomainObjListExport(driver->domains, conn, domains,
2881 virConnectListAllDomainsCheckACL, flags);
2882 }
2883
2884
2885 static int
lxcDomainShutdownFlags(virDomainPtr dom,unsigned int flags)2886 lxcDomainShutdownFlags(virDomainPtr dom,
2887 unsigned int flags)
2888 {
2889 virLXCDriver *driver = dom->conn->privateData;
2890 virLXCDomainObjPrivate *priv;
2891 virDomainObj *vm;
2892 int ret = -1;
2893 int rc = -1;
2894
2895 virCheckFlags(VIR_DOMAIN_SHUTDOWN_INITCTL |
2896 VIR_DOMAIN_SHUTDOWN_SIGNAL, -1);
2897
2898 if (!(vm = lxcDomObjFromDomain(dom)))
2899 goto cleanup;
2900
2901 priv = vm->privateData;
2902
2903 if (virDomainShutdownFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
2904 goto cleanup;
2905
2906 if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
2907 goto cleanup;
2908
2909 if (virDomainObjCheckActive(vm) < 0)
2910 goto endjob;
2911
2912 if (priv->initpid == 0) {
2913 virReportError(VIR_ERR_OPERATION_INVALID,
2914 "%s", _("Init process ID is not yet known"));
2915 goto endjob;
2916 }
2917
2918 if (flags == 0 ||
2919 (flags & VIR_DOMAIN_SHUTDOWN_INITCTL)) {
2920 int command = VIR_INITCTL_RUNLEVEL_POWEROFF;
2921
2922 if ((rc = virLXCDomainSetRunlevel(vm, command)) < 0) {
2923 if (flags != 0 &&
2924 (flags & VIR_DOMAIN_SHUTDOWN_INITCTL)) {
2925 virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
2926 _("Container does not provide an initctl pipe"));
2927 goto endjob;
2928 }
2929 }
2930 }
2931
2932 if (rc < 0 &&
2933 (flags == 0 ||
2934 (flags & VIR_DOMAIN_SHUTDOWN_SIGNAL))) {
2935 if (kill(priv->initpid, SIGTERM) < 0 &&
2936 errno != ESRCH) {
2937 virReportSystemError(errno,
2938 _("Unable to send SIGTERM to init pid %llu"),
2939 (long long)priv->initpid);
2940 goto endjob;
2941 }
2942 }
2943
2944 ret = 0;
2945
2946 endjob:
2947 virLXCDomainObjEndJob(driver, vm);
2948
2949 cleanup:
2950 virDomainObjEndAPI(&vm);
2951 return ret;
2952 }
2953
2954 static int
lxcDomainShutdown(virDomainPtr dom)2955 lxcDomainShutdown(virDomainPtr dom)
2956 {
2957 return lxcDomainShutdownFlags(dom, 0);
2958 }
2959
2960
2961 static int
lxcDomainReboot(virDomainPtr dom,unsigned int flags)2962 lxcDomainReboot(virDomainPtr dom,
2963 unsigned int flags)
2964 {
2965 virLXCDriver *driver = dom->conn->privateData;
2966 virLXCDomainObjPrivate *priv;
2967 virDomainObj *vm;
2968 int ret = -1;
2969 int rc = -1;
2970
2971 virCheckFlags(VIR_DOMAIN_REBOOT_INITCTL |
2972 VIR_DOMAIN_REBOOT_SIGNAL, -1);
2973
2974 if (!(vm = lxcDomObjFromDomain(dom)))
2975 goto cleanup;
2976
2977 priv = vm->privateData;
2978
2979 if (virDomainRebootEnsureACL(dom->conn, vm->def, flags) < 0)
2980 goto cleanup;
2981
2982 if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
2983 goto cleanup;
2984
2985 if (virDomainObjCheckActive(vm) < 0)
2986 goto endjob;
2987
2988 if (priv->initpid == 0) {
2989 virReportError(VIR_ERR_OPERATION_INVALID,
2990 "%s", _("Init process ID is not yet known"));
2991 goto endjob;
2992 }
2993
2994 if (flags == 0 ||
2995 (flags & VIR_DOMAIN_REBOOT_INITCTL)) {
2996 int command = VIR_INITCTL_RUNLEVEL_REBOOT;
2997
2998 if ((rc = virLXCDomainSetRunlevel(vm, command)) < 0) {
2999 if (flags != 0 &&
3000 (flags & VIR_DOMAIN_REBOOT_INITCTL)) {
3001 virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3002 _("Container does not provide an initctl pipe"));
3003 goto endjob;
3004 }
3005 }
3006 }
3007
3008 if (rc < 0 &&
3009 (flags == 0 ||
3010 (flags & VIR_DOMAIN_REBOOT_SIGNAL))) {
3011 if (kill(priv->initpid, SIGHUP) < 0 &&
3012 errno != ESRCH) {
3013 virReportSystemError(errno,
3014 _("Unable to send SIGTERM to init pid %llu"),
3015 (long long)priv->initpid);
3016 goto endjob;
3017 }
3018 }
3019
3020 ret = 0;
3021
3022 endjob:
3023 virLXCDomainObjEndJob(driver, vm);
3024
3025 cleanup:
3026 virDomainObjEndAPI(&vm);
3027 return ret;
3028 }
3029
3030
3031 static int
lxcDomainAttachDeviceConfig(virDomainDef * vmdef,virDomainDeviceDef * dev)3032 lxcDomainAttachDeviceConfig(virDomainDef *vmdef,
3033 virDomainDeviceDef *dev)
3034 {
3035 int ret = -1;
3036 virDomainDiskDef *disk;
3037 virDomainNetDef *net;
3038 virDomainHostdevDef *hostdev;
3039
3040 switch (dev->type) {
3041 case VIR_DOMAIN_DEVICE_DISK:
3042 disk = dev->data.disk;
3043 if (virDomainDiskIndexByName(vmdef, disk->dst, true) >= 0) {
3044 virReportError(VIR_ERR_INVALID_ARG,
3045 _("target %s already exists."), disk->dst);
3046 return -1;
3047 }
3048 virDomainDiskInsert(vmdef, disk);
3049 /* vmdef has the pointer. Generic codes for vmdef will do all jobs */
3050 dev->data.disk = NULL;
3051 ret = 0;
3052 break;
3053
3054 case VIR_DOMAIN_DEVICE_NET:
3055 net = dev->data.net;
3056 if (virDomainNetInsert(vmdef, net) < 0)
3057 return -1;
3058 dev->data.net = NULL;
3059 ret = 0;
3060 break;
3061
3062 case VIR_DOMAIN_DEVICE_HOSTDEV:
3063 hostdev = dev->data.hostdev;
3064 if (virDomainHostdevFind(vmdef, hostdev, NULL) >= 0) {
3065 virReportError(VIR_ERR_INVALID_ARG, "%s",
3066 _("device is already in the domain configuration"));
3067 return -1;
3068 }
3069 if (virDomainHostdevInsert(vmdef, hostdev) < 0)
3070 return -1;
3071 dev->data.hostdev = NULL;
3072 ret = 0;
3073 break;
3074
3075 default:
3076 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
3077 _("persistent attach of device is not supported"));
3078 break;
3079 }
3080
3081 return ret;
3082 }
3083
3084
3085 static int
lxcDomainUpdateDeviceConfig(virDomainDef * vmdef,virDomainDeviceDef * dev)3086 lxcDomainUpdateDeviceConfig(virDomainDef *vmdef,
3087 virDomainDeviceDef *dev)
3088 {
3089 int ret = -1;
3090 virDomainNetDef *net;
3091 virDomainDeviceDef oldDev = { .type = dev->type };
3092 int idx;
3093
3094 switch (dev->type) {
3095 case VIR_DOMAIN_DEVICE_NET:
3096 net = dev->data.net;
3097 if ((idx = virDomainNetFindIdx(vmdef, net)) < 0)
3098 return -1;
3099
3100 oldDev.data.net = vmdef->nets[idx];
3101 if (virDomainDefCompatibleDevice(vmdef, dev, &oldDev,
3102 VIR_DOMAIN_DEVICE_ACTION_UPDATE,
3103 false) < 0)
3104 return -1;
3105
3106 if (virDomainNetUpdate(vmdef, idx, net) < 0)
3107 return -1;
3108
3109 virDomainNetDefFree(oldDev.data.net);
3110 dev->data.net = NULL;
3111 ret = 0;
3112
3113 break;
3114
3115 default:
3116 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
3117 _("persistent update of device is not supported"));
3118 break;
3119 }
3120
3121 return ret;
3122 }
3123
3124
3125 static int
lxcDomainDetachDeviceConfig(virDomainDef * vmdef,virDomainDeviceDef * dev)3126 lxcDomainDetachDeviceConfig(virDomainDef *vmdef,
3127 virDomainDeviceDef *dev)
3128 {
3129 int ret = -1;
3130 virDomainDiskDef *disk;
3131 virDomainDiskDef *det_disk;
3132 virDomainNetDef *net;
3133 virDomainHostdevDef *hostdev;
3134 virDomainHostdevDef *det_hostdev;
3135 int idx;
3136
3137 switch (dev->type) {
3138 case VIR_DOMAIN_DEVICE_DISK:
3139 disk = dev->data.disk;
3140 if (!(det_disk = virDomainDiskRemoveByName(vmdef, disk->dst))) {
3141 virReportError(VIR_ERR_INVALID_ARG,
3142 _("no target device %s"), disk->dst);
3143 return -1;
3144 }
3145 virDomainDiskDefFree(det_disk);
3146 ret = 0;
3147 break;
3148
3149 case VIR_DOMAIN_DEVICE_NET:
3150 net = dev->data.net;
3151 if ((idx = virDomainNetFindIdx(vmdef, net)) < 0)
3152 return -1;
3153
3154 /* this is guaranteed to succeed */
3155 virDomainNetDefFree(virDomainNetRemove(vmdef, idx));
3156 ret = 0;
3157 break;
3158
3159 case VIR_DOMAIN_DEVICE_HOSTDEV: {
3160 hostdev = dev->data.hostdev;
3161 if ((idx = virDomainHostdevFind(vmdef, hostdev, &det_hostdev)) < 0) {
3162 virReportError(VIR_ERR_INVALID_ARG, "%s",
3163 _("device not present in domain configuration"));
3164 return -1;
3165 }
3166 virDomainHostdevRemove(vmdef, idx);
3167 virDomainHostdevDefFree(det_hostdev);
3168 ret = 0;
3169 break;
3170 }
3171
3172 default:
3173 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
3174 _("persistent detach of device is not supported"));
3175 break;
3176 }
3177
3178 return ret;
3179 }
3180
3181
3182 struct lxcDomainAttachDeviceMknodData {
3183 virLXCDriver *driver;
3184 mode_t mode;
3185 dev_t dev;
3186 virDomainObj *vm;
3187 virDomainDeviceDef *def;
3188 char *file;
3189 };
3190
3191 static int
lxcDomainAttachDeviceMknodHelper(pid_t pid G_GNUC_UNUSED,void * opaque)3192 lxcDomainAttachDeviceMknodHelper(pid_t pid G_GNUC_UNUSED,
3193 void *opaque)
3194 {
3195 struct lxcDomainAttachDeviceMknodData *data = opaque;
3196 int ret = -1;
3197
3198 virSecurityManagerPostFork(data->driver->securityManager);
3199
3200 if (virFileMakeParentPath(data->file) < 0) {
3201 virReportSystemError(errno,
3202 _("Unable to create %s"), data->file);
3203 goto cleanup;
3204 }
3205
3206 /* Yes, the device name we're creating may not
3207 * actually correspond to the major:minor number
3208 * we're using, but we've no other option at this
3209 * time. Just have to hope that containerized apps
3210 * don't get upset that the major:minor is different
3211 * to that normally implied by the device name
3212 */
3213 VIR_DEBUG("Creating dev %s (%d,%d)",
3214 data->file, major(data->dev), minor(data->dev));
3215 if (mknod(data->file, data->mode, data->dev) < 0) {
3216 virReportSystemError(errno,
3217 _("Unable to create device %s"),
3218 data->file);
3219 goto cleanup;
3220 }
3221
3222 if (lxcContainerChown(data->vm->def, data->file) < 0)
3223 goto cleanup;
3224
3225 /* Labelling normally operates on src, but we need
3226 * to actually label the dst here, so hack the config */
3227 switch (data->def->type) {
3228 case VIR_DOMAIN_DEVICE_DISK: {
3229 virDomainDiskDef *def = data->def->data.disk;
3230 char *tmpsrc = def->src->path;
3231 def->src->path = data->file;
3232 if (virSecurityManagerSetImageLabel(data->driver->securityManager,
3233 data->vm->def, def->src,
3234 VIR_SECURITY_DOMAIN_IMAGE_LABEL_BACKING_CHAIN) < 0) {
3235 def->src->path = tmpsrc;
3236 goto cleanup;
3237 }
3238 def->src->path = tmpsrc;
3239 } break;
3240
3241 case VIR_DOMAIN_DEVICE_HOSTDEV: {
3242 virDomainHostdevDef *def = data->def->data.hostdev;
3243 if (virSecurityManagerSetHostdevLabel(data->driver->securityManager,
3244 data->vm->def, def, NULL) < 0)
3245 goto cleanup;
3246 } break;
3247
3248 default:
3249 virReportError(VIR_ERR_INTERNAL_ERROR,
3250 _("Unexpected device type %d"),
3251 data->def->type);
3252 goto cleanup;
3253 }
3254
3255 ret = 0;
3256
3257 cleanup:
3258 if (ret < 0)
3259 unlink(data->file);
3260 return ret;
3261 }
3262
3263
3264 static int
lxcDomainAttachDeviceMknod(virLXCDriver * driver,mode_t mode,dev_t dev,virDomainObj * vm,virDomainDeviceDef * def,char * file)3265 lxcDomainAttachDeviceMknod(virLXCDriver *driver,
3266 mode_t mode,
3267 dev_t dev,
3268 virDomainObj *vm,
3269 virDomainDeviceDef *def,
3270 char *file)
3271 {
3272 virLXCDomainObjPrivate *priv = vm->privateData;
3273 struct lxcDomainAttachDeviceMknodData data;
3274
3275 memset(&data, 0, sizeof(data));
3276
3277 data.driver = driver;
3278 data.mode = mode;
3279 data.dev = dev;
3280 data.vm = vm;
3281 data.def = def;
3282 data.file = file;
3283
3284 if (virSecurityManagerPreFork(driver->securityManager) < 0)
3285 return -1;
3286
3287 if (virProcessRunInMountNamespace(priv->initpid,
3288 lxcDomainAttachDeviceMknodHelper,
3289 &data) < 0) {
3290 virSecurityManagerPostFork(driver->securityManager);
3291 return -1;
3292 }
3293
3294 virSecurityManagerPostFork(driver->securityManager);
3295 return 0;
3296 }
3297
3298
3299 static int
lxcDomainAttachDeviceUnlinkHelper(pid_t pid G_GNUC_UNUSED,void * opaque)3300 lxcDomainAttachDeviceUnlinkHelper(pid_t pid G_GNUC_UNUSED,
3301 void *opaque)
3302 {
3303 const char *path = opaque;
3304
3305 VIR_DEBUG("Unlinking %s", path);
3306 if (unlink(path) < 0 && errno != ENOENT) {
3307 virReportSystemError(errno,
3308 _("Unable to remove device %s"), path);
3309 return -1;
3310 }
3311
3312 return 0;
3313 }
3314
3315
3316 static int
lxcDomainAttachDeviceUnlink(virDomainObj * vm,char * file)3317 lxcDomainAttachDeviceUnlink(virDomainObj *vm,
3318 char *file)
3319 {
3320 virLXCDomainObjPrivate *priv = vm->privateData;
3321
3322 if (virProcessRunInMountNamespace(priv->initpid,
3323 lxcDomainAttachDeviceUnlinkHelper,
3324 file) < 0) {
3325 return -1;
3326 }
3327
3328 return 0;
3329 }
3330
3331
3332 static int
lxcDomainAttachDeviceDiskLive(virLXCDriver * driver,virDomainObj * vm,virDomainDeviceDef * dev)3333 lxcDomainAttachDeviceDiskLive(virLXCDriver *driver,
3334 virDomainObj *vm,
3335 virDomainDeviceDef *dev)
3336 {
3337 virLXCDomainObjPrivate *priv = vm->privateData;
3338 virDomainDiskDef *def = dev->data.disk;
3339 int ret = -1;
3340 struct stat sb;
3341 g_autofree char *file = NULL;
3342 int perms;
3343 const char *src = NULL;
3344
3345 if (!priv->initpid) {
3346 virReportError(VIR_ERR_OPERATION_INVALID, "%s",
3347 _("Cannot attach disk until init PID is known"));
3348 goto cleanup;
3349 }
3350
3351 if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
3352 virReportError(VIR_ERR_OPERATION_INVALID, "%s",
3353 _("devices cgroup isn't mounted"));
3354 goto cleanup;
3355 }
3356
3357 src = virDomainDiskGetSource(def);
3358 if (src == NULL) {
3359 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
3360 _("Can't setup disk without media"));
3361 goto cleanup;
3362 }
3363
3364 if (!virStorageSourceIsBlockLocal(def->src)) {
3365 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
3366 _("Can't setup disk for non-block device"));
3367 goto cleanup;
3368 }
3369
3370 if (virDomainDiskIndexByName(vm->def, def->dst, true) >= 0) {
3371 virReportError(VIR_ERR_OPERATION_FAILED,
3372 _("target %s already exists"), def->dst);
3373 goto cleanup;
3374 }
3375
3376 if (stat(src, &sb) < 0) {
3377 virReportSystemError(errno,
3378 _("Unable to access %s"), src);
3379 goto cleanup;
3380 }
3381
3382 if (!S_ISBLK(sb.st_mode)) {
3383 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
3384 _("Disk source %s must be a block device"),
3385 src);
3386 goto cleanup;
3387 }
3388
3389 perms = (def->src->readonly ?
3390 VIR_CGROUP_DEVICE_READ :
3391 VIR_CGROUP_DEVICE_RW) |
3392 VIR_CGROUP_DEVICE_MKNOD;
3393
3394 if (virCgroupAllowDevice(priv->cgroup,
3395 'b',
3396 major(sb.st_rdev),
3397 minor(sb.st_rdev),
3398 perms) < 0)
3399 goto cleanup;
3400
3401 file = g_strdup_printf("/dev/%s", def->dst);
3402
3403 if (lxcDomainAttachDeviceMknod(driver,
3404 0700 | S_IFBLK,
3405 sb.st_rdev,
3406 vm,
3407 dev,
3408 file) < 0) {
3409 if (virCgroupDenyDevice(priv->cgroup,
3410 'b',
3411 major(sb.st_rdev),
3412 minor(sb.st_rdev),
3413 perms) < 0)
3414 VIR_WARN("cannot deny device %s for domain %s: %s",
3415 src, vm->def->name, virGetLastErrorMessage());
3416 goto cleanup;
3417 }
3418
3419 virDomainDiskInsert(vm->def, def);
3420
3421 ret = 0;
3422
3423 cleanup:
3424 if (src)
3425 virDomainAuditDisk(vm, NULL, def->src, "attach", ret == 0);
3426 return ret;
3427 }
3428
3429
3430 static int
lxcDomainAttachDeviceNetLive(virLXCDriver * driver,virDomainObj * vm,virDomainNetDef * net)3431 lxcDomainAttachDeviceNetLive(virLXCDriver *driver,
3432 virDomainObj *vm,
3433 virDomainNetDef *net)
3434 {
3435 virLXCDomainObjPrivate *priv = vm->privateData;
3436 int ret = -1;
3437 virDomainNetType actualType;
3438 const virNetDevBandwidth *actualBandwidth;
3439 char *veth = NULL;
3440
3441 if (!priv->initpid) {
3442 virReportError(VIR_ERR_OPERATION_INVALID, "%s",
3443 _("Cannot attach disk until init PID is known"));
3444 return -1;
3445 }
3446
3447 if (virLXCProcessValidateInterface(net) < 0)
3448 return -1;
3449
3450 /* preallocate new slot for device */
3451 vm->def->nets = g_renew(virDomainNetDef *,
3452 vm->def->nets,
3453 vm->def->nnets + 1);
3454
3455 /* If appropriate, grab a physical device from the configured
3456 * network's pool of devices, or resolve bridge device name
3457 * to the one defined in the network definition.
3458 */
3459 if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
3460 g_autoptr(virConnect) netconn = virGetConnectNetwork();
3461 if (!netconn || virDomainNetAllocateActualDevice(netconn, vm->def, net) < 0)
3462 return -1;
3463 }
3464
3465 /* final validation now that actual type is known */
3466 if (virDomainActualNetDefValidate(net) < 0)
3467 return -1;
3468
3469 actualType = virDomainNetGetActualType(net);
3470
3471 switch (actualType) {
3472 case VIR_DOMAIN_NET_TYPE_BRIDGE:
3473 case VIR_DOMAIN_NET_TYPE_NETWORK: {
3474 const char *brname = virDomainNetGetActualBridgeName(net);
3475 if (!brname) {
3476 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3477 _("No bridge name specified"));
3478 goto cleanup;
3479 }
3480 if (!(veth = virLXCProcessSetupInterfaceTap(vm->def, net, brname)))
3481 goto cleanup;
3482 } break;
3483 case VIR_DOMAIN_NET_TYPE_ETHERNET:
3484 if (!(veth = virLXCProcessSetupInterfaceTap(vm->def, net, NULL)))
3485 goto cleanup;
3486 break;
3487 case VIR_DOMAIN_NET_TYPE_DIRECT: {
3488 if (!(veth = virLXCProcessSetupInterfaceDirect(driver, vm->def, net)))
3489 goto cleanup;
3490 } break;
3491 case VIR_DOMAIN_NET_TYPE_USER:
3492 case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
3493 case VIR_DOMAIN_NET_TYPE_SERVER:
3494 case VIR_DOMAIN_NET_TYPE_CLIENT:
3495 case VIR_DOMAIN_NET_TYPE_MCAST:
3496 case VIR_DOMAIN_NET_TYPE_INTERNAL:
3497 case VIR_DOMAIN_NET_TYPE_HOSTDEV:
3498 case VIR_DOMAIN_NET_TYPE_UDP:
3499 case VIR_DOMAIN_NET_TYPE_VDPA:
3500 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
3501 _("Network device type is not supported"));
3502 goto cleanup;
3503 case VIR_DOMAIN_NET_TYPE_LAST:
3504 default:
3505 virReportEnumRangeError(virDomainNetType, actualType);
3506 goto cleanup;
3507 }
3508 /* Set bandwidth or warn if requested and not supported. */
3509 actualBandwidth = virDomainNetGetActualBandwidth(net);
3510 if (actualBandwidth) {
3511 if (virNetDevSupportsBandwidth(actualType)) {
3512 if (virNetDevBandwidthSet(net->ifname, actualBandwidth, false,
3513 !virDomainNetTypeSharesHostView(net)) < 0)
3514 goto cleanup;
3515 } else {
3516 VIR_WARN("setting bandwidth on interfaces of "
3517 "type '%s' is not implemented yet: %s",
3518 virDomainNetTypeToString(actualType), virGetLastErrorMessage());
3519 }
3520 }
3521
3522 if (virNetDevSetNamespace(veth, priv->initpid) < 0) {
3523 virDomainAuditNet(vm, NULL, net, "attach", false);
3524 goto cleanup;
3525 }
3526
3527 virDomainAuditNet(vm, NULL, net, "attach", true);
3528
3529 ret = 0;
3530
3531 cleanup:
3532 if (!ret) {
3533 vm->def->nets[vm->def->nnets++] = net;
3534 } else if (veth) {
3535 switch (actualType) {
3536 case VIR_DOMAIN_NET_TYPE_BRIDGE:
3537 case VIR_DOMAIN_NET_TYPE_NETWORK:
3538 case VIR_DOMAIN_NET_TYPE_ETHERNET:
3539 ignore_value(virNetDevVethDelete(veth));
3540 break;
3541
3542 case VIR_DOMAIN_NET_TYPE_DIRECT:
3543 ignore_value(virNetDevMacVLanDelete(veth));
3544 break;
3545
3546 case VIR_DOMAIN_NET_TYPE_USER:
3547 case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
3548 case VIR_DOMAIN_NET_TYPE_SERVER:
3549 case VIR_DOMAIN_NET_TYPE_CLIENT:
3550 case VIR_DOMAIN_NET_TYPE_MCAST:
3551 case VIR_DOMAIN_NET_TYPE_INTERNAL:
3552 case VIR_DOMAIN_NET_TYPE_HOSTDEV:
3553 case VIR_DOMAIN_NET_TYPE_UDP:
3554 case VIR_DOMAIN_NET_TYPE_VDPA:
3555 case VIR_DOMAIN_NET_TYPE_LAST:
3556 default:
3557 /* no-op */
3558 break;
3559 }
3560 }
3561
3562 return ret;
3563 }
3564
3565
3566 static int
lxcDomainAttachDeviceHostdevSubsysUSBLive(virLXCDriver * driver,virDomainObj * vm,virDomainDeviceDef * dev)3567 lxcDomainAttachDeviceHostdevSubsysUSBLive(virLXCDriver *driver,
3568 virDomainObj *vm,
3569 virDomainDeviceDef *dev)
3570 {
3571 virLXCDomainObjPrivate *priv = vm->privateData;
3572 virDomainHostdevDef *def = dev->data.hostdev;
3573 int ret = -1;
3574 g_autofree char *src = NULL;
3575 struct stat sb;
3576 virUSBDevice *usb = NULL;
3577 virDomainHostdevSubsysUSB *usbsrc;
3578
3579 if (virDomainHostdevFind(vm->def, def, NULL) >= 0) {
3580 virReportError(VIR_ERR_OPERATION_FAILED, "%s",
3581 _("host USB device already exists"));
3582 return -1;
3583 }
3584
3585 usbsrc = &def->source.subsys.u.usb;
3586 src = g_strdup_printf("/dev/bus/usb/%03d/%03d", usbsrc->bus, usbsrc->device);
3587
3588 if (!(usb = virUSBDeviceNew(usbsrc->bus, usbsrc->device, NULL)))
3589 goto cleanup;
3590
3591 if (stat(src, &sb) < 0) {
3592 virReportSystemError(errno,
3593 _("Unable to access %s"), src);
3594 goto cleanup;
3595 }
3596
3597 if (!S_ISCHR(sb.st_mode)) {
3598 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
3599 _("USB source %s was not a character device"),
3600 src);
3601 goto cleanup;
3602 }
3603
3604 vm->def->hostdevs = g_renew(virDomainHostdevDef *,
3605 vm->def->hostdevs,
3606 vm->def->nhostdevs + 1);
3607
3608 if (virUSBDeviceFileIterate(usb,
3609 virLXCSetupHostUSBDeviceCgroup,
3610 priv->cgroup) < 0)
3611 goto cleanup;
3612
3613 if (lxcDomainAttachDeviceMknod(driver,
3614 0700 | S_IFCHR,
3615 sb.st_rdev,
3616 vm,
3617 dev,
3618 src) < 0) {
3619 if (virUSBDeviceFileIterate(usb,
3620 virLXCTeardownHostUSBDeviceCgroup,
3621 priv->cgroup) < 0)
3622 VIR_WARN("cannot deny device %s for domain %s: %s",
3623 src, vm->def->name, virGetLastErrorMessage());
3624 goto cleanup;
3625 }
3626
3627 vm->def->hostdevs[vm->def->nhostdevs++] = def;
3628
3629 ret = 0;
3630
3631 cleanup:
3632 virDomainAuditHostdev(vm, def, "attach", ret == 0);
3633 virUSBDeviceFree(usb);
3634 return ret;
3635 }
3636
3637
3638 static int
lxcDomainAttachDeviceHostdevStorageLive(virLXCDriver * driver,virDomainObj * vm,virDomainDeviceDef * dev)3639 lxcDomainAttachDeviceHostdevStorageLive(virLXCDriver *driver,
3640 virDomainObj *vm,
3641 virDomainDeviceDef *dev)
3642 {
3643 virLXCDomainObjPrivate *priv = vm->privateData;
3644 virDomainHostdevDef *def = dev->data.hostdev;
3645 int ret = -1;
3646 struct stat sb;
3647
3648 if (!def->source.caps.u.storage.block) {
3649 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
3650 _("Missing storage block path"));
3651 goto cleanup;
3652 }
3653
3654 if (virDomainHostdevFind(vm->def, def, NULL) >= 0) {
3655 virReportError(VIR_ERR_OPERATION_FAILED, "%s",
3656 _("host device already exists"));
3657 return -1;
3658 }
3659
3660 if (stat(def->source.caps.u.storage.block, &sb) < 0) {
3661 virReportSystemError(errno,
3662 _("Unable to access %s"),
3663 def->source.caps.u.storage.block);
3664 goto cleanup;
3665 }
3666
3667 if (!S_ISBLK(sb.st_mode)) {
3668 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
3669 _("Hostdev source %s must be a block device"),
3670 def->source.caps.u.storage.block);
3671 goto cleanup;
3672 }
3673
3674 vm->def->hostdevs = g_renew(virDomainHostdevDef *,
3675 vm->def->hostdevs,
3676 vm->def->nhostdevs + 1);
3677
3678 if (virCgroupAllowDevice(priv->cgroup,
3679 'b',
3680 major(sb.st_rdev),
3681 minor(sb.st_rdev),
3682 VIR_CGROUP_DEVICE_RWM) < 0)
3683 goto cleanup;
3684
3685 if (lxcDomainAttachDeviceMknod(driver,
3686 0700 | S_IFBLK,
3687 sb.st_rdev,
3688 vm,
3689 dev,
3690 def->source.caps.u.storage.block) < 0) {
3691 if (virCgroupDenyDevice(priv->cgroup,
3692 'b',
3693 major(sb.st_rdev),
3694 minor(sb.st_rdev),
3695 VIR_CGROUP_DEVICE_RWM) < 0)
3696 VIR_WARN("cannot deny device %s for domain %s: %s",
3697 def->source.caps.u.storage.block, vm->def->name, virGetLastErrorMessage());
3698 goto cleanup;
3699 }
3700
3701 vm->def->hostdevs[vm->def->nhostdevs++] = def;
3702
3703 ret = 0;
3704
3705 cleanup:
3706 virDomainAuditHostdev(vm, def, "attach", ret == 0);
3707 return ret;
3708 }
3709
3710
3711 static int
lxcDomainAttachDeviceHostdevMiscLive(virLXCDriver * driver,virDomainObj * vm,virDomainDeviceDef * dev)3712 lxcDomainAttachDeviceHostdevMiscLive(virLXCDriver *driver,
3713 virDomainObj *vm,
3714 virDomainDeviceDef *dev)
3715 {
3716 virLXCDomainObjPrivate *priv = vm->privateData;
3717 virDomainHostdevDef *def = dev->data.hostdev;
3718 int ret = -1;
3719 struct stat sb;
3720
3721 if (!def->source.caps.u.misc.chardev) {
3722 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
3723 _("Missing storage block path"));
3724 goto cleanup;
3725 }
3726
3727 if (virDomainHostdevFind(vm->def, def, NULL) >= 0) {
3728 virReportError(VIR_ERR_OPERATION_FAILED, "%s",
3729 _("host device already exists"));
3730 return -1;
3731 }
3732
3733 if (stat(def->source.caps.u.misc.chardev, &sb) < 0) {
3734 virReportSystemError(errno,
3735 _("Unable to access %s"),
3736 def->source.caps.u.misc.chardev);
3737 goto cleanup;
3738 }
3739
3740 if (!S_ISCHR(sb.st_mode)) {
3741 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
3742 _("Hostdev source %s must be a block device"),
3743 def->source.caps.u.misc.chardev);
3744 goto cleanup;
3745 }
3746
3747 if (virCgroupAllowDevice(priv->cgroup,
3748 'c',
3749 major(sb.st_rdev),
3750 minor(sb.st_rdev),
3751 VIR_CGROUP_DEVICE_RWM) < 0)
3752 goto cleanup;
3753
3754 vm->def->hostdevs = g_renew(virDomainHostdevDef *,
3755 vm->def->hostdevs,
3756 vm->def->nhostdevs + 1);
3757
3758 if (lxcDomainAttachDeviceMknod(driver,
3759 0700 | S_IFBLK,
3760 sb.st_rdev,
3761 vm,
3762 dev,
3763 def->source.caps.u.misc.chardev) < 0) {
3764 if (virCgroupDenyDevice(priv->cgroup,
3765 'c',
3766 major(sb.st_rdev),
3767 minor(sb.st_rdev),
3768 VIR_CGROUP_DEVICE_RWM) < 0)
3769 VIR_WARN("cannot deny device %s for domain %s: %s",
3770 def->source.caps.u.storage.block, vm->def->name, virGetLastErrorMessage());
3771 goto cleanup;
3772 }
3773
3774 vm->def->hostdevs[vm->def->nhostdevs++] = def;
3775
3776 ret = 0;
3777
3778 cleanup:
3779 virDomainAuditHostdev(vm, def, "attach", ret == 0);
3780 return ret;
3781 }
3782
3783
3784 static int
lxcDomainAttachDeviceHostdevSubsysLive(virLXCDriver * driver,virDomainObj * vm,virDomainDeviceDef * dev)3785 lxcDomainAttachDeviceHostdevSubsysLive(virLXCDriver *driver,
3786 virDomainObj *vm,
3787 virDomainDeviceDef *dev)
3788 {
3789 switch (dev->data.hostdev->source.subsys.type) {
3790 case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
3791 return lxcDomainAttachDeviceHostdevSubsysUSBLive(driver, vm, dev);
3792
3793 default:
3794 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
3795 _("Unsupported host device type %s"),
3796 virDomainHostdevSubsysTypeToString(dev->data.hostdev->source.subsys.type));
3797 return -1;
3798 }
3799 }
3800
3801
3802 static int
lxcDomainAttachDeviceHostdevCapsLive(virLXCDriver * driver,virDomainObj * vm,virDomainDeviceDef * dev)3803 lxcDomainAttachDeviceHostdevCapsLive(virLXCDriver *driver,
3804 virDomainObj *vm,
3805 virDomainDeviceDef *dev)
3806 {
3807 switch (dev->data.hostdev->source.caps.type) {
3808 case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE:
3809 return lxcDomainAttachDeviceHostdevStorageLive(driver, vm, dev);
3810
3811 case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC:
3812 return lxcDomainAttachDeviceHostdevMiscLive(driver, vm, dev);
3813
3814 default:
3815 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
3816 _("Unsupported host device type %s"),
3817 virDomainHostdevCapsTypeToString(dev->data.hostdev->source.caps.type));
3818 return -1;
3819 }
3820 }
3821
3822
3823 static int
lxcDomainAttachDeviceHostdevLive(virLXCDriver * driver,virDomainObj * vm,virDomainDeviceDef * dev)3824 lxcDomainAttachDeviceHostdevLive(virLXCDriver *driver,
3825 virDomainObj *vm,
3826 virDomainDeviceDef *dev)
3827 {
3828 virLXCDomainObjPrivate *priv = vm->privateData;
3829
3830 if (!priv->initpid) {
3831 virReportError(VIR_ERR_OPERATION_INVALID, "%s",
3832 _("Cannot attach hostdev until init PID is known"));
3833 return -1;
3834 }
3835
3836 if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
3837 virReportError(VIR_ERR_OPERATION_INVALID, "%s",
3838 _("devices cgroup isn't mounted"));
3839 return -1;
3840 }
3841
3842 switch (dev->data.hostdev->mode) {
3843 case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS:
3844 return lxcDomainAttachDeviceHostdevSubsysLive(driver, vm, dev);
3845
3846 case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
3847 return lxcDomainAttachDeviceHostdevCapsLive(driver, vm, dev);
3848
3849 default:
3850 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
3851 _("Unsupported host device mode %s"),
3852 virDomainHostdevModeTypeToString(dev->data.hostdev->mode));
3853 return -1;
3854 }
3855 }
3856
3857
3858 static int
lxcDomainAttachDeviceLive(virLXCDriver * driver,virDomainObj * vm,virDomainDeviceDef * dev)3859 lxcDomainAttachDeviceLive(virLXCDriver *driver,
3860 virDomainObj *vm,
3861 virDomainDeviceDef *dev)
3862 {
3863 int ret = -1;
3864
3865 switch (dev->type) {
3866 case VIR_DOMAIN_DEVICE_DISK:
3867 ret = lxcDomainAttachDeviceDiskLive(driver, vm, dev);
3868 if (!ret)
3869 dev->data.disk = NULL;
3870 break;
3871
3872 case VIR_DOMAIN_DEVICE_NET:
3873 ret = lxcDomainAttachDeviceNetLive(driver, vm,
3874 dev->data.net);
3875 if (!ret)
3876 dev->data.net = NULL;
3877 break;
3878
3879 case VIR_DOMAIN_DEVICE_HOSTDEV:
3880 ret = lxcDomainAttachDeviceHostdevLive(driver, vm, dev);
3881 if (!ret)
3882 dev->data.hostdev = NULL;
3883 break;
3884
3885 default:
3886 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
3887 _("device type '%s' cannot be attached"),
3888 virDomainDeviceTypeToString(dev->type));
3889 break;
3890 }
3891
3892 return ret;
3893 }
3894
3895
3896 static int
lxcDomainDetachDeviceDiskLive(virDomainObj * vm,virDomainDeviceDef * dev)3897 lxcDomainDetachDeviceDiskLive(virDomainObj *vm,
3898 virDomainDeviceDef *dev)
3899 {
3900 virLXCDomainObjPrivate *priv = vm->privateData;
3901 virDomainDiskDef *def = NULL;
3902 int idx;
3903 g_autofree char *dst = NULL;
3904 const char *src;
3905
3906 if (!priv->initpid) {
3907 virReportError(VIR_ERR_OPERATION_INVALID, "%s",
3908 _("Cannot attach disk until init PID is known"));
3909 return -1;
3910 }
3911
3912 if ((idx = virDomainDiskIndexByName(vm->def,
3913 dev->data.disk->dst,
3914 false)) < 0) {
3915 virReportError(VIR_ERR_OPERATION_FAILED,
3916 _("disk %s not found"), dev->data.disk->dst);
3917 return -1;
3918 }
3919
3920 def = vm->def->disks[idx];
3921 src = virDomainDiskGetSource(def);
3922
3923 dst = g_strdup_printf("/dev/%s", def->dst);
3924
3925 if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
3926 virReportError(VIR_ERR_OPERATION_INVALID, "%s",
3927 _("devices cgroup isn't mounted"));
3928 return -1;
3929 }
3930
3931 if (lxcDomainAttachDeviceUnlink(vm, dst) < 0) {
3932 virDomainAuditDisk(vm, def->src, NULL, "detach", false);
3933 return -1;
3934 }
3935 virDomainAuditDisk(vm, def->src, NULL, "detach", true);
3936
3937 if (virCgroupDenyDevicePath(priv->cgroup, src,
3938 VIR_CGROUP_DEVICE_RWM, false) != 0)
3939 VIR_WARN("cannot deny device %s for domain %s: %s",
3940 src, vm->def->name, virGetLastErrorMessage());
3941
3942 virDomainDiskRemove(vm->def, idx);
3943 virDomainDiskDefFree(def);
3944
3945 return 0;
3946 }
3947
3948
3949 static int
lxcDomainDetachDeviceNetLive(virDomainObj * vm,virDomainDeviceDef * dev)3950 lxcDomainDetachDeviceNetLive(virDomainObj *vm,
3951 virDomainDeviceDef *dev)
3952 {
3953 int detachidx, ret = -1;
3954 virDomainNetType actualType;
3955 virDomainNetDef *detach = NULL;
3956 const virNetDevVPortProfile *vport = NULL;
3957 virErrorPtr save_err = NULL;
3958
3959 if ((detachidx = virDomainNetFindIdx(vm->def, dev->data.net)) < 0)
3960 goto cleanup;
3961
3962 detach = vm->def->nets[detachidx];
3963 actualType = virDomainNetGetActualType(detach);
3964
3965 /* clear network bandwidth */
3966 if (virDomainNetGetActualBandwidth(detach) &&
3967 virNetDevSupportsBandwidth(actualType) &&
3968 virNetDevBandwidthClear(detach->ifname))
3969 goto cleanup;
3970
3971 switch (actualType) {
3972 case VIR_DOMAIN_NET_TYPE_BRIDGE:
3973 case VIR_DOMAIN_NET_TYPE_NETWORK:
3974 case VIR_DOMAIN_NET_TYPE_ETHERNET:
3975 if (virNetDevVethDelete(detach->ifname) < 0) {
3976 virDomainAuditNet(vm, detach, NULL, "detach", false);
3977 goto cleanup;
3978 }
3979 break;
3980
3981 /* It'd be nice to support this, but with macvlan
3982 * once assigned to a container nothing exists on
3983 * the host side. Further the container can change
3984 * the mac address of NIC name, so we can't easily
3985 * find out which guest NIC it maps to
3986 */
3987 case VIR_DOMAIN_NET_TYPE_DIRECT:
3988 case VIR_DOMAIN_NET_TYPE_USER:
3989 case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
3990 case VIR_DOMAIN_NET_TYPE_SERVER:
3991 case VIR_DOMAIN_NET_TYPE_CLIENT:
3992 case VIR_DOMAIN_NET_TYPE_MCAST:
3993 case VIR_DOMAIN_NET_TYPE_INTERNAL:
3994 case VIR_DOMAIN_NET_TYPE_HOSTDEV:
3995 case VIR_DOMAIN_NET_TYPE_UDP:
3996 case VIR_DOMAIN_NET_TYPE_VDPA:
3997 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
3998 _("Only bridged veth devices can be detached"));
3999 goto cleanup;
4000 case VIR_DOMAIN_NET_TYPE_LAST:
4001 default:
4002 virReportEnumRangeError(virDomainNetType, actualType);
4003 goto cleanup;
4004 }
4005
4006 virDomainAuditNet(vm, detach, NULL, "detach", true);
4007
4008 virDomainConfNWFilterTeardown(detach);
4009
4010 vport = virDomainNetGetActualVirtPortProfile(detach);
4011 if (vport && vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH)
4012 ignore_value(virNetDevOpenvswitchRemovePort(
4013 virDomainNetGetActualBridgeName(detach),
4014 detach->ifname));
4015 ret = 0;
4016 cleanup:
4017 if (!ret) {
4018 virErrorPreserveLast(&save_err);
4019 if (detach->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
4020 g_autoptr(virConnect) conn = virGetConnectNetwork();
4021 if (conn)
4022 virDomainNetReleaseActualDevice(conn, vm->def, detach);
4023 else
4024 VIR_WARN("Unable to release network device '%s'", NULLSTR(detach->ifname));
4025 }
4026 virDomainNetRemove(vm->def, detachidx);
4027 virDomainNetDefFree(detach);
4028 virErrorRestore(&save_err);
4029 }
4030 return ret;
4031 }
4032
4033
4034 static int
lxcDomainDetachDeviceHostdevUSBLive(virLXCDriver * driver,virDomainObj * vm,virDomainDeviceDef * dev)4035 lxcDomainDetachDeviceHostdevUSBLive(virLXCDriver *driver,
4036 virDomainObj *vm,
4037 virDomainDeviceDef *dev)
4038 {
4039 virLXCDomainObjPrivate *priv = vm->privateData;
4040 virDomainHostdevDef *def = NULL;
4041 int idx, ret = -1;
4042 g_autofree char *dst = NULL;
4043 virUSBDevice *usb = NULL;
4044 virHostdevManager *hostdev_mgr = driver->hostdevMgr;
4045 virDomainHostdevSubsysUSB *usbsrc;
4046
4047 if ((idx = virDomainHostdevFind(vm->def,
4048 dev->data.hostdev,
4049 &def)) < 0) {
4050 virReportError(VIR_ERR_OPERATION_FAILED, "%s",
4051 _("usb device not found"));
4052 goto cleanup;
4053 }
4054
4055 usbsrc = &def->source.subsys.u.usb;
4056 dst = g_strdup_printf("/dev/bus/usb/%03d/%03d", usbsrc->bus, usbsrc->device);
4057
4058 if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
4059 virReportError(VIR_ERR_OPERATION_INVALID, "%s",
4060 _("devices cgroup isn't mounted"));
4061 goto cleanup;
4062 }
4063
4064 if (!(usb = virUSBDeviceNew(usbsrc->bus, usbsrc->device, NULL)))
4065 goto cleanup;
4066
4067 if (lxcDomainAttachDeviceUnlink(vm, dst) < 0) {
4068 virDomainAuditHostdev(vm, def, "detach", false);
4069 goto cleanup;
4070 }
4071 virDomainAuditHostdev(vm, def, "detach", true);
4072
4073 if (virUSBDeviceFileIterate(usb,
4074 virLXCTeardownHostUSBDeviceCgroup,
4075 priv->cgroup) < 0)
4076 VIR_WARN("cannot deny device %s for domain %s: %s",
4077 dst, vm->def->name, virGetLastErrorMessage());
4078
4079 virObjectLock(hostdev_mgr->activeUSBHostdevs);
4080 virUSBDeviceListDel(hostdev_mgr->activeUSBHostdevs, usb);
4081 virObjectUnlock(hostdev_mgr->activeUSBHostdevs);
4082
4083 virDomainHostdevRemove(vm->def, idx);
4084 virDomainHostdevDefFree(def);
4085
4086 ret = 0;
4087
4088 cleanup:
4089 virUSBDeviceFree(usb);
4090 return ret;
4091 }
4092
4093
4094 static int
lxcDomainDetachDeviceHostdevStorageLive(virDomainObj * vm,virDomainDeviceDef * dev)4095 lxcDomainDetachDeviceHostdevStorageLive(virDomainObj *vm,
4096 virDomainDeviceDef *dev)
4097 {
4098 virLXCDomainObjPrivate *priv = vm->privateData;
4099 virDomainHostdevDef *def = NULL;
4100 int idx;
4101
4102 if (!priv->initpid) {
4103 virReportError(VIR_ERR_OPERATION_INVALID, "%s",
4104 _("Cannot attach disk until init PID is known"));
4105 return -1;
4106 }
4107
4108 if ((idx = virDomainHostdevFind(vm->def,
4109 dev->data.hostdev,
4110 &def)) < 0) {
4111 virReportError(VIR_ERR_OPERATION_FAILED,
4112 _("hostdev %s not found"),
4113 dev->data.hostdev->source.caps.u.storage.block);
4114 return -1;
4115 }
4116
4117 if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
4118 virReportError(VIR_ERR_OPERATION_INVALID, "%s",
4119 _("devices cgroup isn't mounted"));
4120 return -1;
4121 }
4122
4123 if (lxcDomainAttachDeviceUnlink(vm, def->source.caps.u.storage.block) < 0) {
4124 virDomainAuditHostdev(vm, def, "detach", false);
4125 return -1;
4126 }
4127 virDomainAuditHostdev(vm, def, "detach", true);
4128
4129 if (virCgroupDenyDevicePath(priv->cgroup, def->source.caps.u.storage.block,
4130 VIR_CGROUP_DEVICE_RWM, false) != 0)
4131 VIR_WARN("cannot deny device %s for domain %s: %s",
4132 def->source.caps.u.storage.block, vm->def->name, virGetLastErrorMessage());
4133
4134 virDomainHostdevRemove(vm->def, idx);
4135 virDomainHostdevDefFree(def);
4136
4137 return 0;
4138 }
4139
4140
4141 static int
lxcDomainDetachDeviceHostdevMiscLive(virDomainObj * vm,virDomainDeviceDef * dev)4142 lxcDomainDetachDeviceHostdevMiscLive(virDomainObj *vm,
4143 virDomainDeviceDef *dev)
4144 {
4145 virLXCDomainObjPrivate *priv = vm->privateData;
4146 virDomainHostdevDef *def = NULL;
4147 int idx;
4148
4149 if (!priv->initpid) {
4150 virReportError(VIR_ERR_OPERATION_INVALID, "%s",
4151 _("Cannot attach disk until init PID is known"));
4152 return -1;
4153 }
4154
4155 if ((idx = virDomainHostdevFind(vm->def,
4156 dev->data.hostdev,
4157 &def)) < 0) {
4158 virReportError(VIR_ERR_OPERATION_FAILED,
4159 _("hostdev %s not found"),
4160 dev->data.hostdev->source.caps.u.misc.chardev);
4161 return -1;
4162 }
4163
4164 if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
4165 virReportError(VIR_ERR_OPERATION_INVALID, "%s",
4166 _("devices cgroup isn't mounted"));
4167 return -1;
4168 }
4169
4170 if (lxcDomainAttachDeviceUnlink(vm, def->source.caps.u.misc.chardev) < 0) {
4171 virDomainAuditHostdev(vm, def, "detach", false);
4172 return -1;
4173 }
4174 virDomainAuditHostdev(vm, def, "detach", true);
4175
4176 if (virCgroupDenyDevicePath(priv->cgroup, def->source.caps.u.misc.chardev,
4177 VIR_CGROUP_DEVICE_RWM, false) != 0)
4178 VIR_WARN("cannot deny device %s for domain %s: %s",
4179 def->source.caps.u.misc.chardev, vm->def->name, virGetLastErrorMessage());
4180
4181 virDomainHostdevRemove(vm->def, idx);
4182 virDomainHostdevDefFree(def);
4183
4184 return 0;
4185 }
4186
4187
4188 static int
lxcDomainDetachDeviceHostdevSubsysLive(virLXCDriver * driver,virDomainObj * vm,virDomainDeviceDef * dev)4189 lxcDomainDetachDeviceHostdevSubsysLive(virLXCDriver *driver,
4190 virDomainObj *vm,
4191 virDomainDeviceDef *dev)
4192 {
4193 switch (dev->data.hostdev->source.subsys.type) {
4194 case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
4195 return lxcDomainDetachDeviceHostdevUSBLive(driver, vm, dev);
4196
4197 default:
4198 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
4199 _("Unsupported host device type %s"),
4200 virDomainHostdevSubsysTypeToString(dev->data.hostdev->source.subsys.type));
4201 return -1;
4202 }
4203 }
4204
4205
4206 static int
lxcDomainDetachDeviceHostdevCapsLive(virDomainObj * vm,virDomainDeviceDef * dev)4207 lxcDomainDetachDeviceHostdevCapsLive(virDomainObj *vm,
4208 virDomainDeviceDef *dev)
4209 {
4210 switch (dev->data.hostdev->source.caps.type) {
4211 case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE:
4212 return lxcDomainDetachDeviceHostdevStorageLive(vm, dev);
4213
4214 case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC:
4215 return lxcDomainDetachDeviceHostdevMiscLive(vm, dev);
4216
4217 default:
4218 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
4219 _("Unsupported host device type %s"),
4220 virDomainHostdevCapsTypeToString(dev->data.hostdev->source.caps.type));
4221 return -1;
4222 }
4223 }
4224
4225
4226 static int
lxcDomainDetachDeviceHostdevLive(virLXCDriver * driver,virDomainObj * vm,virDomainDeviceDef * dev)4227 lxcDomainDetachDeviceHostdevLive(virLXCDriver *driver,
4228 virDomainObj *vm,
4229 virDomainDeviceDef *dev)
4230 {
4231 virLXCDomainObjPrivate *priv = vm->privateData;
4232
4233 if (!priv->initpid) {
4234 virReportError(VIR_ERR_OPERATION_INVALID, "%s",
4235 _("Cannot attach hostdev until init PID is known"));
4236 return -1;
4237 }
4238
4239 switch (dev->data.hostdev->mode) {
4240 case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS:
4241 return lxcDomainDetachDeviceHostdevSubsysLive(driver, vm, dev);
4242
4243 case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
4244 return lxcDomainDetachDeviceHostdevCapsLive(vm, dev);
4245
4246 default:
4247 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
4248 _("Unsupported host device mode %s"),
4249 virDomainHostdevModeTypeToString(dev->data.hostdev->mode));
4250 return -1;
4251 }
4252 }
4253
4254
4255 static int
lxcDomainDetachDeviceLive(virLXCDriver * driver,virDomainObj * vm,virDomainDeviceDef * dev)4256 lxcDomainDetachDeviceLive(virLXCDriver *driver,
4257 virDomainObj *vm,
4258 virDomainDeviceDef *dev)
4259 {
4260 int ret = -1;
4261
4262 switch (dev->type) {
4263 case VIR_DOMAIN_DEVICE_DISK:
4264 ret = lxcDomainDetachDeviceDiskLive(vm, dev);
4265 break;
4266
4267 case VIR_DOMAIN_DEVICE_NET:
4268 ret = lxcDomainDetachDeviceNetLive(vm, dev);
4269 break;
4270
4271 case VIR_DOMAIN_DEVICE_HOSTDEV:
4272 ret = lxcDomainDetachDeviceHostdevLive(driver, vm, dev);
4273 break;
4274
4275 default:
4276 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
4277 _("device type '%s' cannot be detached"),
4278 virDomainDeviceTypeToString(dev->type));
4279 break;
4280 }
4281
4282 return ret;
4283 }
4284
4285
lxcDomainAttachDeviceFlags(virDomainPtr dom,const char * xml,unsigned int flags)4286 static int lxcDomainAttachDeviceFlags(virDomainPtr dom,
4287 const char *xml,
4288 unsigned int flags)
4289 {
4290 virLXCDriver *driver = dom->conn->privateData;
4291 virDomainObj *vm = NULL;
4292 virDomainDef *vmdef = NULL;
4293 virDomainDeviceDef *dev = NULL;
4294 virDomainDeviceDef *dev_copy = NULL;
4295 int ret = -1;
4296 virLXCDriverConfig *cfg = virLXCDriverGetConfig(driver);
4297
4298 virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
4299 VIR_DOMAIN_AFFECT_CONFIG, -1);
4300
4301 if (!(vm = lxcDomObjFromDomain(dom)))
4302 goto cleanup;
4303
4304 if (virDomainAttachDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
4305 goto cleanup;
4306
4307 if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
4308 goto cleanup;
4309
4310 if (virDomainObjUpdateModificationImpact(vm, &flags) < 0)
4311 goto endjob;
4312
4313 dev = dev_copy = virDomainDeviceDefParse(xml, vm->def,
4314 driver->xmlopt, NULL,
4315 VIR_DOMAIN_DEF_PARSE_INACTIVE);
4316 if (dev == NULL)
4317 goto endjob;
4318
4319 if (flags & VIR_DOMAIN_AFFECT_CONFIG &&
4320 flags & VIR_DOMAIN_AFFECT_LIVE) {
4321 /* If we are affecting both CONFIG and LIVE
4322 * create a deep copy of device as adding
4323 * to CONFIG takes one instance.
4324 */
4325 dev_copy = virDomainDeviceDefCopy(dev, vm->def,
4326 driver->xmlopt, NULL);
4327 if (!dev_copy)
4328 goto endjob;
4329 }
4330
4331 if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
4332 /* Make a copy for updated domain. */
4333 vmdef = virDomainObjCopyPersistentDef(vm, driver->xmlopt, NULL);
4334 if (!vmdef)
4335 goto endjob;
4336
4337 if (virDomainDefCompatibleDevice(vmdef, dev, NULL,
4338 VIR_DOMAIN_DEVICE_ACTION_ATTACH,
4339 false) < 0)
4340 goto endjob;
4341
4342 if ((ret = lxcDomainAttachDeviceConfig(vmdef, dev)) < 0)
4343 goto endjob;
4344 }
4345
4346 if (flags & VIR_DOMAIN_AFFECT_LIVE) {
4347 if (virDomainDefCompatibleDevice(vm->def, dev_copy, NULL,
4348 VIR_DOMAIN_DEVICE_ACTION_ATTACH,
4349 true) < 0)
4350 goto endjob;
4351
4352 if ((ret = lxcDomainAttachDeviceLive(driver, vm, dev_copy)) < 0)
4353 goto endjob;
4354 /*
4355 * update domain status forcibly because the domain status may be
4356 * changed even if we failed to attach the device. For example,
4357 * a new controller may be created.
4358 */
4359 if (virDomainObjSave(vm, driver->xmlopt, cfg->stateDir) < 0) {
4360 ret = -1;
4361 goto endjob;
4362 }
4363 }
4364
4365 /* Finally, if no error until here, we can save config. */
4366 if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
4367 ret = virDomainDefSave(vmdef, driver->xmlopt, cfg->configDir);
4368 if (!ret)
4369 virDomainObjAssignDef(vm, &vmdef, false, NULL);
4370 }
4371
4372 endjob:
4373 virLXCDomainObjEndJob(driver, vm);
4374
4375 cleanup:
4376 virDomainDefFree(vmdef);
4377 if (dev != dev_copy)
4378 virDomainDeviceDefFree(dev_copy);
4379 virDomainDeviceDefFree(dev);
4380 virDomainObjEndAPI(&vm);
4381 virObjectUnref(cfg);
4382 return ret;
4383 }
4384
4385
lxcDomainAttachDevice(virDomainPtr dom,const char * xml)4386 static int lxcDomainAttachDevice(virDomainPtr dom,
4387 const char *xml)
4388 {
4389 return lxcDomainAttachDeviceFlags(dom, xml,
4390 VIR_DOMAIN_AFFECT_LIVE);
4391 }
4392
4393
lxcDomainUpdateDeviceFlags(virDomainPtr dom,const char * xml,unsigned int flags)4394 static int lxcDomainUpdateDeviceFlags(virDomainPtr dom,
4395 const char *xml,
4396 unsigned int flags)
4397 {
4398 virLXCDriver *driver = dom->conn->privateData;
4399 virDomainObj *vm = NULL;
4400 virDomainDef *vmdef = NULL;
4401 virDomainDeviceDef *dev = NULL;
4402 int ret = -1;
4403 virLXCDriverConfig *cfg = virLXCDriverGetConfig(driver);
4404
4405 virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
4406 VIR_DOMAIN_AFFECT_CONFIG, -1);
4407
4408 if (!(vm = lxcDomObjFromDomain(dom)))
4409 goto cleanup;
4410
4411 if (virDomainUpdateDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
4412 goto cleanup;
4413
4414 if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
4415 goto cleanup;
4416
4417 if (virDomainObjUpdateModificationImpact(vm, &flags) < 0)
4418 goto endjob;
4419
4420 if (flags & VIR_DOMAIN_AFFECT_LIVE) {
4421 virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
4422 _("Unable to modify live devices"));
4423 goto endjob;
4424 }
4425
4426 if (!(dev = virDomainDeviceDefParse(xml, vm->def, driver->xmlopt, NULL,
4427 VIR_DOMAIN_DEF_PARSE_INACTIVE)))
4428 goto endjob;
4429
4430 /* Make a copy for updated domain. */
4431 if (!(vmdef = virDomainObjCopyPersistentDef(vm, driver->xmlopt, NULL)))
4432 goto endjob;
4433
4434 /* virDomainDefCompatibleDevice call is delayed until we know the
4435 * device we're going to update. */
4436 if (lxcDomainUpdateDeviceConfig(vmdef, dev) < 0)
4437 goto endjob;
4438
4439 if (virDomainDefSave(vmdef, driver->xmlopt, cfg->configDir) < 0)
4440 goto endjob;
4441
4442 virDomainObjAssignDef(vm, &vmdef, false, NULL);
4443 ret = 0;
4444
4445 endjob:
4446 virLXCDomainObjEndJob(driver, vm);
4447
4448 cleanup:
4449 virDomainDefFree(vmdef);
4450 virDomainDeviceDefFree(dev);
4451 virDomainObjEndAPI(&vm);
4452 virObjectUnref(cfg);
4453 return ret;
4454 }
4455
4456
lxcDomainDetachDeviceFlags(virDomainPtr dom,const char * xml,unsigned int flags)4457 static int lxcDomainDetachDeviceFlags(virDomainPtr dom,
4458 const char *xml,
4459 unsigned int flags)
4460 {
4461 virLXCDriver *driver = dom->conn->privateData;
4462 virCaps *caps = NULL;
4463 virDomainObj *vm = NULL;
4464 virDomainDef *vmdef = NULL;
4465 virDomainDeviceDef *dev = NULL;
4466 virDomainDeviceDef *dev_copy = NULL;
4467 int ret = -1;
4468 virLXCDriverConfig *cfg = virLXCDriverGetConfig(driver);
4469
4470 virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
4471 VIR_DOMAIN_AFFECT_CONFIG, -1);
4472
4473 if (!(vm = lxcDomObjFromDomain(dom)))
4474 goto cleanup;
4475
4476 if (virDomainDetachDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
4477 goto cleanup;
4478
4479 if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
4480 goto cleanup;
4481
4482 if (virDomainObjUpdateModificationImpact(vm, &flags) < 0)
4483 goto endjob;
4484
4485 if (!(caps = virLXCDriverGetCapabilities(driver, false)))
4486 goto endjob;
4487
4488 dev = dev_copy = virDomainDeviceDefParse(xml, vm->def,
4489 driver->xmlopt, NULL,
4490 VIR_DOMAIN_DEF_PARSE_INACTIVE |
4491 VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE);
4492 if (dev == NULL)
4493 goto endjob;
4494
4495 if (flags & VIR_DOMAIN_AFFECT_CONFIG &&
4496 flags & VIR_DOMAIN_AFFECT_LIVE) {
4497 /* If we are affecting both CONFIG and LIVE
4498 * create a deep copy of device as adding
4499 * to CONFIG takes one instance.
4500 */
4501 dev_copy = virDomainDeviceDefCopy(dev, vm->def,
4502 driver->xmlopt, NULL);
4503 if (!dev_copy)
4504 goto endjob;
4505 }
4506
4507 if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
4508 /* Make a copy for updated domain. */
4509 vmdef = virDomainObjCopyPersistentDef(vm, driver->xmlopt, NULL);
4510 if (!vmdef)
4511 goto endjob;
4512
4513 if ((ret = lxcDomainDetachDeviceConfig(vmdef, dev)) < 0)
4514 goto endjob;
4515 }
4516
4517 if (flags & VIR_DOMAIN_AFFECT_LIVE) {
4518 if ((ret = lxcDomainDetachDeviceLive(driver, vm, dev_copy)) < 0)
4519 goto endjob;
4520 /*
4521 * update domain status forcibly because the domain status may be
4522 * changed even if we failed to attach the device. For example,
4523 * a new controller may be created.
4524 */
4525 if (virDomainObjSave(vm, driver->xmlopt, cfg->stateDir) < 0) {
4526 ret = -1;
4527 goto endjob;
4528 }
4529 }
4530
4531 /* Finally, if no error until here, we can save config. */
4532 if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
4533 ret = virDomainDefSave(vmdef, driver->xmlopt, cfg->configDir);
4534 if (!ret)
4535 virDomainObjAssignDef(vm, &vmdef, false, NULL);
4536 }
4537
4538 endjob:
4539 virLXCDomainObjEndJob(driver, vm);
4540
4541 cleanup:
4542 virDomainDefFree(vmdef);
4543 if (dev != dev_copy)
4544 virDomainDeviceDefFree(dev_copy);
4545 virDomainDeviceDefFree(dev);
4546 virDomainObjEndAPI(&vm);
4547 virObjectUnref(caps);
4548 virObjectUnref(cfg);
4549 return ret;
4550 }
4551
4552
lxcDomainDetachDevice(virDomainPtr dom,const char * xml)4553 static int lxcDomainDetachDevice(virDomainPtr dom,
4554 const char *xml)
4555 {
4556 return lxcDomainDetachDeviceFlags(dom, xml,
4557 VIR_DOMAIN_AFFECT_LIVE);
4558 }
4559
4560
lxcDomainLxcOpenNamespace(virDomainPtr dom,int ** fdlist,unsigned int flags)4561 static int lxcDomainLxcOpenNamespace(virDomainPtr dom,
4562 int **fdlist,
4563 unsigned int flags)
4564 {
4565 virLXCDriver *driver = dom->conn->privateData;
4566 virDomainObj *vm;
4567 virLXCDomainObjPrivate *priv;
4568 int ret = -1;
4569 size_t nfds = 0;
4570
4571 *fdlist = NULL;
4572 virCheckFlags(0, -1);
4573
4574 if (!(vm = lxcDomObjFromDomain(dom)))
4575 goto cleanup;
4576
4577 priv = vm->privateData;
4578
4579 if (virDomainLxcOpenNamespaceEnsureACL(dom->conn, vm->def) < 0)
4580 goto cleanup;
4581
4582 if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_QUERY) < 0)
4583 goto cleanup;
4584
4585 if (virDomainObjCheckActive(vm) < 0)
4586 goto endjob;
4587
4588 if (!priv->initpid) {
4589 virReportError(VIR_ERR_OPERATION_INVALID, "%s",
4590 _("Init pid is not yet available"));
4591 goto endjob;
4592 }
4593
4594 if (virProcessGetNamespaces(priv->initpid, &nfds, fdlist) < 0)
4595 goto endjob;
4596
4597 ret = nfds;
4598
4599 endjob:
4600 virLXCDomainObjEndJob(driver, vm);
4601
4602 cleanup:
4603 virDomainObjEndAPI(&vm);
4604 return ret;
4605 }
4606
4607
4608 static char *
lxcConnectGetSysinfo(virConnectPtr conn,unsigned int flags)4609 lxcConnectGetSysinfo(virConnectPtr conn, unsigned int flags)
4610 {
4611 virLXCDriver *driver = conn->privateData;
4612 g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
4613
4614 virCheckFlags(0, NULL);
4615
4616 if (virConnectGetSysinfoEnsureACL(conn) < 0)
4617 return NULL;
4618
4619 if (!driver->hostsysinfo) {
4620 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
4621 _("Host SMBIOS information is not available"));
4622 return NULL;
4623 }
4624
4625 if (virSysinfoFormat(&buf, driver->hostsysinfo) < 0)
4626 return NULL;
4627 return virBufferContentAndReset(&buf);
4628 }
4629
4630
4631 static int
lxcNodeGetInfo(virConnectPtr conn,virNodeInfoPtr nodeinfo)4632 lxcNodeGetInfo(virConnectPtr conn,
4633 virNodeInfoPtr nodeinfo)
4634 {
4635 if (virNodeGetInfoEnsureACL(conn) < 0)
4636 return -1;
4637
4638 return virCapabilitiesGetNodeInfo(nodeinfo);
4639 }
4640
4641
4642 static int
lxcDomainMemoryStats(virDomainPtr dom,virDomainMemoryStatPtr stats,unsigned int nr_stats,unsigned int flags)4643 lxcDomainMemoryStats(virDomainPtr dom,
4644 virDomainMemoryStatPtr stats,
4645 unsigned int nr_stats,
4646 unsigned int flags)
4647 {
4648 virDomainObj *vm;
4649 int ret = -1;
4650 virLXCDomainObjPrivate *priv;
4651 unsigned long long swap_usage;
4652 unsigned long mem_usage;
4653 virLXCDriver *driver = dom->conn->privateData;
4654
4655 virCheckFlags(0, -1);
4656
4657 if (!(vm = lxcDomObjFromDomain(dom)))
4658 goto cleanup;
4659
4660 priv = vm->privateData;
4661
4662 if (virDomainMemoryStatsEnsureACL(dom->conn, vm->def) < 0)
4663 goto cleanup;
4664
4665 if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_QUERY) < 0)
4666 goto cleanup;
4667
4668 if (virDomainObjCheckActive(vm) < 0)
4669 goto endjob;
4670
4671 if (virCgroupGetMemSwapUsage(priv->cgroup, &swap_usage) < 0)
4672 goto endjob;
4673
4674 if (virCgroupGetMemoryUsage(priv->cgroup, &mem_usage) < 0)
4675 goto endjob;
4676
4677 ret = 0;
4678 if (ret < nr_stats) {
4679 stats[ret].tag = VIR_DOMAIN_MEMORY_STAT_ACTUAL_BALLOON;
4680 stats[ret].val = vm->def->mem.cur_balloon;
4681 ret++;
4682 }
4683 if (ret < nr_stats) {
4684 stats[ret].tag = VIR_DOMAIN_MEMORY_STAT_SWAP_IN;
4685 stats[ret].val = swap_usage;
4686 ret++;
4687 }
4688 if (ret < nr_stats) {
4689 stats[ret].tag = VIR_DOMAIN_MEMORY_STAT_RSS;
4690 stats[ret].val = mem_usage;
4691 ret++;
4692 }
4693
4694 endjob:
4695 virLXCDomainObjEndJob(driver, vm);
4696
4697 cleanup:
4698 virDomainObjEndAPI(&vm);
4699 return ret;
4700 }
4701
4702
4703 static int
lxcNodeGetCPUStats(virConnectPtr conn,int cpuNum,virNodeCPUStatsPtr params,int * nparams,unsigned int flags)4704 lxcNodeGetCPUStats(virConnectPtr conn,
4705 int cpuNum,
4706 virNodeCPUStatsPtr params,
4707 int *nparams,
4708 unsigned int flags)
4709 {
4710 if (virNodeGetCPUStatsEnsureACL(conn) < 0)
4711 return -1;
4712
4713 return virHostCPUGetStats(cpuNum, params, nparams, flags);
4714 }
4715
4716
4717 static int
lxcNodeGetMemoryStats(virConnectPtr conn,int cellNum,virNodeMemoryStatsPtr params,int * nparams,unsigned int flags)4718 lxcNodeGetMemoryStats(virConnectPtr conn,
4719 int cellNum,
4720 virNodeMemoryStatsPtr params,
4721 int *nparams,
4722 unsigned int flags)
4723 {
4724 if (virNodeGetMemoryStatsEnsureACL(conn) < 0)
4725 return -1;
4726
4727 return virHostMemGetStats(cellNum, params, nparams, flags);
4728 }
4729
4730
4731 static int
lxcNodeGetCellsFreeMemory(virConnectPtr conn,unsigned long long * freeMems,int startCell,int maxCells)4732 lxcNodeGetCellsFreeMemory(virConnectPtr conn,
4733 unsigned long long *freeMems,
4734 int startCell,
4735 int maxCells)
4736 {
4737 if (virNodeGetCellsFreeMemoryEnsureACL(conn) < 0)
4738 return -1;
4739
4740 return virHostMemGetCellsFree(freeMems, startCell, maxCells);
4741 }
4742
4743
4744 static unsigned long long
lxcNodeGetFreeMemory(virConnectPtr conn)4745 lxcNodeGetFreeMemory(virConnectPtr conn)
4746 {
4747 unsigned long long freeMem;
4748
4749 if (virNodeGetFreeMemoryEnsureACL(conn) < 0)
4750 return 0;
4751
4752 if (virHostMemGetInfo(NULL, &freeMem) < 0)
4753 return 0;
4754
4755 return freeMem;
4756 }
4757
4758
4759 static int
lxcNodeGetMemoryParameters(virConnectPtr conn,virTypedParameterPtr params,int * nparams,unsigned int flags)4760 lxcNodeGetMemoryParameters(virConnectPtr conn,
4761 virTypedParameterPtr params,
4762 int *nparams,
4763 unsigned int flags)
4764 {
4765 if (virNodeGetMemoryParametersEnsureACL(conn) < 0)
4766 return -1;
4767
4768 return virHostMemGetParameters(params, nparams, flags);
4769 }
4770
4771
4772 static int
lxcNodeSetMemoryParameters(virConnectPtr conn,virTypedParameterPtr params,int nparams,unsigned int flags)4773 lxcNodeSetMemoryParameters(virConnectPtr conn,
4774 virTypedParameterPtr params,
4775 int nparams,
4776 unsigned int flags)
4777 {
4778 if (virNodeSetMemoryParametersEnsureACL(conn) < 0)
4779 return -1;
4780
4781 return virHostMemSetParameters(params, nparams, flags);
4782 }
4783
4784
4785 static int
lxcNodeGetCPUMap(virConnectPtr conn,unsigned char ** cpumap,unsigned int * online,unsigned int flags)4786 lxcNodeGetCPUMap(virConnectPtr conn,
4787 unsigned char **cpumap,
4788 unsigned int *online,
4789 unsigned int flags)
4790 {
4791 if (virNodeGetCPUMapEnsureACL(conn) < 0)
4792 return -1;
4793
4794 return virHostCPUGetMap(cpumap, online, flags);
4795 }
4796
4797
4798 static int
lxcNodeSuspendForDuration(virConnectPtr conn,unsigned int target,unsigned long long duration,unsigned int flags)4799 lxcNodeSuspendForDuration(virConnectPtr conn,
4800 unsigned int target,
4801 unsigned long long duration,
4802 unsigned int flags)
4803 {
4804 if (virNodeSuspendForDurationEnsureACL(conn) < 0)
4805 return -1;
4806
4807 return virNodeSuspend(target, duration, flags);
4808 }
4809
4810
4811 static int
lxcDomainSetMetadata(virDomainPtr dom,int type,const char * metadata,const char * key,const char * uri,unsigned int flags)4812 lxcDomainSetMetadata(virDomainPtr dom,
4813 int type,
4814 const char *metadata,
4815 const char *key,
4816 const char *uri,
4817 unsigned int flags)
4818 {
4819 virLXCDriver *driver = dom->conn->privateData;
4820 virDomainObj *vm;
4821 virLXCDriverConfig *cfg = NULL;
4822 int ret = -1;
4823
4824 virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
4825 VIR_DOMAIN_AFFECT_CONFIG, -1);
4826
4827 if (!(vm = lxcDomObjFromDomain(dom)))
4828 return -1;
4829
4830 cfg = virLXCDriverGetConfig(driver);
4831
4832 if (virDomainSetMetadataEnsureACL(dom->conn, vm->def, flags) < 0)
4833 goto cleanup;
4834
4835 if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0)
4836 goto cleanup;
4837
4838 ret = virDomainObjSetMetadata(vm, type, metadata, key, uri,
4839 driver->xmlopt, cfg->stateDir,
4840 cfg->configDir, flags);
4841
4842 if (ret == 0) {
4843 virObjectEvent *ev = NULL;
4844 ev = virDomainEventMetadataChangeNewFromObj(vm, type, uri);
4845 virObjectEventStateQueue(driver->domainEventState, ev);
4846 }
4847
4848 virLXCDomainObjEndJob(driver, vm);
4849
4850 cleanup:
4851 virDomainObjEndAPI(&vm);
4852 virObjectUnref(cfg);
4853 return ret;
4854 }
4855
4856
4857 static char *
lxcDomainGetMetadata(virDomainPtr dom,int type,const char * uri,unsigned int flags)4858 lxcDomainGetMetadata(virDomainPtr dom,
4859 int type,
4860 const char *uri,
4861 unsigned int flags)
4862 {
4863 virDomainObj *vm;
4864 char *ret = NULL;
4865
4866 if (!(vm = lxcDomObjFromDomain(dom)))
4867 return NULL;
4868
4869 if (virDomainGetMetadataEnsureACL(dom->conn, vm->def) < 0)
4870 goto cleanup;
4871
4872 ret = virDomainObjGetMetadata(vm, type, uri, flags);
4873
4874 cleanup:
4875 virDomainObjEndAPI(&vm);
4876 return ret;
4877 }
4878
4879
4880 static int
lxcDomainGetCPUStats(virDomainPtr dom,virTypedParameterPtr params,unsigned int nparams,int start_cpu,unsigned int ncpus,unsigned int flags)4881 lxcDomainGetCPUStats(virDomainPtr dom,
4882 virTypedParameterPtr params,
4883 unsigned int nparams,
4884 int start_cpu,
4885 unsigned int ncpus,
4886 unsigned int flags)
4887 {
4888 virDomainObj *vm = NULL;
4889 int ret = -1;
4890 virLXCDomainObjPrivate *priv;
4891
4892 virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1);
4893
4894 if (!(vm = lxcDomObjFromDomain(dom)))
4895 return ret;
4896
4897 priv = vm->privateData;
4898
4899 if (virDomainGetCPUStatsEnsureACL(dom->conn, vm->def) < 0)
4900 goto cleanup;
4901
4902 if (virDomainObjCheckActive(vm) < 0)
4903 goto cleanup;
4904
4905 if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPUACCT)) {
4906 virReportError(VIR_ERR_OPERATION_INVALID,
4907 "%s", _("cgroup CPUACCT controller is not mounted"));
4908 goto cleanup;
4909 }
4910
4911 if (start_cpu == -1)
4912 ret = virCgroupGetDomainTotalCpuStats(priv->cgroup,
4913 params, nparams);
4914 else
4915 ret = virCgroupGetPercpuStats(priv->cgroup, params,
4916 nparams, start_cpu, ncpus, NULL);
4917 cleanup:
4918 virDomainObjEndAPI(&vm);
4919 return ret;
4920 }
4921
4922
4923 static char *
lxcDomainGetHostname(virDomainPtr dom,unsigned int flags)4924 lxcDomainGetHostname(virDomainPtr dom,
4925 unsigned int flags)
4926 {
4927 virLXCDriver *driver = dom->conn->privateData;
4928 virDomainObj *vm = NULL;
4929 char macaddr[VIR_MAC_STRING_BUFLEN];
4930 g_autoptr(virConnect) conn = NULL;
4931 size_t i, j;
4932 char *hostname = NULL;
4933
4934 virCheckFlags(VIR_DOMAIN_GET_HOSTNAME_LEASE, NULL);
4935
4936 if (!(vm = lxcDomObjFromDomain(dom)))
4937 return NULL;
4938
4939 if (virDomainGetHostnameEnsureACL(dom->conn, vm->def) < 0)
4940 goto cleanup;
4941
4942 if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_QUERY) < 0)
4943 goto cleanup;
4944
4945 if (virDomainObjCheckActive(vm) < 0)
4946 goto endjob;
4947
4948 if (!(conn = virGetConnectNetwork()))
4949 goto endjob;
4950
4951 for (i = 0; i < vm->def->nnets; i++) {
4952 g_autoptr(virNetwork) network = NULL;
4953 virDomainNetDef *net = vm->def->nets[i];
4954 g_autofree virNetworkDHCPLeasePtr *leases = NULL;
4955 int n_leases;
4956
4957 if (net->type != VIR_DOMAIN_NET_TYPE_NETWORK)
4958 continue;
4959
4960 virMacAddrFormat(&net->mac, macaddr);
4961 network = virNetworkLookupByName(conn, net->data.network.name);
4962
4963 if (!network)
4964 goto endjob;
4965
4966 if ((n_leases = virNetworkGetDHCPLeases(network, macaddr,
4967 &leases, 0)) < 0)
4968 goto endjob;
4969
4970 for (j = 0; j < n_leases; j++) {
4971 virNetworkDHCPLeasePtr lease = leases[j];
4972
4973 if (lease->hostname && !hostname)
4974 hostname = g_strdup(lease->hostname);
4975
4976 virNetworkDHCPLeaseFree(lease);
4977 }
4978
4979 if (hostname)
4980 goto endjob;
4981 }
4982
4983 if (!hostname) {
4984 virReportError(VIR_ERR_NO_HOSTNAME,
4985 _("no hostname found for domain %s"),
4986 vm->def->name);
4987 goto endjob;
4988 }
4989
4990 endjob:
4991 virLXCDomainObjEndJob(driver, vm);
4992
4993 cleanup:
4994 virDomainObjEndAPI(&vm);
4995 return hostname;
4996 }
4997
4998
4999 static int
lxcNodeGetFreePages(virConnectPtr conn,unsigned int npages,unsigned int * pages,int startCell,unsigned int cellCount,unsigned long long * counts,unsigned int flags)5000 lxcNodeGetFreePages(virConnectPtr conn,
5001 unsigned int npages,
5002 unsigned int *pages,
5003 int startCell,
5004 unsigned int cellCount,
5005 unsigned long long *counts,
5006 unsigned int flags)
5007 {
5008 virLXCDriver *driver = conn->privateData;
5009 g_autoptr(virCaps) caps = NULL;
5010 int lastCell;
5011
5012 virCheckFlags(0, -1);
5013
5014 if (virNodeGetFreePagesEnsureACL(conn) < 0)
5015 return -1;
5016
5017 if (!(caps = virLXCDriverGetCapabilities(driver, false)))
5018 return -1;
5019
5020 lastCell = virCapabilitiesHostNUMAGetMaxNode(caps->host.numa);
5021
5022 return virHostMemGetFreePages(npages, pages, startCell, cellCount,
5023 lastCell, counts);
5024 }
5025
5026
5027 static int
lxcNodeAllocPages(virConnectPtr conn,unsigned int npages,unsigned int * pageSizes,unsigned long long * pageCounts,int startCell,unsigned int cellCount,unsigned int flags)5028 lxcNodeAllocPages(virConnectPtr conn,
5029 unsigned int npages,
5030 unsigned int *pageSizes,
5031 unsigned long long *pageCounts,
5032 int startCell,
5033 unsigned int cellCount,
5034 unsigned int flags)
5035 {
5036 virLXCDriver *driver = conn->privateData;
5037 g_autoptr(virCaps) caps = NULL;
5038 int lastCell;
5039 bool add = !(flags & VIR_NODE_ALLOC_PAGES_SET);
5040
5041 virCheckFlags(VIR_NODE_ALLOC_PAGES_SET, -1);
5042
5043 if (virNodeAllocPagesEnsureACL(conn) < 0)
5044 return -1;
5045
5046 if (!(caps = virLXCDriverGetCapabilities(driver, false)))
5047 return -1;
5048
5049 lastCell = virCapabilitiesHostNUMAGetMaxNode(caps->host.numa);
5050
5051 return virHostMemAllocPages(npages, pageSizes, pageCounts,
5052 startCell, cellCount,
5053 lastCell, add);
5054 }
5055
5056
5057 static int
lxcDomainHasManagedSaveImage(virDomainPtr dom,unsigned int flags)5058 lxcDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags)
5059 {
5060 virDomainObj *vm = NULL;
5061 int ret = -1;
5062
5063 virCheckFlags(0, -1);
5064
5065 if (!(vm = lxcDomObjFromDomain(dom)))
5066 return ret;
5067
5068 if (virDomainHasManagedSaveImageEnsureACL(dom->conn, vm->def) < 0)
5069 goto cleanup;
5070
5071 ret = 0;
5072
5073 cleanup:
5074 virDomainObjEndAPI(&vm);
5075 return ret;
5076 }
5077
5078
5079 /* Function Tables */
5080 static virHypervisorDriver lxcHypervisorDriver = {
5081 .name = LXC_DRIVER_NAME,
5082 .connectURIProbe = lxcConnectURIProbe,
5083 .connectOpen = lxcConnectOpen, /* 0.4.2 */
5084 .connectClose = lxcConnectClose, /* 0.4.2 */
5085 .connectSupportsFeature = lxcConnectSupportsFeature, /* 1.2.2 */
5086 .connectGetVersion = lxcConnectGetVersion, /* 0.4.6 */
5087 .connectGetHostname = lxcConnectGetHostname, /* 0.6.3 */
5088 .connectGetSysinfo = lxcConnectGetSysinfo, /* 1.0.5 */
5089 .nodeGetInfo = lxcNodeGetInfo, /* 0.6.5 */
5090 .connectGetCapabilities = lxcConnectGetCapabilities, /* 0.6.5 */
5091 .connectListDomains = lxcConnectListDomains, /* 0.4.2 */
5092 .connectNumOfDomains = lxcConnectNumOfDomains, /* 0.4.2 */
5093 .connectListAllDomains = lxcConnectListAllDomains, /* 0.9.13 */
5094 .domainCreateXML = lxcDomainCreateXML, /* 0.4.4 */
5095 .domainCreateXMLWithFiles = lxcDomainCreateXMLWithFiles, /* 1.1.1 */
5096 .domainLookupByID = lxcDomainLookupByID, /* 0.4.2 */
5097 .domainLookupByUUID = lxcDomainLookupByUUID, /* 0.4.2 */
5098 .domainLookupByName = lxcDomainLookupByName, /* 0.4.2 */
5099 .domainSuspend = lxcDomainSuspend, /* 0.7.2 */
5100 .domainResume = lxcDomainResume, /* 0.7.2 */
5101 .domainDestroy = lxcDomainDestroy, /* 0.4.4 */
5102 .domainDestroyFlags = lxcDomainDestroyFlags, /* 0.9.4 */
5103 .domainGetOSType = lxcDomainGetOSType, /* 0.4.2 */
5104 .domainGetMaxMemory = lxcDomainGetMaxMemory, /* 0.7.2 */
5105 .domainSetMaxMemory = lxcDomainSetMaxMemory, /* 0.7.2 */
5106 .domainSetMemory = lxcDomainSetMemory, /* 0.7.2 */
5107 .domainSetMemoryFlags = lxcDomainSetMemoryFlags, /* 1.2.7 */
5108 .domainSetMemoryParameters = lxcDomainSetMemoryParameters, /* 0.8.5 */
5109 .domainGetMemoryParameters = lxcDomainGetMemoryParameters, /* 0.8.5 */
5110 .domainSetBlkioParameters = lxcDomainSetBlkioParameters, /* 0.9.8 */
5111 .domainGetBlkioParameters = lxcDomainGetBlkioParameters, /* 0.9.8 */
5112 .domainGetInfo = lxcDomainGetInfo, /* 0.4.2 */
5113 .domainGetState = lxcDomainGetState, /* 0.9.2 */
5114 .domainGetSecurityLabel = lxcDomainGetSecurityLabel, /* 0.9.10 */
5115 .nodeGetSecurityModel = lxcNodeGetSecurityModel, /* 0.9.10 */
5116 .domainGetXMLDesc = lxcDomainGetXMLDesc, /* 0.4.2 */
5117 .connectDomainXMLFromNative = lxcConnectDomainXMLFromNative, /* 1.2.2 */
5118 .connectListDefinedDomains = lxcConnectListDefinedDomains, /* 0.4.2 */
5119 .connectNumOfDefinedDomains = lxcConnectNumOfDefinedDomains, /* 0.4.2 */
5120 .domainCreate = lxcDomainCreate, /* 0.4.4 */
5121 .domainCreateWithFlags = lxcDomainCreateWithFlags, /* 0.8.2 */
5122 .domainCreateWithFiles = lxcDomainCreateWithFiles, /* 1.1.1 */
5123 .domainDefineXML = lxcDomainDefineXML, /* 0.4.2 */
5124 .domainDefineXMLFlags = lxcDomainDefineXMLFlags, /* 1.2.12 */
5125 .domainUndefine = lxcDomainUndefine, /* 0.4.2 */
5126 .domainUndefineFlags = lxcDomainUndefineFlags, /* 0.9.4 */
5127 .domainAttachDevice = lxcDomainAttachDevice, /* 1.0.1 */
5128 .domainAttachDeviceFlags = lxcDomainAttachDeviceFlags, /* 1.0.1 */
5129 .domainDetachDevice = lxcDomainDetachDevice, /* 1.0.1 */
5130 .domainDetachDeviceFlags = lxcDomainDetachDeviceFlags, /* 1.0.1 */
5131 .domainUpdateDeviceFlags = lxcDomainUpdateDeviceFlags, /* 1.0.1 */
5132 .domainGetAutostart = lxcDomainGetAutostart, /* 0.7.0 */
5133 .domainSetAutostart = lxcDomainSetAutostart, /* 0.7.0 */
5134 .domainGetSchedulerType = lxcDomainGetSchedulerType, /* 0.5.0 */
5135 .domainGetSchedulerParameters = lxcDomainGetSchedulerParameters, /* 0.5.0 */
5136 .domainGetSchedulerParametersFlags = lxcDomainGetSchedulerParametersFlags, /* 0.9.2 */
5137 .domainSetSchedulerParameters = lxcDomainSetSchedulerParameters, /* 0.5.0 */
5138 .domainSetSchedulerParametersFlags = lxcDomainSetSchedulerParametersFlags, /* 0.9.2 */
5139 .domainBlockStats = lxcDomainBlockStats, /* 1.2.2 */
5140 .domainBlockStatsFlags = lxcDomainBlockStatsFlags, /* 1.2.2 */
5141 .domainInterfaceStats = lxcDomainInterfaceStats, /* 0.7.3 */
5142 .domainMemoryStats = lxcDomainMemoryStats, /* 1.2.2 */
5143 .nodeGetCPUStats = lxcNodeGetCPUStats, /* 0.9.3 */
5144 .nodeGetMemoryStats = lxcNodeGetMemoryStats, /* 0.9.3 */
5145 .nodeGetCellsFreeMemory = lxcNodeGetCellsFreeMemory, /* 0.6.5 */
5146 .nodeGetFreeMemory = lxcNodeGetFreeMemory, /* 0.6.5 */
5147 .nodeGetCPUMap = lxcNodeGetCPUMap, /* 1.0.0 */
5148 .connectDomainEventRegister = lxcConnectDomainEventRegister, /* 0.7.0 */
5149 .connectDomainEventDeregister = lxcConnectDomainEventDeregister, /* 0.7.0 */
5150 .connectIsEncrypted = lxcConnectIsEncrypted, /* 0.7.3 */
5151 .connectIsSecure = lxcConnectIsSecure, /* 0.7.3 */
5152 .domainIsActive = lxcDomainIsActive, /* 0.7.3 */
5153 .domainIsPersistent = lxcDomainIsPersistent, /* 0.7.3 */
5154 .domainIsUpdated = lxcDomainIsUpdated, /* 0.8.6 */
5155 .connectDomainEventRegisterAny = lxcConnectDomainEventRegisterAny, /* 0.8.0 */
5156 .connectDomainEventDeregisterAny = lxcConnectDomainEventDeregisterAny, /* 0.8.0 */
5157 .domainOpenConsole = lxcDomainOpenConsole, /* 0.8.6 */
5158 .connectIsAlive = lxcConnectIsAlive, /* 0.9.8 */
5159 .nodeSuspendForDuration = lxcNodeSuspendForDuration, /* 0.9.8 */
5160 .domainSetMetadata = lxcDomainSetMetadata, /* 1.1.3 */
5161 .domainGetMetadata = lxcDomainGetMetadata, /* 1.1.3 */
5162 .domainGetCPUStats = lxcDomainGetCPUStats, /* 1.2.2 */
5163 .domainGetHostname = lxcDomainGetHostname, /* 6.0.0 */
5164 .domainInterfaceAddresses = lxcDomainInterfaceAddresses, /* 6.1.0 */
5165 .nodeGetMemoryParameters = lxcNodeGetMemoryParameters, /* 0.10.2 */
5166 .nodeSetMemoryParameters = lxcNodeSetMemoryParameters, /* 0.10.2 */
5167 .domainSendProcessSignal = lxcDomainSendProcessSignal, /* 1.0.1 */
5168 .domainShutdown = lxcDomainShutdown, /* 1.0.1 */
5169 .domainShutdownFlags = lxcDomainShutdownFlags, /* 1.0.1 */
5170 .domainReboot = lxcDomainReboot, /* 1.0.1 */
5171 .domainLxcOpenNamespace = lxcDomainLxcOpenNamespace, /* 1.0.2 */
5172 .nodeGetFreePages = lxcNodeGetFreePages, /* 1.2.6 */
5173 .nodeAllocPages = lxcNodeAllocPages, /* 1.2.9 */
5174 .domainHasManagedSaveImage = lxcDomainHasManagedSaveImage, /* 1.2.13 */
5175 };
5176
5177 static virConnectDriver lxcConnectDriver = {
5178 .localOnly = true,
5179 .uriSchemes = (const char *[]){ "lxc", NULL },
5180 .hypervisorDriver = &lxcHypervisorDriver,
5181 };
5182
5183 static virStateDriver lxcStateDriver = {
5184 .name = LXC_DRIVER_NAME,
5185 .stateInitialize = lxcStateInitialize,
5186 .stateCleanup = lxcStateCleanup,
5187 .stateReload = lxcStateReload,
5188 };
5189
lxcRegister(void)5190 int lxcRegister(void)
5191 {
5192 if (virRegisterConnectDriver(&lxcConnectDriver,
5193 true) < 0)
5194 return -1;
5195 if (virRegisterStateDriver(&lxcStateDriver) < 0)
5196 return -1;
5197 return 0;
5198 }
5199