cpu_conf.c 26.6 KB
Newer Older
1
/*
2
 * cpu_conf.c: CPU XML handling
3
 *
4
 * Copyright (C) 2009-2014 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
VIR_ENUM_IMPL(virCPUFallback, VIR_CPU_FALLBACK_LAST,
              "allow",
              "forbid")

52 53 54 55 56 57 58
VIR_ENUM_IMPL(virCPUFeaturePolicy, VIR_CPU_FEATURE_LAST,
              "force",
              "require",
              "optional",
              "disable",
              "forbid")

59 60 61 62 63
VIR_ENUM_IMPL(virMemAccess, VIR_MEM_ACCESS_LAST,
              "default",
              "shared",
              "private")

64

65 66 67
void ATTRIBUTE_NONNULL(1)
virCPUDefFreeModel(virCPUDefPtr def)
{
68
    size_t i;
69 70 71

    VIR_FREE(def->model);
    VIR_FREE(def->vendor);
72
    VIR_FREE(def->vendor_id);
73 74 75 76 77 78

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

79 80 81
void
virCPUDefFree(virCPUDefPtr def)
{
82
    size_t i;
83 84 85 86

    if (!def)
        return;

87
    virCPUDefFreeModel(def);
88

89
    for (i = 0; i < def->ncells; i++) {
90
        virBitmapFree(def->cells[i].cpumask);
91 92 93
        VIR_FREE(def->cells[i].cpustr);
    }
    VIR_FREE(def->cells);
94
    VIR_FREE(def->vendor_id);
95

96 97 98 99
    VIR_FREE(def);
}


100 101
int ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2)
virCPUDefCopyModel(virCPUDefPtr dst,
102
                   const virCPUDef *src,
103 104
                   bool resetPolicy)
{
105
    size_t i;
106

107 108 109 110
    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)
111
        return -1;
112 113 114 115 116 117 118 119 120 121 122 123 124 125
    dst->nfeatures_max = dst->nfeatures = src->nfeatures;

    for (i = 0; i < dst->nfeatures; i++) {
        if (dst->type != src->type && resetPolicy) {
            if (dst->type == VIR_CPU_TYPE_HOST)
                dst->features[i].policy = -1;
            else if (src->features[i].policy == -1)
                dst->features[i].policy = VIR_CPU_FEATURE_REQUIRE;
            else
                dst->features[i].policy = src->features[i].policy;
        } else {
            dst->features[i].policy = src->features[i].policy;
        }

126 127
        if (VIR_STRDUP(dst->features[i].name, src->features[i].name) < 0)
            return -1;
128 129 130 131 132
    }

    return 0;
}

133
virCPUDefPtr
134
virCPUDefCopy(const virCPUDef *cpu)
135 136
{
    virCPUDefPtr copy;
137
    size_t i;
138

139
    if (!cpu || VIR_ALLOC(copy) < 0)
140 141 142
        return NULL;

    copy->type = cpu->type;
143
    copy->mode = cpu->mode;
144
    copy->match = cpu->match;
145
    copy->fallback = cpu->fallback;
146 147 148
    copy->sockets = cpu->sockets;
    copy->cores = cpu->cores;
    copy->threads = cpu->threads;
149
    copy->arch = cpu->arch;
150 151 152

    if (virCPUDefCopyModel(copy, cpu, false) < 0)
        goto error;
153 154 155

    if (cpu->ncells) {
        if (VIR_ALLOC_N(copy->cells, cpu->ncells) < 0)
156
            goto error;
157 158 159 160 161
        copy->ncells_max = copy->ncells = cpu->ncells;

        for (i = 0; i < cpu->ncells; i++) {
            copy->cells[i].mem = cpu->cells[i].mem;

162 163 164
            copy->cells[i].cpumask = virBitmapNewCopy(cpu->cells[i].cpumask);

            if (!copy->cells[i].cpumask)
165
                goto error;
166

167 168
            if (VIR_STRDUP(copy->cells[i].cpustr, cpu->cells[i].cpustr) < 0)
                goto error;
169 170 171
        }
        copy->cells_cpus = cpu->cells_cpus;
    }
172 173 174

    return copy;

175
 error:
176 177 178 179
    virCPUDefFree(copy);
    return NULL;
}

180
virCPUDefPtr
181
virCPUDefParseXML(xmlNodePtr node,
182
                  xmlXPathContextPtr ctxt,
183
                  virCPUType mode)
184 185 186 187
{
    virCPUDefPtr def;
    xmlNodePtr *nodes = NULL;
    int n;
188
    size_t i;
189
    char *cpuMode;
190 191
    char *fallback = NULL;
    char *vendor_id = NULL;
192

193
    if (!xmlStrEqual(node->name, BAD_CAST "cpu")) {
194
        virReportError(VIR_ERR_XML_ERROR, "%s",
195
                       _("XML does not contain expected 'cpu' element"));
196 197 198
        return NULL;
    }

199
    if (VIR_ALLOC(def) < 0)
200 201
        return NULL;

202
    if (mode == VIR_CPU_TYPE_AUTO) {
203 204
        if (virXPathBoolean("boolean(./arch)", ctxt)) {
            if (virXPathBoolean("boolean(./@match)", ctxt)) {
205
                virReportError(VIR_ERR_XML_ERROR, "%s",
206
                               _("'arch' element cannot be used inside 'cpu'"
207
                                 " element with 'match' attribute'"));
208 209
                goto error;
            }
210
            def->type = VIR_CPU_TYPE_HOST;
211
        } else {
212
            def->type = VIR_CPU_TYPE_GUEST;
213 214
        }
    } else {
215
        def->type = mode;
216 217 218 219 220
    }

    if ((cpuMode = virXMLPropString(node, "mode"))) {
        if (def->type == VIR_CPU_TYPE_HOST) {
            VIR_FREE(cpuMode);
221 222
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("Attribute mode is only allowed for guest CPU"));
223 224 225 226 227
            goto error;
        } else {
            def->mode = virCPUModeTypeFromString(cpuMode);

            if (def->mode < 0) {
228
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
229 230
                               _("Invalid mode attribute '%s'"),
                               cpuMode);
231
                VIR_FREE(cpuMode);
232 233
                goto error;
            }
234
            VIR_FREE(cpuMode);
235 236 237 238 239 240 241
        }
    } else {
        if (def->type == VIR_CPU_TYPE_HOST)
            def->mode = -1;
        else
            def->mode = VIR_CPU_MODE_CUSTOM;
    }
242 243

    if (def->type == VIR_CPU_TYPE_GUEST) {
244 245 246
        char *match = virXMLPropString(node, "match");

        if (!match) {
247 248 249 250
            if (virXPathBoolean("boolean(./model)", ctxt))
                def->match = VIR_CPU_MATCH_EXACT;
            else
                def->match = -1;
251 252 253 254 255
        } else {
            def->match = virCPUMatchTypeFromString(match);
            VIR_FREE(match);

            if (def->match < 0) {
256
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
P
Peter Krempa 已提交
257 258
                               _("Invalid match attribute for CPU "
                                 "specification"));
259 260
                goto error;
            }
261 262 263 264
        }
    }

    if (def->type == VIR_CPU_TYPE_HOST) {
265 266
        char *arch = virXPathString("string(./arch[1])", ctxt);
        if (!arch) {
267 268
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("Missing CPU architecture"));
269 270
            goto error;
        }
271
        if ((def->arch = virArchFromString(arch)) == VIR_ARCH_NONE) {
272
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
273 274 275 276 277
                           _("Unknown architecture %s"), arch);
            VIR_FREE(arch);
            goto error;
        }
        VIR_FREE(arch);
278 279
    }

280
    if (!(def->model = virXPathString("string(./model[1])", ctxt)) &&
281
        def->type == VIR_CPU_TYPE_HOST) {
282 283
        virReportError(VIR_ERR_XML_ERROR, "%s",
                        _("Missing CPU model name"));
284 285 286
        goto error;
    }

287
    if (def->type == VIR_CPU_TYPE_GUEST &&
288 289
        def->mode != VIR_CPU_MODE_HOST_PASSTHROUGH) {

290 291
        if ((fallback = virXPathString("string(./model[1]/@fallback)", ctxt))) {
            if ((def->fallback = virCPUFallbackTypeFromString(fallback)) < 0) {
292
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
293 294
                               _("Invalid fallback attribute"));
                goto error;
295
            }
K
Ken ICHIKAWA 已提交
296
        }
297

298 299 300
        if ((vendor_id = virXPathString("string(./model[1]/@vendor_id)",
                                        ctxt))) {
            if (strlen(vendor_id) != VIR_CPU_VENDOR_ID_LENGTH) {
K
Ken ICHIKAWA 已提交
301
                virReportError(VIR_ERR_XML_ERROR,
302
                               _("vendor_id must be exactly %d characters long"),
K
Ken ICHIKAWA 已提交
303 304 305
                               VIR_CPU_VENDOR_ID_LENGTH);
                goto error;
            }
306

K
Ken ICHIKAWA 已提交
307
            /* ensure that the string can be passed to qemu*/
