cpu_conf.c 26.6 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

248
virCPUDefPtr
249
virCPUDefParseXML(xmlNodePtr node,
250
                  xmlXPathContextPtr ctxt,
251
                  virCPUType type)
252 253 254
{
    virCPUDefPtr def;
    xmlNodePtr *nodes = NULL;
255
    xmlNodePtr oldnode = ctxt->node;
256
    int n;
257
    size_t i;
258
    char *cpuMode;
259 260
    char *fallback = NULL;
    char *vendor_id = NULL;
261

262
    if (!xmlStrEqual(node->name, BAD_CAST "cpu")) {
263
        virReportError(VIR_ERR_XML_ERROR, "%s",
264
                       _("XML does not contain expected 'cpu' element"));
265 266 267
        return NULL;
    }

268
    if (VIR_ALLOC(def) < 0)
269 270
        return NULL;

271
    if (type == VIR_CPU_TYPE_AUTO) {
272 273
        if (virXPathBoolean("boolean(./arch)", ctxt)) {
            if (virXPathBoolean("boolean(./@match)", ctxt)) {
274
                virReportError(VIR_ERR_XML_ERROR, "%s",
275
                               _("'arch' element cannot be used inside 'cpu'"
276
                                 " element with 'match' attribute'"));
277 278
                goto error;
            }
279
            def->type = VIR_CPU_TYPE_HOST;
280
        } else {
281
            def->type = VIR_CPU_TYPE_GUEST;
282 283
        }
    } else {
284
        def->type = type;
285 286 287 288 289
    }

    if ((cpuMode = virXMLPropString(node, "mode"))) {
        if (def->type == VIR_CPU_TYPE_HOST) {
            VIR_FREE(cpuMode);
290 291
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("Attribute mode is only allowed for guest CPU"));
292 293 294 295 296
            goto error;
        } else {
            def->mode = virCPUModeTypeFromString(cpuMode);

            if (def->mode < 0) {
297
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
298 299
                               _("Invalid mode attribute '%s'"),
                               cpuMode);
300
                VIR_FREE(cpuMode);
301 302
                goto error;
            }
303
            VIR_FREE(cpuMode);
304 305 306 307 308 309 310
        }
    } else {
        if (def->type == VIR_CPU_TYPE_HOST)
            def->mode = -1;
        else
            def->mode = VIR_CPU_MODE_CUSTOM;
    }
311 312

    if (def->type == VIR_CPU_TYPE_GUEST) {
313
        char *match = virXMLPropString(node, "match");
314
        char *check;
315 316

        if (!match) {
317 318 319 320
            if (virXPathBoolean("boolean(./model)", ctxt))
                def->match = VIR_CPU_MATCH_EXACT;
            else
                def->match = -1;
321 322 323 324 325
        } else {
            def->match = virCPUMatchTypeFromString(match);
            VIR_FREE(match);

            if (def->match < 0) {
326
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
P
Peter Krempa 已提交
327 328
                               _("Invalid match attribute for CPU "
                                 "specification"));
329 330
                goto error;
            }
331
        }
332 333 334 335 336 337 338 339 340 341 342 343 344

        if ((check = virXMLPropString(node, "check"))) {
            int value = virCPUCheckTypeFromString(check);
            VIR_FREE(check);

            if (value < 0) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("Invalid check attribute for CPU "
                                 "specification"));
                goto error;
            }
            def->check = value;
        }
345 346 347
    }

    if (def->type == VIR_CPU_TYPE_HOST) {
348 349
        char *arch = virXPathString("string(./arch[1])", ctxt);
        if (!arch) {
350 351
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("Missing CPU architecture"));
352 353
            goto error;
        }
354
        if ((def->arch = virArchFromString(arch)) == VIR_ARCH_NONE) {
355
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
356 357 358 359 360
                           _("Unknown architecture %s"), arch);
            VIR_FREE(arch);
            goto error;
        }
        VIR_FREE(arch);
361 362
    }

363
    if (!(def->model = virXPathString("string(./model[1])", ctxt)) &&
364
        def->type == VIR_CPU_TYPE_HOST) {
365 366
        virReportError(VIR_ERR_XML_ERROR, "%s",
                        _("Missing CPU model name"));
367 368 369
        goto error;
    }

