cpu_conf.c 27.2 KB
Newer Older
1
/*
2
 * cpu_conf.c: CPU XML handling
3
 *
4
 * Copyright (C) 2009-2015 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16
 *
 * 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
17
 * License along with this library.  If not, see
O
Osier Yang 已提交
18
 * <http://www.gnu.org/licenses/>.
19 20 21 22 23 24 25
 *
 * Authors:
 *      Jiri Denemark <jdenemar@redhat.com>
 */

#include <config.h>

26
#include "virerror.h"
27
#include "viralloc.h"
28
#include "virbuffer.h"
29
#include "cpu_conf.h"
30
#include "domain_conf.h"
31
#include "virstring.h"
32 33 34

#define VIR_FROM_THIS VIR_FROM_CPU

35 36 37
VIR_ENUM_IMPL(virCPU, VIR_CPU_TYPE_LAST,
              "host", "guest", "auto")

38 39 40 41 42
VIR_ENUM_IMPL(virCPUMode, VIR_CPU_MODE_LAST,
              "custom",
              "host-model",
              "host-passthrough")

43 44 45 46 47
VIR_ENUM_IMPL(virCPUMatch, VIR_CPU_MATCH_LAST,
              "minimum",
              "exact",
              "strict")

48 49 50 51 52 53
VIR_ENUM_IMPL(virCPUCheck, VIR_CPU_CHECK_LAST,
              "default",
              "none",
              "partial",
              "full")

54 55 56 57
VIR_ENUM_IMPL(virCPUFallback, VIR_CPU_FALLBACK_LAST,
              "allow",
              "forbid")

58 59 60 61 62 63 64
VIR_ENUM_IMPL(virCPUFeaturePolicy, VIR_CPU_FEATURE_LAST,
              "force",
              "require",
              "optional",
              "disable",
              "forbid")

65 66 67 68 69 70
VIR_ENUM_IMPL(virCPUCacheMode, VIR_CPU_CACHE_MODE_LAST,
              "emulate",
              "passthrough",
              "disable")


71 72 73 74 75 76 77 78 79 80 81 82 83
void
virCPUDefFreeFeatures(virCPUDefPtr def)
{
    size_t i;

    for (i = 0; i < def->nfeatures; i++)
        VIR_FREE(def->features[i].name);
    VIR_FREE(def->features);

    def->nfeatures = def->nfeatures_max = 0;
}


84 85 86 87 88 89
void ATTRIBUTE_NONNULL(1)
virCPUDefFreeModel(virCPUDefPtr def)
{

    VIR_FREE(def->model);
    VIR_FREE(def->vendor);
90
    VIR_FREE(def->vendor_id);
91
    virCPUDefFreeFeatures(def);
92 93
}

94 95 96 97 98 99
void
virCPUDefFree(virCPUDefPtr def)
{
    if (!def)
        return;

100
    virCPUDefFreeModel(def);
101
    VIR_FREE(def->cache);
102 103 104 105
    VIR_FREE(def);
}


106 107
int ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2)
virCPUDefCopyModel(virCPUDefPtr dst,
108
                   const virCPUDef *src,
109
                   bool resetPolicy)
110 111 112 113 114 115 116 117 118 119 120
{
    return virCPUDefCopyModelFilter(dst, src, resetPolicy, NULL, NULL);
}


int
virCPUDefCopyModelFilter(virCPUDefPtr dst,
                         const virCPUDef *src,
                         bool resetPolicy,
                         virCPUDefFeatureFilter filter,
                         void *opaque)
121
{
122
    size_t i;
123
    size_t n;
124

125 126 127 128
    if (VIR_STRDUP(dst->model, src->model) < 0 ||
        VIR_STRDUP(dst->vendor, src->vendor) < 0 ||
        VIR_STRDUP(dst->vendor_id, src->vendor_id) < 0 ||
        VIR_ALLOC_N(dst->features, src->nfeatures) < 0)
129
        return -1;
130 131 132 133 134 135
    dst->nfeatures_max = src->nfeatures;
    dst->nfeatures = 0;

    for (i = 0; i < src->nfeatures; i++) {
        if (filter && !filter(src->features[i].name, opaque))
            continue;
136

137
        n = dst->nfeatures++;
138 139
        if (dst->type != src->type && resetPolicy) {
            if (dst->type == VIR_CPU_TYPE_HOST)
140
                dst->features[n].policy = -1;
141
            else if (src->features[i].policy == -1)
142
                dst->features[n].policy = VIR_CPU_FEATURE_REQUIRE;
143
            else
144
                dst->features[n].policy = src->features[i].policy;
145
        } else {
146
            dst->features[n].policy = src->features[i].policy;
147 148
        }

149
        if (VIR_STRDUP(dst->features[n].name, src->features[i].name) < 0)
150
            return -1;
151 152 153 154 155
    }

    return 0;
}