308
            if (strchr(vendor_id, ',')) {
K
Ken ICHIKAWA 已提交
309 310
                    virReportError(VIR_ERR_XML_ERROR, "%s",
                                   _("vendor id is invalid"));
311
                    goto error;
312
            }
313

K
Ken ICHIKAWA 已提交
314
            def->vendor_id = vendor_id;
315
            vendor_id = NULL;
316 317 318
        }
    }

J
Jiri Denemark 已提交
319 320
    def->vendor = virXPathString("string(./vendor[1])", ctxt);
    if (def->vendor && !def->model) {
321 322
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("CPU vendor specified without CPU model"));
J
Jiri Denemark 已提交
323 324 325
        goto error;
    }

326
    if (virXPathNode("./topology[1]", ctxt)) {
327 328 329
        int ret;
        unsigned long ul;

330
        ret = virXPathULong("string(./topology[1]/@sockets)",
331 332
                            ctxt, &ul);
        if (ret < 0) {
333
            virReportError(VIR_ERR_XML_ERROR, "%s",
P
Peter Krempa 已提交
334
                           _("Missing 'sockets' attribute in CPU topology"));
335 336 337 338
            goto error;
        }
        def->sockets = (unsigned int) ul;

339
        ret = virXPathULong("string(./topology[1]/@cores)",
340 341
                            ctxt, &ul);
        if (ret < 0) {
342
            virReportError(VIR_ERR_XML_ERROR, "%s",
P
Peter Krempa 已提交
343
                           _("Missing 'cores' attribute in CPU topology"));
344 345 346 347
            goto error;
        }
        def->cores = (unsigned int) ul;

348
        ret = virXPathULong("string(./topology[1]/@threads)",
349 350
                            ctxt, &ul);
        if (ret < 0) {
351
            virReportError(VIR_ERR_XML_ERROR, "%s",
P
Peter Krempa 已提交
352
                           _("Missing 'threads' attribute in CPU topology"));
353 354 355 356 357
            goto error;
        }
        def->threads = (unsigned int) ul;

        if (!def->sockets || !def->cores || !def->threads) {
358 359
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("Invalid CPU topology"));
360 361 362 363
            goto error;
        }
    }

