xen_xm.c 14.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 26 27 28
 *
 * Author: Daniel P. Berrange <berrange@redhat.com>
 * Author: Markus Groß <gross@univention.de>
 */

#include <config.h>

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


40 41
static int
xenParseXMDisk(virConfPtr conf, virDomainDefPtr def, int xendConfigVersion)
42
{
43
    const char *str = NULL;
44
    virDomainDiskDefPtr disk = NULL;
45 46
    int hvm = STREQ(def->os.type, "hvm");
    virConfValuePtr list = virConfGetValue(conf, "disk");
47 48 49 50 51 52 53

    if (list && list->type == VIR_CONF_LIST) {
        list = list->list;
        while (list) {
            char *head;
            char *offset;
            char *tmp;
54
            const char *src;
55 56 57 58

            if ((list->type != VIR_CONF_STRING) || (list->str == NULL))
                goto skipdisk;

59
            head = list->str;
60
            if (!(disk = virDomainDiskDefNew()))
61
                return -1;
62 63 64 65 66 67 68 69 70 71 72 73 74 75

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

            if (offset == head) {
76 77
                /* No source file given, eg CDROM with no media */
                ignore_value(virDomainDiskSetSource(disk, NULL));
78
            } else {
79
                if (VIR_STRNDUP(tmp, head, offset - head) < 0)
80
                    goto cleanup;
81

82 83
                if (virDomainDiskSetSource(disk, tmp) < 0) {
                    VIR_FREE(tmp);
84 85
                    goto cleanup;
                }
86
                VIR_FREE(tmp);
87 88
            }

89
            head = offset + 1;
90 91 92 93 94 95 96
            /* Remove legacy ioemu: junk */
            if (STRPREFIX(head, "ioemu:"))
                head = head + 6;

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

98
            if (VIR_ALLOC_N(disk->dst, (offset - head) + 1) < 0)
99
                goto cleanup;
100

101 102
            if (virStrncpy(disk->dst, head, offset - head,
                           (offset - head) + 1) == NULL) {
103 104
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Dest file %s too big for destination"), head);
105 106 107
                goto cleanup;
            }

108
            head = offset + 1;
109
            /* Extract source driver type */
110 111 112
            src = virDomainDiskGetSource(disk);
            if (src) {
                size_t len;
113
                /* The main type  phy:, file:, tap: ... */
114 115 116
                if ((tmp = strchr(src, ':')) != NULL) {
                    len = tmp - src;
                    if (VIR_STRNDUP(tmp, src, len) < 0)
117
                        goto cleanup;
118

119 120
                    if (virDomainDiskSetDriver(disk, tmp) < 0) {
                        VIR_FREE(tmp);
121 122
                        goto cleanup;
                    }
123
                    VIR_FREE(tmp);
124 125

                    /* Strip the prefix we found off the source file name */
126 127
                    if (virDomainDiskSetSource(disk, src + len + 1) < 0)
                        goto cleanup;
128

129
                    src = virDomainDiskGetSource(disk);
130 131 132
                }

                /* And the sub-type for tap:XXX: type */
133
                if (STREQ_NULLABLE(virDomainDiskGetDriver(disk), "tap")) {
134 135
                    char *driverType;

136
                    if (!(tmp = strchr(src, ':')))
137
                        goto skipdisk;
138
                    len = tmp - src;
139

140
                    if (VIR_STRNDUP(driverType, src, len) < 0)
141
                        goto cleanup;
142

143
                    if (STREQ(driverType, "aio"))
144
                        virDomainDiskSetFormat(disk, VIR_STORAGE_FILE_RAW);
145
                    else
146 147
                        virDomainDiskSetFormat(disk,
                                               virStorageFileFormatTypeFromString(driverType));
148
                    VIR_FREE(driverType);
149
                    if (virDomainDiskGetFormat(disk) <= 0) {
150
                        virReportError(VIR_ERR_INTERNAL_ERROR,
151
                                       _("Unknown driver type %s"),
152
                                       src);
153 154 155 156
                        goto cleanup;
                    }

                    /* Strip the prefix we found off the source file name */
157 158 159
                    if (virDomainDiskSetSource(disk, src + len + 1) < 0)
                        goto cleanup;
                    src = virDomainDiskGetSource(disk);
160 161 162 163
                }
            }

            /* No source, or driver name, so fix to phy: */
164 165
            if (!virDomainDiskGetDriver(disk) &&
                virDomainDiskSetDriver(disk, "phy") < 0)
166
                goto cleanup;
167 168

            /* phy: type indicates a block device */
169 170
            virDomainDiskSetType(disk,
                                 STREQ(virDomainDiskGetDriver(disk), "phy") ?
E
Eric Blake 已提交
171 172
                                 VIR_STORAGE_TYPE_BLOCK :
                                 VIR_STORAGE_TYPE_FILE);
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191

            /* 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';
            }

            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;
            }

            if (STREQ(head, "r") ||
                STREQ(head, "ro"))
192
                disk->src->readonly = true;
193 194
            else if ((STREQ(head, "w!")) ||
                     (STREQ(head, "!")))
195
                disk->src->shared = true;
196 197

            /* Maintain list in sorted order according to target device name */
198
            if (VIR_APPEND_ELEMENT(def->disks, def->ndisks, disk) < 0)
199
                goto cleanup;
200 201 202 203

            skipdisk:
            list = list->next;
            virDomainDiskDefFree(disk);
204
            disk = NULL;
205 206 207
        }
    }

208
    if (hvm && xendConfigVersion == XEND_CONFIG_VERSION_3_0_2) {
209
        if (xenConfigGetString(conf, "cdrom", &str, NULL) < 0)
210 211
            goto cleanup;
        if (str) {
212
            if (!(disk = virDomainDiskDefNew()))
213
                goto cleanup;
214

E
Eric Blake 已提交
215
            virDomainDiskSetType(disk, VIR_STORAGE_TYPE_FILE);
216
            disk->device = VIR_DOMAIN_DISK_DEVICE_CDROM;
217
            if (virDomainDiskSetDriver(disk, "file") < 0)
218
                goto cleanup;
219
            if (virDomainDiskSetSource(disk, str) < 0)
220 221 222
                goto cleanup;
            if (VIR_STRDUP(disk->dst, "hdc") < 0)
                goto cleanup;
223
            disk->bus = VIR_DOMAIN_DISK_BUS_IDE;
224
            disk->src->readonly = true;
225

226
            if (VIR_APPEND_ELEMENT(def->disks, def->ndisks, disk) < 0)
227
                goto cleanup;
228 229 230
        }
    }

231 232 233 234 235 236 237 238
    return 0;

 cleanup:
    virDomainDiskDefFree(disk);
    return -1;
}