156

157 158 159 160 161 162 163
/**
 * virCPUDefStealModel:
 *
 * Move CPU model related parts virCPUDef from @src to @dst. If @keepVendor
 * is true, the function keeps the original vendor/vendor_id in @dst rather
 * than overwriting it with the values from @src.
 */
164 165
void
virCPUDefStealModel(virCPUDefPtr dst,
166 167
                    virCPUDefPtr src,
                    bool keepVendor)
168
{
169 170
    char *vendor = NULL;
    char *vendor_id = NULL;
171 172 173 174 175 176

    if (keepVendor) {
        VIR_STEAL_PTR(vendor, dst->vendor);
        VIR_STEAL_PTR(vendor_id, dst->vendor_id);
    }

177 178 179 180 181 182 183 184
    virCPUDefFreeModel(dst);

    VIR_STEAL_PTR(dst->model, src->model);
    VIR_STEAL_PTR(dst->features, src->features);
    dst->nfeatures_max = src->nfeatures_max;
    src->nfeatures_max = 0;
    dst->nfeatures = src->nfeatures;
    src->nfeatures = 0;
185 186 187 188 189 190 191 192

    if (keepVendor) {
        dst->vendor = vendor;
        dst->vendor_id = vendor_id;
    } else {
        VIR_STEAL_PTR(dst->vendor, src->vendor);
        VIR_STEAL_PTR(dst->vendor_id, src->vendor_id);
    }
193 194 195
}


196
virCPUDefPtr
197
virCPUDefCopyWithoutModel(const virCPUDef *cpu)
198 199 200
{
    virCPUDefPtr copy;

201
    if (!cpu || VIR_ALLOC(copy) < 0)
202 203 204
        return NULL;

    copy->type = cpu->type;
205
    copy->mode = cpu->mode;
206
    copy->match = cpu->match;
207
    copy->check = cpu->check;
208
    copy->fallback = cpu->fallback;
209 210 211
    copy->sockets = cpu->sockets;
    copy->cores = cpu->cores;
    copy->threads = cpu->threads;
212
    copy->arch = cpu->arch;
213

214 215 216 217 218 219 220
    if (cpu->cache) {
        if (VIR_ALLOC(copy->cache) < 0)
            goto error;

        *copy->cache = *cpu->cache;
    }

221
    return copy;
222 223 224 225

 error:
    virCPUDefFree(copy);
    return NULL;
226 227 228 229 230 231 232 233 234 235 236
}


virCPUDefPtr
virCPUDefCopy(const virCPUDef *cpu)
{
    virCPUDefPtr copy;

    if (!(copy = virCPUDefCopyWithoutModel(cpu)))
        return NULL;

237 238
    if (virCPUDefCopyModel(copy, cpu, false) < 0)
        goto error;
239

240 241
    return copy;

242
 error:
243 244 245 246
    virCPUDefFree(copy);
    return NULL;
}

247

J
Jiri Denemark 已提交
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
/*
 * Parses CPU definition XML from a node pointed to by @xpath. If @xpath is
 * NULL, the current node of @ctxt is used (i.e., it is a shortcut to ".").
 *
 * Missing <cpu> element in the XML document is not considered an error unless
 * @xpath is NULL in which case the function expects it was provided with a
 * valid <cpu> element already. In other words, the function returns success
 * and sets @cpu to NULL if @xpath is not NULL and the node pointed to by
 * @xpath is not found.
 *
 * Returns 0 on success, -1 on error.
 */
int
virCPUDefParseXML(xmlXPathContextPtr ctxt,
                  const char *xpath,
                  virCPUType type,
                  virCPUDefPtr *cpu)