370
    if (def->type == VIR_CPU_TYPE_GUEST &&
371 372
        def->mode != VIR_CPU_MODE_HOST_PASSTHROUGH) {

373 374
        if ((fallback = virXPathString("string(./model[1]/@fallback)", ctxt))) {
            if ((def->fallback = virCPUFallbackTypeFromString(fallback)) < 0) {
375
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
376 377
                               _("Invalid fallback attribute"));
                goto error;
378
            }
K
Ken ICHIKAWA 已提交
379
        }
380

381 382 383
        if ((vendor_id = virXPathString("string(./model[1]/@vendor_id)",
                                        ctxt))) {
            if (strlen(vendor_id) != VIR_CPU_VENDOR_ID_LENGTH) {
K
Ken ICHIKAWA 已提交
384
                virReportError(VIR_ERR_XML_ERROR,
385
                               _("vendor_id must be exactly %d characters long"),
K
Ken ICHIKAWA 已提交
386 387 388
                               VIR_CPU_VENDOR_ID_LENGTH);
                goto error;
            }
389

K
Ken ICHIKAWA 已提交
390
            /* ensure that the string can be passed to qemu*/
391
            if (strchr(vendor_id, ',')) {
K
Ken ICHIKAWA 已提交
392 393
                    virReportError(VIR_ERR_XML_ERROR, "%s",
                                   _("vendor id is invalid"));
394
                    goto error;
395
            }
396

K
Ken ICHIKAWA 已提交
397
            def->vendor_id = vendor_id;
398
            vendor_id = NULL;
399 400 401
        }
    }

J
Jiri Denemark 已提交
402 403
    def->vendor = virXPathString("string(./vendor[1])", ctxt);
    if (def->vendor && !def->model) {
404 405
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("CPU vendor specified without CPU model"));
J
Jiri Denemark 已提交
406 407 408
        goto error;
    }

409
    if (virXPathNode("./topology[1]", ctxt)) {
410 411 412
        int ret;
        unsigned long ul;

413
        ret = virXPathULong("string(./topology[1]/@sockets)",
414 415
                            ctxt, &ul);
        if (ret < 0) {
416
            virReportError(VIR_ERR_XML_ERROR, "%s",
P
Peter Krempa 已提交
417
                           _("Missing 'sockets' attribute in CPU topology"));
418 419 420 421
            goto error;
        }
        def->sockets = (unsigned int) ul;

422
        ret = virXPathULong("string(./topology[1]/@cores)",
423 424
                            ctxt, &ul);
        if (ret < 0) {
425
            virReportError(VIR_ERR_XML_ERROR, "%s",
P
Peter Krempa 已提交
426
                           _("Missing 'cores' attribute in CPU topology"));
427 428 429 430
            goto error;
        }
        def->cores = (unsigned int) ul;

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

        if (!def->sockets || !def->cores || !def->threads) {
441 442
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("Invalid CPU topology"));
443 444 445 446
            goto error;
        }
    }

P
Peter Krempa 已提交
447
    if ((n = virXPathNodeSet("./feature", ctxt, &nodes)) < 0)
448 449 450
        goto error;

    if (n > 0) {
451
        if (!def->model && def->mode == VIR_CPU_MODE_CUSTOM) {
452
            virReportError(VIR_ERR_XML_ERROR, "%s",
P
Peter Krempa 已提交
453 454
                           _("Non-empty feature list specified without "
                             "CPU model"));
455 456 457
            goto error;
        }

E
Eric Blake 已提交
458 459
        if (VIR_RESIZE_N(def->features, def->nfeatures_max,
                         def->nfeatures, n) < 0)
460
            goto error;
P
Peter Krempa 已提交
461

462 463 464
        def->nfeatures = n;
    }

465
    for (i = 0; i < n; i++) {
466 467
        char *name;
        int policy; /* enum virDomainCPUFeaturePolicy */
468
        size_t j;
469 470 471 472 473

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

            strpolicy = virXMLPropString(nodes[i], "policy");
474 475 476 477
            if (strpolicy == NULL)
                policy = VIR_CPU_FEATURE_REQUIRE;
            else
                policy = virCPUFeaturePolicyTypeFromString(strpolicy);
478 479 480
            VIR_FREE(strpolicy);

            if (policy < 0) {
481
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
482
                               _("Invalid CPU feature policy"));
483 484
                goto error;
            }
