xen_xm.c 16.6 KB
Newer Older
1 2 3
/*
 * xen_xm.c: Xen XM parsing functions
 *
4
 * Copyright (C) 2006-2007, 2009-2014 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16 17 18
 * Copyright (C) 2011 Univention GmbH
 * Copyright (C) 2006 Daniel P. Berrange
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
19
 * License along with this library.  If not, see
O
Osier Yang 已提交
20
 * <http://www.gnu.org/licenses/>.
21 22 23 24 25
 */

#include <config.h>

#include "internal.h"
26
#include "virerror.h"
27
#include "virconf.h"
28
#include "viralloc.h"
29 30 31
#include "verify.h"
#include "xenxs_private.h"
#include "xen_xm.h"
M
Michal Novotny 已提交
32
#include "domain_conf.h"
33
#include "virstring.h"
34
#include "xen_common.h"
35

J
Jim Fehlig 已提交
36
#define VIR_FROM_THIS VIR_FROM_XENXM
37

38 39 40 41 42
static int
xenParseXMOS(virConfPtr conf, virDomainDefPtr def)
{
    size_t i;

43
    if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) {
44
        g_autofree char *boot = NULL;
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71

        if (VIR_ALLOC(def->os.loader) < 0 ||
            xenConfigCopyString(conf, "kernel", &def->os.loader->path) < 0)
            return -1;

        if (xenConfigGetString(conf, "boot", &boot, "c") < 0)
            return -1;

        for (i = 0; i < VIR_DOMAIN_BOOT_LAST && boot[i]; i++) {
            switch (boot[i]) {
            case 'a':
                def->os.bootDevs[i] = VIR_DOMAIN_BOOT_FLOPPY;
                break;
            case 'd':
                def->os.bootDevs[i] = VIR_DOMAIN_BOOT_CDROM;
                break;
            case 'n':
                def->os.bootDevs[i] = VIR_DOMAIN_BOOT_NET;
                break;
            case 'c':
            default:
                def->os.bootDevs[i] = VIR_DOMAIN_BOOT_DISK;
                break;
            }
            def->os.nBootDevs++;
        }
    } else {
72 73
        g_autofree char *extra = NULL;
        g_autofree char *root = NULL;
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91

        if (xenConfigCopyStringOpt(conf, "bootloader", &def->os.bootloader) < 0)
            return -1;
        if (xenConfigCopyStringOpt(conf, "bootargs", &def->os.bootloaderArgs) < 0)
            return -1;

        if (xenConfigCopyStringOpt(conf, "kernel", &def->os.kernel) < 0)
            return -1;

        if (xenConfigCopyStringOpt(conf, "ramdisk", &def->os.initrd) < 0)
            return -1;

        if (xenConfigGetString(conf, "extra", &extra, NULL) < 0)
            return -1;

        if (xenConfigGetString(conf, "root", &root, NULL) < 0)
            return -1;

92
        if (root && extra) {
93
            def->os.cmdline = g_strdup_printf("root=%s %s", root, extra);
94
        } else if (root) {
95
            def->os.cmdline = g_strdup_printf("root=%s", root);
96
        } else if (extra) {
97
            def->os.cmdline = g_strdup(extra);
98 99 100 101 102 103 104
        }
    }

    return 0;
}