265
{
J
Jiri Denemark 已提交
266
    virCPUDefPtr def = NULL;
267
    xmlNodePtr *nodes = NULL;
268
    xmlNodePtr oldnode = ctxt->node;
269
    int n;
270
    size_t i;
271
    char *cpuMode;
272 273
    char *fallback = NULL;
    char *vendor_id = NULL;
J
Jiri Denemark 已提交
274
    int ret = -1;
275

J
Jiri Denemark 已提交
276 277 278 279 280 281 282 283
    *cpu = NULL;

    if (xpath && !(ctxt->node = virXPathNode(xpath, ctxt))) {
        ret = 0;
        goto cleanup;
    }

    if (!xmlStrEqual(ctxt->node->name, BAD_CAST "cpu")) {
284
        virReportError(VIR_ERR_XML_ERROR, "%s",
285
                       _("XML does not contain expected 'cpu' element"));
J
Jiri Denemark 已提交
286
        goto cleanup;
287 288
    }

289
    if (VIR_ALLOC(def) < 0)
J
Jiri Denemark 已提交
290
        goto cleanup;
291

292
    if (type == VIR_CPU_TYPE_AUTO) {
293 294
        if (virXPathBoolean("boolean(./arch)", ctxt)) {
            if (virXPathBoolean("boolean(./@match)", ctxt)) {
295
                virReportError(VIR_ERR_XML_ERROR, "%s",
296
                               _("'arch' element cannot be used inside 'cpu'"
297
                                 " element with 'match' attribute'"));
J
Jiri Denemark 已提交
298
                goto cleanup;
299
            }
300
            def->type = VIR_CPU_TYPE_HOST;
301
        } else {
302
            def->type = VIR_CPU_TYPE_GUEST;
303 304
        }
    } else {
305
        def->type = type;
306 307
    }

J
Jiri Denemark 已提交
308
    if ((cpuMode = virXMLPropString(ctxt->node, "mode"))) {
309 310
        if (def->type == VIR_CPU_TYPE_HOST) {
            VIR_FREE(cpuMode);
311 312
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("Attribute mode is only allowed for guest CPU"));
J
Jiri Denemark 已提交
313
            goto cleanup;
314 315 316 317
        } else {
            def->mode = virCPUModeTypeFromString(cpuMode);

            if (def->mode < 0) {
318
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
319 320
                               _("Invalid mode attribute '%s'"),
                               cpuMode);
321
                VIR_FREE(cpuMode);
J
Jiri Denemark 已提交
322
                goto cleanup;
323
            }
324
            VIR_FREE(cpuMode);
325 326 327 328 329 330 331
        }
    } else {
        if (def->type == VIR_CPU_TYPE_HOST)
            def->mode = -1;
        else
            def->mode = VIR_CPU_MODE_CUSTOM;
    }
332 333

    if (def->type == VIR_CPU_TYPE_GUEST) {
J
Jiri Denemark 已提交
334
        char *match = virXMLPropString(ctxt->node, "match");
335
        char *check;
336 337

        if (!match) {
338 339 340 341
            if (virXPathBoolean("boolean(./model)", ctxt))
                def->match = VIR_CPU_MATCH_EXACT;
            else
                def->match = -1;
342 343 344 345 346
        } else {
            def->match = virCPUMatchTypeFromString(match);
            VIR_FREE(match);

            if (def->match < 0) {
347
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
P
Peter Krempa 已提交
348 349
                               _("Invalid match attribute for CPU "
                                 "specification"));
J
Jiri Denemark 已提交
350
                goto cleanup;
351
            }
352
        }
353

J
Jiri Denemark 已提交
354
        if ((check = virXMLPropString(ctxt->node, "check"))) {
355 356 357 358 359 360 361
            int value = virCPUCheckTypeFromString(check);
            VIR_FREE(check);

            if (value < 0) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("Invalid check attribute for CPU "
                                 "specification"));
J
Jiri Denemark 已提交
362
                goto cleanup;
363 364 365
            }
            def->check = value;
        }
366 367 368
    }

    if (def->type == VIR_CPU_TYPE_HOST) {
369 370
        char *arch = virXPathString("string(./arch[1])", ctxt);
        if (!arch) {
371 372
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("Missing CPU architecture"));
J
Jiri Denemark 已提交
373
            goto cleanup;
374
        }
375
        if ((def->arch = virArchFromString(arch)) == VIR_ARCH_NONE) {
376
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
377 378
                           _("Unknown architecture %s"), arch);
            VIR_FREE(arch);
J
Jiri Denemark 已提交
379
            goto cleanup;
380 381
        }
        VIR_FREE(arch);