P
Peter Krempa 已提交
364
    if ((n = virXPathNodeSet("./feature", ctxt, &nodes)) < 0)
365 366 367
        goto error;

    if (n > 0) {
368
        if (!def->model && def->mode != VIR_CPU_MODE_HOST_MODEL) {
369
            virReportError(VIR_ERR_XML_ERROR, "%s",
P
Peter Krempa 已提交
370 371
                           _("Non-empty feature list specified without "
                             "CPU model"));
372 373 374
            goto error;
        }

E
Eric Blake 已提交
375 376
        if (VIR_RESIZE_N(def->features, def->nfeatures_max,
                         def->nfeatures, n) < 0)
377
            goto error;
P
Peter Krempa 已提交
378

379 380 381
        def->nfeatures = n;
    }

382
    for (i = 0; i < n; i++) {
383 384
        char *name;
        int policy; /* enum virDomainCPUFeaturePolicy */
385
        size_t j;
386 387 388 389 390

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

            strpolicy = virXMLPropString(nodes[i], "policy");
391 392 393 394
            if (strpolicy == NULL)
                policy = VIR_CPU_FEATURE_REQUIRE;
            else
                policy = virCPUFeaturePolicyTypeFromString(strpolicy);
395 396 397
            VIR_FREE(strpolicy);

            if (policy < 0) {
398
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
399
                               _("Invalid CPU feature policy"));
400 401
                goto error;
            }