105 106
static virDomainDiskDefPtr
xenParseXMDisk(char *entry, int hvm)
107
{
108
    virDomainDiskDefPtr disk = NULL;
109 110 111 112
    char *head;
    char *offset;
    char *tmp;
    const char *src;
113

114 115
    if (!(disk = virDomainDiskDefNew(NULL)))
        return NULL;
116

117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
    head = entry;
    /*
     * Disks have 3 components, SOURCE,DEST-DEVICE,MODE
     * eg, phy:/dev/HostVG/XenGuest1,xvda,w
     * The SOURCE is usually prefixed with a driver type,
     * and optionally driver sub-type
     * The DEST-DEVICE is optionally post-fixed with disk type
     */

    /* Extract the source file path*/
    if (!(offset = strchr(head, ',')))
        goto error;

    if (offset == head) {
        /* No source file given, eg CDROM with no media */
        ignore_value(virDomainDiskSetSource(disk, NULL));
    } else {
134
        tmp = g_strndup(head, offset - head);
135

136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
        if (virDomainDiskSetSource(disk, tmp) < 0) {
            VIR_FREE(tmp);
            goto error;
        }
        VIR_FREE(tmp);
    }

    head = offset + 1;
    /* Remove legacy ioemu: junk */
    if (STRPREFIX(head, "ioemu:"))
        head = head + 6;

    /* Extract the dest device name */
    if (!(offset = strchr(head, ',')))
        goto error;

    if (VIR_ALLOC_N(disk->dst, (offset - head) + 1) < 0)
        goto error;

    if (virStrncpy(disk->dst, head, offset - head,
156
                   (offset - head) + 1) < 0) {
157 158 159 160
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Dest file %s too big for destination"), head);
        goto error;
    }
161

162 163 164 165 166 167 168 169 170 171 172 173
    head = offset + 1;
    /* Extract source driver type */
    src = virDomainDiskGetSource(disk);
    if (src) {
        size_t len;
        /* The main type  phy:, file:, tap: ... */
        if ((tmp = strchr(src, ':')) != NULL) {
            len = tmp - src;
            if (VIR_STRNDUP(tmp, src, len) < 0)
                goto error;

            if (virDomainDiskSetDriver(disk, tmp) < 0) {
174
                VIR_FREE(tmp);
175
                goto error;
176
            }
177
            VIR_FREE(tmp);
178

179 180 181
            /* Strip the prefix we found off the source file name */
            if (virDomainDiskSetSource(disk, src + len + 1) < 0)
                goto error;
182

183 184
            src = virDomainDiskGetSource(disk);
        }
185

186 187 188 189
        /* And the sub-type for tap:XXX: type */
        if (STREQ_NULLABLE(virDomainDiskGetDriver(disk), "tap") ||
            STREQ_NULLABLE(virDomainDiskGetDriver(disk), "tap2")) {
            char *driverType;
190

191 192 193 194 195 196 197 198 199 200 201 202 203 204
            if (!(tmp = strchr(src, ':')))
                goto error;
            len = tmp - src;

            if (VIR_STRNDUP(driverType, src, len) < 0)
                goto error;

            if (STREQ(driverType, "aio"))
                virDomainDiskSetFormat(disk, VIR_STORAGE_FILE_RAW);
            else
                virDomainDiskSetFormat(disk,
                                       virStorageFileFormatTypeFromString(driverType));
            VIR_FREE(driverType);
            if (virDomainDiskGetFormat(disk) <= 0) {
205
                virReportError(VIR_ERR_INTERNAL_ERROR,
206 207 208
                               _("Unknown driver type %s"),
                               src);
                goto error;
209 210
            }

211 212 213
            /* Strip the prefix we found off the source file name */
            if (virDomainDiskSetSource(disk, src + len + 1) < 0)
                goto error;
214
            src = virDomainDiskGetSource(disk);
215 216
        }
    }
217

218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
    /* No source, or driver name, so fix to phy: */
    if (!virDomainDiskGetDriver(disk) &&
        virDomainDiskSetDriver(disk, "phy") < 0)
        goto error;

    /* phy: type indicates a block device */
    virDomainDiskSetType(disk,
                         STREQ(virDomainDiskGetDriver(disk), "phy") ?
                         VIR_STORAGE_TYPE_BLOCK :
                         VIR_STORAGE_TYPE_FILE);

    /* Check for a :cdrom/:disk postfix */
    disk->device = VIR_DOMAIN_DISK_DEVICE_DISK;
    if ((tmp = strchr(disk->dst, ':')) != NULL) {
        if (STREQ(tmp, ":cdrom"))
            disk->device = VIR_DOMAIN_DISK_DEVICE_CDROM;
        tmp[0] = '\0';
    }
236

237 238 239 240 241 242
    if (STRPREFIX(disk->dst, "xvd") || !hvm)
        disk->bus = VIR_DOMAIN_DISK_BUS_XEN;
    else if (STRPREFIX(disk->dst, "sd"))
        disk->bus = VIR_DOMAIN_DISK_BUS_SCSI;
    else
        disk->bus = VIR_DOMAIN_DISK_BUS_IDE;
243

244 245 246 247
    if (STREQ(head, "r") || STREQ(head, "ro"))
        disk->src->readonly = true;
    else if (STREQ(head, "w!") || STREQ(head, "!"))
        disk->src->shared = true;
248

249
    return disk;
250

251 252 253 254
 error:
    virDomainDiskDefFree(disk);
    return NULL;
}
255

