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 = &params[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 = &params[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, &quota);
2002         if (rc != 0)
2003             goto cleanup;
2004     }
2005  out:
2006     if (virTypedParameterAssign(&params[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(&params[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(&params[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 = &params[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 = &params[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 = &params[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 = &params[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