1 /*
2  * libxl_conf.c: libxl configuration management
3  *
4  * Copyright (C) 2012-2014, 2016 Red Hat, Inc.
5  * Copyright (c) 2011-2013 SUSE LINUX Products GmbH, Nuernberg, Germany.
6  * Copyright (C) 2011 Univention GmbH.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library.  If not, see
20  * <http://www.gnu.org/licenses/>.
21  */
22 
23 #include <config.h>
24 
25 #include <libxl.h>
26 #include <sys/types.h>
27 
28 #include "internal.h"
29 #include "virlog.h"
30 #include "virerror.h"
31 #include "datatypes.h"
32 #include "virconf.h"
33 #include "virfile.h"
34 #include "viridentity.h"
35 #include "virstring.h"
36 #include "viralloc.h"
37 #include "viruuid.h"
38 #include "vircommand.h"
39 #include "virsocketaddr.h"
40 #include "libxl_api_wrapper.h"
41 #include "libxl_domain.h"
42 #include "libxl_conf.h"
43 #include "libxl_utils.h"
44 #include "virstoragefile.h"
45 #include "virsecret.h"
46 #include "cpu/cpu.h"
47 #include "xen_common.h"
48 #include "xen_xl.h"
49 #include "virnetdevvportprofile.h"
50 #include "virenum.h"
51 #include "virsecureerase.h"
52 
53 #define VIR_FROM_THIS VIR_FROM_LIBXL
54 
55 VIR_LOG_INIT("libxl.libxl_conf");
56 
57 
58 static virClass *libxlDriverConfigClass;
59 static void libxlDriverConfigDispose(void *obj);
60 
libxlConfigOnceInit(void)61 static int libxlConfigOnceInit(void)
62 {
63     if (!VIR_CLASS_NEW(libxlDriverConfig, virClassForObject()))
64         return -1;
65 
66     return 0;
67 }
68 
69 VIR_ONCE_GLOBAL_INIT(libxlConfig);
70 
71 static void
libxlDriverConfigDispose(void * obj)72 libxlDriverConfigDispose(void *obj)
73 {
74     libxlDriverConfig *cfg = obj;
75 
76     virObjectUnref(cfg->caps);
77     libxl_ctx_free(cfg->ctx);
78     if (cfg->logger)
79         libxlLoggerFree(cfg->logger);
80 
81     g_free(cfg->configBaseDir);
82     g_free(cfg->configDir);
83     g_free(cfg->autostartDir);
84     g_free(cfg->logDir);
85     g_free(cfg->stateDir);
86     g_free(cfg->libDir);
87     g_free(cfg->saveDir);
88     g_free(cfg->autoDumpDir);
89     g_free(cfg->lockManagerName);
90     g_free(cfg->channelDir);
91     virFirmwareFreeList(cfg->firmwares, cfg->nfirmwares);
92 }
93 
94 
95 static libxl_action_on_shutdown
libxlActionFromVirLifecycle(virDomainLifecycleAction action)96 libxlActionFromVirLifecycle(virDomainLifecycleAction action)
97 {
98     switch (action) {
99     case VIR_DOMAIN_LIFECYCLE_ACTION_DESTROY:
100         return LIBXL_ACTION_ON_SHUTDOWN_DESTROY;
101 
102     case VIR_DOMAIN_LIFECYCLE_ACTION_RESTART:
103         return LIBXL_ACTION_ON_SHUTDOWN_RESTART;
104 
105     case VIR_DOMAIN_LIFECYCLE_ACTION_RESTART_RENAME:
106         return LIBXL_ACTION_ON_SHUTDOWN_RESTART_RENAME;
107 
108     case VIR_DOMAIN_LIFECYCLE_ACTION_PRESERVE:
109         return LIBXL_ACTION_ON_SHUTDOWN_PRESERVE;
110 
111     case VIR_DOMAIN_LIFECYCLE_ACTION_COREDUMP_DESTROY:
112         return LIBXL_ACTION_ON_SHUTDOWN_COREDUMP_DESTROY;
113 
114     case VIR_DOMAIN_LIFECYCLE_ACTION_COREDUMP_RESTART:
115         return LIBXL_ACTION_ON_SHUTDOWN_COREDUMP_RESTART;
116 
117     case VIR_DOMAIN_LIFECYCLE_ACTION_LAST:
118         break;
119     }
120 
121     return 0;
122 }
123 
124 
125 static int
libxlMakeDomCreateInfo(libxl_ctx * ctx,virDomainDef * def,libxl_domain_create_info * c_info)126 libxlMakeDomCreateInfo(libxl_ctx *ctx,
127                        virDomainDef *def,
128                        libxl_domain_create_info *c_info)
129 {
130     char uuidstr[VIR_UUID_STRING_BUFLEN];
131 
132     if (def->os.type == VIR_DOMAIN_OSTYPE_HVM ||
133         def->os.type == VIR_DOMAIN_OSTYPE_XENPVH) {
134 #ifdef WITH_XEN_PVH
135         c_info->type = def->os.type == VIR_DOMAIN_OSTYPE_HVM ?
136             LIBXL_DOMAIN_TYPE_HVM : LIBXL_DOMAIN_TYPE_PVH;
137 #else
138         if (def->os.type == VIR_DOMAIN_OSTYPE_XENPVH) {
139             virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
140                     _("PVH guest os type not supported"));
141             return -1;
142         }
143         c_info->type = LIBXL_DOMAIN_TYPE_HVM;
144 #endif
145         switch ((virTristateSwitch) def->features[VIR_DOMAIN_FEATURE_HAP]) {
146         case VIR_TRISTATE_SWITCH_OFF:
147             libxl_defbool_set(&c_info->hap, false);
148             break;
149 
150         case VIR_TRISTATE_SWITCH_ON:
151             libxl_defbool_set(&c_info->hap, true);
152             break;
153 
154         case VIR_TRISTATE_SWITCH_ABSENT:
155         case VIR_TRISTATE_SWITCH_LAST:
156             break;
157         }
158     } else {
159         c_info->type = LIBXL_DOMAIN_TYPE_PV;
160     }
161 
162 #ifdef LIBXL_HAVE_CREATEINFO_PASSTHROUGH
163     if (def->features[VIR_DOMAIN_FEATURE_XEN] == VIR_TRISTATE_SWITCH_ON) {
164         switch ((virTristateSwitch) def->xen_features[VIR_DOMAIN_XEN_PASSTHROUGH]) {
165         case VIR_TRISTATE_SWITCH_ON:
166             if (def->xen_passthrough_mode == VIR_DOMAIN_XEN_PASSTHROUGH_MODE_SYNC_PT)
167                 c_info->passthrough = LIBXL_PASSTHROUGH_SYNC_PT;
168             else if (def->xen_passthrough_mode == VIR_DOMAIN_XEN_PASSTHROUGH_MODE_SHARE_PT)
169                 c_info->passthrough = LIBXL_PASSTHROUGH_SHARE_PT;
170             else
171                 c_info->passthrough = LIBXL_PASSTHROUGH_ENABLED;
172             break;
173         case VIR_TRISTATE_SWITCH_OFF:
174             c_info->passthrough = LIBXL_PASSTHROUGH_DISABLED;
175             break;
176         case VIR_TRISTATE_SWITCH_ABSENT:
177         case VIR_TRISTATE_SWITCH_LAST:
178             break;
179         }
180     }
181 #endif
182 
183     c_info->name = g_strdup(def->name);
184 
185     if (def->nseclabels &&
186         def->seclabels[0]->type == VIR_DOMAIN_SECLABEL_STATIC) {
187         if (libxl_flask_context_to_sid(ctx,
188                                        def->seclabels[0]->label,
189                                        strlen(def->seclabels[0]->label),
190                                        &c_info->ssidref)) {
191             virReportError(VIR_ERR_INTERNAL_ERROR,
192                            _("libxenlight failed to resolve security label '%s'"),
193                            def->seclabels[0]->label);
194         }
195     }
196 
197     virUUIDFormat(def->uuid, uuidstr);
198     if (libxl_uuid_from_string(&c_info->uuid, uuidstr)) {
199         virReportError(VIR_ERR_INTERNAL_ERROR,
200                        _("libxenlight failed to parse UUID '%s'"), uuidstr);
201         goto error;
202     }
203 
204     return 0;
205 
206  error:
207     libxl_domain_create_info_dispose(c_info);
208     return -1;
209 }
210 
211 static int
libxlMakeChrdevStr(virDomainChrDef * def,char ** buf)212 libxlMakeChrdevStr(virDomainChrDef *def, char **buf)
213 {
214     virDomainChrSourceDef *srcdef = def->source;
215     const char *type = virDomainChrTypeToString(srcdef->type);
216 
217     if (!type) {
218         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
219                        "%s", _("unknown chrdev type"));
220         return -1;
221     }
222 
223     switch (srcdef->type) {
224     case VIR_DOMAIN_CHR_TYPE_NULL:
225     case VIR_DOMAIN_CHR_TYPE_STDIO:
226     case VIR_DOMAIN_CHR_TYPE_VC:
227     case VIR_DOMAIN_CHR_TYPE_PTY:
228         *buf = g_strdup(type);
229         break;
230 
231     case VIR_DOMAIN_CHR_TYPE_FILE:
232     case VIR_DOMAIN_CHR_TYPE_PIPE:
233         *buf = g_strdup_printf("%s:%s", type, srcdef->data.file.path);
234         break;
235 
236     case VIR_DOMAIN_CHR_TYPE_DEV:
237         *buf = g_strdup(srcdef->data.file.path);
238         break;
239 
240     case VIR_DOMAIN_CHR_TYPE_UDP: {
241         const char *connectHost = srcdef->data.udp.connectHost;
242         const char *bindHost = srcdef->data.udp.bindHost;
243         const char *bindService  = srcdef->data.udp.bindService;
244 
245         if (connectHost == NULL)
246             connectHost = "";
247         if (bindHost == NULL)
248             bindHost = "";
249         if (bindService == NULL)
250             bindService = "0";
251 
252         *buf = g_strdup_printf("udp:%s:%s@%s:%s", connectHost,
253                                srcdef->data.udp.connectService, bindHost, bindService);
254         break;
255     }
256 
257     case VIR_DOMAIN_CHR_TYPE_TCP: {
258         const char *prefix;
259 
260         if (srcdef->data.tcp.protocol == VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET)
261             prefix = "telnet";
262         else
263             prefix = "tcp";
264 
265         *buf = g_strdup_printf("%s:%s:%s%s", prefix, srcdef->data.tcp.host,
266                                srcdef->data.tcp.service,
267                                srcdef->data.tcp.listen ? ",server,nowait" : "");
268         break;
269     }
270 
271     case VIR_DOMAIN_CHR_TYPE_UNIX:
272         *buf = g_strdup_printf("unix:%s%s", srcdef->data.nix.path,
273                                srcdef->data.nix.listen ? ",server,nowait" : "");
274         break;
275 
276     default:
277         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
278                        _("unsupported chardev '%s'"), type);
279         return -1;
280     }
281 
282     return 0;
283 }
284 
285 static int
libxlSetVcpuAffinities(virDomainDef * def,libxl_ctx * ctx,libxl_domain_build_info * b_info)286 libxlSetVcpuAffinities(virDomainDef *def,
287                        libxl_ctx *ctx,
288                        libxl_domain_build_info *b_info)
289 {
290     libxl_bitmap *vcpu_affinity_array;
291     unsigned int vcpuid;
292     unsigned int vcpu_idx = 0;
293     virDomainVcpuDef *vcpu;
294     bool has_vcpu_pin = false;
295 
296     /* Get highest vcpuid with cpumask */
297     for (vcpuid = 0; vcpuid < b_info->max_vcpus; vcpuid++) {
298         vcpu = virDomainDefGetVcpu(def, vcpuid);
299         if (!vcpu)
300             continue;
301         if (!vcpu->cpumask)
302             continue;
303         vcpu_idx = vcpuid;
304         has_vcpu_pin = true;
305     }
306     /* Nothing to do */
307     if (!has_vcpu_pin)
308         return 0;
309 
310     /* Adjust index */
311     vcpu_idx++;
312 
313     b_info->num_vcpu_hard_affinity = vcpu_idx;
314     /* Will be released by libxl_domain_config_dispose */
315     b_info->vcpu_hard_affinity = g_new0(libxl_bitmap, vcpu_idx);
316     vcpu_affinity_array = b_info->vcpu_hard_affinity;
317 
318     for (vcpuid = 0; vcpuid < vcpu_idx; vcpuid++) {
319         libxl_bitmap *map = &vcpu_affinity_array[vcpuid];
320         libxl_bitmap_init(map);
321         /* libxl owns the bitmap */
322         if (libxl_cpu_bitmap_alloc(ctx, map, 0))
323             return -1;
324         vcpu = virDomainDefGetVcpu(def, vcpuid);
325         /* Apply the given mask, or allow unhandled vcpus to run anywhere */
326         if (vcpu && vcpu->cpumask)
327             virBitmapToDataBuf(vcpu->cpumask, map->map, map->size);
328         else
329             libxl_bitmap_set_any(map);
330     }
331     libxl_defbool_set(&b_info->numa_placement, false);
332     return 0;
333 }
334 
335 static int
libxlMakeDomBuildInfo(virDomainDef * def,libxlDriverConfig * cfg,virCaps * caps,libxl_domain_config * d_config)336 libxlMakeDomBuildInfo(virDomainDef *def,
337                       libxlDriverConfig *cfg,
338                       virCaps *caps,
339                       libxl_domain_config *d_config)
340 {
341     virDomainClockDef clock = def->clock;
342     libxl_ctx *ctx = cfg->ctx;
343     libxl_domain_build_info *b_info = &d_config->b_info;
344     bool hvm = def->os.type == VIR_DOMAIN_OSTYPE_HVM;
345     bool pvh = def->os.type == VIR_DOMAIN_OSTYPE_XENPVH;
346     size_t i;
347     size_t nusbdevice = 0;
348 
349     if (hvm) {
350         libxl_domain_build_info_init_type(b_info, LIBXL_DOMAIN_TYPE_HVM);
351     } else if (pvh) {
352 #ifdef WITH_XEN_PVH
353         libxl_domain_build_info_init_type(b_info, LIBXL_DOMAIN_TYPE_PVH);
354 #else
355         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
356                 _("PVH guest os type not supported"));
357         return -1;
358 #endif
359     } else {
360         libxl_domain_build_info_init_type(b_info, LIBXL_DOMAIN_TYPE_PV);
361     }
362 
363     b_info->max_vcpus = virDomainDefGetVcpusMax(def);
364     if (libxl_cpu_bitmap_alloc(ctx, &b_info->avail_vcpus, b_info->max_vcpus))
365         return -1;
366     libxl_bitmap_set_none(&b_info->avail_vcpus);
367     for (i = 0; i < virDomainDefGetVcpus(def); i++)
368         libxl_bitmap_set((&b_info->avail_vcpus), i);
369 
370     if (libxlSetVcpuAffinities(def, ctx, b_info))
371         return -1;
372 
373     switch ((virDomainClockOffsetType) clock.offset) {
374     case VIR_DOMAIN_CLOCK_OFFSET_VARIABLE:
375         if (clock.data.variable.basis == VIR_DOMAIN_CLOCK_BASIS_LOCALTIME)
376             libxl_defbool_set(&b_info->localtime, true);
377         b_info->rtc_timeoffset = clock.data.variable.adjustment;
378         break;
379 
380     case VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME:
381         libxl_defbool_set(&b_info->localtime, true);
382         break;
383 
384     /* Nothing to do since UTC is the default in libxl */
385     case VIR_DOMAIN_CLOCK_OFFSET_UTC:
386         break;
387 
388     case VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE:
389         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
390                        _("unsupported clock offset '%s'"),
391                        virDomainClockOffsetTypeToString(clock.offset));
392         return -1;
393 
394     case VIR_DOMAIN_CLOCK_OFFSET_LAST:
395     default:
396         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
397                        _("unexpected clock offset '%d'"), clock.offset);
398         return -1;
399     }
400 
401     for (i = 0; i < clock.ntimers; i++) {
402         switch ((virDomainTimerNameType) clock.timers[i]->name) {
403         case VIR_DOMAIN_TIMER_NAME_TSC:
404             switch (clock.timers[i]->mode) {
405             case VIR_DOMAIN_TIMER_MODE_NATIVE:
406                 b_info->tsc_mode = LIBXL_TSC_MODE_NATIVE;
407                 break;
408             case VIR_DOMAIN_TIMER_MODE_PARAVIRT:
409                 b_info->tsc_mode = LIBXL_TSC_MODE_NATIVE_PARAVIRT;
410                 break;
411             case VIR_DOMAIN_TIMER_MODE_EMULATE:
412                 b_info->tsc_mode = LIBXL_TSC_MODE_ALWAYS_EMULATE;
413                 break;
414             default:
415                 b_info->tsc_mode = LIBXL_TSC_MODE_DEFAULT;
416             }
417             break;
418 
419         case VIR_DOMAIN_TIMER_NAME_HPET:
420             if (!hvm) {
421                 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
422                                _("unsupported timer type (name) '%s'"),
423                                virDomainTimerNameTypeToString(clock.timers[i]->name));
424                 return -1;
425             }
426             if (clock.timers[i]->present == 1)
427                 libxl_defbool_set(&b_info->u.hvm.hpet, 1);
428             break;
429 
430         case VIR_DOMAIN_TIMER_NAME_PLATFORM:
431         case VIR_DOMAIN_TIMER_NAME_KVMCLOCK:
432         case VIR_DOMAIN_TIMER_NAME_HYPERVCLOCK:
433         case VIR_DOMAIN_TIMER_NAME_RTC:
434         case VIR_DOMAIN_TIMER_NAME_PIT:
435         case VIR_DOMAIN_TIMER_NAME_ARMVTIMER:
436             virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
437                            _("unsupported timer type (name) '%s'"),
438                            virDomainTimerNameTypeToString(clock.timers[i]->name));
439             return -1;
440 
441         case VIR_DOMAIN_TIMER_NAME_LAST:
442             break;
443         }
444     }
445 
446     if (def->cputune.sharesSpecified)
447         b_info->sched_params.weight = def->cputune.shares;
448 
449     /* Xen requires the memory sizes to be rounded to 1MiB increments */
450     virDomainDefSetMemoryTotal(def,
451                                VIR_ROUND_UP(virDomainDefGetMemoryInitial(def), 1024));
452     def->mem.cur_balloon = VIR_ROUND_UP(def->mem.cur_balloon, 1024);
453     b_info->max_memkb = virDomainDefGetMemoryInitial(def);
454     b_info->target_memkb = def->mem.cur_balloon;
455 
456     for (i = 0; i < def->ncontrollers; i++) {
457         if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_XENBUS) {
458             if (def->controllers[i]->opts.xenbusopts.maxEventChannels > 0)
459                 b_info->event_channels = def->controllers[i]->opts.xenbusopts.maxEventChannels;
460 
461 #ifdef LIBXL_HAVE_BUILDINFO_GRANT_LIMITS
462             if (def->controllers[i]->opts.xenbusopts.maxGrantFrames > 0)
463                 b_info->max_grant_frames = def->controllers[i]->opts.xenbusopts.maxGrantFrames;
464 #endif
465         }
466     }
467 
468     if (hvm || pvh) {
469         if (caps &&
470             def->cpu && def->cpu->mode == (VIR_CPU_MODE_HOST_PASSTHROUGH)) {
471             bool hasHwVirt = false;
472             bool svm = false, vmx = false;
473             char xlCPU[32];
474 
475             /* enable nested HVM only if global nested_hvm option enable it and
476              * host support it */
477             if (ARCH_IS_X86(def->os.arch)) {
478                 vmx = virCPUCheckFeature(caps->host.arch, caps->host.cpu, "vmx");
479                 svm = virCPUCheckFeature(caps->host.arch, caps->host.cpu, "svm");
480                 hasHwVirt = cfg->nested_hvm && (vmx | svm);
481             }
482 
483             if (def->cpu->nfeatures) {
484                 for (i = 0; i < def->cpu->nfeatures; i++) {
485 
486                     switch (def->cpu->features[i].policy) {
487 
488                         case VIR_CPU_FEATURE_DISABLE:
489                         case VIR_CPU_FEATURE_FORBID:
490                             if ((vmx && STREQ(def->cpu->features[i].name, "vmx")) ||
491                                 (svm && STREQ(def->cpu->features[i].name, "svm"))) {
492                                 hasHwVirt = false;
493                                 continue;
494                             }
495 
496                             g_snprintf(xlCPU,
497                                        sizeof(xlCPU),
498                                        "%s=0",
499                                        xenTranslateCPUFeature(
500                                            def->cpu->features[i].name,
501                                            false));
502                             if (libxl_cpuid_parse_config(&b_info->cpuid, xlCPU)) {
503                                 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
504                                         _("unsupported cpu feature '%s'"),
505                                         def->cpu->features[i].name);
506                                 return -1;
507                             }
508                             break;
509 
510                         case VIR_CPU_FEATURE_FORCE:
511                         case VIR_CPU_FEATURE_REQUIRE:
512                             if ((vmx && STREQ(def->cpu->features[i].name, "vmx")) ||
513                                 (svm && STREQ(def->cpu->features[i].name, "svm"))) {
514                                 hasHwVirt = true;
515                                 continue;
516                             }
517 
518                             g_snprintf(xlCPU,
519                                        sizeof(xlCPU),
520                                        "%s=1",
521                                        xenTranslateCPUFeature(
522                                            def->cpu->features[i].name, false));
523                             if (libxl_cpuid_parse_config(&b_info->cpuid, xlCPU)) {
524                                 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
525                                         _("unsupported cpu feature '%s'"),
526                                         def->cpu->features[i].name);
527                                 return -1;
528                             }
529                             break;
530                         case VIR_CPU_FEATURE_OPTIONAL:
531                         case VIR_CPU_FEATURE_LAST:
532                             break;
533                     }
534                 }
535             }
536 #ifdef LIBXL_HAVE_BUILDINFO_NESTED_HVM
537             libxl_defbool_set(&b_info->nested_hvm, hasHwVirt);
538 #else
539             if (hvm) {
540                 libxl_defbool_set(&b_info->u.hvm.nested_hvm, hasHwVirt);
541             } else {
542                 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
543                         _("unsupported nested HVM setting for %s machine on this Xen version"),
544                         def->os.machine);
545                 return -1;
546             }
547 #endif
548         }
549 
550         if (def->cpu && def->cpu->mode == VIR_CPU_MODE_CUSTOM) {
551             VIR_WARN("Ignoring CPU with mode=custom, update your config to "
552                      "mode=host-passthrough to avoid risk of changed guest "
553                      "semantics when mode=custom is supported in the future");
554         }
555     }
556 
557     if (hvm) {
558         char bootorder[VIR_DOMAIN_BOOT_LAST + 1];
559 
560         libxl_defbool_set(&b_info->u.hvm.pae,
561                           def->features[VIR_DOMAIN_FEATURE_PAE] ==
562                           VIR_TRISTATE_SWITCH_ON);
563 #ifdef LIBXL_HAVE_BUILDINFO_APIC
564         libxl_defbool_set(&b_info->apic,
565                           def->features[VIR_DOMAIN_FEATURE_APIC] ==
566                           VIR_TRISTATE_SWITCH_ON);
567         /*
568          * Strictly speaking b_info->acpi was introduced earlier (Xen 4.8), but
569          * there is no separate #define in libxl.h.
570          */
571         libxl_defbool_set(&b_info->acpi,
572                           def->features[VIR_DOMAIN_FEATURE_ACPI] ==
573                           VIR_TRISTATE_SWITCH_ON);
574 #else
575         libxl_defbool_set(&b_info->u.hvm.apic,
576                           def->features[VIR_DOMAIN_FEATURE_APIC] ==
577                           VIR_TRISTATE_SWITCH_ON);
578         libxl_defbool_set(&b_info->u.hvm.acpi,
579                           def->features[VIR_DOMAIN_FEATURE_ACPI] ==
580                           VIR_TRISTATE_SWITCH_ON);
581 #endif
582 
583         /* copy SLIC table path to acpi_firmware */
584         if (def->os.slic_table)
585             b_info->u.hvm.acpi_firmware = g_strdup(def->os.slic_table);
586 
587         if (def->nsounds > 0) {
588             /*
589              * Use first sound device.  man xl.cfg(5) describes soundhw as
590              * a single device.  From the man page: soundhw=DEVICE
591              */
592             virDomainSoundDef *snd = def->sounds[0];
593 
594             b_info->u.hvm.soundhw = g_strdup(virDomainSoundModelTypeToString(snd->model));
595         }
596 
597         for (i = 0; i < def->os.nBootDevs; i++) {
598             switch (def->os.bootDevs[i]) {
599                 case VIR_DOMAIN_BOOT_FLOPPY:
600                     bootorder[i] = 'a';
601                     break;
602                 default:
603                 case VIR_DOMAIN_BOOT_DISK:
604                     bootorder[i] = 'c';
605                     break;
606                 case VIR_DOMAIN_BOOT_CDROM:
607                     bootorder[i] = 'd';
608                     break;
609                 case VIR_DOMAIN_BOOT_NET:
610                     bootorder[i] = 'n';
611                     break;
612             }
613         }
614         if (def->os.nBootDevs == 0) {
615             bootorder[0] = 'c';
616             bootorder[1] = '\0';
617         } else {
618             bootorder[def->os.nBootDevs] = '\0';
619         }
620         b_info->u.hvm.boot = g_strdup(bootorder);
621 
622         b_info->cmdline = g_strdup(def->os.cmdline);
623         b_info->kernel = g_strdup(def->os.kernel);
624         b_info->ramdisk = g_strdup(def->os.initrd);
625 
626         /*
627          * Currently libxl only allows specifying the type of BIOS.
628          * If automatic firmware selection is enabled or the loader
629          * type is PFLASH, we assume OVMF and set libxl_bios_type
630          * to LIBXL_BIOS_TYPE_OVMF. The path to the OVMF firmware is
631          * configured when building Xen using '--with-system-ovmf='. If
632          * not specified, LIBXL_FIRMWARE_DIR/ovmf.bin is used. In the
633          * future, Xen will support a user-specified firmware path. See
634          * https://lists.xenproject.org/archives/html/xen-devel/2016-03/msg01628.html
635          */
636         if (def->os.firmware == VIR_DOMAIN_OS_DEF_FIRMWARE_EFI) {
637             if (def->os.loader == NULL)
638                 def->os.loader = g_new0(virDomainLoaderDef, 1);
639             if (def->os.loader->path == NULL)
640                 def->os.loader->path = g_strdup(cfg->firmwares[0]->name);
641             if (def->os.loader->type == VIR_DOMAIN_LOADER_TYPE_NONE)
642                 def->os.loader->type = VIR_DOMAIN_LOADER_TYPE_PFLASH;
643             if (def->os.loader->readonly == VIR_TRISTATE_BOOL_ABSENT)
644                 def->os.loader->readonly = VIR_TRISTATE_BOOL_YES;
645             b_info->u.hvm.bios = LIBXL_BIOS_TYPE_OVMF;
646             def->os.firmware = VIR_DOMAIN_OS_DEF_FIRMWARE_NONE;
647         } else if (virDomainDefHasOldStyleUEFI(def)) {
648             b_info->u.hvm.bios = LIBXL_BIOS_TYPE_OVMF;
649         }
650 
651         if (def->emulator) {
652             if (!virFileExists(def->emulator)) {
653                 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
654                                _("emulator '%s' not found"),
655                                def->emulator);
656                 return -1;
657             }
658 
659             if (!virFileIsExecutable(def->emulator)) {
660                 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
661                                _("emulator '%s' is not executable"),
662                                def->emulator);
663                 return -1;
664             }
665 
666             VIR_FREE(b_info->device_model);
667             b_info->device_model = g_strdup(def->emulator);
668 
669             b_info->device_model_version = libxlDomainGetEmulatorType(def);
670         }
671 
672         if (def->nserials) {
673             if (def->nserials == 1) {
674                 if (libxlMakeChrdevStr(def->serials[0], &b_info->u.hvm.serial) <
675                     0)
676                     return -1;
677             } else {
678                 b_info->u.hvm.serial_list = *g_new0(libxl_string_list, def->nserials + 1);
679                 for (i = 0; i < def->nserials; i++) {
680                     if (libxlMakeChrdevStr(def->serials[i],
681                                            &b_info->u.hvm.serial_list[i]) < 0)
682                     {
683                         libxl_string_list_dispose(&b_info->u.hvm.serial_list);
684                         return -1;
685                     }
686                 }
687                 b_info->u.hvm.serial_list[i] = NULL;
688             }
689         }
690 
691         if (def->nparallels) {
692             virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
693                            "%s",
694                            _("Parallel devices are not supported by libxl"));
695             return -1;
696         }
697 
698         /* Disable VNC and SDL until explicitly enabled */
699         libxl_defbool_set(&b_info->u.hvm.vnc.enable, 0);
700         libxl_defbool_set(&b_info->u.hvm.sdl.enable, 0);
701 
702         for (i = 0; i < def->ninputs; i++) {
703             char **usbdevice;
704 
705             if (def->inputs[i]->bus != VIR_DOMAIN_INPUT_BUS_USB)
706                 continue;
707 
708             VIR_EXPAND_N(b_info->u.hvm.usbdevice_list, nusbdevice, 1);
709             usbdevice = &b_info->u.hvm.usbdevice_list[nusbdevice - 1];
710             switch (def->inputs[i]->type) {
711                 case VIR_DOMAIN_INPUT_TYPE_MOUSE:
712                     VIR_FREE(*usbdevice);
713                     *usbdevice = g_strdup("mouse");
714                     break;
715                 case VIR_DOMAIN_INPUT_TYPE_TABLET:
716                     VIR_FREE(*usbdevice);
717                     *usbdevice = g_strdup("tablet");
718                     break;
719                 default:
720                     virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
721                             _("Unknown input device type"));
722                     return -1;
723             }
724         }
725 
726         /* NULL-terminate usbdevice_list */
727         if (nusbdevice > 0)
728             VIR_EXPAND_N(b_info->u.hvm.usbdevice_list, nusbdevice, 1);
729     } else if (pvh) {
730         b_info->cmdline = g_strdup(def->os.cmdline);
731         b_info->kernel = g_strdup(def->os.kernel);
732         b_info->ramdisk = g_strdup(def->os.initrd);
733 #ifdef LIBXL_HAVE_BUILDINFO_BOOTLOADER
734         b_info->bootloader = g_strdup(def->os.bootloader);
735         if (def->os.bootloaderArgs) {
736             if (!(b_info->bootloader_args =
737                   g_strsplit(def->os.bootloaderArgs, " \t\n", 0)))
738                 return -1;
739         }
740 #endif
741     } else {
742         /*
743          * For compatibility with the legacy xen toolstack, default to pygrub
744          * if bootloader is not specified AND direct kernel boot is not specified.
745          */
746         if (def->os.bootloader) {
747             b_info->u.pv.bootloader = g_strdup(def->os.bootloader);
748         } else if (def->os.kernel == NULL) {
749             b_info->u.pv.bootloader = g_strdup(LIBXL_BOOTLOADER_PATH);
750         }
751         if (def->os.bootloaderArgs) {
752             if (!(b_info->u.pv.bootloader_args =
753                   g_strsplit(def->os.bootloaderArgs, " \t\n", 0)))
754                 return -1;
755         }
756         b_info->u.pv.cmdline = g_strdup(def->os.cmdline);
757         if (def->os.kernel) {
758             /* libxl_init_build_info() sets kernel.path = g_strdup("hvmloader") */
759             VIR_FREE(b_info->u.pv.kernel);
760             b_info->u.pv.kernel = g_strdup(def->os.kernel);
761         }
762         b_info->u.pv.ramdisk = g_strdup(def->os.initrd);
763 
764         if (def->features[VIR_DOMAIN_FEATURE_XEN] == VIR_TRISTATE_SWITCH_ON) {
765             switch ((virTristateSwitch) def->xen_features[VIR_DOMAIN_XEN_E820_HOST]) {
766                 case VIR_TRISTATE_SWITCH_ON:
767                     libxl_defbool_set(&b_info->u.pv.e820_host, true);
768                     break;
769                 case VIR_TRISTATE_SWITCH_OFF:
770                     libxl_defbool_set(&b_info->u.pv.e820_host, false);
771                     break;
772                 case VIR_TRISTATE_SWITCH_ABSENT:
773                 case VIR_TRISTATE_SWITCH_LAST:
774                     break;
775             }
776         }
777     }
778 
779     /* only the 'xen' balloon device model is supported */
780     if (def->memballoon) {
781         switch (def->memballoon->model) {
782         case VIR_DOMAIN_MEMBALLOON_MODEL_XEN:
783             break;
784         case VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO:
785         case VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO_TRANSITIONAL:
786         case VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO_NON_TRANSITIONAL:
787             virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
788                            _("unsupported balloon device model '%s'"),
789                            virDomainMemballoonModelTypeToString(def->memballoon->model));
790             return -1;
791         case VIR_DOMAIN_MEMBALLOON_MODEL_NONE:
792             virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
793                            "%s",
794                            _("balloon device cannot be disabled"));
795             return -1;
796         case VIR_DOMAIN_MEMBALLOON_MODEL_LAST:
797         default:
798             virReportEnumRangeError(virDomainMemballoonModel, def->memballoon->model);
799             return -1;
800         }
801     }
802 
803     /* Allow libxl to calculate shadow memory requirements */
804     b_info->shadow_memkb =
805         libxl_get_required_shadow_memory(b_info->max_memkb,
806                                          b_info->max_vcpus);
807 
808     if (def->namespaceData) {
809         libxlDomainXmlNsDef *nsdata = def->namespaceData;
810 
811         if (nsdata->num_args > 0)
812             b_info->extra = g_strdupv(nsdata->args);
813     }
814 
815     return 0;
816 }
817 
818 static int
libxlMakeVnumaList(virDomainDef * def,libxl_ctx * ctx,libxl_domain_config * d_config)819 libxlMakeVnumaList(virDomainDef *def,
820                    libxl_ctx *ctx,
821                    libxl_domain_config *d_config)
822 {
823     int ret = -1;
824     size_t i, j;
825     size_t nr_nodes;
826     size_t num_vnuma;
827     bool simulate = false;
828     virBitmap *bitmap = NULL;
829     virDomainNuma *numa = def->numa;
830     libxl_domain_build_info *b_info = &d_config->b_info;
831     libxl_physinfo physinfo;
832     libxl_vnode_info *vnuma_nodes = NULL;
833 
834     if (!numa)
835         return 0;
836 
837     num_vnuma = virDomainNumaGetNodeCount(numa);
838     if (!num_vnuma)
839         return 0;
840 
841     libxl_physinfo_init(&physinfo);
842     if (libxl_get_physinfo(ctx, &physinfo) < 0) {
843         libxl_physinfo_dispose(&physinfo);
844         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
845                        _("libxl_get_physinfo_info failed"));
846         return -1;
847     }
848     nr_nodes = physinfo.nr_nodes;
849     libxl_physinfo_dispose(&physinfo);
850 
851     if (num_vnuma > nr_nodes) {
852         VIR_WARN("Number of configured numa cells %zu exceeds available physical nodes %zu. All cells will use physical node 0",
853                  num_vnuma, nr_nodes);
854         simulate = true;
855     }
856 
857     /*
858      * allocate the vnuma_nodes for assignment under b_info.
859      */
860     vnuma_nodes = g_new0(libxl_vnode_info, num_vnuma);
861 
862     /*
863      * parse the vnuma vnodes data.
864      */
865     for (i = 0; i < num_vnuma; i++) {
866         int cpu;
867         libxl_bitmap vcpu_bitmap;
868         libxl_vnode_info *p = &vnuma_nodes[i];
869 
870         libxl_vnode_info_init(p);
871 
872         /* pnode */
873         p->pnode = simulate ? 0 : i;
874 
875         /* memory size */
876         p->memkb = virDomainNumaGetNodeMemorySize(numa, i);
877 
878         /* vcpus */
879         bitmap = virDomainNumaGetNodeCpumask(numa, i);
880         if (bitmap == NULL) {
881             virReportError(VIR_ERR_INTERNAL_ERROR,
882                            _("vnuma sibling %zu missing vcpus set"), i);
883             goto cleanup;
884         }
885 
886         if ((cpu = virBitmapNextSetBit(bitmap, -1)) < 0)
887             goto cleanup;
888 
889         libxl_bitmap_init(&vcpu_bitmap);
890         if (libxl_cpu_bitmap_alloc(ctx, &vcpu_bitmap, b_info->max_vcpus))
891             abort();
892 
893         do {
894             libxl_bitmap_set(&vcpu_bitmap, cpu);
895         } while ((cpu = virBitmapNextSetBit(bitmap, cpu)) >= 0);
896 
897         libxl_bitmap_copy_alloc(ctx, &p->vcpus, &vcpu_bitmap);
898         libxl_bitmap_dispose(&vcpu_bitmap);
899 
900         /* vdistances */
901         p->distances = g_new0(uint32_t, num_vnuma);
902         p->num_distances = num_vnuma;
903 
904         for (j = 0; j < num_vnuma; j++)
905             p->distances[j] = virDomainNumaGetNodeDistance(numa, i, j);
906     }
907 
908     b_info->vnuma_nodes = vnuma_nodes;
909     b_info->num_vnuma_nodes = num_vnuma;
910 
911     ret = 0;
912 
913  cleanup:
914     if (ret) {
915         for (i = 0; i < num_vnuma; i++) {
916             libxl_vnode_info *p = &vnuma_nodes[i];
917 
918             VIR_FREE(p->distances);
919         }
920         VIR_FREE(vnuma_nodes);
921     }
922 
923     return ret;
924 }
925 
926 static void
libxlDiskSetDiscard(libxl_device_disk * x_disk,virDomainDiskDiscard discard)927 libxlDiskSetDiscard(libxl_device_disk *x_disk, virDomainDiskDiscard discard)
928 {
929     if (!x_disk->readwrite)
930         return;
931     switch (discard) {
932     case VIR_DOMAIN_DISK_DISCARD_DEFAULT:
933     case VIR_DOMAIN_DISK_DISCARD_LAST:
934         break;
935     case VIR_DOMAIN_DISK_DISCARD_UNMAP:
936         libxl_defbool_set(&x_disk->discard_enable, true);
937         break;
938     case VIR_DOMAIN_DISK_DISCARD_IGNORE:
939         libxl_defbool_set(&x_disk->discard_enable, false);
940         break;
941     }
942 }
943 
944 static char *
libxlMakeNetworkDiskSrcStr(virStorageSource * src,const char * username,const char * secret)945 libxlMakeNetworkDiskSrcStr(virStorageSource *src,
946                            const char *username,
947                            const char *secret)
948 {
949     g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
950     size_t i;
951 
952     switch ((virStorageNetProtocol) src->protocol) {
953     case VIR_STORAGE_NET_PROTOCOL_NBD:
954     case VIR_STORAGE_NET_PROTOCOL_HTTP:
955     case VIR_STORAGE_NET_PROTOCOL_HTTPS:
956     case VIR_STORAGE_NET_PROTOCOL_FTP:
957     case VIR_STORAGE_NET_PROTOCOL_FTPS:
958     case VIR_STORAGE_NET_PROTOCOL_TFTP:
959     case VIR_STORAGE_NET_PROTOCOL_ISCSI:
960     case VIR_STORAGE_NET_PROTOCOL_GLUSTER:
961     case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG:
962     case VIR_STORAGE_NET_PROTOCOL_SSH:
963     case VIR_STORAGE_NET_PROTOCOL_VXHS:
964     case VIR_STORAGE_NET_PROTOCOL_NFS:
965     case VIR_STORAGE_NET_PROTOCOL_LAST:
966     case VIR_STORAGE_NET_PROTOCOL_NONE:
967         virReportError(VIR_ERR_NO_SUPPORT,
968                        _("Unsupported network block protocol '%s'"),
969                        virStorageNetProtocolTypeToString(src->protocol));
970         return NULL;
971 
972     case VIR_STORAGE_NET_PROTOCOL_RBD:
973         if (strchr(src->path, ':')) {
974             virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
975                            _("':' not allowed in RBD source volume name '%s'"),
976                            src->path);
977             return NULL;
978         }
979 
980         virBufferStrcat(&buf, "rbd:", src->volume, "/", src->path, NULL);
981 
982         if (username) {
983             virBufferEscape(&buf, '\\', ":", ":id=%s", username);
984             virBufferEscape(&buf, '\\', ":",
985                             ":key=%s:auth_supported=cephx\\;none",
986                             secret);
987         } else {
988             virBufferAddLit(&buf, ":auth_supported=none");
989         }
990 
991         if (src->nhosts > 0) {
992             virBufferAddLit(&buf, ":mon_host=");
993             for (i = 0; i < src->nhosts; i++) {
994                 if (i)
995                     virBufferAddLit(&buf, "\\;");
996 
997                 /* assume host containing : is ipv6 */
998                 if (strchr(src->hosts[i].name, ':'))
999                     virBufferEscape(&buf, '\\', ":", "[%s]",
1000                                     src->hosts[i].name);
1001                 else
1002                     virBufferAsprintf(&buf, "%s", src->hosts[i].name);
1003 
1004                 if (src->hosts[i].port)
1005                     virBufferAsprintf(&buf, "\\:%u", src->hosts[i].port);
1006             }
1007         }
1008 
1009         if (src->configFile)
1010             virBufferEscape(&buf, '\\', ":", ":conf=%s", src->configFile);
1011 
1012         return virBufferContentAndReset(&buf);
1013     }
1014 
1015     return NULL;
1016 }
1017 
1018 static int
libxlMakeNetworkDiskSrc(virStorageSource * src,char ** srcstr)1019 libxlMakeNetworkDiskSrc(virStorageSource *src, char **srcstr)
1020 {
1021     virConnectPtr conn = NULL;
1022     g_autofree char *base64secret = NULL;
1023     char *username = NULL;
1024     int ret = -1;
1025 
1026     *srcstr = NULL;
1027     if (src->auth && src->protocol == VIR_STORAGE_NET_PROTOCOL_RBD) {
1028         g_autofree uint8_t *secret = NULL;
1029         size_t secretlen = 0;
1030         VIR_IDENTITY_AUTORESTORE virIdentity *oldident = virIdentityElevateCurrent();
1031 
1032         if (!oldident)
1033             goto cleanup;
1034 
1035         username = src->auth->username;
1036         if (!(conn = virConnectOpen("xen:///system")))
1037             goto cleanup;
1038 
1039         if (virSecretGetSecretString(conn, &src->auth->seclookupdef,
1040                                      VIR_SECRET_USAGE_TYPE_CEPH,
1041                                      &secret, &secretlen) < 0)
1042             goto cleanup;
1043 
1044         /* RBD expects an encoded secret */
1045         base64secret = g_base64_encode(secret, secretlen);
1046         virSecureErase(secret, secretlen);
1047     }
1048 
1049     *srcstr = libxlMakeNetworkDiskSrcStr(src, username, base64secret);
1050     virSecureEraseString(base64secret);
1051 
1052     if (!*srcstr)
1053         goto cleanup;
1054 
1055     ret = 0;
1056 
1057  cleanup:
1058     virObjectUnref(conn);
1059     return ret;
1060 }
1061 
1062 int
libxlMakeDisk(virDomainDiskDef * l_disk,libxl_device_disk * x_disk)1063 libxlMakeDisk(virDomainDiskDef *l_disk, libxl_device_disk *x_disk)
1064 {
1065     const char *driver = virDomainDiskGetDriver(l_disk);
1066     int format = virDomainDiskGetFormat(l_disk);
1067     int actual_type = virStorageSourceGetActualType(l_disk->src);
1068 
1069     if (actual_type == VIR_STORAGE_TYPE_NETWORK) {
1070         if (STRNEQ_NULLABLE(driver, "qemu")) {
1071             virReportError(VIR_ERR_OPERATION_INVALID, "%s",
1072                            _("only the 'qemu' driver can be used with network disks"));
1073             return -1;
1074         }
1075         if (libxlMakeNetworkDiskSrc(l_disk->src, &x_disk->pdev_path) < 0)
1076             return -1;
1077     } else {
1078         x_disk->pdev_path = g_strdup(virDomainDiskGetSource(l_disk));
1079     }
1080 
1081     x_disk->vdev = g_strdup(l_disk->dst);
1082 
1083     if (driver) {
1084         if (STREQ(driver, "tap") || STREQ(driver, "tap2")) {
1085             switch (format) {
1086             case VIR_STORAGE_FILE_QCOW:
1087                 x_disk->format = LIBXL_DISK_FORMAT_QCOW;
1088                 x_disk->backend = LIBXL_DISK_BACKEND_QDISK;
1089                 break;
1090             case VIR_STORAGE_FILE_QCOW2:
1091                 x_disk->format = LIBXL_DISK_FORMAT_QCOW2;
1092                 x_disk->backend = LIBXL_DISK_BACKEND_QDISK;
1093                 break;
1094             case VIR_STORAGE_FILE_VHD:
1095                 x_disk->format = LIBXL_DISK_FORMAT_VHD;
1096                 x_disk->backend = LIBXL_DISK_BACKEND_TAP;
1097                 break;
1098             case VIR_STORAGE_FILE_RAW:
1099                 x_disk->format = LIBXL_DISK_FORMAT_RAW;
1100                 x_disk->backend = LIBXL_DISK_BACKEND_TAP;
1101                 break;
1102             case VIR_STORAGE_FILE_QED:
1103                 x_disk->format = LIBXL_DISK_FORMAT_QED;
1104                 x_disk->backend = LIBXL_DISK_BACKEND_QDISK;
1105                 break;
1106             default:
1107                 virReportError(VIR_ERR_INTERNAL_ERROR,
1108                                _("libxenlight does not support disk format %s "
1109                                  "with disk driver %s"),
1110                                virStorageFileFormatTypeToString(format),
1111                                driver);
1112                 return -1;
1113             }
1114         } else if (STREQ(driver, "qemu")) {
1115             x_disk->backend = LIBXL_DISK_BACKEND_QDISK;
1116             switch (format) {
1117             case VIR_STORAGE_FILE_QCOW:
1118                 x_disk->format = LIBXL_DISK_FORMAT_QCOW;
1119                 break;
1120             case VIR_STORAGE_FILE_QCOW2:
1121                 x_disk->format = LIBXL_DISK_FORMAT_QCOW2;
1122                 break;
1123             case VIR_STORAGE_FILE_QED:
1124                 x_disk->format = LIBXL_DISK_FORMAT_QED;
1125                 break;
1126             case VIR_STORAGE_FILE_VHD:
1127                 x_disk->format = LIBXL_DISK_FORMAT_VHD;
1128                 break;
1129             case VIR_STORAGE_FILE_RAW:
1130                 x_disk->format = LIBXL_DISK_FORMAT_RAW;
1131                 break;
1132             default:
1133                 virReportError(VIR_ERR_INTERNAL_ERROR,
1134                                _("libxenlight does not support disk format %s "
1135                                  "with disk driver %s"),
1136                                virStorageFileFormatTypeToString(format),
1137                                driver);
1138                 return -1;
1139             }
1140         } else if (STREQ(driver, "file")) {
1141             if (format != VIR_STORAGE_FILE_RAW) {
1142                 virReportError(VIR_ERR_INTERNAL_ERROR,
1143                                _("libxenlight does not support disk format %s "
1144                                  "with disk driver %s"),
1145                                virStorageFileFormatTypeToString(format),
1146                                driver);
1147                 return -1;
1148             }
1149             x_disk->format = LIBXL_DISK_FORMAT_RAW;
1150             x_disk->backend = LIBXL_DISK_BACKEND_QDISK;
1151         } else if (STREQ(driver, "phy")) {
1152             if (format != VIR_STORAGE_FILE_RAW) {
1153                 virReportError(VIR_ERR_INTERNAL_ERROR,
1154                                _("libxenlight does not support disk format %s "
1155                                  "with disk driver %s"),
1156                                virStorageFileFormatTypeToString(format),
1157                                driver);
1158                 return -1;
1159             }
1160             x_disk->format = LIBXL_DISK_FORMAT_RAW;
1161             x_disk->backend = LIBXL_DISK_BACKEND_PHY;
1162         } else {
1163             virReportError(VIR_ERR_INTERNAL_ERROR,
1164                            _("libxenlight does not support disk driver %s"),
1165                            driver);
1166             return -1;
1167         }
1168     } else {
1169         /*
1170          * If driverName is not specified, default to raw as per
1171          * xl-disk-configuration.txt in the xen documentation and let
1172          * libxl pick a suitable backend.
1173          */
1174         x_disk->format = LIBXL_DISK_FORMAT_RAW;
1175         x_disk->backend = LIBXL_DISK_BACKEND_UNKNOWN;
1176     }
1177 
1178     /* XXX is this right? */
1179     x_disk->removable = 1;
1180     x_disk->readwrite = !l_disk->src->readonly;
1181     x_disk->is_cdrom = l_disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM ? 1 : 0;
1182     libxlDiskSetDiscard(x_disk, l_disk->discard);
1183     /* An empty CDROM must have the empty format, otherwise libxl fails. */
1184     if (x_disk->is_cdrom && !x_disk->pdev_path)
1185         x_disk->format = LIBXL_DISK_FORMAT_EMPTY;
1186     if (l_disk->transient) {
1187         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1188                        _("libxenlight does not support transient disks"));
1189         return -1;
1190     }
1191 
1192     if (l_disk->domain_name) {
1193 #ifdef LIBXL_HAVE_DEVICE_BACKEND_DOMNAME
1194         x_disk->backend_domname = g_strdup(l_disk->domain_name);
1195 #else
1196         virReportError(VIR_ERR_XML_DETAIL, "%s",
1197                 _("this version of libxenlight does not "
1198                   "support backend domain name"));
1199         return -1;
1200 #endif
1201     }
1202 
1203     return 0;
1204 }
1205 
1206 static int
libxlMakeDiskList(virDomainDef * def,libxl_domain_config * d_config)1207 libxlMakeDiskList(virDomainDef *def, libxl_domain_config *d_config)
1208 {
1209     virDomainDiskDef **l_disks = def->disks;
1210     int ndisks = def->ndisks;
1211     size_t i;
1212 
1213     d_config->disks = g_new0(libxl_device_disk, ndisks);
1214     d_config->num_disks = ndisks;
1215 
1216     for (i = 0; i < ndisks; i++) {
1217         libxl_device_disk_init(&d_config->disks[i]);
1218         if (libxlMakeDisk(l_disks[i], &d_config->disks[i]) < 0)
1219             return -1;
1220     }
1221 
1222     return 0;
1223 }
1224 
1225 /*
1226  * Update libvirt disk config with libxl disk config.
1227  *
1228  * This function can be used to update the libvirt disk config with default
1229  * values selected by libxl. Currently only the backend type is selected by
1230  * libxl when not explicitly specified by the user.
1231  */
1232 void
libxlUpdateDiskDef(virDomainDiskDef * l_disk,libxl_device_disk * x_disk)1233 libxlUpdateDiskDef(virDomainDiskDef *l_disk, libxl_device_disk *x_disk)
1234 {
1235     const char *driver = NULL;
1236 
1237     if (virDomainDiskGetDriver(l_disk))
1238         return;
1239 
1240     switch (x_disk->backend) {
1241     case LIBXL_DISK_BACKEND_QDISK:
1242         driver = "qemu";
1243         break;
1244     case LIBXL_DISK_BACKEND_TAP:
1245         driver = "tap";
1246         break;
1247     case LIBXL_DISK_BACKEND_PHY:
1248         driver = "phy";
1249         break;
1250     case LIBXL_DISK_BACKEND_UNKNOWN:
1251         break;
1252     }
1253     if (driver)
1254         virDomainDiskSetDriver(l_disk, driver);
1255 }
1256 
1257 int
libxlMakeNic(virDomainDef * def,virDomainNetDef * l_nic,libxl_device_nic * x_nic,bool attach)1258 libxlMakeNic(virDomainDef *def,
1259              virDomainNetDef *l_nic,
1260              libxl_device_nic *x_nic,
1261              bool attach)
1262 {
1263     virDomainNetType actual_type = virDomainNetGetActualType(l_nic);
1264     virNetworkPtr network = NULL;
1265     virConnectPtr conn = NULL;
1266     const virNetDevBandwidth *actual_bw;
1267     const virNetDevVPortProfile *port_profile;
1268     const virNetDevVlan *virt_vlan;
1269     g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
1270     size_t i;
1271     const char *script = NULL;
1272     int ret = -1;
1273 
1274     /* TODO: Where is mtu stored?
1275      *
1276      * x_nics[i].mtu = 1492;
1277      */
1278 
1279     if (l_nic->script && !(actual_type == VIR_DOMAIN_NET_TYPE_BRIDGE ||
1280                            actual_type == VIR_DOMAIN_NET_TYPE_ETHERNET)) {
1281         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
1282                        _("specifying a script is only supported with "
1283                          "interface types bridge and ethernet"));
1284         return -1;
1285     }
1286 
1287     virMacAddrGetRaw(&l_nic->mac, x_nic->mac);
1288 
1289     /*
1290      * The nictype field of libxl_device_nic structure tells Xen which type of
1291      * NIC device to create for the domain. LIBXL_NIC_TYPE_VIF specifies a
1292      * PV NIC. LIBXL_NIC_TYPE_VIF_IOEMU specifies a PV and emulated NIC,
1293      * allowing the domain to choose which NIC to use and unplug the unused
1294      * one. LIBXL_NIC_TYPE_VIF_IOEMU is only valid for HVM domains. Further,
1295      * if hotplugging the NIC, emulated NICs are currently not supported.
1296      * Alternatively one could set LIBXL_NIC_TYPE_UNKNOWN and let libxl decide,
1297      * but its behaviour might not be consistent across all libvirt supported
1298      * versions. The other nictype values are well established already, hence
1299      * we manually select our own default and mimic xl/libxl behaviour starting
1300      * xen commit 32e9d0f ("libxl: nic type defaults to vif in hotplug for
1301      * hvm guest").
1302      */
1303     if (virDomainNetGetModelString(l_nic)) {
1304         if ((def->os.type == VIR_DOMAIN_OSTYPE_XEN ||
1305             def->os.type == VIR_DOMAIN_OSTYPE_XENPVH) &&
1306             l_nic->model != VIR_DOMAIN_NET_MODEL_NETFRONT) {
1307             virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
1308                            _("only model 'netfront' is supported for "
1309                              "Xen PV(H) domains"));
1310             return -1;
1311         }
1312         x_nic->model = g_strdup(virDomainNetGetModelString(l_nic));
1313         if (l_nic->model == VIR_DOMAIN_NET_MODEL_NETFRONT)
1314             x_nic->nictype = LIBXL_NIC_TYPE_VIF;
1315         else
1316             x_nic->nictype = LIBXL_NIC_TYPE_VIF_IOEMU;
1317     } else {
1318         if (def->os.type == VIR_DOMAIN_OSTYPE_HVM && !attach)
1319             x_nic->nictype = LIBXL_NIC_TYPE_VIF_IOEMU;
1320         else
1321             x_nic->nictype = LIBXL_NIC_TYPE_VIF;
1322     }
1323 
1324     x_nic->ifname = g_strdup(l_nic->ifname);
1325 
1326     port_profile = virDomainNetGetActualVirtPortProfile(l_nic);
1327     virt_vlan = virDomainNetGetActualVlan(l_nic);
1328     script = l_nic->script;
1329     switch (actual_type) {
1330         case VIR_DOMAIN_NET_TYPE_BRIDGE:
1331             virBufferAddStr(&buf, virDomainNetGetActualBridgeName(l_nic));
1332             /*
1333              * A bit of special handling if vif will be connected to an
1334              * openvswitch bridge
1335              */
1336             if (port_profile &&
1337                 port_profile->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) {
1338                 /*
1339                  * If a custom script is not specified for openvswitch, use
1340                  * Xen's vif-openvswitch script
1341                  */
1342                 if (!script)
1343                     script = "vif-openvswitch";
1344                 /*
1345                  * libxl_device_nic->bridge supports an extended format for
1346                  * specifying VLAN tags and trunks when using openvswitch
1347                  *
1348                  * BRIDGE_NAME[.VLAN][:TRUNK:TRUNK]
1349                  *
1350                  * See Xen's networking wiki for more details
1351                  * https://wiki.xenproject.org/wiki/Xen_Networking#Open_vSwitch
1352                  */
1353                 if (virt_vlan && virt_vlan->nTags > 0) {
1354                     if (virt_vlan->trunk) {
1355                         for (i = 0; i < virt_vlan->nTags; i++)
1356                             virBufferAsprintf(&buf, ":%d", virt_vlan->tag[i]);
1357                     } else {
1358                         virBufferAsprintf(&buf, ".%d", virt_vlan->tag[0]);
1359                     }
1360                 }
1361             }
1362             x_nic->bridge = virBufferContentAndReset(&buf);
1363             G_GNUC_FALLTHROUGH;
1364         case VIR_DOMAIN_NET_TYPE_ETHERNET:
1365             x_nic->script = g_strdup(script);
1366             if (l_nic->guestIP.nips > 0) {
1367                 x_nic->ip = xenMakeIPList(&l_nic->guestIP);
1368                 if (!x_nic->ip)
1369                     goto cleanup;
1370             }
1371             break;
1372         case VIR_DOMAIN_NET_TYPE_NETWORK:
1373         {
1374             if (!(conn = virConnectOpen("xen:///system")))
1375                 goto cleanup;
1376 
1377             if (!(network =
1378                   virNetworkLookupByName(conn, l_nic->data.network.name))) {
1379                 goto cleanup;
1380             }
1381 
1382             if (l_nic->guestIP.nips > 0) {
1383                 x_nic->ip = xenMakeIPList(&l_nic->guestIP);
1384                 if (!x_nic->ip)
1385                     goto cleanup;
1386             }
1387 
1388             if (!(x_nic->bridge = virNetworkGetBridgeName(network)))
1389                 goto cleanup;
1390             break;
1391         }
1392         case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
1393         case VIR_DOMAIN_NET_TYPE_USER:
1394         case VIR_DOMAIN_NET_TYPE_SERVER:
1395         case VIR_DOMAIN_NET_TYPE_CLIENT:
1396         case VIR_DOMAIN_NET_TYPE_MCAST:
1397         case VIR_DOMAIN_NET_TYPE_UDP:
1398         case VIR_DOMAIN_NET_TYPE_INTERNAL:
1399         case VIR_DOMAIN_NET_TYPE_DIRECT:
1400         case VIR_DOMAIN_NET_TYPE_HOSTDEV:
1401         case VIR_DOMAIN_NET_TYPE_VDPA:
1402         case VIR_DOMAIN_NET_TYPE_LAST:
1403             virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1404                     _("unsupported interface type %s"),
1405                     virDomainNetTypeToString(l_nic->type));
1406             goto cleanup;
1407     }
1408 
1409     if (l_nic->domain_name) {
1410 #ifdef LIBXL_HAVE_DEVICE_BACKEND_DOMNAME
1411         x_nic->backend_domname = g_strdup(l_nic->domain_name);
1412 #else
1413         virReportError(VIR_ERR_XML_DETAIL, "%s",
1414                 _("this version of libxenlight does not "
1415                   "support backend domain name"));
1416         goto cleanup;
1417 #endif
1418     }
1419 
1420     /*
1421      * Set bandwidth.
1422      * From $xen-sources/docs/misc/xl-network-configuration.markdown:
1423      *
1424      *
1425      * Specifies the rate at which the outgoing traffic will be limited to.
1426      * The default if this keyword is not specified is unlimited.
1427      *
1428      * The rate may be specified as "<RATE>/s" or optionally "<RATE>/s@<INTERVAL>".
1429      *
1430      * `RATE` is in bytes and can accept suffixes:
1431      *     GB, MB, KB, B for bytes.
1432      *     Gb, Mb, Kb, b for bits.
1433      * `INTERVAL` is in microseconds and can accept suffixes: ms, us, s.
1434      *     It determines the frequency at which the vif transmission credit
1435      *     is replenished. The default is 50ms.
1436 
1437      * Vif rate limiting is credit-based. It means that for "1MB/s@20ms",
1438      * the available credit will be equivalent of the traffic you would have
1439      * done at "1MB/s" during 20ms. This will results in a credit of 20,000
1440      * bytes replenished every 20,000 us.
1441      *
1442      *
1443      * libvirt doesn't support the notion of rate limiting over an interval.
1444      * Similar to xl's behavior when interval is not specified, set a default
1445      * interval of 50ms and calculate the number of bytes per interval based
1446      * on the specified average bandwidth.
1447      */
1448     actual_bw = virDomainNetGetActualBandwidth(l_nic);
1449     if (actual_bw && actual_bw->out && actual_bw->out->average) {
1450         uint64_t bytes_per_sec = actual_bw->out->average * 1024;
1451         uint64_t bytes_per_interval =
1452             (((uint64_t) bytes_per_sec * 50000UL) / 1000000UL);
1453 
1454         x_nic->rate_bytes_per_interval = bytes_per_interval;
1455         x_nic->rate_interval_usecs =  50000UL;
1456     }
1457 
1458     ret = 0;
1459 
1460  cleanup:
1461     virObjectUnref(network);
1462     virObjectUnref(conn);
1463 
1464     return ret;
1465 }
1466 
1467 static int
libxlMakeNicList(virDomainDef * def,libxl_domain_config * d_config)1468 libxlMakeNicList(virDomainDef *def,  libxl_domain_config *d_config)
1469 {
1470     virDomainNetDef **l_nics = def->nets;
1471     size_t nnics = def->nnets;
1472     libxl_device_nic *x_nics;
1473     size_t i, nvnics = 0;
1474     int ret = -1;
1475 
1476     x_nics = g_new0(libxl_device_nic, nnics);
1477 
1478     for (i = 0; i < nnics; i++) {
1479         if (virDomainNetGetActualType(l_nics[i]) == VIR_DOMAIN_NET_TYPE_HOSTDEV)
1480             continue;
1481 
1482         libxl_device_nic_init(&x_nics[nvnics]);
1483         if (libxlMakeNic(def, l_nics[i], &x_nics[nvnics], false))
1484             goto out;
1485         /*
1486          * The devid (at least right now) will not get initialized by
1487          * libxl in the setup case but is required for starting the
1488          * device-model.
1489          */
1490         if (x_nics[nvnics].devid < 0)
1491             x_nics[nvnics].devid = nvnics;
1492 
1493         nvnics++;
1494     }
1495     ret = 0;
1496 
1497  out:
1498     VIR_SHRINK_N(x_nics, nnics, nnics - nvnics);
1499     d_config->nics = x_nics;
1500     d_config->num_nics = nvnics;
1501 
1502     return ret;
1503 }
1504 
1505 int
libxlMakeVfb(virPortAllocatorRange * graphicsports,virDomainGraphicsDef * l_vfb,libxl_device_vfb * x_vfb)1506 libxlMakeVfb(virPortAllocatorRange *graphicsports,
1507              virDomainGraphicsDef *l_vfb,
1508              libxl_device_vfb *x_vfb)
1509 {
1510     unsigned short port;
1511     virDomainGraphicsListenDef *glisten = NULL;
1512 
1513     libxl_device_vfb_init(x_vfb);
1514 
1515     switch (l_vfb->type) {
1516         case VIR_DOMAIN_GRAPHICS_TYPE_SDL:
1517             libxl_defbool_set(&x_vfb->sdl.enable, 1);
1518             libxl_defbool_set(&x_vfb->vnc.enable, 0);
1519             libxl_defbool_set(&x_vfb->sdl.opengl, 0);
1520             x_vfb->sdl.display = g_strdup(l_vfb->data.sdl.display);
1521             x_vfb->sdl.xauthority = g_strdup(l_vfb->data.sdl.xauth);
1522             break;
1523         case  VIR_DOMAIN_GRAPHICS_TYPE_VNC:
1524             libxl_defbool_set(&x_vfb->vnc.enable, 1);
1525             libxl_defbool_set(&x_vfb->sdl.enable, 0);
1526             /* driver handles selection of free port */
1527             libxl_defbool_set(&x_vfb->vnc.findunused, 0);
1528             if (l_vfb->data.vnc.autoport) {
1529 
1530                 if (virPortAllocatorAcquire(graphicsports, &port) < 0)
1531                     return -1;
1532                 l_vfb->data.vnc.port = port;
1533             }
1534             x_vfb->vnc.display = l_vfb->data.vnc.port - LIBXL_VNC_PORT_MIN;
1535 
1536             if ((glisten = virDomainGraphicsGetListen(l_vfb, 0))) {
1537                 if (glisten->address) {
1538                     /* libxl_device_vfb_init() does g_strdup("127.0.0.1") */
1539                     VIR_FREE(x_vfb->vnc.listen);
1540                     x_vfb->vnc.listen = g_strdup(glisten->address);
1541                 } else {
1542                     glisten->address = g_strdup(VIR_LOOPBACK_IPV4_ADDR);
1543                 }
1544             }
1545 
1546             x_vfb->vnc.passwd = g_strdup(l_vfb->data.vnc.auth.passwd);
1547             x_vfb->keymap = g_strdup(l_vfb->data.vnc.keymap);
1548             break;
1549 
1550         case VIR_DOMAIN_GRAPHICS_TYPE_RDP:
1551         case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP:
1552         case VIR_DOMAIN_GRAPHICS_TYPE_SPICE:
1553         case VIR_DOMAIN_GRAPHICS_TYPE_EGL_HEADLESS:
1554         case VIR_DOMAIN_GRAPHICS_TYPE_LAST:
1555             break;
1556     }
1557 
1558     return 0;
1559 }
1560 
1561 static int
libxlMakeVfbList(virPortAllocatorRange * graphicsports,virDomainDef * def,libxl_domain_config * d_config)1562 libxlMakeVfbList(virPortAllocatorRange *graphicsports,
1563                  virDomainDef *def,
1564                  libxl_domain_config *d_config)
1565 {
1566     virDomainGraphicsDef **l_vfbs = def->graphics;
1567     int nvfbs = def->ngraphics;
1568     libxl_device_vfb *x_vfbs;
1569     libxl_device_vkb *x_vkbs;
1570     size_t i;
1571 
1572     if (nvfbs == 0)
1573         return 0;
1574 
1575     x_vfbs = g_new0(libxl_device_vfb, nvfbs);
1576     x_vkbs = g_new0(libxl_device_vkb, nvfbs);
1577 
1578     for (i = 0; i < nvfbs; i++) {
1579         libxl_device_vkb_init(&x_vkbs[i]);
1580 
1581         if (libxlMakeVfb(graphicsports, l_vfbs[i], &x_vfbs[i]) < 0)
1582             goto error;
1583     }
1584 
1585     d_config->vfbs = x_vfbs;
1586     d_config->vkbs = x_vkbs;
1587     d_config->num_vfbs = d_config->num_vkbs = nvfbs;
1588 
1589     return 0;
1590 
1591  error:
1592     for (i = 0; i < nvfbs; i++) {
1593         libxl_device_vfb_dispose(&x_vfbs[i]);
1594         libxl_device_vkb_dispose(&x_vkbs[i]);
1595     }
1596     VIR_FREE(x_vfbs);
1597     VIR_FREE(x_vkbs);
1598     return -1;
1599 }
1600 
1601 /*
1602  * Populate vfb info in libxl_domain_build_info struct for HVM domains.
1603  * Prior to calling this function, libxlMakeVfbList must be called to
1604  * populate libxl_domain_config->vfbs.
1605  */
1606 static int
libxlMakeBuildInfoVfb(virPortAllocatorRange * graphicsports,virDomainDef * def,libxl_domain_config * d_config)1607 libxlMakeBuildInfoVfb(virPortAllocatorRange *graphicsports,
1608                       virDomainDef *def,
1609                       libxl_domain_config *d_config)
1610 {
1611     libxl_domain_build_info *b_info = &d_config->b_info;
1612     libxl_device_vfb x_vfb;
1613     size_t i;
1614 
1615     if (def->os.type != VIR_DOMAIN_OSTYPE_HVM)
1616         return 0;
1617 
1618     if (def->ngraphics == 0)
1619         return 0;
1620 
1621     /*
1622      * Prefer SPICE, otherwise use first libxl_device_vfb device in
1623      * libxl_domain_config->vfbs. Prior to calling this function,
1624      */
1625     for (i = 0; i < def->ngraphics; i++) {
1626         virDomainGraphicsDef *l_vfb = def->graphics[i];
1627         unsigned short port;
1628         virDomainGraphicsListenDef *glisten = NULL;
1629 
1630         if (l_vfb->type != VIR_DOMAIN_GRAPHICS_TYPE_SPICE)
1631             continue;
1632 
1633         libxl_defbool_set(&b_info->u.hvm.spice.enable, true);
1634 
1635         if (l_vfb->data.spice.autoport) {
1636             if (virPortAllocatorAcquire(graphicsports, &port) < 0)
1637                 return -1;
1638             l_vfb->data.spice.port = port;
1639         }
1640         b_info->u.hvm.spice.port = l_vfb->data.spice.port;
1641 
1642         if ((glisten = virDomainGraphicsGetListen(l_vfb, 0))) {
1643             if (glisten->address) {
1644                 b_info->u.hvm.spice.host = g_strdup(glisten->address);
1645             } else {
1646                 b_info->u.hvm.spice.host = g_strdup(VIR_LOOPBACK_IPV4_ADDR);
1647                 glisten->address = g_strdup(VIR_LOOPBACK_IPV4_ADDR);
1648             }
1649         }
1650 
1651         b_info->u.hvm.keymap = g_strdup(l_vfb->data.spice.keymap);
1652 
1653         if (l_vfb->data.spice.auth.passwd) {
1654             b_info->u.hvm.spice.passwd = g_strdup(l_vfb->data.spice.auth.passwd);
1655             libxl_defbool_set(&b_info->u.hvm.spice.disable_ticketing, false);
1656         } else {
1657             libxl_defbool_set(&b_info->u.hvm.spice.disable_ticketing, true);
1658         }
1659 
1660         switch (l_vfb->data.spice.mousemode) {
1661             /* client mouse mode is default in xl.cfg */
1662         case VIR_DOMAIN_GRAPHICS_SPICE_MOUSE_MODE_DEFAULT:
1663         case VIR_DOMAIN_GRAPHICS_SPICE_MOUSE_MODE_CLIENT:
1664             libxl_defbool_set(&b_info->u.hvm.spice.agent_mouse, true);
1665             break;
1666         case VIR_DOMAIN_GRAPHICS_SPICE_MOUSE_MODE_SERVER:
1667             libxl_defbool_set(&b_info->u.hvm.spice.agent_mouse, false);
1668             break;
1669         case VIR_DOMAIN_GRAPHICS_SPICE_MOUSE_MODE_LAST:
1670             break;
1671         }
1672 
1673         if (l_vfb->data.spice.copypaste == VIR_TRISTATE_BOOL_YES) {
1674             libxl_defbool_set(&b_info->u.hvm.spice.vdagent, true);
1675             libxl_defbool_set(&b_info->u.hvm.spice.clipboard_sharing, true);
1676         } else {
1677             libxl_defbool_set(&b_info->u.hvm.spice.vdagent, false);
1678             libxl_defbool_set(&b_info->u.hvm.spice.clipboard_sharing, false);
1679         }
1680 
1681         return 0;
1682     }
1683 
1684     x_vfb = d_config->vfbs[0];
1685 
1686     if (libxl_defbool_val(x_vfb.vnc.enable)) {
1687         libxl_defbool_set(&b_info->u.hvm.vnc.enable, true);
1688         b_info->u.hvm.vnc.listen = g_strdup(x_vfb.vnc.listen);
1689         b_info->u.hvm.vnc.passwd = g_strdup(x_vfb.vnc.passwd);
1690         b_info->u.hvm.vnc.display = x_vfb.vnc.display;
1691         libxl_defbool_set(&b_info->u.hvm.vnc.findunused,
1692                           libxl_defbool_val(x_vfb.vnc.findunused));
1693     } else if (libxl_defbool_val(x_vfb.sdl.enable)) {
1694         libxl_defbool_set(&b_info->u.hvm.sdl.enable, true);
1695         libxl_defbool_set(&b_info->u.hvm.sdl.opengl,
1696                           libxl_defbool_val(x_vfb.sdl.opengl));
1697         b_info->u.hvm.sdl.display = g_strdup(x_vfb.sdl.display);
1698         b_info->u.hvm.sdl.xauthority = g_strdup(x_vfb.sdl.xauthority);
1699     }
1700 
1701     b_info->u.hvm.keymap = g_strdup(x_vfb.keymap);
1702 
1703     return 0;
1704 }
1705 
1706 /*
1707  * Get domain0 autoballoon configuration.  Honor user-specified
1708  * setting in libxl.conf first.  If not specified, autoballooning
1709  * is disabled when domain0's memory is set with 'dom0_mem'.
1710  * Otherwise autoballooning is enabled.
1711  */
1712 static int
libxlGetAutoballoonConf(libxlDriverConfig * cfg,virConf * conf)1713 libxlGetAutoballoonConf(libxlDriverConfig *cfg,
1714                         virConf *conf)
1715 {
1716     g_autoptr(GRegex) regex = NULL;
1717     g_autoptr(GError) err = NULL;
1718     int res;
1719 
1720     res = virConfGetValueBool(conf, "autoballoon", &cfg->autoballoon);
1721     if (res < 0)
1722         return -1;
1723     else if (res == 1)
1724         return 0;
1725 
1726     regex = g_regex_new("(^| )dom0_mem=((|min:|max:)[0-9]+[bBkKmMgG]?,?)+($| )",
1727                         0, 0, &err);
1728     if (!regex) {
1729         virReportError(VIR_ERR_INTERNAL_ERROR,
1730                        _("Failed to compile regex %s"), err->message);
1731         return -1;
1732     }
1733 
1734     cfg->autoballoon = !g_regex_match(regex, cfg->verInfo->commandline, 0, NULL);
1735     return 0;
1736 }
1737 
1738 libxlDriverConfig *
libxlDriverConfigNew(void)1739 libxlDriverConfigNew(void)
1740 {
1741     libxlDriverConfig *cfg;
1742 
1743     if (libxlConfigInitialize() < 0)
1744         return NULL;
1745 
1746     if (!(cfg = virObjectNew(libxlDriverConfigClass)))
1747         return NULL;
1748 
1749     cfg->configBaseDir = g_strdup(LIBXL_CONFIG_BASE_DIR);
1750     cfg->configDir = g_strdup(LIBXL_CONFIG_DIR);
1751     cfg->autostartDir = g_strdup(LIBXL_AUTOSTART_DIR);
1752     cfg->logDir = g_strdup(LIBXL_LOG_DIR);
1753     cfg->stateDir = g_strdup(LIBXL_STATE_DIR);
1754     cfg->libDir = g_strdup(LIBXL_LIB_DIR);
1755     cfg->saveDir = g_strdup(LIBXL_SAVE_DIR);
1756     cfg->autoDumpDir = g_strdup(LIBXL_DUMP_DIR);
1757     cfg->channelDir = g_strdup(LIBXL_CHANNEL_DIR);
1758 
1759 #ifdef DEFAULT_LOADER_NVRAM
1760     if (virFirmwareParseList(DEFAULT_LOADER_NVRAM,
1761                              &cfg->firmwares,
1762                              &cfg->nfirmwares) < 0) {
1763         virObjectUnref(cfg);
1764         return NULL;
1765     }
1766 #else
1767     cfg->firmwares = g_new0(virFirmware *, 1);
1768     cfg->nfirmwares = 1;
1769     cfg->firmwares[0] = g_new0(virFirmware, 1);
1770     cfg->firmwares[0]->name = g_strdup(LIBXL_FIRMWARE_DIR "/ovmf.bin");
1771 #endif
1772 
1773     /* Always add hvmloader to firmwares */
1774     VIR_REALLOC_N(cfg->firmwares, cfg->nfirmwares + 1);
1775     cfg->nfirmwares++;
1776     cfg->firmwares[cfg->nfirmwares - 1] = g_new0(virFirmware, 1);
1777     cfg->firmwares[cfg->nfirmwares - 1]->name = g_strdup(LIBXL_FIRMWARE_DIR "/hvmloader");
1778 
1779     /* defaults for keepalive messages */
1780     cfg->keepAliveInterval = 5;
1781     cfg->keepAliveCount = 5;
1782 
1783     return cfg;
1784 }
1785 
1786 int
libxlDriverConfigInit(libxlDriverConfig * cfg)1787 libxlDriverConfigInit(libxlDriverConfig *cfg)
1788 {
1789     uint64_t free_mem;
1790 
1791     if (g_mkdir_with_parents(cfg->logDir, 0777) < 0) {
1792         virReportError(VIR_ERR_INTERNAL_ERROR,
1793                        _("failed to create log dir '%s': %s"),
1794                        cfg->logDir,
1795                        g_strerror(errno));
1796         return -1;
1797     }
1798 
1799     cfg->logger = libxlLoggerNew(cfg->logDir, virLogGetDefaultPriority());
1800     if (!cfg->logger) {
1801         VIR_ERROR(_("cannot create logger for libxenlight, disabling driver"));
1802         return -1;
1803     }
1804 
1805     if (libxl_ctx_alloc(&cfg->ctx, LIBXL_VERSION, 0, (xentoollog_logger *)cfg->logger)) {
1806         VIR_ERROR(_("cannot initialize libxenlight context, probably not "
1807                     "running in a Xen Dom0, disabling driver"));
1808         return -1;
1809     }
1810 
1811     if ((cfg->verInfo = libxl_get_version_info(cfg->ctx)) == NULL) {
1812         VIR_ERROR(_("cannot version information from libxenlight, "
1813                     "disabling driver"));
1814         return -1;
1815     }
1816     cfg->version = (cfg->verInfo->xen_version_major * 1000000) +
1817         (cfg->verInfo->xen_version_minor * 1000);
1818 
1819     /* This will fill xenstore info about free and dom0 memory if missing,
1820      * should be called before starting first domain */
1821     if (libxlGetFreeMemoryWrapper(cfg->ctx, &free_mem)) {
1822         VIR_ERROR(_("Unable to configure libxl's memory management parameters"));
1823         return -1;
1824     }
1825 
1826     return 0;
1827 }
1828 
1829 libxlDriverConfig *
libxlDriverConfigGet(libxlDriverPrivate * driver)1830 libxlDriverConfigGet(libxlDriverPrivate *driver)
1831 {
1832     libxlDriverConfig *cfg;
1833 
1834     libxlDriverLock(driver);
1835     cfg = virObjectRef(driver->config);
1836     libxlDriverUnlock(driver);
1837     return cfg;
1838 }
1839 
libxlDriverConfigLoadFile(libxlDriverConfig * cfg,const char * filename)1840 int libxlDriverConfigLoadFile(libxlDriverConfig *cfg,
1841                               const char *filename)
1842 {
1843     g_autoptr(virConf) conf = NULL;
1844 
1845     /* Check the file is readable before opening it, otherwise
1846      * libvirt emits an error.
1847      */
1848     if (access(filename, R_OK) == -1) {
1849         VIR_INFO("Could not read libxl config file %s", filename);
1850         return 0;
1851     }
1852 
1853     if (!(conf = virConfReadFile(filename, 0)))
1854         return -1;
1855 
1856     /* setup autoballoon */
1857     if (libxlGetAutoballoonConf(cfg, conf) < 0)
1858         return -1;
1859 
1860     if (virConfGetValueString(conf, "lock_manager", &cfg->lockManagerName) < 0)
1861         return -1;
1862 
1863     if (virConfGetValueInt(conf, "keepalive_interval", &cfg->keepAliveInterval) < 0)
1864         return -1;
1865 
1866     if (virConfGetValueUInt(conf, "keepalive_count", &cfg->keepAliveCount) < 0)
1867         return -1;
1868 
1869     if (virConfGetValueBool(conf, "nested_hvm", &cfg->nested_hvm) < 0)
1870         return -1;
1871 
1872     return 0;
1873 }
1874 
1875 /*
1876  * dom0's maximum memory can be controlled by the user with the 'dom0_mem' Xen
1877  * command line parameter. E.g. to set dom0's initial memory to 4G and max
1878  * memory to 8G: dom0_mem=4G,max:8G
1879  * Supported unit suffixes are [bBkKmMgGtT]. If not specified the default
1880  * unit is kilobytes.
1881  *
1882  * If not constrained by the user, dom0 can effectively use all host memory.
1883  * This function returns the configured maximum memory for dom0 in kilobytes,
1884  * either the user-specified value or total physical memory as a default.
1885  */
1886 int
libxlDriverGetDom0MaxmemConf(libxlDriverConfig * cfg,unsigned long long * maxmem)1887 libxlDriverGetDom0MaxmemConf(libxlDriverConfig *cfg,
1888                              unsigned long long *maxmem)
1889 {
1890     g_auto(GStrv) cmd_tokens = NULL;
1891     size_t i;
1892     size_t j;
1893     libxl_physinfo physinfo;
1894     int ret = -1;
1895 
1896     if (cfg->verInfo->commandline == NULL ||
1897         !(cmd_tokens = g_strsplit(cfg->verInfo->commandline, " ", 0)))
1898         goto physmem;
1899 
1900     for (i = 0; cmd_tokens[i] != NULL; i++) {
1901         g_auto(GStrv) mem_tokens = NULL;
1902 
1903         if (!STRPREFIX(cmd_tokens[i], "dom0_mem="))
1904             continue;
1905 
1906         if (!(mem_tokens = g_strsplit(cmd_tokens[i], ",", 0)))
1907             break;
1908         for (j = 0; mem_tokens[j] != NULL; j++) {
1909             if (STRPREFIX(mem_tokens[j], "max:")) {
1910                 char *p = mem_tokens[j] + 4;
1911                 unsigned long long multiplier = 1;
1912 
1913                 while (g_ascii_isdigit(*p))
1914                     p++;
1915                 if (virStrToLong_ull(mem_tokens[j] + 4, &p, 10, maxmem) < 0)
1916                     break;
1917                 if (*p) {
1918                     switch (*p) {
1919                     case 'm':
1920                     case 'M':
1921                         multiplier = 1024;
1922                         break;
1923                     case 'g':
1924                     case 'G':
1925                         multiplier = 1024 * 1024;
1926                         break;
1927                     case 't':
1928                     case 'T':
1929                         multiplier = 1024 * 1024 * 1024;
1930                         break;
1931                     }
1932                 }
1933                 *maxmem = *maxmem * multiplier;
1934                 ret = 0;
1935                 goto cleanup;
1936             }
1937         }
1938     }
1939 
1940  physmem:
1941     /* No 'max' specified in dom0_mem, so dom0 can use all physical memory */
1942     libxl_physinfo_init(&physinfo);
1943     if (libxl_get_physinfo(cfg->ctx, &physinfo)) {
1944         VIR_WARN("libxl_get_physinfo failed");
1945         goto cleanup;
1946     }
1947     *maxmem = (physinfo.total_pages * cfg->verInfo->pagesize) / 1024;
1948     libxl_physinfo_dispose(&physinfo);
1949     ret = 0;
1950 
1951  cleanup:
1952     return ret;
1953 }
1954 
1955 
1956 static int
libxlPrepareChannel(virDomainChrDef * channel,const char * channelDir,const char * domainName)1957 libxlPrepareChannel(virDomainChrDef *channel,
1958                     const char *channelDir,
1959                     const char *domainName)
1960 {
1961     if (channel->targetType == VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_XEN &&
1962         channel->source->type == VIR_DOMAIN_CHR_TYPE_UNIX &&
1963         !channel->source->data.nix.path) {
1964         const char *target = channel->target.name;
1965         if (!target)
1966             target = "unknown.sock";
1967         channel->source->data.nix.path = g_strdup_printf("%s/%s-%s", channelDir,
1968                                                          domainName,
1969                                                          target);
1970 
1971         channel->source->data.nix.listen = true;
1972     }
1973 
1974     return 0;
1975 }
1976 
1977 static int
libxlMakeChannel(virDomainChrDef * l_channel,libxl_device_channel * x_channel)1978 libxlMakeChannel(virDomainChrDef *l_channel,
1979                  libxl_device_channel *x_channel)
1980 {
1981     libxl_device_channel_init(x_channel);
1982 
1983     if (l_channel->targetType != VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_XEN) {
1984         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
1985                        _("channel target type not supported"));
1986         return -1;
1987     }
1988 
1989     switch (l_channel->source->type) {
1990     case VIR_DOMAIN_CHR_TYPE_PTY:
1991         x_channel->connection = LIBXL_CHANNEL_CONNECTION_PTY;
1992         break;
1993     case VIR_DOMAIN_CHR_TYPE_UNIX:
1994         x_channel->connection = LIBXL_CHANNEL_CONNECTION_SOCKET;
1995         x_channel->u.socket.path = g_strdup(l_channel->source->data.nix.path);
1996         break;
1997     default:
1998         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
1999                        _("channel source type not supported"));
2000         break;
2001     }
2002 
2003     if (!l_channel->target.name) {
2004         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
2005                        _("channel target name missing"));
2006         return -1;
2007     }
2008 
2009     x_channel->name = g_strdup(l_channel->target.name);
2010 
2011     return 0;
2012 }
2013 
2014 static int
libxlMakeChannelList(const char * channelDir,virDomainDef * def,libxl_domain_config * d_config)2015 libxlMakeChannelList(const char *channelDir,
2016                      virDomainDef *def,
2017                      libxl_domain_config *d_config)
2018 {
2019     virDomainChrDef **l_channels = def->channels;
2020     size_t nchannels = def->nchannels;
2021     libxl_device_channel *x_channels;
2022     size_t i, nvchannels = 0;
2023 
2024     x_channels = g_new0(libxl_device_channel, nchannels);
2025 
2026     for (i = 0; i < nchannels; i++) {
2027         if (l_channels[i]->deviceType != VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL)
2028             continue;
2029 
2030         if (libxlPrepareChannel(l_channels[i], channelDir, def->name) < 0)
2031             goto error;
2032 
2033         if (libxlMakeChannel(l_channels[i], &x_channels[nvchannels]) < 0)
2034             goto error;
2035 
2036         nvchannels++;
2037     }
2038 
2039     VIR_SHRINK_N(x_channels, nchannels, nchannels - nvchannels);
2040     d_config->channels = x_channels;
2041     d_config->num_channels = nvchannels;
2042 
2043     return 0;
2044 
2045  error:
2046     for (i = 0; i < nchannels; i++)
2047         libxl_device_channel_dispose(&x_channels[i]);
2048     VIR_FREE(x_channels);
2049     return -1;
2050 }
2051 
2052 int
libxlMakeUSBController(virDomainControllerDef * controller,libxl_device_usbctrl * usbctrl)2053 libxlMakeUSBController(virDomainControllerDef *controller,
2054                        libxl_device_usbctrl *usbctrl)
2055 {
2056     usbctrl->devid = controller->idx;
2057 
2058     if (controller->type != VIR_DOMAIN_CONTROLLER_TYPE_USB)
2059         return -1;
2060 
2061     if (controller->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_DEFAULT) {
2062         usbctrl->version = 2;
2063         usbctrl->type = LIBXL_USBCTRL_TYPE_QUSB;
2064     } else {
2065         switch (controller->model) {
2066         case VIR_DOMAIN_CONTROLLER_MODEL_USB_QUSB1:
2067             usbctrl->version = 1;
2068             usbctrl->type = LIBXL_USBCTRL_TYPE_QUSB;
2069             break;
2070 
2071         case VIR_DOMAIN_CONTROLLER_MODEL_USB_QUSB2:
2072             usbctrl->version = 2;
2073             usbctrl->type = LIBXL_USBCTRL_TYPE_QUSB;
2074             break;
2075 
2076         default:
2077             virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2078                            _("unsupported usb model"));
2079             return -1;
2080         }
2081     }
2082 
2083     if (controller->opts.usbopts.ports == -1)
2084         usbctrl->ports = 8;
2085     else
2086         usbctrl->ports = controller->opts.usbopts.ports;
2087 
2088     return 0;
2089 }
2090 
2091 static int
libxlMakeDefaultUSBControllers(virDomainDef * def,libxl_domain_config * d_config)2092 libxlMakeDefaultUSBControllers(virDomainDef *def,
2093                                libxl_domain_config *d_config)
2094 {
2095     virDomainControllerDef *l_controller = NULL;
2096     libxl_device_usbctrl *x_controllers = NULL;
2097     size_t nusbdevs = 0;
2098     size_t ncontrollers;
2099     size_t i;
2100 
2101     for (i = 0; i < def->nhostdevs; i++) {
2102         if (def->hostdevs[i]->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
2103             def->hostdevs[i]->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
2104             nusbdevs++;
2105     }
2106 
2107     /* No controllers needed if there are no USB devs */
2108     if (nusbdevs == 0)
2109         return 0;
2110 
2111     /* Create USB controllers with 8 ports */
2112     ncontrollers = VIR_DIV_UP(nusbdevs, 8);
2113     x_controllers = g_new0(libxl_device_usbctrl, ncontrollers);
2114 
2115     for (i = 0; i < ncontrollers; i++) {
2116         if (!(l_controller = virDomainControllerDefNew(VIR_DOMAIN_CONTROLLER_TYPE_USB)))
2117             goto error;
2118 
2119         l_controller->model = VIR_DOMAIN_CONTROLLER_MODEL_USB_QUSB2;
2120         l_controller->idx = i;
2121         l_controller->opts.usbopts.ports = 8;
2122 
2123         libxl_device_usbctrl_init(&x_controllers[i]);
2124 
2125         if (libxlMakeUSBController(l_controller, &x_controllers[i]) < 0)
2126             goto error;
2127 
2128         virDomainControllerInsert(def, l_controller);
2129 
2130         l_controller = NULL;
2131     }
2132 
2133     d_config->usbctrls = x_controllers;
2134     d_config->num_usbctrls = ncontrollers;
2135     return 0;
2136 
2137  error:
2138      virDomainControllerDefFree(l_controller);
2139      for (i = 0; i < ncontrollers; i++)
2140          libxl_device_usbctrl_dispose(&x_controllers[i]);
2141      VIR_FREE(x_controllers);
2142      return -1;
2143 }
2144 
2145 static int
libxlMakeUSBControllerList(virDomainDef * def,libxl_domain_config * d_config)2146 libxlMakeUSBControllerList(virDomainDef *def, libxl_domain_config *d_config)
2147 {
2148     virDomainControllerDef **l_controllers = def->controllers;
2149     size_t ncontrollers = def->ncontrollers;
2150     size_t nusbctrls = 0;
2151     libxl_device_usbctrl *x_usbctrls;
2152     size_t i, j;
2153 
2154     for (i = 0; i < ncontrollers; i++) {
2155         if (l_controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_USB)
2156             nusbctrls++;
2157     }
2158 
2159     if (nusbctrls == 0)
2160         return libxlMakeDefaultUSBControllers(def, d_config);
2161 
2162     x_usbctrls = g_new0(libxl_device_usbctrl, nusbctrls);
2163 
2164     for (i = 0, j = 0; i < ncontrollers && j < nusbctrls; i++) {
2165         if (l_controllers[i]->type != VIR_DOMAIN_CONTROLLER_TYPE_USB)
2166             continue;
2167 
2168         libxl_device_usbctrl_init(&x_usbctrls[j]);
2169 
2170         if (libxlMakeUSBController(l_controllers[i],
2171                                    &x_usbctrls[j]) < 0)
2172             goto error;
2173 
2174         j++;
2175     }
2176 
2177     d_config->usbctrls = x_usbctrls;
2178     d_config->num_usbctrls = nusbctrls;
2179 
2180     return 0;
2181 
2182  error:
2183     for (i = 0; i < nusbctrls; i++)
2184         libxl_device_usbctrl_dispose(&x_usbctrls[i]);
2185 
2186     VIR_FREE(x_usbctrls);
2187     return -1;
2188 }
2189 
2190 int
libxlMakeUSB(virDomainHostdevDef * hostdev,libxl_device_usbdev * usbdev)2191 libxlMakeUSB(virDomainHostdevDef *hostdev, libxl_device_usbdev *usbdev)
2192 {
2193     virDomainHostdevSubsysUSB *usbsrc = &hostdev->source.subsys.u.usb;
2194     virUSBDevice *usb = NULL;
2195     int ret = -1;
2196 
2197     if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
2198         return ret;
2199     if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
2200         return ret;
2201 
2202     if (usbsrc->bus > 0 && usbsrc->device > 0) {
2203         usbdev->u.hostdev.hostbus = usbsrc->bus;
2204         usbdev->u.hostdev.hostaddr = usbsrc->device;
2205     } else {
2206         if (virHostdevFindUSBDevice(hostdev, true, &usb) < 0) {
2207             virReportError(VIR_ERR_OPERATION_FAILED,
2208                            _("failed to find USB device busnum:devnum "
2209                              "for %x:%x"),
2210                            usbsrc->vendor, usbsrc->product);
2211             goto cleanup;
2212         }
2213 
2214         usbdev->u.hostdev.hostbus = virUSBDeviceGetBus(usb);
2215         usbdev->u.hostdev.hostaddr = virUSBDeviceGetDevno(usb);
2216     }
2217 
2218     ret = 0;
2219 
2220  cleanup:
2221     virUSBDeviceFree(usb);
2222 
2223     return ret;
2224 }
2225 
2226 static int
libxlMakeUSBList(virDomainDef * def,libxl_domain_config * d_config)2227 libxlMakeUSBList(virDomainDef *def, libxl_domain_config *d_config)
2228 {
2229     virDomainHostdevDef **l_hostdevs = def->hostdevs;
2230     size_t nhostdevs = def->nhostdevs;
2231     size_t nusbdevs = 0;
2232     libxl_device_usbdev *x_usbdevs;
2233     size_t i, j;
2234 
2235     if (nhostdevs == 0)
2236         return 0;
2237 
2238     x_usbdevs = g_new0(libxl_device_usbdev, nhostdevs);
2239 
2240     for (i = 0, j = 0; i < nhostdevs; i++) {
2241         if (l_hostdevs[i]->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
2242             continue;
2243         if (l_hostdevs[i]->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
2244             continue;
2245 
2246         libxl_device_usbdev_init(&x_usbdevs[j]);
2247 
2248         if (libxlMakeUSB(l_hostdevs[i], &x_usbdevs[j]) < 0)
2249             goto error;
2250 
2251         nusbdevs++;
2252         j++;
2253     }
2254 
2255     VIR_SHRINK_N(x_usbdevs, nhostdevs, nhostdevs - nusbdevs);
2256     d_config->usbdevs = x_usbdevs;
2257     d_config->num_usbdevs = nusbdevs;
2258 
2259     return 0;
2260 
2261  error:
2262     for (i = 0; i < nusbdevs; i++)
2263         libxl_device_usbdev_dispose(&x_usbdevs[i]);
2264 
2265     VIR_FREE(x_usbdevs);
2266     return -1;
2267 }
2268 
2269 int
libxlMakePCI(virDomainHostdevDef * hostdev,libxl_device_pci * pcidev)2270 libxlMakePCI(virDomainHostdevDef *hostdev, libxl_device_pci *pcidev)
2271 {
2272     virDomainHostdevSubsysPCI *pcisrc = &hostdev->source.subsys.u.pci;
2273     if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
2274         return -1;
2275     if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
2276         return -1;
2277 
2278     pcidev->domain = pcisrc->addr.domain;
2279     pcidev->bus = pcisrc->addr.bus;
2280     pcidev->dev = pcisrc->addr.slot;
2281     pcidev->func = pcisrc->addr.function;
2282     pcidev->permissive = hostdev->writeFiltering == VIR_TRISTATE_BOOL_NO;
2283 
2284     return 0;
2285 }
2286 
2287 static int
libxlMakePCIList(virDomainDef * def,libxl_domain_config * d_config)2288 libxlMakePCIList(virDomainDef *def, libxl_domain_config *d_config)
2289 {
2290     virDomainHostdevDef **l_hostdevs = def->hostdevs;
2291     size_t nhostdevs = def->nhostdevs;
2292     size_t npcidevs = 0;
2293     libxl_device_pci *x_pcidevs;
2294     size_t i, j;
2295 
2296     if (nhostdevs == 0)
2297         return 0;
2298 
2299     x_pcidevs = g_new0(libxl_device_pci, nhostdevs);
2300 
2301     for (i = 0, j = 0; i < nhostdevs; i++) {
2302         if (l_hostdevs[i]->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
2303             continue;
2304         if (l_hostdevs[i]->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
2305             continue;
2306 
2307         libxl_device_pci_init(&x_pcidevs[j]);
2308 
2309         if (libxlMakePCI(l_hostdevs[i], &x_pcidevs[j]) < 0)
2310             goto error;
2311 
2312         npcidevs++;
2313         j++;
2314     }
2315 
2316     VIR_SHRINK_N(x_pcidevs, nhostdevs, nhostdevs - npcidevs);
2317     d_config->pcidevs = x_pcidevs;
2318     d_config->num_pcidevs = npcidevs;
2319 
2320     return 0;
2321 
2322  error:
2323     for (i = 0; i < npcidevs; i++)
2324         libxl_device_pci_dispose(&x_pcidevs[i]);
2325 
2326     VIR_FREE(x_pcidevs);
2327     return -1;
2328 }
2329 
2330 static int
libxlMakeVideo(virDomainDef * def,libxl_domain_config * d_config)2331 libxlMakeVideo(virDomainDef *def, libxl_domain_config *d_config)
2332 
2333 {
2334     libxl_domain_build_info *b_info = &d_config->b_info;
2335     int dm_type = libxlDomainGetEmulatorType(def);
2336 
2337     if (d_config->c_info.type != LIBXL_DOMAIN_TYPE_HVM)
2338         return 0;
2339 
2340     /*
2341      * Take the first defined video device (graphics card) to display
2342      * on the first graphics device (display).
2343      */
2344     if (def->nvideos) {
2345         switch (def->videos[0]->type) {
2346         case VIR_DOMAIN_VIDEO_TYPE_VGA:
2347         case VIR_DOMAIN_VIDEO_TYPE_XEN:
2348             b_info->u.hvm.vga.kind = LIBXL_VGA_INTERFACE_TYPE_STD;
2349             if (dm_type == LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN) {
2350                 if (def->videos[0]->vram < 16 * 1024) {
2351                     virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2352                                    _("videoram must be at least 16MB for VGA"));
2353                     return -1;
2354                 }
2355             } else {
2356                 if (def->videos[0]->vram < 8 * 1024) {
2357                     virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2358                                    _("videoram must be at least 8MB for VGA"));
2359                     return -1;
2360                 }
2361             }
2362             break;
2363 
2364         case VIR_DOMAIN_VIDEO_TYPE_CIRRUS:
2365             b_info->u.hvm.vga.kind = LIBXL_VGA_INTERFACE_TYPE_CIRRUS;
2366             if (dm_type == LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN) {
2367                 if (def->videos[0]->vram < 8 * 1024) {
2368                     virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2369                                    _("videoram must be at least 8MB for CIRRUS"));
2370                     return -1;
2371                 }
2372             } else {
2373                 if (def->videos[0]->vram < 4 * 1024) {
2374                     virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2375                                    _("videoram must be at least 4MB for CIRRUS"));
2376                     return -1;
2377                 }
2378             }
2379             break;
2380 
2381         case VIR_DOMAIN_VIDEO_TYPE_QXL:
2382             b_info->u.hvm.vga.kind = LIBXL_VGA_INTERFACE_TYPE_QXL;
2383             if (def->videos[0]->vram < 128 * 1024) {
2384                 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2385                                _("videoram must be at least 128MB for QXL"));
2386                 return -1;
2387             }
2388             break;
2389 
2390         default:
2391             virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
2392                            _("video type %s is not supported by libxl"),
2393                            virDomainVideoTypeToString(def->videos[0]->type));
2394             return -1;
2395         }
2396         /* vram validated for each video type, now set it */
2397         b_info->video_memkb = def->videos[0]->vram;
2398     } else {
2399         libxl_defbool_set(&b_info->u.hvm.nographic, 1);
2400         b_info->u.hvm.vga.kind = LIBXL_VGA_INTERFACE_TYPE_NONE;
2401     }
2402 
2403     return 0;
2404 }
2405 
2406 int
libxlDriverNodeGetInfo(libxlDriverPrivate * driver,virNodeInfoPtr info)2407 libxlDriverNodeGetInfo(libxlDriverPrivate *driver, virNodeInfoPtr info)
2408 {
2409     libxl_physinfo phy_info;
2410     virArch hostarch = virArchFromHost();
2411     libxlDriverConfig *cfg = libxlDriverConfigGet(driver);
2412     int ret = -1;
2413 
2414     libxl_physinfo_init(&phy_info);
2415     if (libxl_get_physinfo(cfg->ctx, &phy_info)) {
2416         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2417                        _("libxl_get_physinfo_info failed"));
2418         goto cleanup;
2419     }
2420 
2421     if (virStrcpyStatic(info->model, virArchToString(hostarch)) < 0) {
2422         virReportError(VIR_ERR_INTERNAL_ERROR,
2423                        _("host arch %s is too big for destination"),
2424                        virArchToString(hostarch));
2425         goto cleanup;
2426     }
2427 
2428     info->memory = phy_info.total_pages * (cfg->verInfo->pagesize / 1024);
2429     info->cpus = phy_info.nr_cpus;
2430     info->nodes = phy_info.nr_nodes;
2431     info->cores = phy_info.cores_per_socket;
2432     info->threads = phy_info.threads_per_core;
2433     info->sockets = 1;
2434     info->mhz = phy_info.cpu_khz / 1000;
2435 
2436     ret = 0;
2437 
2438  cleanup:
2439     libxl_physinfo_dispose(&phy_info);
2440     virObjectUnref(cfg);
2441     return ret;
2442 }
2443 
2444 int
libxlBuildDomainConfig(virPortAllocatorRange * graphicsports,virDomainDef * def,libxlDriverConfig * cfg,libxl_domain_config * d_config)2445 libxlBuildDomainConfig(virPortAllocatorRange *graphicsports,
2446                        virDomainDef *def,
2447                        libxlDriverConfig *cfg,
2448                        libxl_domain_config *d_config)
2449 {
2450     virCaps *caps = cfg->caps;
2451     libxl_ctx *ctx = cfg->ctx;
2452 
2453     if (libxlMakeDomCreateInfo(ctx, def, &d_config->c_info) < 0)
2454         return -1;
2455 
2456     if (libxlMakeDomBuildInfo(def, cfg, caps, d_config) < 0)
2457         return -1;
2458 
2459     if (libxlMakeVnumaList(def, ctx, d_config) < 0)
2460         return -1;
2461 
2462     if (libxlMakeDiskList(def, d_config) < 0)
2463         return -1;
2464 
2465     if (libxlMakeNicList(def, d_config) < 0)
2466         return -1;
2467 
2468     if (libxlMakeVfbList(graphicsports, def, d_config) < 0)
2469         return -1;
2470 
2471     if (libxlMakeBuildInfoVfb(graphicsports, def, d_config) < 0)
2472         return -1;
2473 
2474     if (libxlMakePCIList(def, d_config) < 0)
2475         return -1;
2476 
2477     if (libxlMakeUSBControllerList(def, d_config) < 0)
2478         return -1;
2479 
2480     if (libxlMakeUSBList(def, d_config) < 0)
2481         return -1;
2482 
2483     if (libxlMakeChannelList(cfg->channelDir, def, d_config) < 0)
2484         return -1;
2485 
2486     /*
2487      * Now that any potential VFBs are defined, update the build info with
2488      * the data of the primary display. Some day libxl might implicitly do
2489      * so but as it does not right now, better be explicit.
2490      */
2491     if (libxlMakeVideo(def, d_config) < 0)
2492         return -1;
2493 
2494     d_config->on_reboot = libxlActionFromVirLifecycle(def->onReboot);
2495     d_config->on_poweroff = libxlActionFromVirLifecycle(def->onPoweroff);
2496     d_config->on_crash = libxlActionFromVirLifecycle(def->onCrash);
2497 
2498     return 0;
2499 }
2500 
2501 virDomainXMLOption *
libxlCreateXMLConf(libxlDriverPrivate * driver)2502 libxlCreateXMLConf(libxlDriverPrivate *driver)
2503 {
2504     libxlDomainDefParserConfig.priv = driver;
2505     return virDomainXMLOptionNew(&libxlDomainDefParserConfig,
2506                                  &libxlDomainXMLPrivateDataCallbacks,
2507                                  &libxlDriverDomainXMLNamespace,
2508                                  NULL, NULL);
2509 }
2510