382 383
    }

384
    if (!(def->model = virXPathString("string(./model[1])", ctxt)) &&
385
        def->type == VIR_CPU_TYPE_HOST) {
386 387
        virReportError(VIR_ERR_XML_ERROR, "%s",
                        _("Missing CPU model name"));
J
Jiri Denemark 已提交
388
        goto cleanup;
389 390
    }

391
    if (def->type == VIR_CPU_TYPE_GUEST &&
392 393
        def->mode != VIR_CPU_MODE_HOST_PASSTHROUGH) {

394 395
        if ((fallback = virXPathString("string(./model[1]/@fallback)", ctxt))) {
            if ((def->fallback = virCPUFallbackTypeFromString(fallback)) < 0) {
396
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
397
                               _("Invalid fallback attribute"));
J
Jiri Denemark 已提交
398
                goto cleanup;
399
            }
K
Ken ICHIKAWA 已提交
400
        }
401

402 403 404
        if ((vendor_id = virXPathString("string(./model[1]/@vendor_id)",
                                        ctxt))) {
            if (strlen(vendor_id) != VIR_CPU_VENDOR_ID_LENGTH) {
K
Ken ICHIKAWA 已提交
405
                virReportError(VIR_ERR_XML_ERROR,
406
                               _("vendor_id must be exactly %d characters long"),
K
Ken ICHIKAWA 已提交
407
                               VIR_CPU_VENDOR_ID_LENGTH);
J
Jiri Denemark 已提交
408
                goto cleanup;
K
Ken ICHIKAWA 已提交
409
            }
410

K
Ken ICHIKAWA 已提交
411
            /* ensure that the string can be passed to qemu*/
412
            if (strchr(vendor_id, ',')) {
K
Ken ICHIKAWA 已提交
413 414
                    virReportError(VIR_ERR_XML_ERROR, "%s",
                                   _("vendor id is invalid"));
J
Jiri Denemark 已提交
415
                    goto cleanup;
416
            }
417

K
Ken ICHIKAWA 已提交
418
            def->vendor_id = vendor_id;
419
            vendor_id = NULL;
420 421 422
        }
    }

J
Jiri Denemark 已提交
423 424
    def->vendor = virXPathString("string(./vendor[1])", ctxt);
    if (def->vendor && !def->model) {
425 426
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("CPU vendor specified without CPU model"));
J
Jiri Denemark 已提交
427
        goto cleanup;
J
Jiri Denemark 已提交
428 429
    }

430
    if (virXPathNode("./topology[1]", ctxt)) {
431 432
        unsigned long ul;

J
Jiri Denemark 已提交
433
        if (virXPathULong("string(./topology[1]/@sockets)", ctxt, &ul) < 0) {
434
            virReportError(VIR_ERR_XML_ERROR, "%s",
P
Peter Krempa 已提交
435
                           _("Missing 'sockets' attribute in CPU topology"));
J
Jiri Denemark 已提交
436
            goto cleanup;
437 438 439
        }
        def->sockets = (unsigned int) ul;

J
Jiri Denemark 已提交
440
        if (virXPathULong("string(./topology[1]/@cores)", ctxt, &ul) < 0) {
441
            virReportError(VIR_ERR_XML_ERROR, "%s",
P
Peter Krempa 已提交
442
                           _("Missing 'cores' attribute in CPU topology"));
J
Jiri Denemark 已提交
443
            goto cleanup;
444 445 446
        }
        def->cores = (unsigned int) ul;

J
Jiri Denemark 已提交
447
        if (virXPathULong("string(./topology[1]/@threads)", ctxt, &ul) < 0) {
448
            virReportError(VIR_ERR_XML_ERROR, "%s",
P
Peter Krempa 已提交
449
                           _("Missing 'threads' attribute in CPU topology"));
J
Jiri Denemark 已提交
450
            goto cleanup;
451 452 453 454
        }
        def->threads = (unsigned int) ul;

        if (!def->sockets || !def->cores || !def->threads) {
455 456
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("Invalid CPU topology"));
J
Jiri Denemark 已提交
457
            goto cleanup;
458 459 460
        }
    }

P
Peter Krempa 已提交
461
    if ((n = virXPathNodeSet("./feature", ctxt, &nodes)) < 0)
J
Jiri Denemark 已提交
462
        goto cleanup;