402
        } else {
403
            policy = -1;
404
        }
405 406 407

        if (!(name = virXMLPropString(nodes[i], "name")) || *name == 0) {
            VIR_FREE(name);
408 409
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("Invalid CPU feature name"));
410 411 412
            goto error;
        }

413
        for (j = 0; j < i; j++) {
414
            if (STREQ(name, def->features[j].name)) {
415
                virReportError(VIR_ERR_XML_ERROR,
C
Chen Fan 已提交
416
                               _("CPU feature '%s' specified more than once"),
417
                               name);
418 419 420 421 422 423 424 425 426
                VIR_FREE(name);
                goto error;
            }
        }

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

427 428 429 430
    if (virXPathNode("./numa[1]", ctxt)) {
        VIR_FREE(nodes);
        n = virXPathNodeSet("./numa[1]/cell", ctxt, &nodes);
        if (n <= 0) {
431 432
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("NUMA topology defined without NUMA cells"));
433 434 435 436 437
            goto error;
        }

        if (VIR_RESIZE_N(def->cells, def->ncells_max,
                         def->ncells, n) < 0)
438
            goto error;
439 440 441

        def->ncells = n;

442
        for (i = 0; i < n; i++) {
443
            char *cpus, *memory, *memAccessStr;
444
            int ret, ncpus = 0;
445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476
            unsigned int cur_cell;
            char *tmp = NULL;

            tmp = virXMLPropString(nodes[i], "id");
            if (!tmp) {
                cur_cell = i;
            } else {
                ret  = virStrToLong_ui(tmp, NULL, 10, &cur_cell);
                if (ret == -1) {
                    virReportError(VIR_ERR_XML_ERROR,
                                   _("Invalid 'id' attribute in NUMA cell: %s"),
                                   tmp);
                    VIR_FREE(tmp);
                    goto error;
                }
                VIR_FREE(tmp);
            }

            if (cur_cell >= n) {
                virReportError(VIR_ERR_XML_ERROR, "%s",
                               _("Exactly one 'cell' element per guest "
                                 "NUMA cell allowed, non-contiguous ranges or "
                                 "ranges not starting from 0 are not allowed"));
                goto error;
            }

            if (def->cells[cur_cell].cpustr) {
                virReportError(VIR_ERR_XML_ERROR,
                               _("Duplicate NUMA cell info for cell id '%u'"),
                               cur_cell);
                goto error;
            }
477

478
            cpus = virXMLPropString(nodes[i], "cpus");
479
            if (!cpus) {
480 481
                virReportError(VIR_ERR_XML_ERROR, "%s",
                               _("Missing 'cpus' attribute in NUMA cell"));
482 483
                goto error;
            }
484
            def->cells[cur_cell].cpustr = cpus;
485

486
            ncpus = virBitmapParse(cpus, 0, &def->cells[cur_cell].cpumask,
487
                                   VIR_DOMAIN_CPUMASK_LEN);
488
            if (ncpus <= 0)
489 490 491 492 493
                goto error;
            def->cells_cpus += ncpus;

            memory = virXMLPropString(nodes[i], "memory");
            if (!memory) {
494 495
                virReportError(VIR_ERR_XML_ERROR, "%s",
                               _("Missing 'memory' attribute in NUMA cell"));
496 497 498
                goto error;
            }

499
            ret = virStrToLong_ull(memory, NULL, 10, &def->cells[cur_cell].mem);
500
            if (ret == -1) {
501 502
                virReportError(VIR_ERR_XML_ERROR, "%s",
                               _("Invalid 'memory' attribute in NUMA cell"));
503 504 505 506
                VIR_FREE(memory);
                goto error;
            }
            VIR_FREE(memory);
507 508 509

            memAccessStr = virXMLPropString(nodes[i], "memAccess");
            if (memAccessStr) {
510
                int rc = virMemAccessTypeFromString(memAccessStr);
511

512
                if (rc <= 0) {
513 514 515 516 517
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("Invalid 'memAccess' attribute "
                                     "value '%s'"),
                                   memAccessStr);
                    VIR_FREE(memAccessStr);
518
                    goto error;
519
                }
520 521 522

                def->cells[cur_cell].memAccess = rc;

523 524
                VIR_FREE(memAccessStr);
            }
