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