485
        } else {
486
            policy = -1;
487
        }
488 489 490

        if (!(name = virXMLPropString(nodes[i], "name")) || *name == 0) {
            VIR_FREE(name);
491 492
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("Invalid CPU feature name"));
493 494 495
            goto error;
        }

496
        for (j = 0; j < i; j++) {
497
            if (STREQ(name, def->features[j].name)) {
498
                virReportError(VIR_ERR_XML_ERROR,
C
Chen Fan 已提交
499
                               _("CPU feature '%s' specified more than once"),
500
                               name);
501 502 503 504 505 506 507 508 509
                VIR_FREE(name);
                goto error;
            }
        }

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

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

545
 cleanup:
546
    ctxt->node = oldnode;
547 548
    VIR_FREE(fallback);
    VIR_FREE(vendor_id);
549 550 551
    VIR_FREE(nodes);
    return def;

552
 error:
553 554 555 556 557 558 559
    virCPUDefFree(def);
    def = NULL;
    goto cleanup;
}


char *
560
virCPUDefFormat(virCPUDefPtr def,
561
                virDomainNumaPtr numa,
562
                bool updateCPU)
563 564 565
{
    virBuffer buf = VIR_BUFFER_INITIALIZER;

566
    if (virCPUDefFormatBufFull(&buf, def, numa, updateCPU) < 0)
567 568
        goto cleanup;

569 570
    if (virBufferCheckError(&buf) < 0)
        goto cleanup;
571 572 573

    return virBufferContentAndReset(&buf);

574
 cleanup:
575
    virBufferFreeAndReset(&buf);
576 577 578 579
    return NULL;
}


580 581
int
virCPUDefFormatBufFull(virBufferPtr buf,
582
                       virCPUDefPtr def,
583
                       virDomainNumaPtr numa,
584
                       bool updateCPU)