525 526 527
        }
    }

528
 cleanup:
529 530
    VIR_FREE(fallback);
    VIR_FREE(vendor_id);
531 532 533
    VIR_FREE(nodes);
    return def;

534
 error:
535 536 537 538 539 540 541
    virCPUDefFree(def);
    def = NULL;
    goto cleanup;
}


char *
542 543
virCPUDefFormat(virCPUDefPtr def,
                unsigned int flags)
544 545 546
{
    virBuffer buf = VIR_BUFFER_INITIALIZER;

547
    if (virCPUDefFormatBufFull(&buf, def, flags) < 0)
548 549
        goto cleanup;

550 551
    if (virBufferCheckError(&buf) < 0)
        goto cleanup;
552 553 554

    return virBufferContentAndReset(&buf);

555
 cleanup:
556
    virBufferFreeAndReset(&buf);
557 558 559 560
    return NULL;
}


561 562
int
virCPUDefFormatBufFull(virBufferPtr buf,
563 564
                       virCPUDefPtr def,
                       unsigned int flags)
565 566 567 568
{
    if (!def)
        return 0;

569 570 571 572 573 574
    virBufferAddLit(buf, "<cpu");
    if (def->type == VIR_CPU_TYPE_GUEST) {
        const char *tmp;

        if (def->mode != VIR_CPU_MODE_CUSTOM || def->model) {
            if (!(tmp = virCPUModeTypeToString(def->mode))) {
575 576
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Unexpected CPU mode %d"), def->mode);
577 578 579
                return -1;
            }
            virBufferAsprintf(buf, " mode='%s'", tmp);
580 581
        }

582 583 584 585
        if (def->model &&
            (def->mode == VIR_CPU_MODE_CUSTOM ||
             (flags & VIR_DOMAIN_XML_UPDATE_CPU))) {
            if (!(tmp = virCPUMatchTypeToString(def->match))) {
586 587 588
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Unexpected CPU match policy %d"),
                               def->match);
589 590 591 592
                return -1;
            }
            virBufferAsprintf(buf, " match='%s'", tmp);
        }
593
    }
594
    virBufferAddLit(buf, ">\n");
595
    virBufferAdjustIndent(buf, 2);
596 597

    if (def->arch)
598
        virBufferAsprintf(buf, "<arch>%s</arch>\n",
599
                          virArchToString(def->arch));
600
    if (virCPUDefFormatBuf(buf, def, flags) < 0)
601 602 603 604 605 606 607 608
        return -1;
    virBufferAdjustIndent(buf, -2);

    virBufferAddLit(buf, "</cpu>\n");

    return 0;
}

609
int
610
virCPUDefFormatBuf(virBufferPtr buf,
611 612
                   virCPUDefPtr def,
                   unsigned int flags)
