xen_xm.c 16.9 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
        VIR_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
        VIR_AUTOFREE(char *) extra = NULL;
        VIR_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 94
            if (virAsprintf(&def->os.cmdline, "root=%s %s", root, extra) < 0)
                return -1;
95 96 97 98
        } else if (root) {
            if (virAsprintf(&def->os.cmdline, "root=%s", root) < 0)
                return -1;
        } else if (extra) {
99 100 101 102 103 104 105 106 107
            if (VIR_STRDUP(def->os.cmdline, extra) < 0)
                return -1;
        }
    }

    return 0;
}


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

117 118
    if (!(disk = virDomainDiskDefNew(NULL)))
        return NULL;
119

120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
    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 {
        if (VIR_STRNDUP(tmp, head, offset - head) < 0)
            goto error;
139

140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
        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,
160
                   (offset - head) + 1) < 0) {
161 162 163 164
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Dest file %s too big for destination"), head);
        goto error;
    }
165

166 167 168 169 170 171 172 173 174 175 176 177
    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) {
178
                VIR_FREE(tmp);
179
                goto error;
180
            }
181
            VIR_FREE(tmp);
182

183 184 185
            /* Strip the prefix we found off the source file name */
            if (virDomainDiskSetSource(disk, src + len + 1) < 0)
                goto error;
186

187 188
            src = virDomainDiskGetSource(disk);
        }
189

190 191 192 193
        /* And the sub-type for tap:XXX: type */
        if (STREQ_NULLABLE(virDomainDiskGetDriver(disk), "tap") ||
            STREQ_NULLABLE(virDomainDiskGetDriver(disk), "tap2")) {
            char *driverType;
194

195 196 197 198 199 200 201 202 203 204 205 206 207 208
            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) {
209
                virReportError(VIR_ERR_INTERNAL_ERROR,
210 211 212
                               _("Unknown driver type %s"),
                               src);
                goto error;
213 214
            }

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

222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
    /* 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';
    }
240

241 242 243 244 245 246
    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;
247

248 249 250 251
    if (STREQ(head, "r") || STREQ(head, "ro"))
        disk->src->readonly = true;
    else if (STREQ(head, "w!") || STREQ(head, "!"))
        disk->src->shared = true;
252

253
    return disk;
254

255 256 257 258
 error:
    virDomainDiskDefFree(disk);
    return NULL;
}
259

260 261 262 263

static int
xenParseXMDiskList(virConfPtr conf, virDomainDefPtr def)
{
264
    char **disks = NULL, **entries;
265
    int hvm = def->os.type == VIR_DOMAIN_OSTYPE_HVM;
266 267
    int ret = -1;
    int rc;
268

269 270 271
    rc = virConfGetValueStringList(conf, "disk", false, &disks);
    if (rc <= 0)
        return rc;
272

273
    for (entries = disks; *entries; entries++) {
274
        virDomainDiskDefPtr disk;
275
        char *entry = *entries;
276

277
        if (!(disk = xenParseXMDisk(entry, hvm)))
278 279 280 281 282 283 284
            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)
285
            goto cleanup;
286 287
    }

288 289 290 291 292
    ret = 0;

 cleanup:
    virStringListFree(disks);
    return ret;
293 294 295
}


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

306 307 308
    if (src) {
        if (format) {
            const char *type;
309

310 311 312 313
            if (format == VIR_STORAGE_FILE_RAW)
                type = "aio";
            else
                type = virStorageFileFormatTypeToString(format);
314 315 316

            if (driver) {
                virBufferAsprintf(&buf, "%s:", driver);
317
                if (STREQ(driver, "tap") || STREQ(driver, "tap2"))
318 319
                    virBufferAsprintf(&buf, "%s:", type);
            }
320
        } else {
321 322 323 324 325 326 327 328 329 330 331
            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)));
332 333 334
                goto cleanup;
            }
        }
335
        virBufferAdd(&buf, src, -1);
336
    }
337
    virBufferAddLit(&buf, ",");
338

339 340 341
    virBufferAdd(&buf, disk->dst, -1);
    if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM)
        virBufferAddLit(&buf, ":cdrom");
342

343 344 345 346 347 348 349 350 351
    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"));
352 353 354
        return -1;
    }

355 356
    if (virBufferCheckError(&buf) < 0)
        goto cleanup;
357

358 359
    if (VIR_ALLOC(val) < 0)
        goto cleanup;
360

361 362 363 364 365 366 367 368 369
    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;
370 371

    return 0;
372

373 374 375
 cleanup:
    virBufferFreeAndReset(&buf);
    return -1;
376 377 378
}


379
static int
380
xenFormatXMDisks(virConfPtr conf, virDomainDefPtr def)
381 382 383 384 385 386 387 388 389 390 391 392 393 394
{
    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;

395
        if (xenFormatXMDisk(diskVal, def->disks[i]) < 0)
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414
            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;
}


415 416 417
static int
xenParseXMInputDevs(virConfPtr conf, virDomainDefPtr def)
{
418
    VIR_AUTOFREE(char *) str = NULL;
419

420
    if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) {
421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446
        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;
}

447 448 449 450 451
/*
 * Convert an XM config record into a virDomainDef object.
 */