239
static int
240 241 242 243
xenFormatXMDisk(virConfValuePtr list,
                virDomainDiskDefPtr disk,
                int hvm,
                int xendConfigVersion)
244
{
245 246 247 248 249
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    virConfValuePtr val, tmp;
    const char *src = virDomainDiskGetSource(disk);
    int format = virDomainDiskGetFormat(disk);
    const char *driver = virDomainDiskGetDriver(disk);
250

251 252 253
    if (src) {
        if (format) {
            const char *type;
254

255 256 257 258 259 260 261
            if (format == VIR_STORAGE_FILE_RAW)
                type = "aio";
            else
                type = virStorageFileFormatTypeToString(format);
            virBufferAsprintf(&buf, "%s:", driver);
            if (STREQ(driver, "tap"))
                virBufferAsprintf(&buf, "%s:", type);
262
        } else {
263 264 265 266 267 268 269 270 271 272 273
            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)));
274 275 276
                goto cleanup;
            }
        }
277
        virBufferAdd(&buf, src, -1);
278
    }
279 280 281
    virBufferAddLit(&buf, ",");
    if (hvm && xendConfigVersion == XEND_CONFIG_VERSION_3_0_2)
        virBufferAddLit(&buf, "ioemu:");
282

283 284 285
    virBufferAdd(&buf, disk->dst, -1);
    if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM)
        virBufferAddLit(&buf, ":cdrom");