463 464

    if (n > 0) {
465
        if (!def->model && def->mode == VIR_CPU_MODE_CUSTOM) {
466
            virReportError(VIR_ERR_XML_ERROR, "%s",
P
Peter Krempa 已提交
467 468
                           _("Non-empty feature list specified without "
                             "CPU model"));
J
Jiri Denemark 已提交
469
            goto cleanup;
470 471
        }

E
Eric Blake 已提交
472 473
        if (VIR_RESIZE_N(def->features, def->nfeatures_max,
                         def->nfeatures, n) < 0)
J
Jiri Denemark 已提交
474
            goto cleanup;
P
Peter Krempa 已提交
475

476 477 478
        def->nfeatures = n;
    }

479
    for (i = 0; i < n; i++) {
480 481
        char *name;
        int policy; /* enum virDomainCPUFeaturePolicy */
482
        size_t j;
483 484 485 486 487

        if (def->type == VIR_CPU_TYPE_GUEST) {
            char *strpolicy;

            strpolicy = virXMLPropString(nodes[i], "policy");
488 489 490 491
            if (strpolicy == NULL)
                policy = VIR_CPU_FEATURE_REQUIRE;
            else
                policy = virCPUFeaturePolicyTypeFromString(strpolicy);
492 493 494
            VIR_FREE(strpolicy);

            if (policy < 0) {
495
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
496
                               _("Invalid CPU feature policy"));
J
Jiri Denemark 已提交
497
                goto cleanup;
498
            }
499
        } else {
500
            policy = -1;
501
        }
502 503 504

        if (!(name = virXMLPropString(nodes[i], "name")) || *name == 0) {
            VIR_FREE(name);
505 506
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("Invalid CPU feature name"));
J
Jiri Denemark 已提交
507
            goto cleanup;
508 509
        }

510
        for (j = 0; j < i; j++) {
511
            if (STREQ(name, def->features[j].name)) {
512
                virReportError(VIR_ERR_XML_ERROR,
C
Chen Fan 已提交
513
                               _("CPU feature '%s' specified more than once"),
514
                               name);
515
                VIR_FREE(name);
J
Jiri Denemark 已提交
516
                goto cleanup;
517 518 519 520 521 522 523
            }
        }

        def->features[i].name = name;
        def->features[i].policy = policy;
    }

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 556 557 558
    if (virXPathInt("count(./cache)", ctxt, &n) < 0) {
        goto cleanup;
    } else if (n > 1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("at most one CPU cache element may be specified"));
        goto cleanup;
    } else if (n == 1) {
        int level = -1;
        char *strmode;
        int mode;

        if (virXPathBoolean("boolean(./cache[1]/@level)", ctxt) == 1 &&
            (virXPathInt("string(./cache[1]/@level)", ctxt, &level) < 0 ||
             level < 1 || level > 3)) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("invalid CPU cache level, must be in range [1,3]"));
            goto cleanup;
        }

        if (!(strmode = virXPathString("string(./cache[1]/@mode)", ctxt)) ||
            (mode = virCPUCacheModeTypeFromString(strmode)) < 0) {
            VIR_FREE(strmode);
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("missing or invalid CPU cache mode"));
            goto cleanup;
        }
        VIR_FREE(strmode);

        if (VIR_ALLOC(def->cache) < 0)
            goto cleanup;

        def->cache->level = level;
        def->cache->mode = mode;
    }

J
Jiri Denemark 已提交
559 560 561
    VIR_STEAL_PTR(*cpu, def);
    ret = 0;

562
 cleanup:
563
    ctxt->node = oldnode;
564 565
    VIR_FREE(fallback);
    VIR_FREE(vendor_id);
566 567
    VIR_FREE(nodes);
    virCPUDefFree(def);
J
Jiri Denemark 已提交
568
    return ret;
569 570 571 572
}


char *
573
virCPUDefFormat(virCPUDefPtr def,
574
                virDomainNumaPtr numa,
575
                bool updateCPU)
576 577 578
{
    virBuffer buf = VIR_BUFFER_INITIALIZER;

579
    if (virCPUDefFormatBufFull(&buf, def, numa, updateCPU) < 0)
580 581
        goto cleanup;

582 583
    if (virBufferCheckError(&buf) < 0)
        goto cleanup;
584 585 586

    return virBufferContentAndReset(&buf);

587
 cleanup:
588
    virBufferFreeAndReset(&buf);
589 590 591 592
    return NULL;
}