613
{
614
    size_t i;
615 616
    bool formatModel;
    bool formatFallback;
617 618 619 620

    if (!def)
        return 0;

621 622 623 624 625 626
    formatModel = (def->mode == VIR_CPU_MODE_CUSTOM ||
                   (flags & VIR_DOMAIN_XML_UPDATE_CPU));
    formatFallback = (def->type == VIR_CPU_TYPE_GUEST &&
                      (def->mode == VIR_CPU_MODE_HOST_MODEL ||
                       (def->mode == VIR_CPU_MODE_CUSTOM && def->model)));

627 628 629
    if (!def->model &&
        def->mode != VIR_CPU_MODE_HOST_MODEL &&
        def->nfeatures) {
630 631
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Non-empty feature list specified without CPU model"));
632 633 634
        return -1;
    }

635
    if ((formatModel && def->model) || formatFallback) {
636
        virBufferAddLit(buf, "<model");
637
        if (formatFallback) {
638 639 640 641
            const char *fallback;

            fallback = virCPUFallbackTypeToString(def->fallback);
            if (!fallback) {
642 643 644
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Unexpected CPU fallback value: %d"),
                               def->fallback);
645 646 647
                return -1;
            }
            virBufferAsprintf(buf, " fallback='%s'", fallback);
648 649
            if (def->vendor_id)
                virBufferAsprintf(buf, " vendor_id='%s'", def->vendor_id);
650
        }
651 652 653 654 655
        if (formatModel && def->model) {
            virBufferAsprintf(buf, ">%s</model>\n", def->model);
        } else {
            virBufferAddLit(buf, "/>\n");
        }
656
    }
657

658
    if (formatModel && def->vendor)
659
        virBufferAsprintf(buf, "<vendor>%s</vendor>\n", def->vendor);
J
Jiri Denemark 已提交
660

661
    if (def->sockets && def->cores && def->threads) {
662
        virBufferAddLit(buf, "<topology");
663 664 665
        virBufferAsprintf(buf, " sockets='%u'", def->sockets);
        virBufferAsprintf(buf, " cores='%u'", def->cores);
        virBufferAsprintf(buf, " threads='%u'", def->threads);
666 667 668
        virBufferAddLit(buf, "/>\n");
    }

669 670
    for (i = 0; i < def->nfeatures; i++) {
        virCPUFeatureDefPtr feature = def->features + i;
671

672 673 674 675 676
        if (!feature->name) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Missing CPU feature name"));
            return -1;
        }
677

678 679 680 681 682 683 684 685 686
        if (def->type == VIR_CPU_TYPE_GUEST) {
            const char *policy;

            policy = virCPUFeaturePolicyTypeToString(feature->policy);
            if (!policy) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Unexpected CPU feature policy %d"),
                               feature->policy);
                return -1;
687
            }
688 689 690 691 692
            virBufferAsprintf(buf, "<feature policy='%s' name='%s'/>\n",
                              policy, feature->name);
        } else {
            virBufferAsprintf(buf, "<feature name='%s'/>\n",
                              feature->name);
693 694 695
        }
    }

696 697
    if (def->ncells) {
        virBufferAddLit(buf, "<numa>\n");
698
        virBufferAdjustIndent(buf, 2);
699
        for (i = 0; i < def->ncells; i++) {
700 701
            virMemAccess memAccess = def->cells[i].memAccess;

702
            virBufferAddLit(buf, "<cell");
703
            virBufferAsprintf(buf, " id='%zu'", i);
704
            virBufferAsprintf(buf, " cpus='%s'", def->cells[i].cpustr);
705
            virBufferAsprintf(buf, " memory='%llu'", def->cells[i].mem);
706 707 708
            if (memAccess)
                virBufferAsprintf(buf, " memAccess='%s'",
                                  virMemAccessTypeToString(memAccess));
709 710
            virBufferAddLit(buf, "/>\n");
        }
711
        virBufferAdjustIndent(buf, -2);
712 713
        virBufferAddLit(buf, "</numa>\n");
    }
714 715 716
    return 0;
}

P
Peter Krempa 已提交
717 718 719 720 721
static int
virCPUDefUpdateFeatureInternal(virCPUDefPtr def,
                               const char *name,
                               int policy,
                               bool update)