585
{
586
    int ret = -1;
587
    virBuffer attributeBuf = VIR_BUFFER_INITIALIZER;
M
Michal Privoznik 已提交
588 589
    virBuffer childrenBuf = VIR_BUFFER_INITIALIZER;
    int indent = virBufferGetIndent(buf, false);
590

591 592 593
    if (!def)
        return 0;

594
    /* Format attributes */
595 596 597 598 599
    if (def->type == VIR_CPU_TYPE_GUEST) {
        const char *tmp;

        if (def->mode != VIR_CPU_MODE_CUSTOM || def->model) {
            if (!(tmp = virCPUModeTypeToString(def->mode))) {
600 601
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Unexpected CPU mode %d"), def->mode);
602
                goto cleanup;
603
            }
604
            virBufferAsprintf(&attributeBuf, " mode='%s'", tmp);
605 606
        }

607 608
        if (def->model &&
            (def->mode == VIR_CPU_MODE_CUSTOM ||
609
             updateCPU)) {
610
            if (!(tmp = virCPUMatchTypeToString(def->match))) {
611 612 613
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Unexpected CPU match policy %d"),
                               def->match);
614
                goto cleanup;
615
            }
616
            virBufferAsprintf(&attributeBuf, " match='%s'", tmp);
617
        }
618 619 620 621 622

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

625
    /* Format children */
M
Michal Privoznik 已提交
626
    virBufferAdjustIndent(&childrenBuf, indent + 2);
627
    if (def->type == VIR_CPU_TYPE_HOST && def->arch)
M
Michal Privoznik 已提交
628
        virBufferAsprintf(&childrenBuf, "<arch>%s</arch>\n",
629
                          virArchToString(def->arch));
M
Michal Privoznik 已提交
630
    if (virCPUDefFormatBuf(&childrenBuf, def, updateCPU) < 0)
631
        goto cleanup;
632

M
Michal Privoznik 已提交
633
    if (virDomainNumaDefCPUFormat(&childrenBuf, numa) < 0)
634
        goto cleanup;
635

636 637 638 639 640 641 642 643 644 645 646 647 648 649
    /* 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 已提交
650
    }
651

652 653
    ret = 0;
 cleanup:
654
    virBufferFreeAndReset(&attributeBuf);
M
Michal Privoznik 已提交
655
    virBufferFreeAndReset(&childrenBuf);
656
    return ret;
657 658
}

659
int
660
virCPUDefFormatBuf(virBufferPtr buf,
661
                   virCPUDefPtr def,
662
                   bool updateCPU)
663
{
664
    size_t i;
665 666
    bool formatModel;
    bool formatFallback;
667 668 669 670

    if (!def)
        return 0;

671
    formatModel = (def->mode == VIR_CPU_MODE_CUSTOM ||
672
                   def->mode == VIR_CPU_MODE_HOST_MODEL ||
673
                   updateCPU);
674 675 676 677
    formatFallback = (def->type == VIR_CPU_TYPE_GUEST &&
                      (def->mode == VIR_CPU_MODE_HOST_MODEL ||
                       (def->mode == VIR_CPU_MODE_CUSTOM && def->model)));

678
    if (!def->model && def->mode == VIR_CPU_MODE_CUSTOM && def->nfeatures) {
679 680
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Non-empty feature list specified without CPU model"));
681 682 683
        return -1;
    }

684
    if ((formatModel && def->model) || formatFallback) {
685
        virBufferAddLit(buf, "<model");
686
        if (formatFallback) {
687 688 689 690
            const char *fallback;

            fallback = virCPUFallbackTypeToString(def->fallback);
            if (!fallback) {
691 692 693
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Unexpected CPU fallback value: %d"),
                               def->fallback);
694 695 696
                return -1;
            }
            virBufferAsprintf(buf, " fallback='%s'", fallback);
697
            if (def->vendor_id)
698
                virBufferEscapeString(buf, " vendor_id='%s'", def->vendor_id);
699
        }
700
        if (formatModel && def->model) {
701
            virBufferEscapeString(buf, ">%s</model>\n", def->model);
702 703 704
        } else {
            virBufferAddLit(buf, "/>\n");
        }
705
    }
706

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

710
    if (def->sockets && def->cores && def->threads) {
711
        virBufferAddLit(buf, "<topology");
712 713 714
        virBufferAsprintf(buf, " sockets='%u'", def->sockets);
        virBufferAsprintf(buf, " cores='%u'", def->cores);
        virBufferAsprintf(buf, " threads='%u'", def->threads);
715 716 717
        virBufferAddLit(buf, "/>\n");
    }

718 719 720 721 722 723 724 725 726
    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");
    }

727 728
    for (i = 0; i < def->nfeatures; i++) {
        virCPUFeatureDefPtr feature = def->features + i;
729

730 731 732 733 734
        if (!feature->name) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Missing CPU feature name"));
            return -1;
        }
735

736 737
        if (def->type == VIR_CPU_TYPE_GUEST) {
            const char *policy;
738

739 740 741 742 743 744
            policy = virCPUFeaturePolicyTypeToString(feature->policy);
            if (!policy) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Unexpected CPU feature policy %d"),
                               feature->policy);
                return -1;
745
            }
746 747 748 749 750
            virBufferAsprintf(buf, "<feature policy='%s' name='%s'/>\n",
                              policy, feature->name);
        } else {
            virBufferAsprintf(buf, "<feature name='%s'/>\n",
                              feature->name);
751 752 753 754 755 756
        }
    }

    return 0;
}

P
Peter Krempa 已提交
757 758 759 760 761
static int
virCPUDefUpdateFeatureInternal(virCPUDefPtr def,
                               const char *name,
                               int policy,
                               bool update)
762
{
763
    size_t i;
764

P
Peter Krempa 已提交
765 766 767
    if (def->type == VIR_CPU_TYPE_HOST)
        policy = -1;

768
    for (i = 0; i < def->nfeatures; i++) {
769
        if (STREQ(name, def->features[i].name)) {
P
Peter Krempa 已提交
770 771 772 773 774
            if (update) {
                def->features[i].policy = policy;
                return 0;
            }

775
            virReportError(VIR_ERR_INTERNAL_ERROR,
C
Chen Fan 已提交
776
                           _("CPU feature '%s' specified more than once"),
777
                           name);
P
Peter Krempa 已提交
778

779 780 781 782
            return -1;
        }
    }

E
Eric Blake 已提交
783 784
    if (VIR_RESIZE_N(def->features, def->nfeatures_max,
                     def->nfeatures, 1) < 0)
785
        return -1;
786

787 788
    if (VIR_STRDUP(def->features[def->nfeatures].name, name) < 0)
        return -1;
789 790 791 792 793 794

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

    return 0;
}
795

P
Peter Krempa 已提交
796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811
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);
}

812 813
bool
virCPUDefIsEqual(virCPUDefPtr src,
814 815
                 virCPUDefPtr dst,
                 bool reportError)
816 817
{
    bool identical = false;
818
    size_t i;
819 820 821 822

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

823 824 825 826
#define MISMATCH(fmt, ...)                                              \
    if (reportError)                                                    \
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, fmt, __VA_ARGS__)

827
    if ((src && !dst) || (!src && dst)) {
828
        MISMATCH("%s", _("Target CPU does not match source"));
829 830 831 832
        goto cleanup;
    }

    if (src->type != dst->type) {
833 834 835
        MISMATCH(_("Target CPU type %s does not match source %s"),
                 virCPUTypeToString(dst->type),
                 virCPUTypeToString(src->type));
836 837 838
        goto cleanup;
    }

839
    if (src->mode != dst->mode) {
840 841 842
        MISMATCH(_("Target CPU mode %s does not match source %s"),
                 virCPUModeTypeToString(dst->mode),
                 virCPUModeTypeToString(src->mode));
843 844 845
        goto cleanup;
    }

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

    if (STRNEQ_NULLABLE(src->model, dst->model)) {
854 855
        MISMATCH(_("Target CPU model %s does not match source %s"),
                 NULLSTR(dst->model), NULLSTR(src->model));
856 857 858 859
        goto cleanup;
    }

    if (STRNEQ_NULLABLE(src->vendor, dst->vendor)) {
860 861
        MISMATCH(_("Target CPU vendor %s does not match source %s"),
                 NULLSTR(dst->vendor), NULLSTR(src->vendor));
862 863 864
        goto cleanup;
    }

865
    if (STRNEQ_NULLABLE(src->vendor_id, dst->vendor_id)) {
866 867
        MISMATCH(_("Target CPU vendor id %s does not match source %s"),
                 NULLSTR(dst->vendor_id), NULLSTR(src->vendor_id));
868 869 870
        goto cleanup;
    }

871
    if (src->sockets != dst->sockets) {
872 873
        MISMATCH(_("Target CPU sockets %d does not match source %d"),
                 dst->sockets, src->sockets);
874 875 876 877
        goto cleanup;
    }

    if (src->cores != dst->cores) {
878 879
        MISMATCH(_("Target CPU cores %d does not match source %d"),
                 dst->cores, src->cores);
880 881 882 883
        goto cleanup;
    }

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

    if (src->nfeatures != dst->nfeatures) {
890 891
        MISMATCH(_("Target CPU feature count %zu does not match source %zu"),
                 dst->nfeatures, src->nfeatures);
892 893 894
        goto cleanup;
    }

895
    for (i = 0; i < src->nfeatures; i++) {
896
        if (STRNEQ(src->features[i].name, dst->features[i].name)) {
897 898
            MISMATCH(_("Target CPU feature %s does not match source %s"),
                     dst->features[i].name, src->features[i].name);
899 900 901 902
            goto cleanup;
        }

        if (src->features[i].policy != dst->features[i].policy) {
903 904 905
            MISMATCH(_("Target CPU feature policy %s does not match source %s"),
                     virCPUFeaturePolicyTypeToString(dst->features[i].policy),
                     virCPUFeaturePolicyTypeToString(src->features[i].policy));
906 907 908 909
            goto cleanup;
        }
    }

910 911 912 913 914
    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))) {
915
        MISMATCH("%s", _("Target CPU cache does not match source"));
916 917 918
        goto cleanup;
    }

919 920
#undef MISMATCH

921 922
    identical = true;

923
 cleanup:
924 925
    return identical;
}