virDomainDefPtr
xenParseXM(virConfPtr conf,
452 453
           virCapsPtr caps,
           virDomainXMLOptionPtr xmlopt)
454
{
455
    virDomainDefPtr def = NULL;
456

457
    if (!(def = virDomainDefNew()))
458
        return NULL;
459

460 461
    def->virtType = VIR_DOMAIN_VIRT_XEN;
    def->id = -1;
462

463 464
    if (xenParseConfigCommon(conf, def, caps, XEN_CONFIG_FORMAT_XM,
                             xmlopt) < 0)
465 466
        goto cleanup;

467 468 469
    if (xenParseXMOS(conf, def) < 0)
         goto cleanup;

470
    if (xenParseXMDiskList(conf, def) < 0)
471
         goto cleanup;
472

473 474 475
    if (xenParseXMInputDevs(conf, def) < 0)
         goto cleanup;

476
    if (virDomainDefPostParse(def, caps, VIR_DOMAIN_DEF_PARSE_ABI_UPDATE,
477
                              xmlopt, NULL) < 0)
478 479
        goto cleanup;

480
    return def;
481 482

 cleanup:
483 484
    virDomainDefFree(def);
    return NULL;
485 486
}

487 488 489 490 491
static int
xenFormatXMOS(virConfPtr conf, virDomainDefPtr def)
{
    size_t i;

492
    if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) {
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 549 550 551 552 553 554 555
        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;
}


556 557 558 559 560 561
static int
xenFormatXMInputDevs(virConfPtr conf, virDomainDefPtr def)
{
    size_t i;
    const char *devtype;

562
    if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) {
563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589
        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;
}

590 591 592 593 594

/* 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);

595
/*
M
Martin Kletzander 已提交
596
 * Convert a virDomainDef object into an XM config record.
597
 */
598 599
virConfPtr
xenFormatXM(virConnectPtr conn,
600
            virDomainDefPtr def)
601 602 603 604 605 606
{
    virConfPtr conf = NULL;

    if (!(conf = virConfNew()))
        goto cleanup;

607
    if (xenFormatConfigCommon(conf, def, conn, XEN_CONFIG_FORMAT_XM) < 0)
608 609
        goto cleanup;

610 611 612
    if (xenFormatXMOS(conf, def) < 0)
        goto cleanup;

613
    if (xenFormatXMDisks(conf, def) < 0)
614
        goto cleanup;
615

616 617 618
    if (xenFormatXMInputDevs(conf, def) < 0)
        goto cleanup;

619 620
    return conf;

621
 cleanup:
622 623
    if (conf)
        virConfFree(conf);
624
    return NULL;
625
}