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