256 257 258 259

static int
xenParseXMDiskList(virConfPtr conf, virDomainDefPtr def)
{
260
    char **disks = NULL, **entries;
261
    int hvm = def->os.type == VIR_DOMAIN_OSTYPE_HVM;
262 263
    int ret = -1;
    int rc;
264

265 266 267
    rc = virConfGetValueStringList(conf, "disk", false, &disks);
    if (rc <= 0)
        return rc;
268

269
    for (entries = disks; *entries; entries++) {
270
        virDomainDiskDefPtr disk;
271
        char *entry = *entries;
272

273
        if (!(disk = xenParseXMDisk(entry, hvm)))
274 275 276 277 278 279 280
            continue;

        /* Maintain list in sorted order according to target device name */
        rc = VIR_APPEND_ELEMENT(def->disks, def->ndisks, disk);
        virDomainDiskDefFree(disk);

        if (rc < 0)
281
            goto cleanup;
282 283
    }

284 285 286 287 288
    ret = 0;

 cleanup:
    virStringListFree(disks);
    return ret;
289 290 291
}


292
static int
293
xenFormatXMDisk(virConfValuePtr list,
294
                virDomainDiskDefPtr disk)
295
{
296 297 298 299 300
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    virConfValuePtr val, tmp;
    const char *src = virDomainDiskGetSource(disk);
    int format = virDomainDiskGetFormat(disk);
    const char *driver = virDomainDiskGetDriver(disk);
301

302 303 304
    if (src) {
        if (format) {
            const char *type;
305

306 307 308 309
            if (format == VIR_STORAGE_FILE_RAW)
                type = "aio";
            else
                type = virStorageFileFormatTypeToString(format);
310 311 312

            if (driver) {
                virBufferAsprintf(&buf, "%s:", driver);
313
                if (STREQ(driver, "tap") || STREQ(driver, "tap2"))
314 315
                    virBufferAsprintf(&buf, "%s:", type);
            }
316
        } else {
317 318 319 320 321 322 323 324 325 326 327
            switch (virDomainDiskGetType(disk)) {
            case VIR_STORAGE_TYPE_FILE:
                virBufferAddLit(&buf, "file:");
                break;
            case VIR_STORAGE_TYPE_BLOCK:
                virBufferAddLit(&buf, "phy:");
                break;
            default:
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unsupported disk type %s"),
                               virStorageTypeToString(virDomainDiskGetType(disk)));
328 329 330
                goto cleanup;
            }
        }
331
        virBufferAdd(&buf, src, -1);
332
    }
333
    virBufferAddLit(&buf, ",");
334

335 336 337
    virBufferAdd(&buf, disk->dst, -1);
    if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM)
        virBufferAddLit(&buf, ":cdrom");
338

339 340 341 342 343 344 345 346 347
    if (disk->src->readonly)
        virBufferAddLit(&buf, ",r");
    else if (disk->src->shared)
        virBufferAddLit(&buf, ",!");
    else
        virBufferAddLit(&buf, ",w");
    if (disk->transient) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("transient disks not supported yet"));
348 349 350
        return -1;
    }

351 352
    if (VIR_ALLOC(val) < 0)
        goto cleanup;
353

