1 /*
2  * libxl_domain.c: libxl domain object private state
3  *
4  * Copyright (C) 2011-2015 SUSE LINUX Products GmbH, Nuernberg, Germany.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library.  If not, see
18  * <http://www.gnu.org/licenses/>.
19  */
20 
21 #include <config.h>
22 
23 #include <fcntl.h>
24 
25 #include "libxl_api_wrapper.h"
26 #include "libxl_domain.h"
27 #include "libxl_capabilities.h"
28 
29 #include "datatypes.h"
30 #include "viralloc.h"
31 #include "virfile.h"
32 #include "virerror.h"
33 #include "virhook.h"
34 #include "virlog.h"
35 #include "virstring.h"
36 #include "virtime.h"
37 #include "locking/domain_lock.h"
38 #include "xen_common.h"
39 #include "driver.h"
40 #include "domain_validate.h"
41 
42 #define VIR_FROM_THIS VIR_FROM_LIBXL
43 
44 VIR_LOG_INIT("libxl.libxl_domain");
45 
46 VIR_ENUM_IMPL(libxlDomainJob,
47               LIBXL_JOB_LAST,
48               "none",
49               "query",
50               "destroy",
51               "modify",
52 );
53 
54 
55 static int
libxlDomainObjInitJob(libxlDomainObjPrivate * priv)56 libxlDomainObjInitJob(libxlDomainObjPrivate *priv)
57 {
58     memset(&priv->job, 0, sizeof(priv->job));
59 
60     if (virCondInit(&priv->job.cond) < 0)
61         return -1;
62 
63     priv->job.current = g_new0(virDomainJobInfo, 1);
64 
65     return 0;
66 }
67 
68 static void
libxlDomainObjResetJob(libxlDomainObjPrivate * priv)69 libxlDomainObjResetJob(libxlDomainObjPrivate *priv)
70 {
71     struct libxlDomainJobObj *job = &priv->job;
72 
73     job->active = LIBXL_JOB_NONE;
74     job->owner = 0;
75 }
76 
77 static void
libxlDomainObjFreeJob(libxlDomainObjPrivate * priv)78 libxlDomainObjFreeJob(libxlDomainObjPrivate *priv)
79 {
80     ignore_value(virCondDestroy(&priv->job.cond));
81     VIR_FREE(priv->job.current);
82 }
83 
84 /* Give up waiting for mutex after 30 seconds */
85 #define LIBXL_JOB_WAIT_TIME (1000ull * 30)
86 
87 /*
88  * obj must be locked before calling, libxlDriverPrivate *must NOT be locked
89  *
90  * This must be called by anything that will change the VM state
91  * in any way
92  *
93  * Upon successful return, the object will have its ref count increased,
94  * successful calls must be followed by EndJob eventually
95  */
96 int
libxlDomainObjBeginJob(libxlDriverPrivate * driver G_GNUC_UNUSED,virDomainObj * obj,enum libxlDomainJob job)97 libxlDomainObjBeginJob(libxlDriverPrivate *driver G_GNUC_UNUSED,
98                        virDomainObj *obj,
99                        enum libxlDomainJob job)
100 {
101     libxlDomainObjPrivate *priv = obj->privateData;
102     unsigned long long now;
103     unsigned long long then;
104 
105     if (virTimeMillisNow(&now) < 0)
106         return -1;
107     then = now + LIBXL_JOB_WAIT_TIME;
108 
109     while (priv->job.active) {
110         VIR_DEBUG("Wait normal job condition for starting job: %s",
111                   libxlDomainJobTypeToString(job));
112         if (virCondWaitUntil(&priv->job.cond, &obj->parent.lock, then) < 0)
113             goto error;
114     }
115 
116     libxlDomainObjResetJob(priv);
117 
118     VIR_DEBUG("Starting job: %s", libxlDomainJobTypeToString(job));
119     priv->job.active = job;
120     priv->job.owner = virThreadSelfID();
121     priv->job.started = now;
122     priv->job.current->type = VIR_DOMAIN_JOB_UNBOUNDED;
123 
124     return 0;
125 
126  error:
127     VIR_WARN("Cannot start job (%s) for domain %s;"
128              " current job is (%s) owned by (%d)",
129              libxlDomainJobTypeToString(job),
130              obj->def->name,
131              libxlDomainJobTypeToString(priv->job.active),
132              priv->job.owner);
133 
134     if (errno == ETIMEDOUT)
135         virReportError(VIR_ERR_OPERATION_TIMEOUT,
136                        "%s", _("cannot acquire state change lock"));
137     else
138         virReportSystemError(errno,
139                              "%s", _("cannot acquire job mutex"));
140 
141     return -1;
142 }
143 
144 /*
145  * obj must be locked before calling
146  *
147  * To be called after completing the work associated with the
148  * earlier libxlDomainBeginJob() call
149  *
150  * Returns true if the remaining reference count on obj is
151  * non-zero, false if the reference count has dropped to zero
152  * and obj is disposed.
153  */
154 void
libxlDomainObjEndJob(libxlDriverPrivate * driver G_GNUC_UNUSED,virDomainObj * obj)155 libxlDomainObjEndJob(libxlDriverPrivate *driver G_GNUC_UNUSED,
156                      virDomainObj *obj)
157 {
158     libxlDomainObjPrivate *priv = obj->privateData;
159     enum libxlDomainJob job = priv->job.active;
160 
161     VIR_DEBUG("Stopping job: %s",
162               libxlDomainJobTypeToString(job));
163 
164     libxlDomainObjResetJob(priv);
165     virCondSignal(&priv->job.cond);
166 }
167 
168 int
libxlDomainJobUpdateTime(struct libxlDomainJobObj * job)169 libxlDomainJobUpdateTime(struct libxlDomainJobObj *job)
170 {
171     virDomainJobInfoPtr jobInfo = job->current;
172     unsigned long long now;
173 
174     if (!job->started)
175         return 0;
176 
177     if (virTimeMillisNow(&now) < 0)
178         return -1;
179 
180     if (now < job->started) {
181         job->started = 0;
182         return 0;
183     }
184 
185     jobInfo->timeElapsed = now - job->started;
186     return 0;
187 }
188 
189 static void *
libxlDomainObjPrivateAlloc(void * opaque G_GNUC_UNUSED)190 libxlDomainObjPrivateAlloc(void *opaque G_GNUC_UNUSED)
191 {
192     libxlDomainObjPrivate *priv;
193 
194     priv = g_new0(libxlDomainObjPrivate, 1);
195 
196     if (!(priv->devs = virChrdevAlloc())) {
197         g_free(priv);
198         return NULL;
199     }
200 
201     if (libxlDomainObjInitJob(priv) < 0) {
202         virChrdevFree(priv->devs);
203         g_free(priv);
204         return NULL;
205     }
206 
207     return priv;
208 }
209 
210 static void
libxlDomainObjPrivateFree(void * data)211 libxlDomainObjPrivateFree(void *data)
212 {
213     libxlDomainObjPrivate *priv = data;
214 
215     g_free(priv->lockState);
216     libxlDomainObjFreeJob(priv);
217     virChrdevFree(priv->devs);
218     g_free(priv);
219 }
220 
221 static int
libxlDomainObjPrivateXMLParse(xmlXPathContextPtr ctxt,virDomainObj * vm,virDomainDefParserConfig * config G_GNUC_UNUSED)222 libxlDomainObjPrivateXMLParse(xmlXPathContextPtr ctxt,
223                               virDomainObj *vm,
224                               virDomainDefParserConfig *config G_GNUC_UNUSED)
225 {
226     libxlDomainObjPrivate *priv = vm->privateData;
227 
228     priv->lockState = virXPathString("string(./lockstate)", ctxt);
229 
230     return 0;
231 }
232 
233 static int
libxlDomainObjPrivateXMLFormat(virBuffer * buf,virDomainObj * vm)234 libxlDomainObjPrivateXMLFormat(virBuffer *buf,
235                                virDomainObj *vm)
236 {
237     libxlDomainObjPrivate *priv = vm->privateData;
238 
239     if (priv->lockState)
240         virBufferAsprintf(buf, "<lockstate>%s</lockstate>\n", priv->lockState);
241 
242     return 0;
243 }
244 
245 virDomainXMLPrivateDataCallbacks libxlDomainXMLPrivateDataCallbacks = {
246     .alloc = libxlDomainObjPrivateAlloc,
247     .free = libxlDomainObjPrivateFree,
248     .parse = libxlDomainObjPrivateXMLParse,
249     .format = libxlDomainObjPrivateXMLFormat,
250 };
251 
252 
253 static int
libxlDomainDeviceDefPostParse(virDomainDeviceDef * dev,const virDomainDef * def,unsigned int parseFlags G_GNUC_UNUSED,void * opaque G_GNUC_UNUSED,void * parseOpaque G_GNUC_UNUSED)254 libxlDomainDeviceDefPostParse(virDomainDeviceDef *dev,
255                               const virDomainDef *def,
256                               unsigned int parseFlags G_GNUC_UNUSED,
257                               void *opaque G_GNUC_UNUSED,
258                               void *parseOpaque G_GNUC_UNUSED)
259 {
260     if (dev->type == VIR_DOMAIN_DEVICE_CHR &&
261         dev->data.chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE &&
262         dev->data.chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_NONE &&
263         def->os.type != VIR_DOMAIN_OSTYPE_HVM)
264         dev->data.chr->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_XEN;
265 
266     if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV ||
267         (dev->type == VIR_DOMAIN_DEVICE_NET &&
268          dev->data.net->type == VIR_DOMAIN_NET_TYPE_HOSTDEV)) {
269 
270         virDomainHostdevDef *hostdev;
271         virDomainHostdevSubsysPCI *pcisrc;
272 
273         if (dev->type == VIR_DOMAIN_DEVICE_NET)
274             hostdev = &dev->data.net->data.hostdev.def;
275         else
276             hostdev = dev->data.hostdev;
277         pcisrc = &hostdev->source.subsys.u.pci;
278 
279         /* forbid capabilities mode hostdev in this kind of hypervisor */
280         if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES) {
281             virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
282                            _("hostdev mode 'capabilities' is not "
283                              "supported in %s"),
284                            virDomainVirtTypeToString(def->virtType));
285             return -1;
286         }
287 
288         if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
289             hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI &&
290             pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT)
291             pcisrc->backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_XEN;
292     }
293 
294     if (dev->type == VIR_DOMAIN_DEVICE_VIDEO) {
295         if (dev->data.video->type == VIR_DOMAIN_VIDEO_TYPE_DEFAULT) {
296             if (def->os.type == VIR_DOMAIN_OSTYPE_XEN ||
297                 def->os.type == VIR_DOMAIN_OSTYPE_LINUX)
298                 dev->data.video->type = VIR_DOMAIN_VIDEO_TYPE_XEN;
299             else if (ARCH_IS_PPC64(def->os.arch))
300                 dev->data.video->type = VIR_DOMAIN_VIDEO_TYPE_VGA;
301             else
302                 dev->data.video->type = VIR_DOMAIN_VIDEO_TYPE_CIRRUS;
303         }
304 
305         if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) {
306             int dm_type = libxlDomainGetEmulatorType(def);
307 
308             switch (dev->data.video->type) {
309                 case VIR_DOMAIN_VIDEO_TYPE_VGA:
310                 case VIR_DOMAIN_VIDEO_TYPE_XEN:
311                     if (dev->data.video->vram == 0) {
312                         if (dm_type == LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN)
313                             dev->data.video->vram = 16 * 1024;
314                         else
315                             dev->data.video->vram = 8 * 1024;
316                     }
317                     break;
318                 case VIR_DOMAIN_VIDEO_TYPE_CIRRUS:
319                     if (dev->data.video->vram == 0) {
320                         if (dm_type == LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN)
321                             dev->data.video->vram = 8 * 1024;
322                         else
323                             dev->data.video->vram = 4 * 1024;
324                     }
325                     break;
326                 case VIR_DOMAIN_VIDEO_TYPE_QXL:
327                     if (dev->data.video->vram == 0)
328                         dev->data.video->vram = 128 * 1024;
329                     break;
330             }
331         }
332     }
333 
334     if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
335         virDomainDiskDef *disk = dev->data.disk;
336         int actual_type = virStorageSourceGetActualType(disk->src);
337         int format = virDomainDiskGetFormat(disk);
338 
339         /* for network-based disks, set 'qemu' as the default driver */
340         if (actual_type == VIR_STORAGE_TYPE_NETWORK) {
341             if (!virDomainDiskGetDriver(disk))
342                 virDomainDiskSetDriver(disk, "qemu");
343         }
344 
345         /* xl.cfg default format is raw. See xl-disk-configuration(5) */
346         if (format == VIR_STORAGE_FILE_NONE)
347             virDomainDiskSetFormat(disk, VIR_STORAGE_FILE_RAW);
348     }
349 
350     return 0;
351 }
352 
353 static int
libxlDomainDefPostParse(virDomainDef * def,unsigned int parseFlags G_GNUC_UNUSED,void * opaque G_GNUC_UNUSED,void * parseOpaque G_GNUC_UNUSED)354 libxlDomainDefPostParse(virDomainDef *def,
355                         unsigned int parseFlags G_GNUC_UNUSED,
356                         void *opaque G_GNUC_UNUSED,
357                         void *parseOpaque G_GNUC_UNUSED)
358 {
359     /* Xen PV domains always have a PV console, so add one to the domain config
360      * via post-parse callback if not explicitly specified in the XML. */
361     if (def->os.type != VIR_DOMAIN_OSTYPE_HVM && def->nconsoles == 0) {
362         virDomainChrDef *chrdef;
363 
364         if (!(chrdef = virDomainChrDefNew(NULL)))
365             return -1;
366 
367         chrdef->source->type = VIR_DOMAIN_CHR_TYPE_PTY;
368         chrdef->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE;
369         chrdef->target.port = 0;
370         chrdef->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_XEN;
371 
372         def->consoles = g_new0(virDomainChrDef *, 1);
373         def->nconsoles = 1;
374         def->consoles[0] = chrdef;
375     }
376 
377     /* add implicit input devices */
378     if (xenDomainDefAddImplicitInputDevice(def) < 0)
379         return -1;
380 
381     /* For x86_64 HVM */
382     if (def->os.type == VIR_DOMAIN_OSTYPE_HVM &&
383         def->os.arch == VIR_ARCH_X86_64) {
384         /* always enable pae */
385         def->features[VIR_DOMAIN_FEATURE_PAE] = VIR_TRISTATE_SWITCH_ON;
386 
387         /* if vnuma is effective enable acpi */
388         if (virDomainNumaGetNodeCount(def->numa) > 0)
389             def->features[VIR_DOMAIN_FEATURE_ACPI] = VIR_TRISTATE_SWITCH_ON;
390     }
391 
392     /* add implicit balloon device */
393     if (def->memballoon == NULL) {
394         virDomainMemballoonDef *memballoon;
395         memballoon = g_new0(virDomainMemballoonDef,
396                             1);
397 
398         memballoon->model = VIR_DOMAIN_MEMBALLOON_MODEL_XEN;
399         def->memballoon = memballoon;
400     }
401 
402     /* add implicit xenbus device */
403     if (virDomainControllerFindByType(def, VIR_DOMAIN_CONTROLLER_TYPE_XENBUS) == -1)
404         if (virDomainDefAddController(def, VIR_DOMAIN_CONTROLLER_TYPE_XENBUS, -1, -1) == NULL)
405             return -1;
406 
407     return 0;
408 }
409 
410 static int
libxlDomainDefValidate(const virDomainDef * def,void * opaque,void * parseOpaque G_GNUC_UNUSED)411 libxlDomainDefValidate(const virDomainDef *def,
412                        void *opaque,
413                        void *parseOpaque G_GNUC_UNUSED)
414 {
415     libxlDriverPrivate *driver = opaque;
416     g_autoptr(libxlDriverConfig) cfg = libxlDriverConfigGet(driver);
417     bool reqSecureBoot = false;
418 
419     if (!virCapabilitiesDomainSupported(cfg->caps, def->os.type,
420                                         def->os.arch,
421                                         def->virtType))
422         return -1;
423 
424     /* Xen+ovmf does not support secure boot */
425     if (def->os.firmware == VIR_DOMAIN_OS_DEF_FIRMWARE_EFI) {
426         if (def->os.firmwareFeatures &&
427             def->os.firmwareFeatures[VIR_DOMAIN_OS_DEF_FIRMWARE_FEATURE_SECURE_BOOT])
428             reqSecureBoot = true;
429     }
430     if (virDomainDefHasOldStyleUEFI(def)) {
431         if (def->os.loader &&
432             def->os.loader->secure == VIR_TRISTATE_BOOL_YES)
433             reqSecureBoot = true;
434     }
435     if (reqSecureBoot) {
436         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
437                        _("Secure boot is not supported on Xen"));
438         return -1;
439     }
440 
441     return 0;
442 }
443 
444 virDomainDefParserConfig libxlDomainDefParserConfig = {
445     .macPrefix = { 0x00, 0x16, 0x3e },
446     .netPrefix = LIBXL_GENERATED_PREFIX_XEN,
447     .devicesPostParseCallback = libxlDomainDeviceDefPostParse,
448     .domainPostParseCallback = libxlDomainDefPostParse,
449     .domainValidateCallback = libxlDomainDefValidate,
450 
451     .features = VIR_DOMAIN_DEF_FEATURE_FW_AUTOSELECT |
452                 VIR_DOMAIN_DEF_FEATURE_NET_MODEL_STRING,
453 };
454 
455 
456 static void
libxlDomainShutdownHandleDestroy(libxlDriverPrivate * driver,virDomainObj * vm)457 libxlDomainShutdownHandleDestroy(libxlDriverPrivate *driver,
458                                  virDomainObj *vm)
459 {
460     libxlDomainDestroyInternal(driver, vm);
461     libxlDomainCleanup(driver, vm);
462     if (!vm->persistent)
463         virDomainObjListRemove(driver->domains, vm);
464 }
465 
466 
467 static void
libxlDomainShutdownHandleRestart(libxlDriverPrivate * driver,virDomainObj * vm)468 libxlDomainShutdownHandleRestart(libxlDriverPrivate *driver,
469                                  virDomainObj *vm)
470 {
471     libxlDomainDestroyInternal(driver, vm);
472     libxlDomainCleanup(driver, vm);
473     if (libxlDomainStartNew(driver, vm, false) < 0) {
474         VIR_ERROR(_("Failed to restart VM '%s': %s"),
475                   vm->def->name, virGetLastErrorMessage());
476     }
477 }
478 
479 
480 struct libxlShutdownThreadInfo
481 {
482     libxlDriverPrivate *driver;
483     virDomainObj *vm;
484     libxl_event *event;
485 };
486 
487 
488 static void
libxlDomainShutdownThread(void * opaque)489 libxlDomainShutdownThread(void *opaque)
490 {
491     struct libxlShutdownThreadInfo *shutdown_info = opaque;
492     virDomainObj *vm = shutdown_info->vm;
493     libxl_event *ev = shutdown_info->event;
494     libxlDriverPrivate *driver = shutdown_info->driver;
495     virObjectEvent *dom_event = NULL;
496     libxl_shutdown_reason xl_reason = ev->u.domain_shutdown.shutdown_reason;
497     g_autoptr(libxlDriverConfig) cfg = libxlDriverConfigGet(driver);
498     libxl_domain_config d_config;
499 
500     libxl_domain_config_init(&d_config);
501 
502     if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
503         goto cleanup;
504 
505     if (xl_reason == LIBXL_SHUTDOWN_REASON_POWEROFF) {
506         virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF,
507                              VIR_DOMAIN_SHUTOFF_SHUTDOWN);
508 
509         dom_event = virDomainEventLifecycleNewFromObj(vm,
510                                            VIR_DOMAIN_EVENT_STOPPED,
511                                            VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
512         switch ((virDomainLifecycleAction) vm->def->onPoweroff) {
513         case VIR_DOMAIN_LIFECYCLE_ACTION_DESTROY:
514             libxlDomainShutdownHandleDestroy(driver, vm);
515             goto endjob;
516         case VIR_DOMAIN_LIFECYCLE_ACTION_RESTART:
517         case VIR_DOMAIN_LIFECYCLE_ACTION_RESTART_RENAME:
518             libxlDomainShutdownHandleRestart(driver, vm);
519             goto endjob;
520         case VIR_DOMAIN_LIFECYCLE_ACTION_PRESERVE:
521         case VIR_DOMAIN_LIFECYCLE_ACTION_COREDUMP_DESTROY:
522         case VIR_DOMAIN_LIFECYCLE_ACTION_COREDUMP_RESTART:
523         case VIR_DOMAIN_LIFECYCLE_ACTION_LAST:
524             goto endjob;
525         }
526     } else if (xl_reason == LIBXL_SHUTDOWN_REASON_CRASH) {
527         virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF,
528                              VIR_DOMAIN_SHUTOFF_CRASHED);
529 
530         dom_event = virDomainEventLifecycleNewFromObj(vm,
531                                            VIR_DOMAIN_EVENT_STOPPED,
532                                            VIR_DOMAIN_EVENT_STOPPED_CRASHED);
533         switch ((virDomainLifecycleAction) vm->def->onCrash) {
534         case VIR_DOMAIN_LIFECYCLE_ACTION_DESTROY:
535             libxlDomainShutdownHandleDestroy(driver, vm);
536             goto endjob;
537         case VIR_DOMAIN_LIFECYCLE_ACTION_RESTART:
538         case VIR_DOMAIN_LIFECYCLE_ACTION_RESTART_RENAME:
539             libxlDomainShutdownHandleRestart(driver, vm);
540             goto endjob;
541         case VIR_DOMAIN_LIFECYCLE_ACTION_PRESERVE:
542         case VIR_DOMAIN_LIFECYCLE_ACTION_LAST:
543             goto endjob;
544         case VIR_DOMAIN_LIFECYCLE_ACTION_COREDUMP_DESTROY:
545             libxlDomainAutoCoreDump(driver, vm);
546             libxlDomainShutdownHandleDestroy(driver, vm);
547             goto endjob;
548         case VIR_DOMAIN_LIFECYCLE_ACTION_COREDUMP_RESTART:
549             libxlDomainAutoCoreDump(driver, vm);
550             libxlDomainShutdownHandleRestart(driver, vm);
551             goto endjob;
552         }
553     } else if (xl_reason == LIBXL_SHUTDOWN_REASON_REBOOT) {
554         virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF,
555                              VIR_DOMAIN_SHUTOFF_SHUTDOWN);
556 
557         dom_event = virDomainEventLifecycleNewFromObj(vm,
558                                            VIR_DOMAIN_EVENT_STOPPED,
559                                            VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
560         switch ((virDomainLifecycleAction) vm->def->onReboot) {
561         case VIR_DOMAIN_LIFECYCLE_ACTION_DESTROY:
562             libxlDomainShutdownHandleDestroy(driver, vm);
563             goto endjob;
564         case VIR_DOMAIN_LIFECYCLE_ACTION_RESTART:
565         case VIR_DOMAIN_LIFECYCLE_ACTION_RESTART_RENAME:
566             libxlDomainShutdownHandleRestart(driver, vm);
567             goto endjob;
568         case VIR_DOMAIN_LIFECYCLE_ACTION_PRESERVE:
569         case VIR_DOMAIN_LIFECYCLE_ACTION_COREDUMP_DESTROY:
570         case VIR_DOMAIN_LIFECYCLE_ACTION_COREDUMP_RESTART:
571         case VIR_DOMAIN_LIFECYCLE_ACTION_LAST:
572             goto endjob;
573         }
574     } else if (xl_reason == LIBXL_SHUTDOWN_REASON_SOFT_RESET) {
575         libxlDomainObjPrivate *priv = vm->privateData;
576 
577         if (libxlRetrieveDomainConfigurationWrapper(cfg->ctx, vm->def->id,
578                                                     &d_config) != 0) {
579             VIR_ERROR(_("Failed to retrieve config for VM '%s'. "
580                         "Unable to perform soft reset. Destroying VM"),
581                       vm->def->name);
582             libxlDomainShutdownHandleDestroy(driver, vm);
583             goto endjob;
584         }
585 
586         if (priv->deathW) {
587             libxl_evdisable_domain_death(cfg->ctx, priv->deathW);
588             priv->deathW = NULL;
589         }
590 
591         if (libxl_domain_soft_reset(cfg->ctx, &d_config, vm->def->id,
592                                     NULL, NULL) != 0) {
593             VIR_ERROR(_("Failed to soft reset VM '%s'. Destroying VM"),
594                       vm->def->name);
595             libxlDomainShutdownHandleDestroy(driver, vm);
596             goto endjob;
597         }
598         libxl_evenable_domain_death(cfg->ctx, vm->def->id, 0, &priv->deathW);
599         libxlDomainUnpauseWrapper(cfg->ctx, vm->def->id);
600     } else {
601         VIR_INFO("Unhandled shutdown_reason %d", xl_reason);
602     }
603 
604  endjob:
605     libxlDomainObjEndJob(driver, vm);
606 
607  cleanup:
608     virDomainObjEndAPI(&vm);
609     virObjectEventStateQueue(driver->domainEventState, dom_event);
610     libxl_event_free(cfg->ctx, ev);
611     VIR_FREE(shutdown_info);
612     libxl_domain_config_dispose(&d_config);
613 }
614 
615 static void
libxlDomainHandleDeath(libxlDriverPrivate * driver,virDomainObj * vm)616 libxlDomainHandleDeath(libxlDriverPrivate *driver, virDomainObj *vm)
617 {
618     virObjectEvent *dom_event = NULL;
619     libxlDomainObjPrivate *priv = vm->privateData;
620 
621     if (priv->ignoreDeathEvent) {
622         priv->ignoreDeathEvent = false;
623         return;
624     }
625 
626     if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
627         return;
628 
629     virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, VIR_DOMAIN_SHUTOFF_DESTROYED);
630     dom_event = virDomainEventLifecycleNewFromObj(vm,
631                                                   VIR_DOMAIN_EVENT_STOPPED,
632                                                   VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
633     libxlDomainCleanup(driver, vm);
634     if (!vm->persistent)
635         virDomainObjListRemove(driver->domains, vm);
636     libxlDomainObjEndJob(driver, vm);
637     virObjectEventStateQueue(driver->domainEventState, dom_event);
638 }
639 
640 
641 /*
642  * Handle previously registered domain event notification from libxenlight.
643  */
644 void
libxlDomainEventHandler(void * data,libxl_event * event)645 libxlDomainEventHandler(void *data, libxl_event *event)
646 {
647     libxlDriverPrivate *driver = data;
648     libxl_shutdown_reason xl_reason = event->u.domain_shutdown.shutdown_reason;
649     virDomainObj *vm = NULL;
650     g_autoptr(libxlDriverConfig) cfg = NULL;
651 
652     VIR_DEBUG("Received libxl event '%d' for domid '%d'", event->type, event->domid);
653 
654     if (event->type != LIBXL_EVENT_TYPE_DOMAIN_SHUTDOWN &&
655             event->type != LIBXL_EVENT_TYPE_DOMAIN_DEATH) {
656         VIR_INFO("Unhandled event type %d", event->type);
657         goto cleanup;
658     }
659 
660     /*
661      * Similar to the xl implementation, ignore SUSPEND.  Any actions needed
662      * after calling libxl_domain_suspend() are handled by its callers.
663      */
664     if (xl_reason == LIBXL_SHUTDOWN_REASON_SUSPEND)
665         goto cleanup;
666 
667     vm = virDomainObjListFindByID(driver->domains, event->domid);
668     if (!vm) {
669         /* Nothing to do if we can't find the virDomainObj */
670         goto cleanup;
671     }
672 
673     if (event->type == LIBXL_EVENT_TYPE_DOMAIN_SHUTDOWN) {
674         libxlDomainObjPrivate *priv = vm->privateData;
675         struct libxlShutdownThreadInfo *shutdown_info = NULL;
676         virThread thread;
677         g_autofree char *name = NULL;
678 
679         /*
680          * Start a thread to handle shutdown.  We don't want to be tying up
681          * libxl's event machinery by doing a potentially lengthy shutdown.
682          */
683         shutdown_info = g_new0(struct libxlShutdownThreadInfo, 1);
684 
685         shutdown_info->driver = driver;
686         shutdown_info->vm = vm;
687         shutdown_info->event = (libxl_event *)event;
688         name = g_strdup_printf("ev-%d", event->domid);
689         /*
690          * Cleanup will be handled by the shutdown thread.
691          * Ignore the forthcoming death event from libxl
692          */
693         priv->ignoreDeathEvent = true;
694         if (virThreadCreateFull(&thread, false, libxlDomainShutdownThread,
695                                 name, false, shutdown_info) < 0) {
696              priv->ignoreDeathEvent = false;
697             /*
698              * Not much we can do on error here except log it.
699              */
700             VIR_ERROR(_("Failed to create thread to handle domain shutdown"));
701             VIR_FREE(shutdown_info);
702             goto cleanup;
703         }
704         /*
705          * virDomainObjEndAPI is called in the shutdown thread, where
706          * libxlShutdownThreadInfo and libxl_event are also freed.
707          */
708         return;
709     } else if (event->type == LIBXL_EVENT_TYPE_DOMAIN_DEATH) {
710         /*
711          * On death the domain is cleaned up from Xen's perspective.
712          * Cleanup on the libvirt side can be done synchronously.
713          */
714         libxlDomainHandleDeath(driver, vm);
715     }
716 
717  cleanup:
718     virDomainObjEndAPI(&vm);
719     cfg = libxlDriverConfigGet(driver);
720     /* Cast away any const */
721     libxl_event_free(cfg->ctx, (libxl_event *)event);
722 }
723 
724 char *
libxlDomainManagedSavePath(libxlDriverPrivate * driver,virDomainObj * vm)725 libxlDomainManagedSavePath(libxlDriverPrivate *driver, virDomainObj *vm)
726 {
727     char *ret;
728     g_autoptr(libxlDriverConfig) cfg = libxlDriverConfigGet(driver);
729 
730     ret = g_strdup_printf("%s/%s.save", cfg->saveDir, vm->def->name);
731     return ret;
732 }
733 
734 /*
735  * Open a saved image file and initialize domain definition from the header.
736  *
737  * Returns the opened fd on success, -1 on failure.
738  */
739 int
libxlDomainSaveImageOpen(libxlDriverPrivate * driver,const char * from,virDomainDef ** ret_def,libxlSavefileHeader * ret_hdr)740 libxlDomainSaveImageOpen(libxlDriverPrivate *driver,
741                          const char *from,
742                          virDomainDef **ret_def,
743                          libxlSavefileHeader *ret_hdr)
744 {
745     int fd;
746     virDomainDef *def = NULL;
747     libxlSavefileHeader hdr;
748     g_autofree char *xml = NULL;
749 
750     if ((fd = virFileOpenAs(from, O_RDONLY, 0, -1, -1, 0)) < 0) {
751         virReportSystemError(-fd,
752                              _("Failed to open domain image file '%s'"), from);
753         goto error;
754     }
755 
756     if (saferead(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
757         virReportError(VIR_ERR_OPERATION_FAILED,
758                        "%s", _("failed to read libxl header"));
759         goto error;
760     }
761 
762     if (memcmp(hdr.magic, LIBXL_SAVE_MAGIC, sizeof(hdr.magic))) {
763         virReportError(VIR_ERR_INVALID_ARG, "%s", _("image magic is incorrect"));
764         goto error;
765     }
766 
767     if (hdr.version > LIBXL_SAVE_VERSION) {
768         virReportError(VIR_ERR_OPERATION_FAILED,
769                        _("image version is not supported (%d > %d)"),
770                        hdr.version, LIBXL_SAVE_VERSION);
771         goto error;
772     }
773 
774     if (hdr.xmlLen <= 0) {
775         virReportError(VIR_ERR_OPERATION_FAILED,
776                        _("invalid XML length: %d"), hdr.xmlLen);
777         goto error;
778     }
779 
780     xml = g_new0(char, hdr.xmlLen);
781 
782     if (saferead(fd, xml, hdr.xmlLen) != hdr.xmlLen) {
783         virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("failed to read XML"));
784         goto error;
785     }
786 
787     if (!(def = virDomainDefParseString(xml, driver->xmlopt, NULL,
788                                         VIR_DOMAIN_DEF_PARSE_INACTIVE |
789                                         VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE)))
790         goto error;
791 
792     *ret_def = def;
793     *ret_hdr = hdr;
794 
795     return fd;
796 
797  error:
798     virDomainDefFree(def);
799     VIR_FORCE_CLOSE(fd);
800     return -1;
801 }
802 
803 static void
libxlNetworkUnwindDevices(virDomainDef * def)804 libxlNetworkUnwindDevices(virDomainDef *def)
805 {
806     if (def->nnets) {
807         size_t i;
808 
809         for (i = 0; i < def->nnets; i++) {
810             virDomainNetDef *net = def->nets[i];
811 
812             if (net->ifname &&
813                 STRPREFIX(net->ifname, LIBXL_GENERATED_PREFIX_XEN))
814                 VIR_FREE(net->ifname);
815 
816             /* cleanup actual device */
817             virDomainNetRemoveHostdev(def, net);
818             if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
819                 g_autoptr(virConnect) conn = virGetConnectNetwork();
820 
821                 if (conn)
822                     virDomainNetReleaseActualDevice(conn, def, net);
823                 else
824                     VIR_WARN("Unable to release network device '%s'", NULLSTR(net->ifname));
825             }
826         }
827     }
828 }
829 
830 int
libxlDomainHookRun(libxlDriverPrivate * driver,virDomainDef * def,unsigned int def_fmtflags,int hookop,int hooksubop,char ** output)831 libxlDomainHookRun(libxlDriverPrivate *driver,
832                    virDomainDef *def,
833                    unsigned int def_fmtflags,
834                    int hookop,
835                    int hooksubop,
836                    char **output)
837 {
838     g_autofree char *xml = NULL;
839 
840     if (!virHookPresent(VIR_HOOK_DRIVER_LIBXL))
841         return 0;
842 
843     xml = virDomainDefFormat(def, driver->xmlopt, def_fmtflags);
844     return virHookCall(VIR_HOOK_DRIVER_LIBXL, def->name,
845                        hookop, hooksubop,
846                        NULL, xml, output);
847 }
848 
849 /*
850  * Internal domain destroy function.
851  *
852  * virDomainObj *must be locked on invocation
853  */
854 int
libxlDomainDestroyInternal(libxlDriverPrivate * driver,virDomainObj * vm)855 libxlDomainDestroyInternal(libxlDriverPrivate *driver,
856                            virDomainObj *vm)
857 {
858     g_autoptr(libxlDriverConfig) cfg = libxlDriverConfigGet(driver);
859     libxlDomainObjPrivate *priv = vm->privateData;
860     int ret = -1;
861 
862     /* Ignore next LIBXL_EVENT_TYPE_DOMAIN_DEATH as the caller will handle
863      * domain death appropriately already (having more info, like the reason).
864      */
865     priv->ignoreDeathEvent = true;
866     /* Unlock virDomainObj during destroy, which can take considerable
867      * time on large memory domains.
868      */
869     virObjectUnlock(vm);
870     ret = libxl_domain_destroy(cfg->ctx, vm->def->id, NULL);
871     virObjectLock(vm);
872     if (ret)
873         priv->ignoreDeathEvent = false;
874 
875     return ret;
876 }
877 
878 /*
879  * Cleanup function for domain that has reached shutoff state.
880  *
881  * virDomainObj *must be locked on invocation
882  */
883 void
libxlDomainCleanup(libxlDriverPrivate * driver,virDomainObj * vm)884 libxlDomainCleanup(libxlDriverPrivate *driver,
885                    virDomainObj *vm)
886 {
887     libxlDomainObjPrivate *priv = vm->privateData;
888     g_autoptr(libxlDriverConfig) cfg = libxlDriverConfigGet(driver);
889     int vnc_port;
890     char *file;
891     virHostdevManager *hostdev_mgr = driver->hostdevMgr;
892     unsigned int hostdev_flags = VIR_HOSTDEV_SP_PCI;
893 
894     VIR_DEBUG("Cleaning up domain with id '%d' and name '%s'",
895               vm->def->id, vm->def->name);
896 
897     hostdev_flags |= VIR_HOSTDEV_SP_USB;
898 
899     /* Call hook with stopped operation. Ignore error and continue with cleanup */
900     ignore_value(libxlDomainHookRun(driver, vm->def, 0,
901                                     VIR_HOOK_LIBXL_OP_STOPPED,
902                                     VIR_HOOK_SUBOP_END, NULL));
903 
904     virHostdevReAttachDomainDevices(hostdev_mgr, LIBXL_DRIVER_INTERNAL_NAME,
905                                     vm->def, hostdev_flags);
906 
907     if (priv->lockProcessRunning) {
908         VIR_FREE(priv->lockState);
909         if (virDomainLockProcessPause(driver->lockManager, vm, &priv->lockState) < 0)
910             VIR_WARN("Unable to release lease on %s", vm->def->name);
911         else
912             priv->lockProcessRunning = false;
913         VIR_DEBUG("Preserving lock state '%s'", NULLSTR(priv->lockState));
914     }
915 
916     libxlLoggerCloseFile(cfg->logger, vm->def->id);
917     vm->def->id = -1;
918 
919     if (priv->deathW) {
920         libxl_evdisable_domain_death(cfg->ctx, priv->deathW);
921         priv->deathW = NULL;
922     }
923 
924     priv->ignoreDeathEvent = false;
925 
926     if (!!g_atomic_int_dec_and_test(&driver->nactive) && driver->inhibitCallback)
927         driver->inhibitCallback(false, driver->inhibitOpaque);
928 
929     if ((vm->def->ngraphics == 1) &&
930         vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
931         vm->def->graphics[0]->data.vnc.autoport) {
932         vnc_port = vm->def->graphics[0]->data.vnc.port;
933         if (vnc_port >= LIBXL_VNC_PORT_MIN) {
934             if (virPortAllocatorRelease(vnc_port) < 0)
935                 VIR_DEBUG("Could not mark port %d as unused", vnc_port);
936         }
937     }
938 
939     libxlNetworkUnwindDevices(vm->def);
940 
941     file = g_strdup_printf("%s/%s.xml", cfg->stateDir, vm->def->name);
942     if (unlink(file) < 0 && errno != ENOENT && errno != ENOTDIR)
943         VIR_DEBUG("Failed to remove domain XML for %s", vm->def->name);
944     VIR_FREE(file);
945 
946     /* Call hook with release operation. Ignore error and continue with cleanup */
947     ignore_value(libxlDomainHookRun(driver, vm->def, 0,
948                                     VIR_HOOK_LIBXL_OP_RELEASE,
949                                     VIR_HOOK_SUBOP_END, NULL));
950 
951     virDomainObjRemoveTransientDef(vm);
952 }
953 
954 /*
955  * Core dump domain to default dump path.
956  *
957  * virDomainObj *must be locked on invocation
958  */
959 int
libxlDomainAutoCoreDump(libxlDriverPrivate * driver,virDomainObj * vm)960 libxlDomainAutoCoreDump(libxlDriverPrivate *driver,
961                         virDomainObj *vm)
962 {
963     g_autoptr(libxlDriverConfig) cfg = libxlDriverConfigGet(driver);
964     g_autoptr(GDateTime) now = g_date_time_new_now_local();
965     g_autofree char *nowstr = NULL;
966     g_autofree char *dumpfile = NULL;
967 
968     nowstr = g_date_time_format(now, "%Y-%m-%d-%H:%M:%S");
969 
970     dumpfile = g_strdup_printf("%s/%s-%s", cfg->autoDumpDir, vm->def->name,
971                                nowstr);
972 
973     /* Unlock virDomainObj while dumping core */
974     virObjectUnlock(vm);
975     libxl_domain_core_dump(cfg->ctx, vm->def->id, dumpfile, NULL);
976     virObjectLock(vm);
977 
978     return 0;
979 }
980 
981 static int
libxlDomainFreeMem(libxl_ctx * ctx,libxl_domain_config * d_config)982 libxlDomainFreeMem(libxl_ctx *ctx, libxl_domain_config *d_config)
983 {
984     uint64_t needed_mem;
985     uint64_t free_mem;
986     uint64_t target_mem;
987     int tries = 3;
988     int wait_secs = 10;
989 
990     if (libxlDomainNeedMemoryWrapper(ctx, d_config, &needed_mem) < 0)
991         goto error;
992 
993     do {
994         if (libxlGetFreeMemoryWrapper(ctx, &free_mem) < 0)
995             goto error;
996 
997         if (free_mem >= needed_mem)
998             return 0;
999 
1000         target_mem = free_mem - needed_mem;
1001         if (libxlSetMemoryTargetWrapper(ctx, 0, target_mem,
1002                                         /* relative */ 1, 0) < 0)
1003             goto error;
1004 
1005         if (libxl_wait_for_memory_target(ctx, 0, wait_secs) < 0)
1006             goto error;
1007 
1008         tries--;
1009     } while (tries > 0);
1010 
1011  error:
1012     virReportError(VIR_ERR_OPERATION_FAILED, "%s",
1013                    _("Failed to balloon domain0 memory"));
1014     return -1;
1015 }
1016 
1017 static int
libxlNetworkPrepareDevices(virDomainDef * def)1018 libxlNetworkPrepareDevices(virDomainDef *def)
1019 {
1020     size_t i;
1021     g_autoptr(virConnect) conn = NULL;
1022 
1023     for (i = 0; i < def->nnets; i++) {
1024         virDomainNetDef *net = def->nets[i];
1025         virDomainNetType actualType;
1026 
1027         /* If appropriate, grab a physical device from the configured
1028          * network's pool of devices, or resolve bridge device name
1029          * to the one defined in the network definition.
1030          */
1031         if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
1032             if (!conn && !(conn = virGetConnectNetwork()))
1033                 return -1;
1034             if (virDomainNetAllocateActualDevice(conn, def, net) < 0)
1035                 return -1;
1036         }
1037 
1038         /* final validation now that actual type is known */
1039         if (virDomainActualNetDefValidate(net) < 0)
1040             return -1;
1041 
1042         actualType = virDomainNetGetActualType(net);
1043         if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV &&
1044             net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
1045             /* Each type='hostdev' network device must also have a
1046              * corresponding entry in the hostdevs array. For netdevs
1047              * that are hardcoded as type='hostdev', this is already
1048              * done by the parser, but for those allocated from a
1049              * network / determined at runtime, we need to do it
1050              * separately.
1051              */
1052             virDomainHostdevDef *hostdev = virDomainNetGetActualHostdev(net);
1053             virDomainHostdevSubsysPCI *pcisrc = &hostdev->source.subsys.u.pci;
1054 
1055             if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
1056                 hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
1057                 pcisrc->backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_XEN;
1058 
1059             if (virDomainHostdevInsert(def, hostdev) < 0)
1060                 return -1;
1061         }
1062     }
1063 
1064     return 0;
1065 }
1066 
1067 static void
libxlConsoleCallback(libxl_ctx * ctx,libxl_event * ev,void * for_callback)1068 libxlConsoleCallback(libxl_ctx *ctx, libxl_event *ev, void *for_callback)
1069 {
1070     virDomainObj *vm = for_callback;
1071     size_t i;
1072     virDomainChrDef *chr;
1073     char *console = NULL;
1074     int ret;
1075 
1076     virObjectLock(vm);
1077     for (i = 0; i < vm->def->nconsoles; i++) {
1078         chr = vm->def->consoles[i];
1079 
1080         if (i == 0 &&
1081             chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL)
1082             chr = vm->def->serials[0];
1083 
1084         if (chr->source->type == VIR_DOMAIN_CHR_TYPE_PTY) {
1085             libxl_console_type console_type;
1086 
1087             console_type =
1088                 (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL ?
1089                  LIBXL_CONSOLE_TYPE_SERIAL : LIBXL_CONSOLE_TYPE_PV);
1090             ret = libxl_console_get_tty(ctx, ev->domid,
1091                                         chr->target.port, console_type,
1092                                         &console);
1093             if (!ret) {
1094                 VIR_FREE(chr->source->data.file.path);
1095                 if (console && console[0] != '\0')
1096                     chr->source->data.file.path = g_strdup(console);
1097             }
1098             VIR_FREE(console);
1099         }
1100     }
1101     for (i = 0; i < vm->def->nserials; i++) {
1102         chr = vm->def->serials[i];
1103 
1104         chr->info.alias = g_strdup_printf("serial%zd", i);
1105         if (chr->source->type == VIR_DOMAIN_CHR_TYPE_PTY) {
1106             if (chr->source->data.file.path)
1107                 continue;
1108             ret = libxl_console_get_tty(ctx, ev->domid,
1109                                         chr->target.port,
1110                                         LIBXL_CONSOLE_TYPE_SERIAL,
1111                                         &console);
1112             if (!ret) {
1113                 VIR_FREE(chr->source->data.file.path);
1114                 if (console && console[0] != '\0')
1115                     chr->source->data.file.path = g_strdup(console);
1116             }
1117             VIR_FREE(console);
1118         }
1119     }
1120     virObjectUnlock(vm);
1121     libxl_event_free(ctx, ev);
1122 }
1123 
1124 /*
1125  * Create interface names for the network devices in parameter def.
1126  * Names are created with the pattern 'vif<domid>.<devid><suffix>'.
1127  * devid is extracted from the network devices in the d_config
1128  * parameter. User-provided interface names are skipped.
1129  */
1130 static void
libxlDomainCreateIfaceNames(virDomainDef * def,libxl_domain_config * d_config)1131 libxlDomainCreateIfaceNames(virDomainDef *def, libxl_domain_config *d_config)
1132 {
1133     size_t i;
1134 
1135     for (i = 0; i < def->nnets && i < d_config->num_nics; i++) {
1136         virDomainNetDef *net = def->nets[i];
1137         libxl_device_nic *x_nic = &d_config->nics[i];
1138         const char *suffix =
1139             x_nic->nictype != LIBXL_NIC_TYPE_VIF ? "-emu" : "";
1140 
1141         if (net->ifname)
1142             continue;
1143 
1144         net->ifname = g_strdup_printf(LIBXL_GENERATED_PREFIX_XEN "%d.%d%s",
1145                                       def->id, x_nic->devid, suffix);
1146     }
1147 }
1148 
1149 static void
libxlDomainUpdateDiskParams(virDomainDef * def,libxl_ctx * ctx)1150 libxlDomainUpdateDiskParams(virDomainDef *def, libxl_ctx *ctx)
1151 {
1152     libxl_device_disk *disks;
1153     int num_disks = 0;
1154     size_t i;
1155     int idx;
1156 
1157     disks = libxl_device_disk_list(ctx, def->id, &num_disks);
1158     if (!disks)
1159         return;
1160 
1161     for (i = 0; i < num_disks; i++) {
1162         if ((idx = virDomainDiskIndexByName(def, disks[i].vdev, false)) < 0)
1163             continue;
1164 
1165         libxlUpdateDiskDef(def->disks[idx], &disks[i]);
1166     }
1167 
1168     for (i = 0; i < num_disks; i++)
1169         libxl_device_disk_dispose(&disks[i]);
1170     VIR_FREE(disks);
1171 }
1172 
1173 static void
libxlDomainCreateChannelPTY(virDomainDef * def,libxl_ctx * ctx)1174 libxlDomainCreateChannelPTY(virDomainDef *def, libxl_ctx *ctx)
1175 {
1176     libxl_device_channel *x_channels;
1177     virDomainChrDef *chr;
1178     size_t i;
1179     int nchannels;
1180 
1181     x_channels = libxl_device_channel_list(ctx, def->id, &nchannels);
1182     if (!x_channels)
1183         return;
1184 
1185     for (i = 0; i < def->nchannels; i++) {
1186         libxl_channelinfo channelinfo;
1187         int ret;
1188 
1189         chr = def->channels[i];
1190         if (chr->source->type != VIR_DOMAIN_CHR_TYPE_PTY)
1191             continue;
1192 
1193         ret = libxl_device_channel_getinfo(ctx, def->id, &x_channels[i],
1194                                            &channelinfo);
1195 
1196         if (!ret && channelinfo.u.pty.path &&
1197             *channelinfo.u.pty.path != '\0') {
1198                 VIR_FREE(chr->source->data.file.path);
1199                 chr->source->data.file.path = g_strdup(channelinfo.u.pty.path);
1200             }
1201     }
1202 
1203     for (i = 0; i < nchannels; i++)
1204         libxl_device_channel_dispose(&x_channels[i]);
1205 }
1206 
1207 static int
libxlDomainStartPrepare(libxlDriverPrivate * driver,virDomainObj * vm)1208 libxlDomainStartPrepare(libxlDriverPrivate *driver,
1209                         virDomainObj *vm)
1210 {
1211     virHostdevManager *hostdev_mgr = driver->hostdevMgr;
1212     unsigned int hostdev_flags = VIR_HOSTDEV_SP_PCI | VIR_HOSTDEV_SP_USB;
1213 
1214     if (virDomainObjSetDefTransient(driver->xmlopt, vm, NULL) < 0)
1215         return -1;
1216 
1217     /* Run an early hook to set-up missing devices */
1218     if (libxlDomainHookRun(driver, vm->def, 0,
1219                            VIR_HOOK_LIBXL_OP_PREPARE,
1220                            VIR_HOOK_SUBOP_BEGIN, NULL) < 0)
1221         goto error;
1222 
1223     if (virDomainLockProcessStart(driver->lockManager,
1224                                   "xen:///system",
1225                                   vm,
1226                                   true,
1227                                   NULL) < 0)
1228         goto error;
1229 
1230     if (libxlNetworkPrepareDevices(vm->def) < 0)
1231         goto error;
1232 
1233     if (virHostdevPrepareDomainDevices(hostdev_mgr, LIBXL_DRIVER_INTERNAL_NAME,
1234                                        vm->def, hostdev_flags) < 0)
1235         goto error;
1236 
1237     return 0;
1238 
1239  error:
1240     libxlNetworkUnwindDevices(vm->def);
1241     virHostdevReAttachDomainDevices(hostdev_mgr, LIBXL_DRIVER_INTERNAL_NAME,
1242                                     vm->def, hostdev_flags);
1243     virDomainObjRemoveTransientDef(vm);
1244     return -1;
1245 }
1246 
1247 static int
libxlDomainStartPerform(libxlDriverPrivate * driver,virDomainObj * vm,bool start_paused,int restore_fd,uint32_t restore_ver)1248 libxlDomainStartPerform(libxlDriverPrivate *driver,
1249                         virDomainObj *vm,
1250                         bool start_paused,
1251                         int restore_fd,
1252                         uint32_t restore_ver)
1253 {
1254     libxl_domain_config d_config;
1255     int ret = -1;
1256     int libxlret = -1;
1257     uint32_t domid = 0;
1258     g_autofree char *dom_xml = NULL;
1259     libxlDomainObjPrivate *priv = vm->privateData;
1260     g_autoptr(libxlDriverConfig) cfg = libxlDriverConfigGet(driver);
1261     libxl_asyncprogress_how aop_console_how;
1262     libxl_domain_restore_params params;
1263     g_autofree char *config_json = NULL;
1264 
1265     libxl_domain_config_init(&d_config);
1266 
1267     if (libxlBuildDomainConfig(driver->reservedGraphicsPorts, vm->def,
1268                                cfg, &d_config) < 0)
1269         goto cleanup;
1270 
1271     if (cfg->autoballoon && libxlDomainFreeMem(cfg->ctx, &d_config) < 0)
1272         goto cleanup;
1273 
1274     /* now that we know it is about to start call the hook if present */
1275     if (libxlDomainHookRun(driver, vm->def, 0,
1276                            VIR_HOOK_LIBXL_OP_START,
1277                            VIR_HOOK_SUBOP_BEGIN, NULL) < 0)
1278         goto cleanup;
1279 
1280     if (priv->hookRun) {
1281         char uuidstr[VIR_UUID_STRING_BUFLEN];
1282         virUUIDFormat(vm->def->uuid, uuidstr);
1283 
1284         VIR_WARN("Domain id='%d' name='%s' uuid='%s' is tainted: hook",
1285                  vm->def->id,
1286                  vm->def->name,
1287                  uuidstr);
1288     }
1289 
1290     /* Unlock virDomainObj while creating the domain */
1291     virObjectUnlock(vm);
1292 
1293     aop_console_how.for_callback = vm;
1294     aop_console_how.callback = libxlConsoleCallback;
1295     if (restore_fd < 0) {
1296         libxlret = libxl_domain_create_new(cfg->ctx, &d_config,
1297                                       &domid, NULL, &aop_console_how);
1298     } else {
1299         libxl_domain_restore_params_init(&params);
1300         params.stream_version = restore_ver;
1301         libxlret = libxlDomainCreateRestoreWrapper(cfg->ctx, &d_config, &domid,
1302                                               restore_fd, &params,
1303                                           &aop_console_how);
1304         libxl_domain_restore_params_dispose(&params);
1305     }
1306     virObjectLock(vm);
1307 
1308     if (libxlret) {
1309         if (restore_fd < 0)
1310             virReportError(VIR_ERR_INTERNAL_ERROR,
1311                            _("libxenlight failed to create new domain '%s'"),
1312                            d_config.c_info.name);
1313         else
1314             virReportError(VIR_ERR_INTERNAL_ERROR,
1315                            _("libxenlight failed to restore domain '%s'"),
1316                            d_config.c_info.name);
1317         goto cleanup;
1318     }
1319 
1320     /*
1321      * The domain has been successfully created with libxl, so it should
1322      * be cleaned up if there are any subsequent failures.
1323      */
1324     vm->def->id = domid;
1325     config_json = libxl_domain_config_to_json(cfg->ctx, &d_config);
1326 
1327     libxlLoggerOpenFile(cfg->logger, domid, vm->def->name, config_json);
1328 
1329     if (virDomainLockProcessResume(driver->lockManager,
1330                                   "xen:///system",
1331                                   vm,
1332                                   priv->lockState) < 0)
1333         goto destroy_dom;
1334     VIR_FREE(priv->lockState);
1335     priv->lockProcessRunning = true;
1336 
1337     /* Always enable domain death events */
1338     if (libxl_evenable_domain_death(cfg->ctx, vm->def->id, 0, &priv->deathW))
1339         goto destroy_dom;
1340 
1341     libxlDomainCreateIfaceNames(vm->def, &d_config);
1342     libxlDomainUpdateDiskParams(vm->def, cfg->ctx);
1343 
1344     if (vm->def->nchannels > 0)
1345         libxlDomainCreateChannelPTY(vm->def, cfg->ctx);
1346 
1347     if ((dom_xml = virDomainDefFormat(vm->def, driver->xmlopt, 0)) == NULL)
1348         goto destroy_dom;
1349 
1350     if (libxl_userdata_store(cfg->ctx, domid, "libvirt-xml",
1351                              (uint8_t *)dom_xml, strlen(dom_xml) + 1)) {
1352         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1353                        _("libxenlight failed to store userdata"));
1354         goto destroy_dom;
1355     }
1356 
1357     if (!start_paused) {
1358         libxlDomainUnpauseWrapper(cfg->ctx, domid);
1359         virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_BOOTED);
1360     } else {
1361         virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
1362     }
1363 
1364     if (virDomainObjSave(vm, driver->xmlopt, cfg->stateDir) < 0)
1365         goto destroy_dom;
1366 
1367     /* finally we can call the 'started' hook script if any */
1368     if (libxlDomainHookRun(driver, vm->def, 0,
1369                            VIR_HOOK_LIBXL_OP_STARTED,
1370                            VIR_HOOK_SUBOP_BEGIN, NULL) < 0)
1371         goto destroy_dom;
1372 
1373     ret = 0;
1374     goto cleanup;
1375 
1376  destroy_dom:
1377     libxlDomainDestroyInternal(driver, vm);
1378     vm->def->id = -1;
1379     virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, VIR_DOMAIN_SHUTOFF_FAILED);
1380 
1381  cleanup:
1382     libxl_domain_config_dispose(&d_config);
1383     return ret;
1384 }
1385 
1386 /*
1387  * Start a domain through libxenlight.
1388  *
1389  * virDomainObj must be locked and a job acquired on invocation
1390  */
1391 static int
libxlDomainStart(libxlDriverPrivate * driver,virDomainObj * vm,bool start_paused,int restore_fd,uint32_t restore_ver)1392 libxlDomainStart(libxlDriverPrivate *driver,
1393                  virDomainObj *vm,
1394                  bool start_paused,
1395                  int restore_fd,
1396                  uint32_t restore_ver)
1397 {
1398     virObjectEvent *event = NULL;
1399 
1400     if (libxlDomainStartPrepare(driver, vm) < 0)
1401         return -1;
1402 
1403     if (libxlDomainStartPerform(driver, vm, start_paused,
1404                                 restore_fd, restore_ver) < 0) {
1405         libxlDomainCleanup(driver, vm);
1406         return -1;
1407     }
1408 
1409     if (g_atomic_int_add(&driver->nactive, 1) == 0 && driver->inhibitCallback)
1410         driver->inhibitCallback(true, driver->inhibitOpaque);
1411 
1412     event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STARTED,
1413                                               restore_fd < 0 ?
1414                                               VIR_DOMAIN_EVENT_STARTED_BOOTED :
1415                                               VIR_DOMAIN_EVENT_STARTED_RESTORED);
1416     virObjectEventStateQueue(driver->domainEventState, event);
1417 
1418     return 0;
1419 }
1420 
1421 int
libxlDomainStartNew(libxlDriverPrivate * driver,virDomainObj * vm,bool start_paused)1422 libxlDomainStartNew(libxlDriverPrivate *driver,
1423             virDomainObj *vm,
1424             bool start_paused)
1425 {
1426     g_autofree char *managed_save_path = NULL;
1427     int restore_fd = -1;
1428     virDomainDef *def = NULL;
1429     libxlSavefileHeader hdr;
1430     uint32_t restore_ver = LIBXL_SAVE_VERSION;
1431     int ret = -1;
1432 
1433     /* If there is a managed saved state restore it instead of starting
1434      * from scratch. The old state is removed once the restoring succeeded. */
1435     managed_save_path = libxlDomainManagedSavePath(driver, vm);
1436     if (managed_save_path == NULL)
1437         return -1;
1438 
1439     if (virFileExists(managed_save_path)) {
1440         restore_fd = libxlDomainSaveImageOpen(driver, managed_save_path,
1441                                               &def, &hdr);
1442         if (restore_fd < 0)
1443             goto cleanup;
1444 
1445         restore_ver = hdr.version;
1446 
1447         if (STRNEQ(vm->def->name, def->name) ||
1448             memcmp(vm->def->uuid, def->uuid, VIR_UUID_BUFLEN)) {
1449             char vm_uuidstr[VIR_UUID_STRING_BUFLEN];
1450             char def_uuidstr[VIR_UUID_STRING_BUFLEN];
1451             virUUIDFormat(vm->def->uuid, vm_uuidstr);
1452             virUUIDFormat(def->uuid, def_uuidstr);
1453             virReportError(VIR_ERR_OPERATION_FAILED,
1454                            _("cannot restore domain '%s' uuid %s from a file which belongs to domain '%s' uuid %s"),
1455                            vm->def->name, vm_uuidstr, def->name, def_uuidstr);
1456             goto cleanup;
1457         }
1458 
1459         virDomainObjAssignDef(vm, &def, true, NULL);
1460 
1461         if (unlink(managed_save_path) < 0)
1462             VIR_WARN("Failed to remove the managed state %s",
1463                      managed_save_path);
1464 
1465         vm->hasManagedSave = false;
1466     }
1467 
1468     ret = libxlDomainStart(driver, vm, start_paused, restore_fd, restore_ver);
1469 
1470  cleanup:
1471     virDomainDefFree(def);
1472     VIR_FORCE_CLOSE(restore_fd);
1473     return ret;
1474 }
1475 
1476 int
libxlDomainStartRestore(libxlDriverPrivate * driver,virDomainObj * vm,bool start_paused,int restore_fd,uint32_t restore_ver)1477 libxlDomainStartRestore(libxlDriverPrivate *driver,
1478                         virDomainObj *vm,
1479                         bool start_paused,
1480                         int restore_fd,
1481                         uint32_t restore_ver)
1482 {
1483     return libxlDomainStart(driver, vm, start_paused,
1484                             restore_fd, restore_ver);
1485 }
1486 
1487 bool
libxlDomainDefCheckABIStability(libxlDriverPrivate * driver,virDomainDef * src,virDomainDef * dst)1488 libxlDomainDefCheckABIStability(libxlDriverPrivate *driver,
1489                                 virDomainDef *src,
1490                                 virDomainDef *dst)
1491 {
1492     virDomainDef *migratableDefSrc = NULL;
1493     virDomainDef *migratableDefDst = NULL;
1494     bool ret = false;
1495 
1496     if (!(migratableDefSrc = virDomainDefCopy(src, driver->xmlopt, NULL, true)) ||
1497         !(migratableDefDst = virDomainDefCopy(dst, driver->xmlopt, NULL, true)))
1498         goto cleanup;
1499 
1500     ret = virDomainDefCheckABIStability(migratableDefSrc,
1501                                         migratableDefDst,
1502                                         driver->xmlopt);
1503 
1504  cleanup:
1505     virDomainDefFree(migratableDefSrc);
1506     virDomainDefFree(migratableDefDst);
1507     return ret;
1508 }
1509 
1510 
1511 static void
libxlDomainDefNamespaceFree(void * nsdata)1512 libxlDomainDefNamespaceFree(void *nsdata)
1513 {
1514     libxlDomainXmlNsDef *def = nsdata;
1515 
1516     if (!def)
1517         return;
1518 
1519     g_strfreev(def->args);
1520     g_free(def);
1521 }
1522 
1523 
1524 static int
libxlDomainDefNamespaceParse(xmlXPathContextPtr ctxt,void ** data)1525 libxlDomainDefNamespaceParse(xmlXPathContextPtr ctxt,
1526                              void **data)
1527 {
1528     libxlDomainXmlNsDef *nsdata = NULL;
1529     g_autofree xmlNodePtr *nodes = NULL;
1530     ssize_t nnodes;
1531     size_t i;
1532     int ret = -1;
1533 
1534     if ((nnodes = virXPathNodeSet("./xen:commandline/xen:arg", ctxt, &nodes)) < 0)
1535         return -1;
1536 
1537     if (nnodes == 0)
1538         return 0;
1539 
1540     nsdata = g_new0(libxlDomainXmlNsDef, 1);
1541     nsdata->args = g_new0(char *, nnodes + 1);
1542 
1543     for (i = 0; i < nnodes; i++) {
1544         if (!(nsdata->args[nsdata->num_args++] = virXMLPropString(nodes[i], "value"))) {
1545             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1546                            _("No device model command-line argument specified"));
1547             goto cleanup;
1548         }
1549     }
1550 
1551     *data = g_steal_pointer(&nsdata);
1552     ret = 0;
1553 
1554  cleanup:
1555     libxlDomainDefNamespaceFree(nsdata);
1556     return ret;
1557 }
1558 
1559 
1560 static int
libxlDomainDefNamespaceFormatXML(virBuffer * buf,void * nsdata)1561 libxlDomainDefNamespaceFormatXML(virBuffer *buf,
1562                                  void *nsdata)
1563 {
1564     libxlDomainXmlNsDef *cmd = nsdata;
1565     size_t i;
1566 
1567     if (!cmd->num_args)
1568         return 0;
1569 
1570     virBufferAddLit(buf, "<xen:commandline>\n");
1571     virBufferAdjustIndent(buf, 2);
1572 
1573     for (i = 0; i < cmd->num_args; i++)
1574         virBufferEscapeString(buf, "<xen:arg value='%s'/>\n",
1575                               cmd->args[i]);
1576 
1577     virBufferAdjustIndent(buf, -2);
1578     virBufferAddLit(buf, "</xen:commandline>\n");
1579 
1580     return 0;
1581 }
1582 
1583 
1584 virXMLNamespace libxlDriverDomainXMLNamespace = {
1585     .parse = libxlDomainDefNamespaceParse,
1586     .free = libxlDomainDefNamespaceFree,
1587     .format = libxlDomainDefNamespaceFormatXML,
1588     .prefix = "xen",
1589     .uri = "http://libvirt.org/schemas/domain/xen/1.0",
1590 };
1591