1 /*
2 * xen_xl.c: Xen XL parsing functions
3 *
4 * Copyright (c) 2015 SUSE LINUX Products GmbH, Nuernberg, Germany.
5 * Copyright (C) 2014 David Kiarie Kahurani
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library. If not, see
19 * <http://www.gnu.org/licenses/>.
20 */
21
22 #include <config.h>
23
24 #include <libxl.h>
25
26 #include "virconf.h"
27 #include "virerror.h"
28 #include "virlog.h"
29 #include "domain_conf.h"
30 #include "viralloc.h"
31 #include "virstring.h"
32 #include "storage_source.h"
33 #include "xen_xl.h"
34 #include "libxl_capabilities.h"
35 #include "libxl_conf.h"
36 #include "cpu/cpu.h"
37
38 #define VIR_FROM_THIS VIR_FROM_XENXL
39
40 VIR_LOG_INIT("xen.xen_xl");
41
42 /*
43 * Xen provides a libxl utility library, with several useful functions,
44 * specifically xlu_disk_parse for parsing xl disk config strings.
45 * Although the libxlutil library is installed, until recently the
46 * corresponding header file wasn't. Use the header file if detected during
47 * configure, otherwise provide extern declarations for any functions used.
48 */
49 #ifdef WITH_LIBXLUTIL_H
50 # include <libxlutil.h>
51 #else
52 typedef struct XLU_Config XLU_Config;
53
54 extern XLU_Config *xlu_cfg_init(FILE *report,
55 const char *report_filename);
56
57 extern void xlu_cfg_destroy(XLU_Config*);
58
59 extern int xlu_disk_parse(XLU_Config *cfg,
60 int nspecs,
61 const char *const *specs,
62 libxl_device_disk *disk);
63 #endif
64
xenParseCmdline(virConf * conf,char ** r_cmdline)65 static int xenParseCmdline(virConf *conf, char **r_cmdline)
66 {
67 char *cmdline = NULL;
68 g_autofree char *root = NULL;
69 g_autofree char *extra = NULL;
70 g_autofree char *buf = NULL;
71
72 if (xenConfigGetString(conf, "cmdline", &buf, NULL) < 0)
73 return -1;
74
75 if (xenConfigGetString(conf, "root", &root, NULL) < 0)
76 return -1;
77
78 if (xenConfigGetString(conf, "extra", &extra, NULL) < 0)
79 return -1;
80
81 if (buf) {
82 cmdline = g_strdup(buf);
83 if (root || extra)
84 VIR_WARN("ignoring root= and extra= in favour of cmdline=");
85 } else {
86 if (root && extra) {
87 cmdline = g_strdup_printf("root=%s %s", root, extra);
88 } else if (root) {
89 cmdline = g_strdup_printf("root=%s", root);
90 } else if (extra) {
91 cmdline = g_strdup(extra);
92 }
93 }
94
95 *r_cmdline = cmdline;
96 return 0;
97 }
98
99 static int
xenParseXLOS(virConf * conf,virDomainDef * def,virCaps * caps)100 xenParseXLOS(virConf *conf, virDomainDef *def, virCaps *caps)
101 {
102 size_t i;
103
104 if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) {
105 g_autofree char *bios = NULL;
106 g_autofree char *boot = NULL;
107 int val = 0;
108
109 if (xenConfigGetString(conf, "bios", &bios, NULL) < 0)
110 return -1;
111
112 if (bios && STREQ(bios, "ovmf")) {
113 def->os.loader = g_new0(virDomainLoaderDef, 1);
114 def->os.loader->type = VIR_DOMAIN_LOADER_TYPE_PFLASH;
115 def->os.loader->readonly = VIR_TRISTATE_BOOL_YES;
116
117 def->os.loader->path = g_strdup(LIBXL_FIRMWARE_DIR "/ovmf.bin");
118 } else {
119 for (i = 0; i < caps->nguests; i++) {
120 if (caps->guests[i]->ostype == VIR_DOMAIN_OSTYPE_HVM &&
121 caps->guests[i]->arch.id == def->os.arch) {
122 def->os.loader = g_new0(virDomainLoaderDef, 1);
123 def->os.loader->path = g_strdup(caps->guests[i]->arch.defaultInfo.loader);
124 }
125 }
126 }
127
128 if (xenConfigCopyStringOpt(conf, "acpi_firmware", &def->os.slic_table) < 0)
129 return -1;
130
131 if (xenConfigCopyStringOpt(conf, "kernel", &def->os.kernel) < 0)
132 return -1;
133
134 if (xenConfigCopyStringOpt(conf, "ramdisk", &def->os.initrd) < 0)
135 return -1;
136
137 if (xenParseCmdline(conf, &def->os.cmdline) < 0)
138 return -1;
139
140 if (xenConfigGetString(conf, "boot", &boot, "c") < 0)
141 return -1;
142
143 for (i = 0; i < VIR_DOMAIN_BOOT_LAST && boot[i]; i++) {
144 switch (boot[i]) {
145 case 'a':
146 def->os.bootDevs[i] = VIR_DOMAIN_BOOT_FLOPPY;
147 break;
148 case 'd':
149 def->os.bootDevs[i] = VIR_DOMAIN_BOOT_CDROM;
150 break;
151 case 'n':
152 def->os.bootDevs[i] = VIR_DOMAIN_BOOT_NET;
153 break;
154 case 'c':
155 default:
156 def->os.bootDevs[i] = VIR_DOMAIN_BOOT_DISK;
157 break;
158 }
159 def->os.nBootDevs++;
160 }
161
162 if (xenConfigGetBool(conf, "nestedhvm", &val, -1) < 0)
163 return -1;
164
165 if (val != -1) {
166 const char *vtfeature = "vmx";
167
168 if (caps && caps->host.cpu && ARCH_IS_X86(def->os.arch)) {
169 if (virCPUCheckFeature(caps->host.arch, caps->host.cpu, "vmx"))
170 vtfeature = "vmx";
171 else if (virCPUCheckFeature(caps->host.arch, caps->host.cpu, "svm"))
172 vtfeature = "svm";
173 }
174
175 if (!def->cpu) {
176 virCPUDef *cpu = virCPUDefNew();
177 cpu->mode = VIR_CPU_MODE_HOST_PASSTHROUGH;
178 cpu->type = VIR_CPU_TYPE_GUEST;
179 cpu->nfeatures = 0;
180 cpu->nfeatures_max = 0;
181 def->cpu = cpu;
182 }
183
184 if (val == 0) {
185 if (virCPUDefAddFeature(def->cpu,
186 vtfeature,
187 VIR_CPU_FEATURE_DISABLE) < 0)
188 return -1;
189 }
190 }
191 } else {
192 if (xenConfigCopyStringOpt(conf, "bootloader", &def->os.bootloader) < 0)
193 return -1;
194 if (xenConfigCopyStringOpt(conf, "bootargs", &def->os.bootloaderArgs) < 0)
195 return -1;
196
197 if (xenConfigCopyStringOpt(conf, "kernel", &def->os.kernel) < 0)
198 return -1;
199
200 if (xenConfigCopyStringOpt(conf, "ramdisk", &def->os.initrd) < 0)
201 return -1;
202
203 if (xenParseCmdline(conf, &def->os.cmdline) < 0)
204 return -1;
205 }
206
207 return 0;
208 }
209
210 /*
211 * Translate CPU feature name from libvirt to libxl (from_libxl=false) or from
212 * libxl to libvirt (from_libxl=true).
213 */
214 const char *
xenTranslateCPUFeature(const char * feature_name,bool from_libxl)215 xenTranslateCPUFeature(const char *feature_name, bool from_libxl)
216 {
217 static const char *translation_table[][2] = {
218 /* libvirt name, libxl name */
219 { "cx16", "cmpxchg16" },
220 { "cid", "cntxid" },
221 { "ds_cpl", "dscpl" },
222 { "pclmuldq", "pclmulqdq" },
223 { "pni", "sse3" },
224 { "ht", "htt" },
225 { "pn", "psn" },
226 { "clflush", "clfsh" },
227 { "sep", "sysenter" },
228 { "cx8", "cmpxchg8" },
229 { "nodeid_msr", "nodeid" },
230 { "cr8legacy", "altmovcr8" },
231 { "lahf_lm", "lahfsahf" },
232 { "cmp_legacy", "cmplegacy" },
233 { "fxsr_opt", "ffxsr" },
234 { "pdpe1gb", "page1gb" },
235 { "spec-ctrl", "ibrsb" },
236 };
237 size_t i;
238
239 for (i = 0; i < G_N_ELEMENTS(translation_table); i++)
240 if (STREQ(translation_table[i][from_libxl], feature_name))
241 return translation_table[i][!from_libxl];
242 return feature_name;
243 }
244
245 static int
xenParseXLCPUID(virConf * conf,virDomainDef * def)246 xenParseXLCPUID(virConf *conf, virDomainDef *def)
247 {
248 g_autofree char *cpuid_str = NULL;
249 g_auto(GStrv) cpuid_pairs = NULL;
250 size_t i;
251 int ret = -1;
252 int policy;
253
254 if (xenConfigGetString(conf, "cpuid", &cpuid_str, NULL) < 0)
255 return -1;
256
257 if (!cpuid_str)
258 return 0;
259
260 if (!def->cpu) {
261 def->cpu = virCPUDefNew();
262 def->cpu->mode = VIR_CPU_MODE_HOST_PASSTHROUGH;
263 def->cpu->type = VIR_CPU_TYPE_GUEST;
264 def->cpu->nfeatures = 0;
265 def->cpu->nfeatures_max = 0;
266 }
267
268 cpuid_pairs = g_strsplit(cpuid_str, ",", 0);
269 if (!cpuid_pairs)
270 goto cleanup;
271
272 if (!cpuid_pairs[0]) {
273 ret = 0;
274 goto cleanup;
275 }
276
277 if (STRNEQ(cpuid_pairs[0], "host")) {
278 virReportError(VIR_ERR_CONF_SYNTAX,
279 _("cpuid starting with %s is not supported, only libxl format is"),
280 cpuid_pairs[0]);
281 goto cleanup;
282 }
283
284 for (i = 1; cpuid_pairs[i]; i++) {
285 g_auto(GStrv) name_and_value = g_strsplit(cpuid_pairs[i], "=", 2);
286 if (!name_and_value)
287 goto cleanup;
288 if (!name_and_value[0] || !name_and_value[1]) {
289 virReportError(VIR_ERR_CONF_SYNTAX,
290 _("Invalid libxl cpuid key=value element: %s"),
291 cpuid_pairs[i]);
292 goto cleanup;
293 }
294 if (STREQ(name_and_value[1], "1")) {
295 policy = VIR_CPU_FEATURE_FORCE;
296 } else if (STREQ(name_and_value[1], "0")) {
297 policy = VIR_CPU_FEATURE_DISABLE;
298 } else if (STREQ(name_and_value[1], "x")) {
299 policy = VIR_CPU_FEATURE_OPTIONAL;
300 } else if (STREQ(name_and_value[1], "k")) {
301 policy = VIR_CPU_FEATURE_OPTIONAL;
302 } else if (STREQ(name_and_value[1], "s")) {
303 policy = VIR_CPU_FEATURE_OPTIONAL;
304 } else {
305 virReportError(VIR_ERR_CONF_SYNTAX,
306 _("Invalid libxl cpuid value: %s"),
307 cpuid_pairs[i]);
308 goto cleanup;
309 }
310
311 if (virCPUDefAddFeature(def->cpu,
312 xenTranslateCPUFeature(name_and_value[0], true),
313 policy) < 0)
314 goto cleanup;
315 }
316
317 ret = 0;
318
319 cleanup:
320 return ret;
321 }
322
323
324 static int
xenParseXLSpice(virConf * conf,virDomainDef * def)325 xenParseXLSpice(virConf *conf, virDomainDef *def)
326 {
327 virDomainGraphicsDef *graphics = NULL;
328 unsigned long port;
329 char *listenAddr = NULL;
330 int val;
331
332 if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) {
333 if (xenConfigGetBool(conf, "spice", &val, 0) < 0)
334 return -1;
335
336 if (val) {
337 graphics = g_new0(virDomainGraphicsDef, 1);
338 graphics->type = VIR_DOMAIN_GRAPHICS_TYPE_SPICE;
339 if (xenConfigCopyStringOpt(conf, "spicehost", &listenAddr) < 0)
340 goto cleanup;
341 if (virDomainGraphicsListenAppendAddress(graphics, listenAddr) < 0)
342 goto cleanup;
343 VIR_FREE(listenAddr);
344
345 if (xenConfigGetULong(conf, "spicetls_port", &port, 0) < 0)
346 goto cleanup;
347 graphics->data.spice.tlsPort = (int)port;
348
349 if (xenConfigGetULong(conf, "spiceport", &port, 0) < 0)
350 goto cleanup;
351
352 graphics->data.spice.port = (int)port;
353
354 if (!graphics->data.spice.tlsPort && !graphics->data.spice.port)
355 graphics->data.spice.autoport = 1;
356
357 if (xenConfigGetBool(conf, "spicedisable_ticketing", &val, 0) < 0)
358 goto cleanup;
359 if (!val) {
360 if (xenConfigCopyString(conf, "spicepasswd",
361 &graphics->data.spice.auth.passwd) < 0)
362 goto cleanup;
363 }
364
365 if (xenConfigGetBool(conf, "spiceagent_mouse",
366 &val, 0) < 0)
367 goto cleanup;
368 if (val) {
369 graphics->data.spice.mousemode =
370 VIR_DOMAIN_GRAPHICS_SPICE_MOUSE_MODE_CLIENT;
371 } else {
372 graphics->data.spice.mousemode =
373 VIR_DOMAIN_GRAPHICS_SPICE_MOUSE_MODE_SERVER;
374 }
375
376 if (xenConfigGetBool(conf, "spice_clipboard_sharing", &val, 0) < 0)
377 goto cleanup;
378 if (val)
379 graphics->data.spice.copypaste = VIR_TRISTATE_BOOL_YES;
380 else
381 graphics->data.spice.copypaste = VIR_TRISTATE_BOOL_NO;
382
383 def->graphics = g_new0(virDomainGraphicsDef *, 1);
384 def->graphics[0] = graphics;
385 def->ngraphics = 1;
386 }
387 }
388
389 return 0;
390
391 cleanup:
392 VIR_FREE(listenAddr);
393 virDomainGraphicsDefFree(graphics);
394 return -1;
395 }
396
397 static int
xenParseXLVnuma(virConf * conf,virDomainDef * def)398 xenParseXLVnuma(virConf *conf,
399 virDomainDef *def)
400 {
401 int ret = -1;
402 char *tmp = NULL;
403 size_t vcpus = 0;
404 size_t nr_nodes = 0;
405 size_t vnodeCnt = 0;
406 virCPUDef *cpu = NULL;
407 virConfValue *list;
408 virConfValue *vnode;
409 virDomainNuma *numa;
410
411 numa = def->numa;
412 if (numa == NULL)
413 return -1;
414
415 list = virConfGetValue(conf, "vnuma");
416 if (!list || list->type != VIR_CONF_LIST)
417 return 0;
418
419 vnode = list->list;
420 while (vnode && vnode->type == VIR_CONF_LIST) {
421 vnode = vnode->next;
422 nr_nodes++;
423 }
424
425 if (!virDomainNumaSetNodeCount(numa, nr_nodes))
426 goto cleanup;
427
428 cpu = virCPUDefNew();
429
430 list = list->list;
431 while (list) {
432 int pnode = -1;
433 virBitmap *cpumask = NULL;
434 unsigned long long kbsize = 0;
435
436 /* Is there a sublist (vnode)? */
437 if (list->type == VIR_CONF_LIST) {
438 vnode = list->list;
439
440 while (vnode && vnode->type == VIR_CONF_STRING) {
441 const char *data;
442 const char *str = vnode->str;
443
444 if (!str ||
445 !(data = strrchr(str, '='))) {
446 virReportError(VIR_ERR_INTERNAL_ERROR,
447 _("vnuma vnode invalid format '%s'"),
448 str);
449 goto cleanup;
450 }
451 data++;
452
453 if (*data) {
454 char vtoken[64];
455
456 if (STRPREFIX(str, "pnode")) {
457 unsigned int cellid;
458
459 if (virStrcpyStatic(vtoken, data) < 0) {
460 virReportError(VIR_ERR_INTERNAL_ERROR,
461 _("vnuma vnode %zu pnode '%s' too long for destination"),
462 vnodeCnt, data);
463 goto cleanup;
464 }
465
466 if ((virStrToLong_ui(vtoken, NULL, 10, &cellid) < 0) ||
467 (cellid >= nr_nodes)) {
468 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
469 _("vnuma vnode %zu contains invalid pnode value '%s'"),
470 vnodeCnt, data);
471 goto cleanup;
472 }
473 pnode = cellid;
474 } else if (STRPREFIX(str, "size")) {
475 if (virStrcpyStatic(vtoken, data) < 0) {
476 virReportError(VIR_ERR_INTERNAL_ERROR,
477 _("vnuma vnode %zu size '%s' too long for destination"),
478 vnodeCnt, data);
479 goto cleanup;
480 }
481
482 if (virStrToLong_ull(vtoken, NULL, 10, &kbsize) < 0)
483 goto cleanup;
484
485 virDomainNumaSetNodeMemorySize(numa, vnodeCnt, (kbsize * 1024));
486
487 } else if (STRPREFIX(str, "vcpus")) {
488 if (virStrcpyStatic(vtoken, data) < 0) {
489 virReportError(VIR_ERR_INTERNAL_ERROR,
490 _("vnuma vnode %zu vcpus '%s' too long for destination"),
491 vnodeCnt, data);
492 goto cleanup;
493 }
494
495 if (virBitmapParse(vtoken, &cpumask, VIR_DOMAIN_CPUMASK_LEN) < 0)
496 goto cleanup;
497
498 virDomainNumaSetNodeCpumask(numa, vnodeCnt, cpumask);
499 vcpus += virBitmapCountBits(cpumask);
500
501 } else if (STRPREFIX(str, "vdistances")) {
502 g_auto(GStrv) token = NULL;
503 size_t i, ndistances;
504 unsigned int value;
505
506 if (virStrcpyStatic(vtoken, data) < 0) {
507 virReportError(VIR_ERR_INTERNAL_ERROR,
508 _("vnuma vnode %zu vdistances '%s' too long for destination"),
509 vnodeCnt, data);
510 goto cleanup;
511 }
512
513 VIR_FREE(tmp);
514 tmp = g_strdup(vtoken);
515
516 if (!(token = g_strsplit(tmp, ",", 0)))
517 goto cleanup;
518
519 ndistances = g_strv_length(token);
520
521 if (ndistances != nr_nodes) {
522 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
523 _("vnuma pnode %d configured '%s' (count %zu) doesn't fit the number of specified vnodes %zu"),
524 pnode, str, ndistances, nr_nodes);
525 goto cleanup;
526 }
527
528 if (virDomainNumaSetNodeDistanceCount(numa, vnodeCnt, ndistances) != ndistances)
529 goto cleanup;
530
531 for (i = 0; i < ndistances; i++) {
532 if ((virStrToLong_ui(token[i], NULL, 10, &value) < 0) ||
533 (virDomainNumaSetNodeDistance(numa, vnodeCnt, i, value) != value))
534 goto cleanup;
535 }
536
537 } else {
538 virReportError(VIR_ERR_CONF_SYNTAX,
539 _("Invalid vnuma configuration for vnode %zu"),
540 vnodeCnt);
541 goto cleanup;
542 }
543 }
544 vnode = vnode->next;
545 }
546 }
547
548 if ((pnode < 0) ||
549 (cpumask == NULL) ||
550 (kbsize == 0)) {
551 virReportError(VIR_ERR_CONF_SYNTAX,
552 _("Incomplete vnuma configuration for vnode %zu"),
553 vnodeCnt);
554 goto cleanup;
555 }
556
557 list = list->next;
558 vnodeCnt++;
559 }
560
561 if (def->maxvcpus == 0)
562 def->maxvcpus = vcpus;
563
564 if (def->maxvcpus < vcpus) {
565 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
566 _("vnuma configuration contains %zu vcpus, which is greater than %zu maxvcpus"),
567 vcpus, def->maxvcpus);
568 goto cleanup;
569 }
570
571 cpu->type = VIR_CPU_TYPE_GUEST;
572 def->cpu = cpu;
573
574 ret = 0;
575
576 cleanup:
577 if (ret)
578 VIR_FREE(cpu);
579 VIR_FREE(tmp);
580
581 return ret;
582 }
583
584 static int
xenParseXLXenbusLimits(virConf * conf,virDomainDef * def)585 xenParseXLXenbusLimits(virConf *conf, virDomainDef *def)
586 {
587 int ctlr_idx;
588 virDomainControllerDef *xenbus_ctlr;
589 unsigned long limit;
590
591 ctlr_idx = virDomainControllerFindByType(def, VIR_DOMAIN_CONTROLLER_TYPE_XENBUS);
592 if (ctlr_idx == -1)
593 xenbus_ctlr = virDomainDefAddController(def, VIR_DOMAIN_CONTROLLER_TYPE_XENBUS, -1, -1);
594 else
595 xenbus_ctlr = def->controllers[ctlr_idx];
596
597 if (xenbus_ctlr == NULL)
598 return -1;
599
600 if (xenConfigGetULong(conf, "max_event_channels", &limit, 0) < 0)
601 return -1;
602 if (limit > 0)
603 xenbus_ctlr->opts.xenbusopts.maxEventChannels = limit;
604
605 #ifdef LIBXL_HAVE_BUILDINFO_GRANT_LIMITS
606 if (xenConfigGetULong(conf, "max_grant_frames", &limit, 0) < 0)
607 return -1;
608 if (limit > 0)
609 xenbus_ctlr->opts.xenbusopts.maxGrantFrames = limit;
610 #endif
611
612 return 0;
613 }
614
615 static int
xenParseXLDiskSrc(virDomainDiskDef * disk,char * srcstr)616 xenParseXLDiskSrc(virDomainDiskDef *disk, char *srcstr)
617 {
618 char *tmpstr = NULL;
619 int ret = -1;
620
621 /* A NULL source is valid, e.g. an empty CDROM */
622 if (srcstr == NULL)
623 return 0;
624
625 if (STRPREFIX(srcstr, "rbd:")) {
626 if (!(tmpstr = virStringReplace(srcstr, "\\\\", "\\")))
627 goto cleanup;
628
629 virDomainDiskSetType(disk, VIR_STORAGE_TYPE_NETWORK);
630 disk->src->protocol = VIR_STORAGE_NET_PROTOCOL_RBD;
631 ret = virStorageSourceParseRBDColonString(tmpstr, disk->src);
632 } else {
633 virDomainDiskSetSource(disk, srcstr);
634
635 ret = 0;
636 }
637
638 cleanup:
639 VIR_FREE(tmpstr);
640 return ret;
641 }
642
643
644 /*
645 * For details on xl disk config syntax, see
646 * docs/misc/xl-disk-configuration.txt in the Xen sources. The important
647 * section of text is:
648 *
649 * More formally, the string is a series of comma-separated keyword/value
650 * pairs, flags and positional parameters. Parameters which are not bare
651 * keywords and which do not contain "=" symbols are assigned to the
652 * so-far-unspecified positional parameters, in the order below. The
653 * positional parameters may also be specified explicitly by name.
654 *
655 * Each parameter may be specified at most once, either as a positional
656 * parameter or a named parameter. Default values apply if the parameter
657 * is not specified, or if it is specified with an empty value (whether
658 * positionally or explicitly).
659 *
660 * Whitespace may appear before each parameter and will be ignored.
661 *
662 * The order of the positional parameters mentioned in the quoted text is:
663 *
664 * target,format,vdev,access
665 *
666 * The following options must be specified by key=value:
667 *
668 * devtype=<devtype>
669 * backendtype=<backend-type>
670 *
671 * The following options are currently not supported:
672 *
673 * backend=<domain-name>
674 * script=<script>
675 * direct-io-safe
676 *
677 */
678 static int
xenParseXLDisk(virConf * conf,virDomainDef * def)679 xenParseXLDisk(virConf *conf, virDomainDef *def)
680 {
681 int ret = -1;
682 virConfValue *list = virConfGetValue(conf, "disk");
683 XLU_Config *xluconf;
684 libxl_device_disk *libxldisk;
685 virDomainDiskDef *disk = NULL;
686
687 libxldisk = g_new0(libxl_device_disk, 1);
688
689 if (!(xluconf = xlu_cfg_init(stderr, "command line")))
690 goto cleanup;
691
692 if (list && list->type == VIR_CONF_LIST) {
693 list = list->list;
694 while (list) {
695 const char *disk_spec = list->str;
696
697 if (list->type != VIR_CONF_STRING || list->str == NULL)
698 goto skipdisk;
699
700 libxl_device_disk_init(libxldisk);
701
702 if (xlu_disk_parse(xluconf, 1, &disk_spec, libxldisk))
703 goto fail;
704
705 if (!(disk = virDomainDiskDefNew(NULL)))
706 goto fail;
707
708 if (xenParseXLDiskSrc(disk, libxldisk->pdev_path) < 0)
709 goto fail;
710
711 disk->dst = g_strdup(libxldisk->vdev);
712
713 disk->src->readonly = !libxldisk->readwrite;
714 disk->removable = libxldisk->removable;
715
716 if (libxldisk->is_cdrom) {
717 virDomainDiskSetDriver(disk, "qemu");
718
719 virDomainDiskSetType(disk, VIR_STORAGE_TYPE_FILE);
720 disk->device = VIR_DOMAIN_DISK_DEVICE_CDROM;
721 if (!disk->src->path || STREQ(disk->src->path, ""))
722 disk->src->format = VIR_STORAGE_FILE_NONE;
723 else
724 disk->src->format = VIR_STORAGE_FILE_RAW;
725 } else {
726 switch (libxldisk->format) {
727 case LIBXL_DISK_FORMAT_QCOW:
728 disk->src->format = VIR_STORAGE_FILE_QCOW;
729 break;
730
731 case LIBXL_DISK_FORMAT_QCOW2:
732 disk->src->format = VIR_STORAGE_FILE_QCOW2;
733 break;
734
735 case LIBXL_DISK_FORMAT_VHD:
736 disk->src->format = VIR_STORAGE_FILE_VHD;
737 break;
738
739 case LIBXL_DISK_FORMAT_RAW:
740 case LIBXL_DISK_FORMAT_UNKNOWN:
741 disk->src->format = VIR_STORAGE_FILE_RAW;
742 break;
743
744 case LIBXL_DISK_FORMAT_EMPTY:
745 break;
746
747 case LIBXL_DISK_FORMAT_QED:
748 disk->src->format = VIR_STORAGE_FILE_QED;
749 break;
750
751 default:
752 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
753 _("disk image format not supported: %s"),
754 libxl_disk_format_to_string(libxldisk->format));
755 goto fail;
756 }
757
758 switch (libxldisk->backend) {
759 case LIBXL_DISK_BACKEND_QDISK:
760 case LIBXL_DISK_BACKEND_UNKNOWN:
761 virDomainDiskSetDriver(disk, "qemu");
762 if (virDomainDiskGetType(disk) == VIR_STORAGE_TYPE_NONE)
763 virDomainDiskSetType(disk, VIR_STORAGE_TYPE_FILE);
764 break;
765
766 case LIBXL_DISK_BACKEND_TAP:
767 virDomainDiskSetDriver(disk, "tap");
768 virDomainDiskSetType(disk, VIR_STORAGE_TYPE_FILE);
769 break;
770
771 case LIBXL_DISK_BACKEND_PHY:
772 virDomainDiskSetDriver(disk, "phy");
773 virDomainDiskSetType(disk, VIR_STORAGE_TYPE_BLOCK);
774 break;
775 default:
776 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
777 _("disk backend not supported: %s"),
778 libxl_disk_backend_to_string(libxldisk->backend));
779 goto fail;
780 }
781 }
782
783 if (STRPREFIX(libxldisk->vdev, "xvd") ||
784 def->os.type != VIR_DOMAIN_OSTYPE_HVM)
785 disk->bus = VIR_DOMAIN_DISK_BUS_XEN;
786 else if (STRPREFIX(libxldisk->vdev, "sd"))
787 disk->bus = VIR_DOMAIN_DISK_BUS_SCSI;
788 else
789 disk->bus = VIR_DOMAIN_DISK_BUS_IDE;
790
791 VIR_APPEND_ELEMENT(def->disks, def->ndisks, disk);
792
793 libxl_device_disk_dispose(libxldisk);
794
795 skipdisk:
796 list = list->next;
797 }
798 }
799 ret = 0;
800
801 cleanup:
802 virDomainDiskDefFree(disk);
803 xlu_cfg_destroy(xluconf);
804 VIR_FREE(libxldisk);
805 return ret;
806
807 fail:
808 libxl_device_disk_dispose(libxldisk);
809 goto cleanup;
810 }
811
812 static int
xenParseXLInputDevs(virConf * conf,virDomainDef * def)813 xenParseXLInputDevs(virConf *conf, virDomainDef *def)
814 {
815 const char *str;
816 virConfValue *val;
817
818 if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) {
819 val = virConfGetValue(conf, "usbdevice");
820 /* usbdevice can be defined as either a single string or a list */
821 if (val && val->type == VIR_CONF_LIST)
822 val = val->list;
823
824 /* otherwise val->next is NULL, so can be handled by the same code */
825 while (val) {
826 if (val->type != VIR_CONF_STRING) {
827 virReportError(VIR_ERR_INTERNAL_ERROR,
828 _("config value %s was malformed"),
829 "usbdevice");
830 return -1;
831 }
832 str = val->str;
833
834 if (str &&
835 (STREQ(str, "tablet") ||
836 STREQ(str, "mouse") ||
837 STREQ(str, "keyboard"))) {
838 virDomainInputDef *input;
839 input = g_new0(virDomainInputDef,
840 1);
841
842 input->bus = VIR_DOMAIN_INPUT_BUS_USB;
843 if (STREQ(str, "mouse"))
844 input->type = VIR_DOMAIN_INPUT_TYPE_MOUSE;
845 else if (STREQ(str, "tablet"))
846 input->type = VIR_DOMAIN_INPUT_TYPE_TABLET;
847 else if (STREQ(str, "keyboard"))
848 input->type = VIR_DOMAIN_INPUT_TYPE_KBD;
849 VIR_APPEND_ELEMENT(def->inputs, def->ninputs, input);
850 }
851 val = val->next;
852 }
853 }
854 return 0;
855 }
856
857 static int
xenParseXLUSBController(virConf * conf,virDomainDef * def)858 xenParseXLUSBController(virConf *conf, virDomainDef *def)
859 {
860 virConfValue *list = virConfGetValue(conf, "usbctrl");
861 virDomainControllerDef *controller = NULL;
862
863 if (list && list->type == VIR_CONF_LIST) {
864 list = list->list;
865 while (list) {
866 char *key;
867 int usbctrl_version = 2; /* by default USB 2.0 */
868 int usbctrl_ports = 8; /* by default 8 ports */
869 int usbctrl_type = -1;
870
871 if ((list->type != VIR_CONF_STRING) || (list->str == NULL))
872 goto skipusbctrl;
873 /* usbctrl=['type=pv,version=2,ports=8'] */
874 key = list->str;
875 while (key) {
876 char *data;
877 char *nextkey = strchr(key, ',');
878
879 if (!(data = strchr(key, '=')))
880 goto skipusbctrl;
881 data++;
882
883 if (STRPREFIX(key, "type=")) {
884 if (!STRPREFIX(data, "qusb"))
885 goto skipusbctrl;
886 } else if (STRPREFIX(key, "version=")) {
887 int len = nextkey ? (nextkey - data) : strlen(data);
888 g_autofree char *tmp = g_strndup(data, len);
889
890 if (virStrToLong_i(tmp, NULL, 16, &usbctrl_version) < 0)
891 goto skipusbctrl;
892 } else if (STRPREFIX(key, "ports=")) {
893 int len = nextkey ? (nextkey - data) : strlen(data);
894 g_autofree char *tmp = g_strndup(data, len);
895
896 if (virStrToLong_i(tmp, NULL, 16, &usbctrl_ports) < 0)
897 goto skipusbctrl;
898 }
899
900 while (nextkey && (nextkey[0] == ',' ||
901 nextkey[0] == ' ' ||
902 nextkey[0] == '\t'))
903 nextkey++;
904 key = nextkey;
905 }
906
907 if (usbctrl_version == 1)
908 usbctrl_type = VIR_DOMAIN_CONTROLLER_MODEL_USB_QUSB1;
909 else
910 usbctrl_type = VIR_DOMAIN_CONTROLLER_MODEL_USB_QUSB2;
911
912 if (!(controller = virDomainControllerDefNew(VIR_DOMAIN_CONTROLLER_TYPE_USB)))
913 return -1;
914
915 controller->type = VIR_DOMAIN_CONTROLLER_TYPE_USB;
916 controller->model = usbctrl_type;
917 controller->opts.usbopts.ports = usbctrl_ports;
918
919 VIR_APPEND_ELEMENT(def->controllers, def->ncontrollers, controller);
920
921 skipusbctrl:
922 list = list->next;
923 }
924 }
925
926 return 0;
927 }
928
929 static int
xenParseXLUSB(virConf * conf,virDomainDef * def)930 xenParseXLUSB(virConf *conf, virDomainDef *def)
931 {
932 virConfValue *list = virConfGetValue(conf, "usbdev");
933 virDomainHostdevDef *hostdev = NULL;
934
935 if (list && list->type == VIR_CONF_LIST) {
936 list = list->list;
937 while (list) {
938 char *key;
939 int busNum;
940 int devNum;
941
942 if ((list->type != VIR_CONF_STRING) || (list->str == NULL))
943 goto skipusb;
944 /* usbdev=['hostbus=1,hostaddr=3'] */
945 key = list->str;
946 while (key) {
947 char *data;
948 char *nextkey = strchr(key, ',');
949
950 if (!(data = strchr(key, '=')))
951 goto skipusb;
952 data++;
953
954 if (STRPREFIX(key, "hostbus=")) {
955 int len = nextkey ? (nextkey - data) : strlen(data);
956 g_autofree char *tmp = g_strndup(data, len);
957
958 if (virStrToLong_i(tmp, NULL, 16, &busNum) < 0)
959 goto skipusb;
960 } else if (STRPREFIX(key, "hostaddr=")) {
961 int len = nextkey ? (nextkey - data) : strlen(data);
962 g_autofree char *tmp = g_strndup(data, len);
963
964 if (virStrToLong_i(tmp, NULL, 16, &devNum) < 0)
965 goto skipusb;
966 }
967
968 while (nextkey && (nextkey[0] == ',' ||
969 nextkey[0] == ' ' ||
970 nextkey[0] == '\t'))
971 nextkey++;
972 key = nextkey;
973 }
974
975 if (!(hostdev = virDomainHostdevDefNew()))
976 return -1;
977
978 hostdev->managed = false;
979 hostdev->source.subsys.type = VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB;
980 hostdev->source.subsys.u.usb.bus = busNum;
981 hostdev->source.subsys.u.usb.device = devNum;
982
983 VIR_APPEND_ELEMENT(def->hostdevs, def->nhostdevs, hostdev);
984
985 skipusb:
986 list = list->next;
987 }
988 }
989
990 return 0;
991 }
992
993 static int
xenParseXLChannel(virConf * conf,virDomainDef * def)994 xenParseXLChannel(virConf *conf, virDomainDef *def)
995 {
996 virConfValue *list = virConfGetValue(conf, "channel");
997 virDomainChrDef *channel = NULL;
998 char *name = NULL;
999 char *path = NULL;
1000
1001 if (list && list->type == VIR_CONF_LIST) {
1002 list = list->list;
1003 while (list) {
1004 g_autofree char *type = NULL;
1005 char *key;
1006
1007 if ((list->type != VIR_CONF_STRING) || (list->str == NULL))
1008 goto skipchannel;
1009
1010 key = list->str;
1011 while (key) {
1012 char *data;
1013 char *nextkey = strchr(key, ',');
1014
1015 if (!(data = strchr(key, '=')))
1016 goto skipchannel;
1017 data++;
1018
1019 if (STRPREFIX(key, "connection=")) {
1020 int len = nextkey ? (nextkey - data) : strlen(data);
1021 g_clear_pointer(&type, g_free);
1022 type = g_strndup(data, len);
1023 } else if (STRPREFIX(key, "name=")) {
1024 int len = nextkey ? (nextkey - data) : strlen(data);
1025 VIR_FREE(name);
1026 name = g_strndup(data, len);
1027 } else if (STRPREFIX(key, "path=")) {
1028 int len = nextkey ? (nextkey - data) : strlen(data);
1029 VIR_FREE(path);
1030 path = g_strndup(data, len);
1031 }
1032
1033 while (nextkey && (nextkey[0] == ',' ||
1034 nextkey[0] == ' ' ||
1035 nextkey[0] == '\t'))
1036 nextkey++;
1037 key = nextkey;
1038 }
1039
1040 if (!(channel = virDomainChrDefNew(NULL)))
1041 goto cleanup;
1042
1043 if (STRPREFIX(type, "socket")) {
1044 channel->source->type = VIR_DOMAIN_CHR_TYPE_UNIX;
1045 channel->source->data.nix.listen = 1;
1046 channel->source->data.nix.path = g_steal_pointer(&path);
1047 } else if (STRPREFIX(type, "pty")) {
1048 channel->source->type = VIR_DOMAIN_CHR_TYPE_PTY;
1049 VIR_FREE(path);
1050 } else {
1051 goto cleanup;
1052 }
1053
1054 channel->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL;
1055 channel->targetType = VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_XEN;
1056 channel->target.name = g_steal_pointer(&name);
1057
1058 VIR_APPEND_ELEMENT(def->channels, def->nchannels, channel);
1059
1060 skipchannel:
1061 list = list->next;
1062 }
1063 }
1064
1065 return 0;
1066
1067 cleanup:
1068 virDomainChrDefFree(channel);
1069 VIR_FREE(path);
1070 VIR_FREE(name);
1071 return -1;
1072 }
1073
1074 static int
xenParseXLNamespaceData(virConf * conf,virDomainDef * def)1075 xenParseXLNamespaceData(virConf *conf, virDomainDef *def)
1076 {
1077 virConfValue *list = virConfGetValue(conf, "device_model_args");
1078 virConfValue *next;
1079 size_t nargs = 0;
1080 libxlDomainXmlNsDef *nsdata = NULL;
1081 size_t n = 0;
1082
1083 if (!list || list->type != VIR_CONF_LIST)
1084 return 0;
1085
1086 list = list->list;
1087
1088 for (next = list; next; next = next->next) {
1089 if (next->type != VIR_CONF_STRING || !next->str)
1090 continue;
1091
1092 nargs++;
1093 }
1094
1095 if (nargs == 0)
1096 return 0;
1097
1098 nsdata = g_new0(libxlDomainXmlNsDef, 1);
1099 def->namespaceData = nsdata;
1100 nsdata->args = g_new0(char *, nargs + 1);
1101 nsdata->num_args = nargs;
1102
1103 for (next = list; next; next = next->next) {
1104 if (next->type != VIR_CONF_STRING || !next->str)
1105 continue;
1106
1107 nsdata->args[n++] = g_strdup(next->str);
1108 }
1109
1110 return 0;
1111 }
1112
1113 virDomainDef *
xenParseXL(virConf * conf,virCaps * caps,virDomainXMLOption * xmlopt)1114 xenParseXL(virConf *conf,
1115 virCaps *caps,
1116 virDomainXMLOption *xmlopt)
1117 {
1118 virDomainDef *def = NULL;
1119
1120 if (!(def = virDomainDefNew(xmlopt)))
1121 return NULL;
1122
1123 def->virtType = VIR_DOMAIN_VIRT_XEN;
1124 def->id = -1;
1125 def->ns = *(virDomainXMLOptionGetNamespace(xmlopt));
1126
1127 if (xenParseConfigCommon(conf, def, caps, XEN_CONFIG_FORMAT_XL,
1128 xmlopt) < 0)
1129 goto cleanup;
1130
1131 if (xenParseXLOS(conf, def, caps) < 0)
1132 goto cleanup;
1133
1134 if (xenParseXLVnuma(conf, def) < 0)
1135 goto cleanup;
1136
1137 if (xenParseXLXenbusLimits(conf, def) < 0)
1138 goto cleanup;
1139
1140 if (xenParseXLCPUID(conf, def) < 0)
1141 goto cleanup;
1142
1143 if (xenParseXLDisk(conf, def) < 0)
1144 goto cleanup;
1145
1146 if (xenParseXLSpice(conf, def) < 0)
1147 goto cleanup;
1148
1149 if (xenParseXLInputDevs(conf, def) < 0)
1150 goto cleanup;
1151
1152 if (xenParseXLUSB(conf, def) < 0)
1153 goto cleanup;
1154
1155 if (xenParseXLUSBController(conf, def) < 0)
1156 goto cleanup;
1157
1158 if (xenParseXLChannel(conf, def) < 0)
1159 goto cleanup;
1160
1161 if (xenParseXLNamespaceData(conf, def) < 0)
1162 goto cleanup;
1163
1164 if (virDomainDefPostParse(def, VIR_DOMAIN_DEF_PARSE_ABI_UPDATE,
1165 xmlopt, NULL) < 0)
1166 goto cleanup;
1167
1168 return def;
1169
1170 cleanup:
1171 virDomainDefFree(def);
1172 return NULL;
1173 }
1174
1175
1176 static int
xenFormatXLOS(virConf * conf,virDomainDef * def)1177 xenFormatXLOS(virConf *conf, virDomainDef *def)
1178 {
1179 size_t i;
1180
1181 if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) {
1182 char boot[VIR_DOMAIN_BOOT_LAST+1];
1183 if (xenConfigSetString(conf, "builder", "hvm") < 0)
1184 return -1;
1185
1186 if (virDomainDefHasOldStyleUEFI(def) &&
1187 xenConfigSetString(conf, "bios", "ovmf") < 0)
1188 return -1;
1189
1190 if (def->os.slic_table &&
1191 xenConfigSetString(conf, "acpi_firmware", def->os.slic_table) < 0)
1192 return -1;
1193
1194 if (def->os.kernel &&
1195 xenConfigSetString(conf, "kernel", def->os.kernel) < 0)
1196 return -1;
1197
1198 if (def->os.initrd &&
1199 xenConfigSetString(conf, "ramdisk", def->os.initrd) < 0)
1200 return -1;
1201
1202 if (def->os.cmdline &&
1203 xenConfigSetString(conf, "cmdline", def->os.cmdline) < 0)
1204 return -1;
1205
1206 for (i = 0; i < def->os.nBootDevs; i++) {
1207 switch (def->os.bootDevs[i]) {
1208 case VIR_DOMAIN_BOOT_FLOPPY:
1209 boot[i] = 'a';
1210 break;
1211 case VIR_DOMAIN_BOOT_CDROM:
1212 boot[i] = 'd';
1213 break;
1214 case VIR_DOMAIN_BOOT_NET:
1215 boot[i] = 'n';
1216 break;
1217 case VIR_DOMAIN_BOOT_DISK:
1218 default:
1219 boot[i] = 'c';
1220 break;
1221 }
1222 }
1223
1224 if (!def->os.nBootDevs) {
1225 boot[0] = 'c';
1226 boot[1] = '\0';
1227 } else {
1228 boot[def->os.nBootDevs] = '\0';
1229 }
1230
1231 if (xenConfigSetString(conf, "boot", boot) < 0)
1232 return -1;
1233
1234 if (def->cpu &&
1235 def->cpu->mode == VIR_CPU_MODE_HOST_PASSTHROUGH) {
1236 bool hasHwVirt = true;
1237
1238 if (def->cpu->nfeatures) {
1239 for (i = 0; i < def->cpu->nfeatures; i++) {
1240
1241 switch (def->cpu->features[i].policy) {
1242 case VIR_CPU_FEATURE_DISABLE:
1243 case VIR_CPU_FEATURE_FORBID:
1244 if (STREQ(def->cpu->features[i].name, "vmx") ||
1245 STREQ(def->cpu->features[i].name, "svm"))
1246 hasHwVirt = false;
1247 break;
1248
1249 case VIR_CPU_FEATURE_FORCE:
1250 case VIR_CPU_FEATURE_REQUIRE:
1251 case VIR_CPU_FEATURE_OPTIONAL:
1252 case VIR_CPU_FEATURE_LAST:
1253 break;
1254 }
1255 }
1256 }
1257
1258 if (xenConfigSetInt(conf, "nestedhvm", hasHwVirt) < 0)
1259 return -1;
1260 }
1261
1262 /* XXX floppy disks */
1263 } else {
1264 if (def->os.type == VIR_DOMAIN_OSTYPE_XENPVH) {
1265 if (xenConfigSetString(conf, "type", "pvh") < 0)
1266 return -1;
1267 }
1268
1269 if (def->os.bootloader &&
1270 xenConfigSetString(conf, "bootloader", def->os.bootloader) < 0)
1271 return -1;
1272
1273 if (def->os.bootloaderArgs &&
1274 xenConfigSetString(conf, "bootargs", def->os.bootloaderArgs) < 0)
1275 return -1;
1276
1277 if (def->os.kernel &&
1278 xenConfigSetString(conf, "kernel", def->os.kernel) < 0)
1279 return -1;
1280
1281 if (def->os.initrd &&
1282 xenConfigSetString(conf, "ramdisk", def->os.initrd) < 0)
1283 return -1;
1284
1285 if (def->os.cmdline &&
1286 xenConfigSetString(conf, "cmdline", def->os.cmdline) < 0)
1287 return -1;
1288 } /* !hvm */
1289
1290 return 0;
1291 }
1292
1293 static int
xenFormatXLCPUID(virConf * conf,virDomainDef * def)1294 xenFormatXLCPUID(virConf *conf, virDomainDef *def)
1295 {
1296 g_auto(GStrv) cpuid_pairs = NULL;
1297 g_autofree char *cpuid_string = NULL;
1298 size_t i, j;
1299 int ret = -1;
1300
1301 if (!def->cpu)
1302 return 0;
1303
1304 if (def->cpu->mode != VIR_CPU_MODE_HOST_PASSTHROUGH) {
1305 VIR_WARN("ignoring CPU mode '%s', only host-passthrough mode "
1306 "is supported", virCPUModeTypeToString(def->cpu->mode));
1307 return 0;
1308 }
1309
1310 /* "host" + all features + NULL */
1311 cpuid_pairs = g_new0(char *, def->cpu->nfeatures + 2);
1312
1313 cpuid_pairs[0] = g_strdup("host");
1314
1315 j = 1;
1316 for (i = 0; i < def->cpu->nfeatures; i++) {
1317 const char *feature_name = xenTranslateCPUFeature(
1318 def->cpu->features[i].name,
1319 false);
1320 const char *policy = NULL;
1321
1322 if (STREQ(feature_name, "vmx") || STREQ(feature_name, "svm"))
1323 /* ignore vmx/svm in cpuid option, translated into nestedhvm
1324 * elsewhere */
1325 continue;
1326
1327 switch (def->cpu->features[i].policy) {
1328 case VIR_CPU_FEATURE_FORCE:
1329 case VIR_CPU_FEATURE_REQUIRE:
1330 policy = "1";
1331 break;
1332 case VIR_CPU_FEATURE_OPTIONAL:
1333 policy = "x";
1334 break;
1335 case VIR_CPU_FEATURE_DISABLE:
1336 case VIR_CPU_FEATURE_FORBID:
1337 policy = "0";
1338 break;
1339 }
1340 cpuid_pairs[j++] = g_strdup_printf("%s=%s", feature_name, policy);
1341 }
1342 cpuid_pairs[j] = NULL;
1343
1344 if (j > 1) {
1345 cpuid_string = g_strjoinv(",", cpuid_pairs);
1346
1347 if (xenConfigSetString(conf, "cpuid", cpuid_string) < 0)
1348 goto cleanup;
1349 }
1350
1351 ret = 0;
1352
1353 cleanup:
1354 return ret;
1355 }
1356
1357 static int
xenFormatXLVnode(virConfValue * list,virBuffer * buf)1358 xenFormatXLVnode(virConfValue *list,
1359 virBuffer *buf)
1360 {
1361 virConfValue *numaPnode;
1362 virConfValue *tmp;
1363
1364 numaPnode = g_new0(virConfValue, 1);
1365
1366 /* Place VNODE directive */
1367 numaPnode->type = VIR_CONF_STRING;
1368 numaPnode->str = virBufferContentAndReset(buf);
1369
1370 tmp = list->list;
1371 while (tmp && tmp->next)
1372 tmp = tmp->next;
1373 if (tmp)
1374 tmp->next = numaPnode;
1375 else
1376 list->list = numaPnode;
1377
1378 return 0;
1379 }
1380
1381 static int
xenFormatXLVnuma(virConfValue * list,virDomainNuma * numa,size_t node,size_t nr_nodes)1382 xenFormatXLVnuma(virConfValue *list,
1383 virDomainNuma *numa,
1384 size_t node,
1385 size_t nr_nodes)
1386 {
1387 int ret = -1;
1388 size_t i;
1389 g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
1390 virConfValue *numaVnode;
1391 virConfValue *tmp;
1392 virBitmap *cpumask = virDomainNumaGetNodeCpumask(numa, node);
1393 size_t nodeSize = virDomainNumaGetNodeMemorySize(numa, node) / 1024;
1394 g_autofree char *nodeVcpus = NULL;
1395
1396 if (!cpumask)
1397 return -1;
1398
1399 numaVnode = g_new0(virConfValue, 1);
1400 numaVnode->type = VIR_CONF_LIST;
1401 numaVnode->list = NULL;
1402
1403 nodeVcpus = virBitmapFormat(cpumask);
1404
1405 /* pnode */
1406 virBufferAsprintf(&buf, "pnode=%zu", node);
1407 xenFormatXLVnode(numaVnode, &buf);
1408
1409 /* size */
1410 virBufferAsprintf(&buf, "size=%zu", nodeSize);
1411 xenFormatXLVnode(numaVnode, &buf);
1412
1413 /* vcpus */
1414 virBufferAsprintf(&buf, "vcpus=%s", nodeVcpus);
1415 xenFormatXLVnode(numaVnode, &buf);
1416
1417 /* distances */
1418 virBufferAddLit(&buf, "vdistances=");
1419 for (i = 0; i < nr_nodes; i++) {
1420 virBufferAsprintf(&buf, "%zu",
1421 virDomainNumaGetNodeDistance(numa, node, i));
1422 if ((nr_nodes - i) > 1)
1423 virBufferAddLit(&buf, ",");
1424 }
1425 xenFormatXLVnode(numaVnode, &buf);
1426
1427 tmp = list->list;
1428 while (tmp && tmp->next)
1429 tmp = tmp->next;
1430 if (tmp)
1431 tmp->next = numaVnode;
1432 else
1433 list->list = numaVnode;
1434 ret = 0;
1435
1436 VIR_FREE(nodeVcpus);
1437 return ret;
1438 }
1439
1440 static int
xenFormatXLDomainVnuma(virConf * conf,virDomainDef * def)1441 xenFormatXLDomainVnuma(virConf *conf,
1442 virDomainDef *def)
1443 {
1444 virDomainNuma *numa = def->numa;
1445 virConfValue *vnumaVal;
1446 size_t i;
1447 size_t nr_nodes;
1448
1449 if (numa == NULL)
1450 return -1;
1451
1452 vnumaVal = g_new0(virConfValue, 1);
1453
1454 vnumaVal->type = VIR_CONF_LIST;
1455 vnumaVal->list = NULL;
1456
1457 nr_nodes = virDomainNumaGetNodeCount(numa);
1458 for (i = 0; i < nr_nodes; i++) {
1459 if (xenFormatXLVnuma(vnumaVal, numa, i, nr_nodes) < 0)
1460 goto cleanup;
1461 }
1462
1463 if (vnumaVal->list != NULL) {
1464 int ret = virConfSetValue(conf, "vnuma", vnumaVal);
1465 vnumaVal = NULL;
1466 if (ret < 0)
1467 return -1;
1468 }
1469 VIR_FREE(vnumaVal);
1470
1471 return 0;
1472
1473 cleanup:
1474 virConfFreeValue(vnumaVal);
1475 return -1;
1476 }
1477
1478 static int
xenFormatXLXenbusLimits(virConf * conf,virDomainDef * def)1479 xenFormatXLXenbusLimits(virConf *conf, virDomainDef *def)
1480 {
1481 size_t i;
1482
1483 for (i = 0; i < def->ncontrollers; i++) {
1484 if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_XENBUS) {
1485 if (def->controllers[i]->opts.xenbusopts.maxEventChannels > 0) {
1486 if (xenConfigSetInt(conf, "max_event_channels",
1487 def->controllers[i]->opts.xenbusopts.maxEventChannels) < 0)
1488 return -1;
1489 }
1490
1491 #ifdef LIBXL_HAVE_BUILDINFO_GRANT_LIMITS
1492 if (def->controllers[i]->opts.xenbusopts.maxGrantFrames > 0) {
1493 if (xenConfigSetInt(conf, "max_grant_frames",
1494 def->controllers[i]->opts.xenbusopts.maxGrantFrames) < 0)
1495 return -1;
1496 }
1497 #endif
1498 }
1499 }
1500
1501 return 0;
1502 }
1503
1504 static char *
xenFormatXLDiskSrcNet(virStorageSource * src)1505 xenFormatXLDiskSrcNet(virStorageSource *src)
1506 {
1507 g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
1508 size_t i;
1509
1510 switch ((virStorageNetProtocol) src->protocol) {
1511 case VIR_STORAGE_NET_PROTOCOL_NBD:
1512 case VIR_STORAGE_NET_PROTOCOL_HTTP:
1513 case VIR_STORAGE_NET_PROTOCOL_HTTPS:
1514 case VIR_STORAGE_NET_PROTOCOL_FTP:
1515 case VIR_STORAGE_NET_PROTOCOL_FTPS:
1516 case VIR_STORAGE_NET_PROTOCOL_TFTP:
1517 case VIR_STORAGE_NET_PROTOCOL_ISCSI:
1518 case VIR_STORAGE_NET_PROTOCOL_GLUSTER:
1519 case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG:
1520 case VIR_STORAGE_NET_PROTOCOL_SSH:
1521 case VIR_STORAGE_NET_PROTOCOL_VXHS:
1522 case VIR_STORAGE_NET_PROTOCOL_NFS:
1523 case VIR_STORAGE_NET_PROTOCOL_LAST:
1524 case VIR_STORAGE_NET_PROTOCOL_NONE:
1525 virReportError(VIR_ERR_NO_SUPPORT,
1526 _("Unsupported network block protocol '%s'"),
1527 virStorageNetProtocolTypeToString(src->protocol));
1528 return NULL;
1529
1530 case VIR_STORAGE_NET_PROTOCOL_RBD:
1531 if (strchr(src->path, ':')) {
1532 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1533 _("':' not allowed in RBD source volume name '%s'"),
1534 src->path);
1535 return NULL;
1536 }
1537
1538 virBufferStrcat(&buf, "rbd:", src->volume, "/", src->path, NULL);
1539
1540 virBufferAddLit(&buf, ":auth_supported=none");
1541
1542 if (src->nhosts > 0) {
1543 virBufferAddLit(&buf, ":mon_host=");
1544 for (i = 0; i < src->nhosts; i++) {
1545 if (i)
1546 virBufferAddLit(&buf, "\\\\;");
1547
1548 /* assume host containing : is ipv6 */
1549 if (strchr(src->hosts[i].name, ':'))
1550 virBufferEscape(&buf, '\\', ":", "[%s]",
1551 src->hosts[i].name);
1552 else
1553 virBufferAsprintf(&buf, "%s", src->hosts[i].name);
1554
1555 if (src->hosts[i].port)
1556 virBufferAsprintf(&buf, "\\\\:%u", src->hosts[i].port);
1557 }
1558 }
1559
1560 return virBufferContentAndReset(&buf);
1561 }
1562
1563 return NULL;
1564 }
1565
1566
1567 static int
xenFormatXLDiskSrc(virStorageSource * src,char ** srcstr)1568 xenFormatXLDiskSrc(virStorageSource *src, char **srcstr)
1569 {
1570 int actualType = virStorageSourceGetActualType(src);
1571
1572 *srcstr = NULL;
1573
1574 if (virStorageSourceIsEmpty(src))
1575 return 0;
1576
1577 switch ((virStorageType)actualType) {
1578 case VIR_STORAGE_TYPE_BLOCK:
1579 case VIR_STORAGE_TYPE_FILE:
1580 case VIR_STORAGE_TYPE_DIR:
1581 *srcstr = g_strdup(src->path);
1582 break;
1583
1584 case VIR_STORAGE_TYPE_NETWORK:
1585 if (!(*srcstr = xenFormatXLDiskSrcNet(src)))
1586 return -1;
1587 break;
1588
1589 case VIR_STORAGE_TYPE_VOLUME:
1590 case VIR_STORAGE_TYPE_NVME:
1591 case VIR_STORAGE_TYPE_VHOST_USER:
1592 case VIR_STORAGE_TYPE_NONE:
1593 case VIR_STORAGE_TYPE_LAST:
1594 break;
1595 }
1596
1597 return 0;
1598 }
1599
1600
1601 static int
xenFormatXLDisk(virConfValue * list,virDomainDiskDef * disk)1602 xenFormatXLDisk(virConfValue *list, virDomainDiskDef *disk)
1603 {
1604 g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
1605 virConfValue *val;
1606 virConfValue *tmp;
1607 int format = virDomainDiskGetFormat(disk);
1608 const char *driver = virDomainDiskGetDriver(disk);
1609 g_autofree char *target = NULL;
1610
1611 /* format */
1612 virBufferAddLit(&buf, "format=");
1613 switch (format) {
1614 case VIR_STORAGE_FILE_RAW:
1615 virBufferAddLit(&buf, "raw");
1616 break;
1617 case VIR_STORAGE_FILE_VHD:
1618 virBufferAddLit(&buf, "xvhd");
1619 break;
1620 case VIR_STORAGE_FILE_QCOW:
1621 virBufferAddLit(&buf, "qcow");
1622 break;
1623 case VIR_STORAGE_FILE_QCOW2:
1624 virBufferAddLit(&buf, "qcow2");
1625 break;
1626 case VIR_STORAGE_FILE_QED:
1627 virBufferAddLit(&buf, "qed");
1628 break;
1629 /* set default */
1630 default:
1631 virBufferAddLit(&buf, "raw");
1632 }
1633
1634 /* device */
1635 virBufferAsprintf(&buf, ",vdev=%s", disk->dst);
1636
1637 /* access */
1638 virBufferAddLit(&buf, ",access=");
1639 if (disk->src->readonly)
1640 virBufferAddLit(&buf, "ro");
1641 else if (disk->src->shared)
1642 virBufferAddLit(&buf, "!");
1643 else
1644 virBufferAddLit(&buf, "rw");
1645 if (disk->transient) {
1646 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
1647 _("transient disks not supported yet"));
1648 return -1;
1649 }
1650
1651 /* backendtype */
1652 if (driver) {
1653 virBufferAddLit(&buf, ",backendtype=");
1654 if (STREQ(driver, "qemu") || STREQ(driver, "file"))
1655 virBufferAddLit(&buf, "qdisk");
1656 else if (STREQ(driver, "tap"))
1657 virBufferAddLit(&buf, "tap");
1658 else if (STREQ(driver, "phy"))
1659 virBufferAddLit(&buf, "phy");
1660 }
1661
1662 /* devtype */
1663 if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM)
1664 virBufferAddLit(&buf, ",devtype=cdrom");
1665
1666 /*
1667 * target
1668 * From $xensrc/docs/misc/xl-disk-configuration.txt:
1669 * When this parameter is specified by name, ie with the "target="
1670 * syntax in the configuration file, it consumes the whole rest of the
1671 * <diskspec> including trailing whitespaces. Therefore in that case
1672 * it must come last.
1673 */
1674 if (xenFormatXLDiskSrc(disk->src, &target) < 0)
1675 return -1;
1676
1677 if (target)
1678 virBufferAsprintf(&buf, ",target=%s", target);
1679
1680 val = g_new0(virConfValue, 1);
1681
1682 val->type = VIR_CONF_STRING;
1683 val->str = virBufferContentAndReset(&buf);
1684 tmp = list->list;
1685 while (tmp && tmp->next)
1686 tmp = tmp->next;
1687 if (tmp)
1688 tmp->next = val;
1689 else
1690 list->list = val;
1691
1692 return 0;
1693 }
1694
1695
1696 static int
xenFormatXLDomainDisks(virConf * conf,virDomainDef * def)1697 xenFormatXLDomainDisks(virConf *conf, virDomainDef *def)
1698 {
1699 virConfValue *diskVal;
1700 size_t i;
1701
1702 diskVal = g_new0(virConfValue, 1);
1703
1704 diskVal->type = VIR_CONF_LIST;
1705 diskVal->list = NULL;
1706
1707 for (i = 0; i < def->ndisks; i++) {
1708 if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY)
1709 continue;
1710
1711 if (xenFormatXLDisk(diskVal, def->disks[i]) < 0)
1712 goto cleanup;
1713 }
1714
1715 if (diskVal->list != NULL) {
1716 int ret = virConfSetValue(conf, "disk", diskVal);
1717 diskVal = NULL;
1718 if (ret < 0)
1719 return -1;
1720 }
1721 VIR_FREE(diskVal);
1722
1723 return 0;
1724
1725 cleanup:
1726 virConfFreeValue(diskVal);
1727 return -1;
1728 }
1729
1730
1731 static int
xenFormatXLSpice(virConf * conf,virDomainDef * def)1732 xenFormatXLSpice(virConf *conf, virDomainDef *def)
1733 {
1734 virDomainGraphicsListenDef *glisten;
1735 virDomainGraphicsDef *graphics;
1736
1737 if (def->os.type == VIR_DOMAIN_OSTYPE_HVM && def->graphics) {
1738 graphics = def->graphics[0];
1739
1740 if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
1741 /* set others to false but may not be necessary */
1742 if (xenConfigSetInt(conf, "sdl", 0) < 0)
1743 return -1;
1744
1745 if (xenConfigSetInt(conf, "vnc", 0) < 0)
1746 return -1;
1747
1748 if (xenConfigSetInt(conf, "spice", 1) < 0)
1749 return -1;
1750
1751 if ((glisten = virDomainGraphicsGetListen(graphics, 0)) &&
1752 glisten->address &&
1753 xenConfigSetString(conf, "spicehost", glisten->address) < 0)
1754 return -1;
1755
1756 if (xenConfigSetInt(conf, "spiceport",
1757 graphics->data.spice.port) < 0)
1758 return -1;
1759
1760 if (xenConfigSetInt(conf, "spicetls_port",
1761 graphics->data.spice.tlsPort) < 0)
1762 return -1;
1763
1764 if (graphics->data.spice.auth.passwd) {
1765 if (xenConfigSetInt(conf, "spicedisable_ticketing", 0) < 0)
1766 return -1;
1767
1768 if (xenConfigSetString(conf, "spicepasswd",
1769 graphics->data.spice.auth.passwd) < 0)
1770 return -1;
1771 } else {
1772 if (xenConfigSetInt(conf, "spicedisable_ticketing", 1) < 0)
1773 return -1;
1774 }
1775
1776 if (graphics->data.spice.mousemode) {
1777 switch (graphics->data.spice.mousemode) {
1778 case VIR_DOMAIN_GRAPHICS_SPICE_MOUSE_MODE_SERVER:
1779 if (xenConfigSetInt(conf, "spiceagent_mouse", 0) < 0)
1780 return -1;
1781 break;
1782 case VIR_DOMAIN_GRAPHICS_SPICE_MOUSE_MODE_CLIENT:
1783 if (xenConfigSetInt(conf, "spiceagent_mouse", 1) < 0)
1784 return -1;
1785 /*
1786 * spicevdagent must be enabled if using client
1787 * mode mouse
1788 */
1789 if (xenConfigSetInt(conf, "spicevdagent", 1) < 0)
1790 return -1;
1791 break;
1792 case VIR_DOMAIN_GRAPHICS_SPICE_MOUSE_MODE_DEFAULT:
1793 break;
1794 case VIR_DOMAIN_GRAPHICS_SPICE_MOUSE_MODE_LAST:
1795 default:
1796 virReportEnumRangeError(virDomainGraphicsSpiceMouseMode,
1797 graphics->data.spice.mousemode);
1798 return -1;
1799 }
1800 }
1801
1802 if (graphics->data.spice.copypaste == VIR_TRISTATE_BOOL_YES) {
1803 if (xenConfigSetInt(conf, "spice_clipboard_sharing", 1) < 0)
1804 return -1;
1805 /*
1806 * spicevdagent must be enabled if spice_clipboard_sharing
1807 * is enabled
1808 */
1809 if (xenConfigSetInt(conf, "spicevdagent", 1) < 0)
1810 return -1;
1811 }
1812 }
1813 }
1814
1815 return 0;
1816 }
1817
1818 static int
xenFormatXLInputDevs(virConf * conf,virDomainDef * def)1819 xenFormatXLInputDevs(virConf *conf, virDomainDef *def)
1820 {
1821 size_t i;
1822 const char *devtype;
1823 virConfValue *usbdevices = NULL;
1824 virConfValue *lastdev;
1825
1826 if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) {
1827 usbdevices = g_new0(virConfValue, 1);
1828 usbdevices->type = VIR_CONF_LIST;
1829 usbdevices->list = NULL;
1830 lastdev = NULL;
1831 for (i = 0; i < def->ninputs; i++) {
1832 if (def->inputs[i]->bus == VIR_DOMAIN_INPUT_BUS_USB) {
1833 if (xenConfigSetInt(conf, "usb", 1) < 0)
1834 goto error;
1835
1836 switch (def->inputs[i]->type) {
1837 case VIR_DOMAIN_INPUT_TYPE_MOUSE:
1838 devtype = "mouse";
1839 break;
1840 case VIR_DOMAIN_INPUT_TYPE_TABLET:
1841 devtype = "tablet";
1842 break;
1843 case VIR_DOMAIN_INPUT_TYPE_KBD:
1844 devtype = "keyboard";
1845 break;
1846 default:
1847 continue;
1848 }
1849
1850 if (lastdev == NULL) {
1851 lastdev = g_new0(virConfValue, 1);
1852 usbdevices->list = lastdev;
1853 } else {
1854 lastdev->next = g_new0(virConfValue, 1);
1855 lastdev = lastdev->next;
1856 }
1857 lastdev->type = VIR_CONF_STRING;
1858 lastdev->str = g_strdup(devtype);
1859 }
1860 }
1861 if (usbdevices->list != NULL) {
1862 if (usbdevices->list->next == NULL) {
1863 /* for compatibility with Xen <= 4.2, use old syntax when
1864 * only one device present */
1865 if (xenConfigSetString(conf, "usbdevice", usbdevices->list->str) < 0)
1866 goto error;
1867 virConfFreeValue(usbdevices);
1868 } else {
1869 virConfSetValue(conf, "usbdevice", usbdevices);
1870 }
1871 } else {
1872 VIR_FREE(usbdevices);
1873 }
1874 }
1875
1876 return 0;
1877 error:
1878 virConfFreeValue(usbdevices);
1879 return -1;
1880 }
1881
1882 static int
xenFormatXLUSBController(virConf * conf,virDomainDef * def)1883 xenFormatXLUSBController(virConf *conf,
1884 virDomainDef *def)
1885 {
1886 virConfValue *usbctrlVal = NULL;
1887 int hasUSBCtrl = 0;
1888 size_t i;
1889
1890 for (i = 0; i < def->ncontrollers; i++) {
1891 if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_USB) {
1892 hasUSBCtrl = 1;
1893 break;
1894 }
1895 }
1896
1897 if (!hasUSBCtrl)
1898 return 0;
1899
1900 usbctrlVal = g_new0(virConfValue, 1);
1901
1902 usbctrlVal->type = VIR_CONF_LIST;
1903 usbctrlVal->list = NULL;
1904
1905 for (i = 0; i < def->ncontrollers; i++) {
1906 if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_USB) {
1907 virConfValue *val;
1908 virConfValue *tmp;
1909 g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
1910
1911 if (def->controllers[i]->model != -1) {
1912 switch (def->controllers[i]->model) {
1913 case VIR_DOMAIN_CONTROLLER_MODEL_USB_QUSB1:
1914 virBufferAddLit(&buf, "type=qusb,version=1,");
1915 break;
1916
1917 case VIR_DOMAIN_CONTROLLER_MODEL_USB_QUSB2:
1918 virBufferAddLit(&buf, "type=qusb,version=2,");
1919 break;
1920
1921 default:
1922 goto error;
1923 }
1924 }
1925
1926 if (def->controllers[i]->opts.usbopts.ports != -1)
1927 virBufferAsprintf(&buf, "ports=%x",
1928 def->controllers[i]->opts.usbopts.ports);
1929
1930 val = g_new0(virConfValue, 1);
1931 val->type = VIR_CONF_STRING;
1932 val->str = virBufferContentAndReset(&buf);
1933 tmp = usbctrlVal->list;
1934 while (tmp && tmp->next)
1935 tmp = tmp->next;
1936 if (tmp)
1937 tmp->next = val;
1938 else
1939 usbctrlVal->list = val;
1940 }
1941 }
1942
1943 if (usbctrlVal->list != NULL) {
1944 int ret = virConfSetValue(conf, "usbctrl", usbctrlVal);
1945 usbctrlVal = NULL;
1946 if (ret < 0)
1947 return -1;
1948 }
1949 VIR_FREE(usbctrlVal);
1950
1951 return 0;
1952
1953 error:
1954 virConfFreeValue(usbctrlVal);
1955 return -1;
1956 }
1957
1958
1959 static int
xenFormatXLUSB(virConf * conf,virDomainDef * def)1960 xenFormatXLUSB(virConf *conf,
1961 virDomainDef *def)
1962 {
1963 virConfValue *usbVal = NULL;
1964 int hasUSB = 0;
1965 size_t i;
1966
1967 for (i = 0; i < def->nhostdevs; i++) {
1968 if (def->hostdevs[i]->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
1969 def->hostdevs[i]->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
1970 hasUSB = 1;
1971 break;
1972 }
1973 }
1974
1975 if (!hasUSB)
1976 return 0;
1977
1978 usbVal = g_new0(virConfValue, 1);
1979
1980 usbVal->type = VIR_CONF_LIST;
1981 usbVal->list = NULL;
1982
1983 for (i = 0; i < def->nhostdevs; i++) {
1984 if (def->hostdevs[i]->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
1985 def->hostdevs[i]->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
1986 virConfValue *val;
1987 virConfValue *tmp;
1988 char *buf;
1989
1990 buf = g_strdup_printf("hostbus=%x,hostaddr=%x",
1991 def->hostdevs[i]->source.subsys.u.usb.bus,
1992 def->hostdevs[i]->source.subsys.u.usb.device);
1993
1994 val = g_new0(virConfValue, 1);
1995 val->type = VIR_CONF_STRING;
1996 val->str = buf;
1997 tmp = usbVal->list;
1998 while (tmp && tmp->next)
1999 tmp = tmp->next;
2000 if (tmp)
2001 tmp->next = val;
2002 else
2003 usbVal->list = val;
2004 }
2005 }
2006
2007 if (usbVal->list != NULL) {
2008 int ret = virConfSetValue(conf, "usbdev", usbVal);
2009 usbVal = NULL;
2010 if (ret < 0)
2011 return -1;
2012 }
2013 VIR_FREE(usbVal);
2014
2015 return 0;
2016 }
2017
2018 static int
xenFormatXLChannel(virConfValue * list,virDomainChrDef * channel)2019 xenFormatXLChannel(virConfValue *list, virDomainChrDef *channel)
2020 {
2021 g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
2022 int sourceType = channel->source->type;
2023 virConfValue *val;
2024 virConfValue *tmp;
2025
2026 /* connection */
2027 virBufferAddLit(&buf, "connection=");
2028 switch (sourceType) {
2029 case VIR_DOMAIN_CHR_TYPE_PTY:
2030 virBufferAddLit(&buf, "pty,");
2031 break;
2032 case VIR_DOMAIN_CHR_TYPE_UNIX:
2033 virBufferAddLit(&buf, "socket,");
2034 /* path */
2035 if (channel->source->data.nix.path)
2036 virBufferAsprintf(&buf, "path=%s,",
2037 channel->source->data.nix.path);
2038 break;
2039 default:
2040 return -1;
2041 }
2042
2043 /* name */
2044 virBufferAsprintf(&buf, "name=%s", channel->target.name);
2045
2046 val = g_new0(virConfValue, 1);
2047 val->type = VIR_CONF_STRING;
2048 val->str = virBufferContentAndReset(&buf);
2049 tmp = list->list;
2050 while (tmp && tmp->next)
2051 tmp = tmp->next;
2052 if (tmp)
2053 tmp->next = val;
2054 else
2055 list->list = val;
2056 return 0;
2057 }
2058
2059 static int
xenFormatXLDomainChannels(virConf * conf,virDomainDef * def)2060 xenFormatXLDomainChannels(virConf *conf, virDomainDef *def)
2061 {
2062 virConfValue *channelVal = NULL;
2063 size_t i;
2064
2065 channelVal = g_new0(virConfValue, 1);
2066
2067 channelVal->type = VIR_CONF_LIST;
2068 channelVal->list = NULL;
2069
2070 for (i = 0; i < def->nchannels; i++) {
2071 virDomainChrDef *chr = def->channels[i];
2072
2073 if (chr->targetType != VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_XEN)
2074 continue;
2075
2076 if (xenFormatXLChannel(channelVal, def->channels[i]) < 0)
2077 goto cleanup;
2078 }
2079
2080 if (channelVal->list != NULL) {
2081 int ret = virConfSetValue(conf, "channel", channelVal);
2082 channelVal = NULL;
2083 if (ret < 0)
2084 goto cleanup;
2085 }
2086
2087 VIR_FREE(channelVal);
2088 return 0;
2089
2090 cleanup:
2091 virConfFreeValue(channelVal);
2092 return -1;
2093 }
2094
2095 static int
xenFormatXLDomainNamespaceData(virConf * conf,virDomainDef * def)2096 xenFormatXLDomainNamespaceData(virConf *conf, virDomainDef *def)
2097 {
2098 libxlDomainXmlNsDef *nsdata = def->namespaceData;
2099 virConfValue *args = NULL;
2100 size_t i;
2101
2102 if (!nsdata)
2103 return 0;
2104
2105 if (nsdata->num_args == 0)
2106 return 0;
2107
2108 args = g_new0(virConfValue, 1);
2109
2110 args->type = VIR_CONF_LIST;
2111 args->list = NULL;
2112
2113 for (i = 0; i < nsdata->num_args; i++) {
2114 virConfValue *val;
2115 virConfValue *tmp;
2116
2117 val = g_new0(virConfValue, 1);
2118
2119 val->type = VIR_CONF_STRING;
2120 val->str = g_strdup(nsdata->args[i]);
2121 tmp = args->list;
2122 while (tmp && tmp->next)
2123 tmp = tmp->next;
2124 if (tmp)
2125 tmp->next = val;
2126 else
2127 args->list = val;
2128 }
2129
2130 if (args->list != NULL)
2131 if (virConfSetValue(conf, "device_model_args", args) < 0)
2132 goto error;
2133
2134 return 0;
2135
2136 error:
2137 virConfFreeValue(args);
2138 return -1;
2139 }
2140
2141 virConf *
xenFormatXL(virDomainDef * def,virConnectPtr conn)2142 xenFormatXL(virDomainDef *def, virConnectPtr conn)
2143 {
2144 g_autoptr(virConf) conf = NULL;
2145
2146 if (!(conf = virConfNew()))
2147 return NULL;
2148
2149 if (xenFormatConfigCommon(conf, def, conn, XEN_CONFIG_FORMAT_XL) < 0)
2150 return NULL;
2151
2152 if (xenFormatXLOS(conf, def) < 0)
2153 return NULL;
2154
2155 if (xenFormatXLCPUID(conf, def) < 0)
2156 return NULL;
2157
2158 if (xenFormatXLDomainVnuma(conf, def) < 0)
2159 return NULL;
2160
2161 if (xenFormatXLXenbusLimits(conf, def) < 0)
2162 return NULL;
2163
2164 if (xenFormatXLDomainDisks(conf, def) < 0)
2165 return NULL;
2166
2167 if (xenFormatXLSpice(conf, def) < 0)
2168 return NULL;
2169
2170 if (xenFormatXLInputDevs(conf, def) < 0)
2171 return NULL;
2172
2173 if (xenFormatXLUSB(conf, def) < 0)
2174 return NULL;
2175
2176 if (xenFormatXLUSBController(conf, def) < 0)
2177 return NULL;
2178
2179 if (xenFormatXLDomainChannels(conf, def) < 0)
2180 return NULL;
2181
2182 if (xenFormatXLDomainNamespaceData(conf, def) < 0)
2183 return NULL;
2184
2185 return g_steal_pointer(&conf);
2186 }
2187