354 355 356 357 358 359 360 361 362
    val->type = VIR_CONF_STRING;
    val->str = virBufferContentAndReset(&buf);
    tmp = list->list;
    while (tmp && tmp->next)
        tmp = tmp->next;
    if (tmp)
        tmp->next = val;
    else
        list->list = val;
363 364

    return 0;
365

366 367 368
 cleanup:
    virBufferFreeAndReset(&buf);
    return -1;
369 370 371
}


372
static int
373
xenFormatXMDisks(virConfPtr conf, virDomainDefPtr def)
374 375 376 377 378 379 380 381 382 383 384 385 386 387
{
    virConfValuePtr diskVal = NULL;
    size_t i = 0;

    if (VIR_ALLOC(diskVal) < 0)
        goto cleanup;

    diskVal->type = VIR_CONF_LIST;
    diskVal->list = NULL;

    for (i = 0; i < def->ndisks; i++) {
        if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY)
            continue;

388
        if (xenFormatXMDisk(diskVal, def->disks[i]) < 0)
389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407
            goto cleanup;
    }

    if (diskVal->list != NULL) {
        int ret = virConfSetValue(conf, "disk", diskVal);
        diskVal = NULL;
        if (ret < 0)
            goto cleanup;
    }
    VIR_FREE(diskVal);

    return 0;

 cleanup:
    virConfFreeValue(diskVal);
    return -1;
}


408 409 410
static int
xenParseXMInputDevs(virConfPtr conf, virDomainDefPtr def)
{
411
    g_autofree char *str = NULL;
412

413
    if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) {
414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
        if (xenConfigGetString(conf, "usbdevice", &str, NULL) < 0)
            return -1;
        if (str &&
                (STREQ(str, "tablet") ||
                 STREQ(str, "mouse") ||
                 STREQ(str, "keyboard"))) {
            virDomainInputDefPtr input;
            if (VIR_ALLOC(input) < 0)
                return -1;

            input->bus = VIR_DOMAIN_INPUT_BUS_USB;
            if (STREQ(str, "mouse"))
                input->type = VIR_DOMAIN_INPUT_TYPE_MOUSE;
            else if (STREQ(str, "tablet"))
                input->type = VIR_DOMAIN_INPUT_TYPE_TABLET;
            else if (STREQ(str, "keyboard"))
                input->type = VIR_DOMAIN_INPUT_TYPE_KBD;
            if (VIR_APPEND_ELEMENT(def->inputs, def->ninputs, input) < 0) {
                virDomainInputDefFree(input);
                return -1;
            }
        }
    }
    return 0;
}

440 441 442 443 444
/*
 * Convert an XM config record into a virDomainDef object.
 */
virDomainDefPtr
xenParseXM(virConfPtr conf,
445 446
           virCapsPtr caps,
           virDomainXMLOptionPtr xmlopt)
447
{
448
    virDomainDefPtr def = NULL;
449

450
    if (!(def = virDomainDefNew()))
451
        return NULL;
452

453 454
    def->virtType = VIR_DOMAIN_VIRT_XEN;
    def->id = -1;
455

456 457
    if (xenParseConfigCommon(conf, def, caps, XEN_CONFIG_FORMAT_XM,
                             xmlopt) < 0)
458 459
        goto cleanup;

460 461 462
    if (xenParseXMOS(conf, def) < 0)
         goto cleanup;

463
    if (xenParseXMDiskList(conf, def) < 0)
464
         goto cleanup;
465

466 467 468
    if (xenParseXMInputDevs(conf, def) < 0)
         goto cleanup;

469
    if (virDomainDefPostParse(def, VIR_DOMAIN_DEF_PARSE_ABI_UPDATE,
470
                              xmlopt, NULL) < 0)
471 472
        goto cleanup;

473
    return def;
474 475

 cleanup:
476 477
    virDomainDefFree(def);
    return NULL;
478 479
}