722
{
723
    size_t i;
724

P
Peter Krempa 已提交
725 726 727
    if (def->type == VIR_CPU_TYPE_HOST)
        policy = -1;

728
    for (i = 0; i < def->nfeatures; i++) {
729
        if (STREQ(name, def->features[i].name)) {
P
Peter Krempa 已提交
730 731 732 733 734
            if (update) {
                def->features[i].policy = policy;
                return 0;
            }

735
            virReportError(VIR_ERR_INTERNAL_ERROR,
C
Chen Fan 已提交
736
                           _("CPU feature '%s' specified more than once"),
737
                           name);
P
Peter Krempa 已提交
738

739 740 741 742
            return -1;
        }
    }

E
Eric Blake 已提交
743 744
    if (VIR_RESIZE_N(def->features, def->nfeatures_max,
                     def->nfeatures, 1) < 0)
745
        return -1;
746

747 748
    if (VIR_STRDUP(def->features[def->nfeatures].name, name) < 0)
        return -1;
749 750 751 752 753 754

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

    return 0;
}
755

P
Peter Krempa 已提交
756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771
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);
}

772 773 774 775 776
bool
virCPUDefIsEqual(virCPUDefPtr src,
                 virCPUDefPtr dst)
{
    bool identical = false;
777
    size_t i;
778 779 780 781 782

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

    if ((src && !dst) || (!src && dst)) {
783 784
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Target CPU does not match source"));
785 786 787 788
        goto cleanup;
    }

    if (src->type != dst->type) {
789 790 791 792
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target CPU type %s does not match source %s"),
                       virCPUTypeToString(dst->type),
                       virCPUTypeToString(src->type));
793 794 795
        goto cleanup;
    }

796
    if (src->mode != dst->mode) {
797 798 799 800
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target CPU mode %s does not match source %s"),
                       virCPUModeTypeToString(dst->mode),
                       virCPUModeTypeToString(src->mode));
801 802 803
        goto cleanup;
    }

804
    if (src->arch != dst->arch) {
805 806
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target CPU arch %s does not match source %s"),
807 808
                       virArchToString(dst->arch),
                       virArchToString(src->arch));
809 810 811 812
        goto cleanup;
    }

    if (STRNEQ_NULLABLE(src->model, dst->model)) {
813 814 815
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target CPU model %s does not match source %s"),
                       NULLSTR(dst->model), NULLSTR(src->model));
816 817 818 819
        goto cleanup;
    }

    if (STRNEQ_NULLABLE(src->vendor, dst->vendor)) {
820 821 822
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target CPU vendor %s does not match source %s"),
                       NULLSTR(dst->vendor), NULLSTR(src->vendor));
823 824 825
        goto cleanup;
    }

826
    if (STRNEQ_NULLABLE(src->vendor_id, dst->vendor_id)) {
827
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
828
                       _("Target CPU vendor id %s does not match source %s"),
829
                       NULLSTR(dst->vendor_id), NULLSTR(src->vendor_id));
830 831 832
        goto cleanup;
    }

833
    if (src->sockets != dst->sockets) {
834 835 836
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target CPU sockets %d does not match source %d"),
                       dst->sockets, src->sockets);
837 838 839 840
        goto cleanup;
    }

    if (src->cores != dst->cores) {
841 842 843
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target CPU cores %d does not match source %d"),
                       dst->cores, src->cores);
844 845 846 847
        goto cleanup;
    }

    if (src->threads != dst->threads) {
848 849 850
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target CPU threads %d does not match source %d"),
                       dst->threads, src->threads);
851 852 853 854
        goto cleanup;
    }

    if (src->nfeatures != dst->nfeatures) {
855 856 857
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target CPU feature count %zu does not match source %zu"),
                       dst->nfeatures, src->nfeatures);
858 859 860
        goto cleanup;
    }

861
    for (i = 0; i < src->nfeatures; i++) {
862
        if (STRNEQ(src->features[i].name, dst->features[i].name)) {
863 864 865
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target CPU feature %s does not match source %s"),
                           dst->features[i].name, src->features[i].name);
866 867 868 869
            goto cleanup;
        }

        if (src->features[i].policy != dst->features[i].policy) {
870 871 872 873
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target CPU feature policy %s does not match source %s"),
                           virCPUFeaturePolicyTypeToString(dst->features[i].policy),
                           virCPUFeaturePolicyTypeToString(src->features[i].policy));
874 875 876 877 878 879
            goto cleanup;
        }
    }

    identical = true;

880
 cleanup:
881 882
    return identical;
}