593 594
int
virCPUDefFormatBufFull(virBufferPtr buf,
595
                       virCPUDefPtr def,
596
                       virDomainNumaPtr numa,
597
                       bool updateCPU)
598
{
599
    int ret = -1;
600
    virBuffer attributeBuf = VIR_BUFFER_INITIALIZER;
M
Michal Privoznik 已提交
601 602
    virBuffer childrenBuf = VIR_BUFFER_INITIALIZER;
    int indent = virBufferGetIndent(buf, false);
603

604 605 606
    if (!def)
        return 0;

607
    /* Format attributes */
608 609 610 611 612
    if (def->type == VIR_CPU_TYPE_GUEST) {
        const char *tmp;

        if (def->mode != VIR_CPU_MODE_CUSTOM || def->model) {
            if (!(tmp = virCPUModeTypeToString(def->mode))) {
613 614
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Unexpected CPU mode %d"), def->mode);
615
                goto cleanup;
616
            }
617
            virBufferAsprintf(&attributeBuf, " mode='%s'", tmp);
618 619
        }

620 621
        if (def->model &&
            (def->mode == VIR_CPU_MODE_CUSTOM ||
622
             updateCPU)) {
623
            if (!(tmp = virCPUMatchTypeToString(def->match))) {
624 625 626
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Unexpected CPU match policy %d"),
                               def->match);
627
                goto cleanup;
628
            }
629
            virBufferAsprintf(&attributeBuf, " match='%s'", tmp);
630
        }
631 632 633 634 635

        if (def->check) {
            virBufferAsprintf(&attributeBuf, " check='%s'",
                              virCPUCheckTypeToString(def->check));
        }
636 637
    }

638
    /* Format children */
M
Michal Privoznik 已提交
639
    virBufferAdjustIndent(&childrenBuf, indent + 2);
640
    if (def->type == VIR_CPU_TYPE_HOST && def->arch)
M
Michal Privoznik 已提交
641
        virBufferAsprintf(&childrenBuf, "<arch>%s</arch>\n",
642
                          virArchToString(def->arch));
M
Michal Privoznik 已提交
643
    if (virCPUDefFormatBuf(&childrenBuf, def, updateCPU) < 0)
644
        goto cleanup;
645

M
Michal Privoznik 已提交
646
    if (virDomainNumaDefCPUFormat(&childrenBuf, numa) < 0)
647
        goto cleanup;
648

649 650 651 652 653 654 655 656 657 658 659 660 661 662
    /* Put it all together */
    if (virBufferUse(&attributeBuf) || virBufferUse(&childrenBuf)) {
        virBufferAddLit(buf, "<cpu");

        if (virBufferUse(&attributeBuf))
            virBufferAddBuffer(buf, &attributeBuf);

        if (virBufferUse(&childrenBuf)) {
            virBufferAddLit(buf, ">\n");
            virBufferAddBuffer(buf, &childrenBuf);
            virBufferAddLit(buf, "</cpu>\n");
        } else {
            virBufferAddLit(buf, "/>\n");
        }
M
Michal Privoznik 已提交
663
    }
664

665 666
    ret = 0;
 cleanup:
667
    virBufferFreeAndReset(&attributeBuf);
M
Michal Privoznik 已提交
668
    virBufferFreeAndReset(&childrenBuf);
669
    return ret;
670 671
}

672
int
673
virCPUDefFormatBuf(virBufferPtr buf,
674
                   virCPUDefPtr def,
675
                   bool updateCPU)
676
{
677
    size_t i;
678 679
    bool formatModel;
    bool formatFallback;
680 681 682 683

    if (!def)
        return 0;

684
    formatModel = (def->mode == VIR_CPU_MODE_CUSTOM ||
685
                   def->mode == VIR_CPU_MODE_HOST_MODEL ||
686
                   updateCPU);
687 688 689 690
    formatFallback = (def->type == VIR_CPU_TYPE_GUEST &&
                      (def->mode == VIR_CPU_MODE_HOST_MODEL ||
                       (def->mode == VIR_CPU_MODE_CUSTOM && def->model)));

691
    if (!def->model && def->mode == VIR_CPU_MODE_CUSTOM && def->nfeatures) {
692 693
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Non-empty feature list specified without CPU model"));
694 695 696
        return -1;
    }

697
    if ((formatModel && def->model) || formatFallback) {
698
        virBufferAddLit(buf, "<model");
699
        if (formatFallback) {
700 701 702 703
            const char *fallback;

            fallback = virCPUFallbackTypeToString(def->fallback);
            if (!fallback) {
704 705 706
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Unexpected CPU fallback value: %d"),
                               def->fallback);
707 708 709
                return -1;
            }
            virBufferAsprintf(buf, " fallback='%s'", fallback);
710
            if (def->vendor_id)
711
                virBufferEscapeString(buf, " vendor_id='%s'", def->vendor_id);
712
        }
713
        if (formatModel && def->model) {
714
            virBufferEscapeString(buf, ">%s</model>\n", def->model);
715 716 717
        } else {
            virBufferAddLit(buf, "/>\n");
        }
718
    }