480 481 482 483 484
static int
xenFormatXMOS(virConfPtr conf, virDomainDefPtr def)
{
    size_t i;

485
    if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) {
486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548
        char boot[VIR_DOMAIN_BOOT_LAST+1];
        if (xenConfigSetString(conf, "builder", "hvm") < 0)
            return -1;

        if (def->os.loader && def->os.loader->path &&
            xenConfigSetString(conf, "kernel", def->os.loader->path) < 0)
            return -1;

        for (i = 0; i < def->os.nBootDevs; i++) {
            switch (def->os.bootDevs[i]) {
            case VIR_DOMAIN_BOOT_FLOPPY:
                boot[i] = 'a';
                break;
            case VIR_DOMAIN_BOOT_CDROM:
                boot[i] = 'd';
                break;
            case VIR_DOMAIN_BOOT_NET:
                boot[i] = 'n';
                break;
            case VIR_DOMAIN_BOOT_DISK:
            default:
                boot[i] = 'c';
                break;
            }
        }

        if (!def->os.nBootDevs) {
            boot[0] = 'c';
            boot[1] = '\0';
        } else {
            boot[def->os.nBootDevs] = '\0';
        }

        if (xenConfigSetString(conf, "boot", boot) < 0)
            return -1;

        /* XXX floppy disks */
    } else {
        if (def->os.bootloader &&
             xenConfigSetString(conf, "bootloader", def->os.bootloader) < 0)
            return -1;

         if (def->os.bootloaderArgs &&
             xenConfigSetString(conf, "bootargs", def->os.bootloaderArgs) < 0)
            return -1;

         if (def->os.kernel &&
             xenConfigSetString(conf, "kernel", def->os.kernel) < 0)
            return -1;

         if (def->os.initrd &&
             xenConfigSetString(conf, "ramdisk", def->os.initrd) < 0)
            return -1;

         if (def->os.cmdline &&
             xenConfigSetString(conf, "extra", def->os.cmdline) < 0)
            return -1;
     } /* !hvm */

    return 0;
}


549 550 551 552 553 554
static int
xenFormatXMInputDevs(virConfPtr conf, virDomainDefPtr def)
{
    size_t i;
    const char *devtype;

555
    if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) {
556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582
        for (i = 0; i < def->ninputs; i++) {
            if (def->inputs[i]->bus == VIR_DOMAIN_INPUT_BUS_USB) {
                if (xenConfigSetInt(conf, "usb", 1) < 0)
                    return -1;

                switch (def->inputs[i]->type) {
                    case VIR_DOMAIN_INPUT_TYPE_MOUSE:
                        devtype = "mouse";
                        break;
                    case VIR_DOMAIN_INPUT_TYPE_TABLET:
                        devtype = "tablet";
                        break;
                    case VIR_DOMAIN_INPUT_TYPE_KBD:
                        devtype = "keyboard";
                        break;
                    default:
                        continue;
                }
                if (xenConfigSetString(conf, "usbdevice", devtype) < 0)
                    return -1;
                break;
            }
        }
    }
    return 0;
}

583 584 585 586 587

/* Computing the vcpu_avail bitmask works because MAX_VIRT_CPUS is
   either 32, or 64 on a platform where long is big enough.  */
verify(MAX_VIRT_CPUS <= sizeof(1UL) * CHAR_BIT);

588
/*
M
Martin Kletzander 已提交
589
 * Convert a virDomainDef object into an XM config record.
590
 */
591 592
virConfPtr
xenFormatXM(virConnectPtr conn,
593
            virDomainDefPtr def)
594
{
J
Ján Tomko 已提交
595
    g_autoptr(virConf) conf = NULL;
596 597

    if (!(conf = virConfNew()))
598
        return NULL;
599

600
    if (xenFormatConfigCommon(conf, def, conn, XEN_CONFIG_FORMAT_XM) < 0)
601
        return NULL;
602

603
    if (xenFormatXMOS(conf, def) < 0)
604
        return NULL;
605

606
    if (xenFormatXMDisks(conf, def) < 0)
607
        return NULL;
608

609
    if (xenFormatXMInputDevs(conf, def) < 0)
610
        return NULL;
611

J
Ján Tomko 已提交
612
    return g_steal_pointer(&conf);
613
}