286

287 288 289 290 291 292 293 294 295
    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"));
296 297 298
        return -1;
    }

299 300
    if (virBufferCheckError(&buf) < 0)
        goto cleanup;
301

302 303
    if (VIR_ALLOC(val) < 0)
        goto cleanup;
304

305 306 307 308 309 310 311 312 313
    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;
314 315

    return 0;
316

317 318 319
 cleanup:
    virBufferFreeAndReset(&buf);
    return -1;
320 321 322
}


323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367
static int
xenFormatXMDisks(virConfPtr conf, virDomainDefPtr def, int xendConfigVersion)
{
    virConfValuePtr diskVal = NULL;
    size_t i = 0;
    int hvm = STREQ(def->os.type, "hvm");

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

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

    for (i = 0; i < def->ndisks; i++) {
        if (xendConfigVersion == XEND_CONFIG_VERSION_3_0_2 &&
            def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_CDROM &&
            def->disks[i]->dst &&
            STREQ(def->disks[i]->dst, "hdc")) {
            continue;
        }

        if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY)
            continue;

        if (xenFormatXMDisk(diskVal, def->disks[i],
                            hvm, xendConfigVersion) < 0)
            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;
}


368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399
static int
xenParseXMInputDevs(virConfPtr conf, virDomainDefPtr def)
{
    const char *str;

    if (STREQ(def->os.type, "hvm")) {
        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;
}

400 401 402 403 404 405 406
/*
 * Convert an XM config record into a virDomainDef object.
 */
virDomainDefPtr
xenParseXM(virConfPtr conf,
           int xendConfigVersion,
           virCapsPtr caps)
407
{
408
    virDomainDefPtr def = NULL;
409

410
    if (!(def = virDomainDefNew()))
411
        return NULL;
412

413 414
    def->virtType = VIR_DOMAIN_VIRT_XEN;
    def->id = -1;
415

416
    if (xenParseConfigCommon(conf, def, caps, xendConfigVersion) < 0)
417 418
        goto cleanup;

419 420
    if (xenParseXMDisk(conf, def, xendConfigVersion) < 0)
         goto cleanup;
421

422 423 424
    if (xenParseXMInputDevs(conf, def) < 0)
         goto cleanup;

425
    return def;
426 427

 cleanup:
428 429
    virDomainDefFree(def);
    return NULL;
430 431
}

432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465
static int
xenFormatXMInputDevs(virConfPtr conf, virDomainDefPtr def)
{
    size_t i;
    const char *devtype;

    if (STREQ(def->os.type, "hvm")) {
        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;
}

466 467 468 469 470

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

471
/*
M
Martin Kletzander 已提交
472
 * Convert a virDomainDef object into an XM config record.
473
 */
474 475 476 477 478 479 480 481 482 483 484 485 486 487
virConfPtr
xenFormatXM(virConnectPtr conn,
            virDomainDefPtr def,
            int xendConfigVersion)
{
    virConfPtr conf = NULL;

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

    if (xenFormatConfigCommon(conf, def, conn, xendConfigVersion) < 0)
        goto cleanup;

    if (xenFormatXMDisks(conf, def, xendConfigVersion) < 0)
488
        goto cleanup;
489

490 491 492
    if (xenFormatXMInputDevs(conf, def) < 0)
        goto cleanup;

493 494
    return conf;

495
 cleanup:
496 497
    if (conf)
        virConfFree(conf);
498
    return NULL;
499
}