719

720
    if (formatModel && def->vendor)
721
        virBufferEscapeString(buf, "<vendor>%s</vendor>\n", def->vendor);
J
Jiri Denemark 已提交
722

723
    if (def->sockets && def->cores && def->threads) {
724
        virBufferAddLit(buf, "<topology");
725 726 727
        virBufferAsprintf(buf, " sockets='%u'", def->sockets);
        virBufferAsprintf(buf, " cores='%u'", def->cores);
        virBufferAsprintf(buf, " threads='%u'", def->threads);
728 729 730
        virBufferAddLit(buf, "/>\n");
    }

731 732 733 734 735 736 737 738 739
    if (def->cache) {
        virBufferAddLit(buf, "<cache ");
        if (def->cache->level != -1)
            virBufferAsprintf(buf, "level='%d' ", def->cache->level);
        virBufferAsprintf(buf, "mode='%s'",
                          virCPUCacheModeTypeToString(def->cache->mode));
        virBufferAddLit(buf, "/>\n");
    }

740 741
    for (i = 0; i < def->nfeatures; i++) {
        virCPUFeatureDefPtr feature = def->features + i;
742

743 744 745 746 747
        if (!feature->name) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Missing CPU feature name"));
            return -1;
        }
748

749 750
        if (def->type == VIR_CPU_TYPE_GUEST) {
            const char *policy;
751

752 753 754 755 756 757
            policy = virCPUFeaturePolicyTypeToString(feature->policy);
            if (!policy) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Unexpected CPU feature policy %d"),
                               feature->policy);
                return -1;
758
            }
759 760 761 762 763
            virBufferAsprintf(buf, "<feature policy='%s' name='%s'/>\n",
                              policy, feature->name);
        } else {
            virBufferAsprintf(buf, "<feature name='%s'/>\n",
                              feature->name);
764 765 766 767 768 769
        }
    }

    return 0;
}

P
Peter Krempa 已提交
770 771 772 773 774
static int
virCPUDefUpdateFeatureInternal(virCPUDefPtr def,
                               const char *name,
                               int policy,
                               bool update)
775
{
776
    size_t i;
777

P
Peter Krempa 已提交
778 779 780
    if (def->type == VIR_CPU_TYPE_HOST)
        policy = -1;

781
    for (i = 0; i < def->nfeatures; i++) {
782
        if (STREQ(name, def->features[i].name)) {
P
Peter Krempa 已提交
783 784 785 786 787
            if (update) {
                def->features[i].policy = policy;
                return 0;
            }

788
            virReportError(VIR_ERR_INTERNAL_ERROR,
C
Chen Fan 已提交
789
                           _("CPU feature '%s' specified more than once"),
790
                           name);
P
Peter Krempa 已提交
791

792 793 794 795
            return -1;
        }
    }

E
Eric Blake 已提交
796 797
    if (VIR_RESIZE_N(def->features, def->nfeatures_max,
                     def->nfeatures, 1) < 0)
798
        return -1;
799

800 801
    if (VIR_STRDUP(def->features[def->nfeatures].name, name) < 0)
        return -1;
802 803 804 805 806 807

    def->features[def->nfeatures].policy = policy;
    def->nfeatures++;

    return 0;
}
808

P
Peter Krempa 已提交
809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824
int
virCPUDefUpdateFeature(virCPUDefPtr def,
                       const char *name,
                       int policy)
{
    return virCPUDefUpdateFeatureInternal(def, name, policy, true);
}

int
virCPUDefAddFeature(virCPUDefPtr def,
                    const char *name,
                    int policy)
{
    return virCPUDefUpdateFeatureInternal(def, name, policy, false);
}

825 826
bool
virCPUDefIsEqual(virCPUDefPtr src,
827 828
                 virCPUDefPtr dst,
                 bool reportError)
829 830
{
    bool identical = false;
831
    size_t i;
832 833 834 835

    if (!src && !dst)
        return true;

836 837 838 839
#define MISMATCH(fmt, ...)                                              \
    if (reportError)                                                    \
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, fmt, __VA_ARGS__)

840
    if ((src && !dst) || (!src && dst)) {
841
        MISMATCH("%s", _("Target CPU does not match source"));
842 843 844 845
        goto cleanup;
    }

    if (src->type != dst->type) {
846 847 848
        MISMATCH(_("Target CPU type %s does not match source %s"),
                 virCPUTypeToString(dst->type),
                 virCPUTypeToString(src->type));
849 850 851
        goto cleanup;
    }

852
    if (src->mode != dst->mode) {
853 854 855
        MISMATCH(_("Target CPU mode %s does not match source %s"),
                 virCPUModeTypeToString(dst->mode),
                 virCPUModeTypeToString(src->mode));
856 857 858
        goto cleanup;
    }

859
    if (src->arch != dst->arch) {
860 861 862
        MISMATCH(_("Target CPU arch %s does not match source %s"),
                 virArchToString(dst->arch),
                 virArchToString(src->arch));
863 864 865 866
        goto cleanup;
    }

    if (STRNEQ_NULLABLE(src->model, dst->model)) {
867 868
        MISMATCH(_("Target CPU model %s does not match source %s"),
                 NULLSTR(dst->model), NULLSTR(src->model));
869 870 871 872
        goto cleanup;
    }

    if (STRNEQ_NULLABLE(src->vendor, dst->vendor)) {
873 874
        MISMATCH(_("Target CPU vendor %s does not match source %s"),
                 NULLSTR(dst->vendor), NULLSTR(src->vendor));
875 876 877
        goto cleanup;
    }

878
    if (STRNEQ_NULLABLE(src->vendor_id, dst->vendor_id)) {
879 880
        MISMATCH(_("Target CPU vendor id %s does not match source %s"),
                 NULLSTR(dst->vendor_id), NULLSTR(src->vendor_id));
881 882 883
        goto cleanup;
    }

884
    if (src->sockets != dst->sockets) {
885 886
        MISMATCH(_("Target CPU sockets %d does not match source %d"),
                 dst->sockets, src->sockets);
887 888 889 890
        goto cleanup;
    }

    if (src->cores != dst->cores) {
891 892
        MISMATCH(_("Target CPU cores %d does not match source %d"),
                 dst->cores, src->cores);
893 894 895 896
        goto cleanup;
    }

    if (src->threads != dst->threads) {
897 898
        MISMATCH(_("Target CPU threads %d does not match source %d"),
                 dst->threads, src->threads);
899 900 901 902
        goto cleanup;
    }

    if (src->nfeatures != dst->nfeatures) {
903 904
        MISMATCH(_("Target CPU feature count %zu does not match source %zu"),
                 dst->nfeatures, src->nfeatures);
905 906 907
        goto cleanup;
    }

908
    for (i = 0; i < src->nfeatures; i++) {
909
        if (STRNEQ(src->features[i].name, dst->features[i].name)) {
910 911
            MISMATCH(_("Target CPU feature %s does not match source %s"),
                     dst->features[i].name, src->features[i].name);
912 913 914 915
            goto cleanup;
        }

        if (src->features[i].policy != dst->features[i].policy) {
916 917 918
            MISMATCH(_("Target CPU feature policy %s does not match source %s"),
                     virCPUFeaturePolicyTypeToString(dst->features[i].policy),
                     virCPUFeaturePolicyTypeToString(src->features[i].policy));
919 920 921 922
            goto cleanup;
        }
    }

923 924 925 926 927
    if ((src->cache && !dst->cache) ||
        (!src->cache && dst->cache) ||
        (src->cache && dst->cache &&
         (src->cache->level != dst->cache->level ||
          src->cache->mode != dst->cache->mode))) {
928
        MISMATCH("%s", _("Target CPU cache does not match source"));
929 930 931
        goto cleanup;
    }

932 933
#undef MISMATCH

934 935
    identical = true;

936
 cleanup:
937 938
    return identical;
}