capabilities.c 32.5 KB
Newer Older
1 2 3
/*
 * capabilities.c: hypervisor capabilities
 *
4
 * Copyright (C) 2006-2014 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16 17
 * Copyright (C) 2006-2008 Daniel P. Berrange
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with this library.  If not, see
O
Osier Yang 已提交
19
 * <http://www.gnu.org/licenses/>.
20 21 22 23
 *
 * Author: Daniel P. Berrange <berrange@redhat.com>
 */

24 25
#include <config.h>

26 27
#include <strings.h>

28
#include "capabilities.h"
29
#include "virbuffer.h"
30
#include "viralloc.h"
31
#include "viruuid.h"
32
#include "cpu_conf.h"
33
#include "virerror.h"
34
#include "virstring.h"
35 36 37

#define VIR_FROM_THIS VIR_FROM_CAPABILITIES

38 39
VIR_ENUM_DECL(virCapsHostPMTarget)
VIR_ENUM_IMPL(virCapsHostPMTarget, VIR_NODE_SUSPEND_TARGET_LAST,
40
              "suspend_mem", "suspend_disk", "suspend_hybrid");
41

42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
static virClassPtr virCapsClass;
static void virCapabilitiesDispose(void *obj);

static int virCapabilitiesOnceInit(void)
{
    if (!(virCapsClass = virClassNew(virClassForObject(),
                                     "virCaps",
                                     sizeof(virCaps),
                                     virCapabilitiesDispose)))
        return -1;

    return 0;
}

VIR_ONCE_GLOBAL_INIT(virCapabilities)

58 59
/**
 * virCapabilitiesNew:
60
 * @hostarch: host machine architecture
61 62
 * @offlineMigrate: true if offline migration is available
 * @liveMigrate: true if live migration is available
63
 *
64 65 66
 * Allocate a new capabilities object
 */
virCapsPtr
67
virCapabilitiesNew(virArch hostarch,
68 69
                   bool offlineMigrate,
                   bool liveMigrate)
70 71 72
{
    virCapsPtr caps;

73 74 75 76
    if (virCapabilitiesInitialize() < 0)
        return NULL;

    if (!(caps = virObjectNew(virCapsClass)))
77
        return NULL;
78

79
    caps->host.arch = hostarch;
80 81 82 83 84 85
    caps->host.offlineMigrate = offlineMigrate;
    caps->host.liveMigrate = liveMigrate;

    return caps;
}

86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
void
virCapabilitiesClearHostNUMACellCPUTopology(virCapsHostNUMACellCPUPtr cpus,
                                            size_t ncpus)
{
    size_t i;

    if (!cpus)
        return;

    for (i = 0; i < ncpus; i++) {
        virBitmapFree(cpus[i].siblings);
        cpus[i].siblings = NULL;
    }
}

101 102 103
static void
virCapabilitiesFreeHostNUMACell(virCapsHostNUMACellPtr cell)
{
104 105 106
    if (cell == NULL)
        return;

107 108
    virCapabilitiesClearHostNUMACellCPUTopology(cell->cpus, cell->ncpus);

109
    VIR_FREE(cell->cpus);
110
    VIR_FREE(cell->siblings);
M
Michal Privoznik 已提交
111
    VIR_FREE(cell->pageinfo);
112
    VIR_FREE(cell);
113 114
}

115 116 117 118 119 120 121 122 123 124
static void
virCapabilitiesFreeGuestMachine(virCapsGuestMachinePtr machine)
{
    if (machine == NULL)
        return;
    VIR_FREE(machine->name);
    VIR_FREE(machine->canonical);
    VIR_FREE(machine);
}

125 126 127
static void
virCapabilitiesFreeGuestDomain(virCapsGuestDomainPtr dom)
{
128
    size_t i;
129 130 131
    if (dom == NULL)
        return;

132 133
    VIR_FREE(dom->info.emulator);
    VIR_FREE(dom->info.loader);
134
    for (i = 0; i < dom->info.nmachines; i++)
135
        virCapabilitiesFreeGuestMachine(dom->info.machines[i]);
136 137
    VIR_FREE(dom->info.machines);
    VIR_FREE(dom->type);
138

139
    VIR_FREE(dom);
140 141 142 143 144
}

static void
virCapabilitiesFreeGuestFeature(virCapsGuestFeaturePtr feature)
{
145 146
    if (feature == NULL)
        return;
147 148
    VIR_FREE(feature->name);
    VIR_FREE(feature);
149 150 151 152 153
}

static void
virCapabilitiesFreeGuest(virCapsGuestPtr guest)
{
154
    size_t i;
155 156 157
    if (guest == NULL)
        return;

158
    VIR_FREE(guest->ostype);
159

160 161
    VIR_FREE(guest->arch.defaultInfo.emulator);
    VIR_FREE(guest->arch.defaultInfo.loader);
162
    for (i = 0; i < guest->arch.defaultInfo.nmachines; i++)
163
        virCapabilitiesFreeGuestMachine(guest->arch.defaultInfo.machines[i]);
164
    VIR_FREE(guest->arch.defaultInfo.machines);
165

166
    for (i = 0; i < guest->arch.ndomains; i++)
167
        virCapabilitiesFreeGuestDomain(guest->arch.domains[i]);
168
    VIR_FREE(guest->arch.domains);
169

170
    for (i = 0; i < guest->nfeatures; i++)
171
        virCapabilitiesFreeGuestFeature(guest->features[i]);
172
    VIR_FREE(guest->features);
173

174
    VIR_FREE(guest);
175 176
}

177 178 179
void
virCapabilitiesFreeNUMAInfo(virCapsPtr caps)
{
180
    size_t i;
181

182
    for (i = 0; i < caps->host.nnumaCell; i++)
183 184
        virCapabilitiesFreeHostNUMACell(caps->host.numaCell[i]);
    VIR_FREE(caps->host.numaCell);
185
    caps->host.nnumaCell = 0;
186
}
187

188 189 190 191 192 193 194 195 196 197 198 199 200 201
static void
virCapabilitiesClearSecModel(virCapsHostSecModelPtr secmodel)
{
    size_t i;
    for (i = 0; i < secmodel->nlabels; i++) {
        VIR_FREE(secmodel->labels[i].type);
        VIR_FREE(secmodel->labels[i].label);
    }

    VIR_FREE(secmodel->labels);
    VIR_FREE(secmodel->model);
    VIR_FREE(secmodel->doi);
}

202 203 204 205
static void
virCapabilitiesDispose(void *object)
{
    virCapsPtr caps = object;
206
    size_t i;
207

208
    for (i = 0; i < caps->nguests; i++)
209
        virCapabilitiesFreeGuest(caps->guests[i]);
210
    VIR_FREE(caps->guests);
211

212
    for (i = 0; i < caps->host.nfeatures; i++)
213 214
        VIR_FREE(caps->host.features[i]);
    VIR_FREE(caps->host.features);
215 216

    virCapabilitiesFreeNUMAInfo(caps);
217

218
    for (i = 0; i < caps->host.nmigrateTrans; i++)
219 220
        VIR_FREE(caps->host.migrateTrans[i]);
    VIR_FREE(caps->host.migrateTrans);
221

222
    for (i = 0; i < caps->host.nsecModels; i++) {
223
        virCapabilitiesClearSecModel(&caps->host.secModels[i]);
224 225 226
    }
    VIR_FREE(caps->host.secModels);

M
Michal Privoznik 已提交
227
    VIR_FREE(caps->host.pagesSize);
228
    virCPUDefFree(caps->host.cpu);
229 230 231 232 233 234 235 236 237 238 239 240 241 242
}


/**
 * virCapabilitiesAddHostFeature:
 * @caps: capabilities to extend
 * @name: name of new feature
 *
 * Registers a new host CPU feature, eg 'pae', or 'vmx'
 */
int
virCapabilitiesAddHostFeature(virCapsPtr caps,
                              const char *name)
{
E
Eric Blake 已提交
243 244
    if (VIR_RESIZE_N(caps->host.features, caps->host.nfeatures_max,
                     caps->host.nfeatures, 1) < 0)
245 246
        return -1;

247
    if (VIR_STRDUP(caps->host.features[caps->host.nfeatures], name) < 0)
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
        return -1;
    caps->host.nfeatures++;

    return 0;
}

/**
 * virCapabilitiesAddHostMigrateTransport:
 * @caps: capabilities to extend
 * @name: name of migration transport
 *
 * Registers a new domain migration transport URI
 */
int
virCapabilitiesAddHostMigrateTransport(virCapsPtr caps,
                                       const char *name)
{
E
Eric Blake 已提交
265 266
    if (VIR_RESIZE_N(caps->host.migrateTrans, caps->host.nmigrateTrans_max,
                     caps->host.nmigrateTrans, 1) < 0)
267 268
        return -1;

269
    if (VIR_STRDUP(caps->host.migrateTrans[caps->host.nmigrateTrans], name) < 0)
270 271 272 273 274 275 276 277 278 279 280
        return -1;
    caps->host.nmigrateTrans++;

    return 0;
}


/**
 * virCapabilitiesAddHostNUMACell:
 * @caps: capabilities to extend
 * @num: ID number of NUMA cell
281
 * @mem: Total size of memory in the NUMA node (in KiB)
282
 * @ncpus: number of CPUs in cell
283
 * @cpus: array of CPU definition structures, the pointer is stolen
284 285
 * @nsiblings: number of sibling NUMA nodes
 * @siblings: info on sibling NUMA nodes
M
Michal Privoznik 已提交
286 287
 * @npageinfo: number of pages at node @num
 * @pageinfo: info on each single memory page
288 289 290 291 292 293 294
 *
 * Registers a new NUMA cell for a host, passing in a
 * array of CPU IDs belonging to the cell
 */
int
virCapabilitiesAddHostNUMACell(virCapsPtr caps,
                               int num,
295
                               unsigned long long mem,
296 297 298
                               int ncpus,
                               virCapsHostNUMACellCPUPtr cpus,
                               int nsiblings,
M
Michal Privoznik 已提交
299 300 301
                               virCapsHostNUMACellSiblingInfoPtr siblings,
                               int npageinfo,
                               virCapsHostNUMACellPageInfoPtr pageinfo)
302
{
303
    virCapsHostNUMACellPtr cell;
304

E
Eric Blake 已提交
305 306
    if (VIR_RESIZE_N(caps->host.numaCell, caps->host.nnumaCell_max,
                     caps->host.nnumaCell, 1) < 0)
307 308
        return -1;

309
    if (VIR_ALLOC(cell) < 0)
310 311
        return -1;

312
    cell->num = num;
313
    cell->mem = mem;
M
Michal Privoznik 已提交
314
    cell->ncpus = ncpus;
315
    cell->cpus = cpus;
316
    cell->nsiblings = nsiblings;
M
Michal Privoznik 已提交
317 318 319
    cell->siblings = siblings;
    cell->npageinfo = npageinfo;
    cell->pageinfo = pageinfo;
320

E
Eric Blake 已提交
321
    caps->host.numaCell[caps->host.nnumaCell++] = cell;
322 323 324 325

    return 0;
}

326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346

/**
 * virCapabilitiesSetHostCPU:
 * @caps: capabilities to extend
 * @cpu: CPU definition
 *
 * Sets host CPU specification
 */
int
virCapabilitiesSetHostCPU(virCapsPtr caps,
                          virCPUDefPtr cpu)
{
    if (cpu == NULL)
        return -1;

    caps->host.cpu = cpu;

    return 0;
}


347 348 349 350 351 352 353 354 355 356 357 358
/**
 * virCapabilitiesAllocMachines:
 * @machines: machine variants for emulator ('pc', or 'isapc', etc)
 * @nmachines: number of machine variants for emulator
 *
 * Allocate a table of virCapsGuestMachinePtr from the supplied table
 * of machine names.
 */
virCapsGuestMachinePtr *
virCapabilitiesAllocMachines(const char *const *names, int nnames)
{
    virCapsGuestMachinePtr *machines;
359
    size_t i;
360 361 362 363 364 365

    if (VIR_ALLOC_N(machines, nnames) < 0)
        return NULL;

    for (i = 0; i < nnames; i++) {
        if (VIR_ALLOC(machines[i]) < 0 ||
366
            VIR_STRDUP(machines[i]->name, names[i]) < 0) {
367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
            virCapabilitiesFreeMachines(machines, nnames);
            return NULL;
        }
    }

    return machines;
}

/**
 * virCapabilitiesFreeMachines:
 * @machines: table of vircapsGuestMachinePtr
 *
 * Free a table of virCapsGuestMachinePtr
 */
void
virCapabilitiesFreeMachines(virCapsGuestMachinePtr *machines,
                            int nmachines)
{
385
    size_t i;
386 387 388 389 390 391 392 393
    if (!machines)
        return;
    for (i = 0; i < nmachines && machines[i]; i++) {
        virCapabilitiesFreeGuestMachine(machines[i]);
        machines[i] = NULL;
    }
    VIR_FREE(machines);
}
394 395 396 397 398

/**
 * virCapabilitiesAddGuest:
 * @caps: capabilities to extend
 * @ostype: guest operating system type ('hvm' or 'xen')
399
 * @arch: guest CPU architecture
400 401 402 403 404 405 406 407 408 409 410 411 412
 * @wordsize: number of bits in CPU word
 * @emulator: path to default device emulator for arch/ostype
 * @loader: path to default BIOS loader for arch/ostype
 * @nmachines: number of machine variants for emulator
 * @machines: machine variants for emulator ('pc', or 'isapc', etc)
 *
 * Registers a new guest operating system. This should be
 * followed by registration of at least one domain for
 * running the guest
 */
virCapsGuestPtr
virCapabilitiesAddGuest(virCapsPtr caps,
                        const char *ostype,
413
                        virArch arch,
414 415 416
                        const char *emulator,
                        const char *loader,
                        int nmachines,
417
                        virCapsGuestMachinePtr *machines)
418
{
419
    virCapsGuestPtr guest;
420

421
    if (VIR_ALLOC(guest) < 0)
422
        goto error;
423

424 425
    if (VIR_STRDUP(guest->ostype, ostype) < 0)
        goto error;
426

427 428
    guest->arch.id = arch;
    guest->arch.wordsize = virArchGetWordSize(arch);
429

430 431 432
    if (VIR_STRDUP(guest->arch.defaultInfo.emulator, emulator) < 0 ||
        VIR_STRDUP(guest->arch.defaultInfo.loader, loader) < 0)
        goto error;
433

E
Eric Blake 已提交
434 435
    if (VIR_RESIZE_N(caps->guests, caps->nguests_max,
                     caps->nguests, 1) < 0)
436
        goto error;
E
Eric Blake 已提交
437
    caps->guests[caps->nguests++] = guest;
438

D
Daniel P. Berrange 已提交
439 440 441 442 443
    if (nmachines) {
        guest->arch.defaultInfo.nmachines = nmachines;
        guest->arch.defaultInfo.machines = machines;
    }

444 445
    return guest;

446
 error:
447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469
    virCapabilitiesFreeGuest(guest);
    return NULL;
}


/**
 * virCapabilitiesAddGuestDomain:
 * @guest: guest to support
 * @hvtype: hypervisor type ('xen', 'qemu', 'kvm')
 * @emulator: specialized device emulator for domain
 * @loader: specialized BIOS loader for domain
 * @nmachines: number of machine variants for emulator
 * @machines: specialized machine variants for emulator
 *
 * Registers a virtual domain capable of running a
 * guest operating system
 */
virCapsGuestDomainPtr
virCapabilitiesAddGuestDomain(virCapsGuestPtr guest,
                              const char *hvtype,
                              const char *emulator,
                              const char *loader,
                              int nmachines,
470
                              virCapsGuestMachinePtr *machines)
471
{
472
    virCapsGuestDomainPtr dom;
473

474
    if (VIR_ALLOC(dom) < 0)
475
        goto error;
476

477 478 479 480
    if (VIR_STRDUP(dom->type, hvtype) < 0 ||
        VIR_STRDUP(dom->info.emulator, emulator) < 0 ||
        VIR_STRDUP(dom->info.loader, loader) < 0)
        goto error;
481

E
Eric Blake 已提交
482 483
    if (VIR_RESIZE_N(guest->arch.domains, guest->arch.ndomains_max,
                     guest->arch.ndomains, 1) < 0)
484
        goto error;
485 486 487
    guest->arch.domains[guest->arch.ndomains] = dom;
    guest->arch.ndomains++;

D
Daniel P. Berrange 已提交
488 489 490 491
    if (nmachines) {
        dom->info.nmachines = nmachines;
        dom->info.machines = machines;
    }
492 493 494

    return dom;

495
 error:
496 497 498 499 500 501 502 503 504
    virCapabilitiesFreeGuestDomain(dom);
    return NULL;
}


/**
 * virCapabilitiesAddGuestFeature:
 * @guest: guest to associate feature with
 * @name: name of feature ('pae', 'acpi', 'apic')
505 506
 * @defaultOn: true if it defaults to on
 * @toggle: true if its state can be toggled
507
 *
508
 * Registers a feature for a guest domain.
509 510 511 512
 */
virCapsGuestFeaturePtr
virCapabilitiesAddGuestFeature(virCapsGuestPtr guest,
                               const char *name,
513 514
                               bool defaultOn,
                               bool toggle)
515
{
516
    virCapsGuestFeaturePtr feature;
517

518
    if (VIR_ALLOC(feature) < 0)
519 520
        goto no_memory;

521
    if (VIR_STRDUP(feature->name, name) < 0)
522 523 524 525
        goto no_memory;
    feature->defaultOn = defaultOn;
    feature->toggle = toggle;

E
Eric Blake 已提交
526 527
    if (VIR_RESIZE_N(guest->features, guest->nfeatures_max,
                     guest->nfeatures, 1) < 0)
528
        goto no_memory;
E
Eric Blake 已提交
529
    guest->features[guest->nfeatures++] = feature;
530 531 532 533 534 535 536 537

    return feature;

 no_memory:
    virCapabilitiesFreeGuestFeature(feature);
    return NULL;
}

538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569
/**
 * virCapabilitiesHostSecModelAddBaseLabel
 * @secmodel: Security model to add a base label for
 * @type: virtualization type
 * @label: base label
 *
 * Returns non-zero on error.
 */
extern int
virCapabilitiesHostSecModelAddBaseLabel(virCapsHostSecModelPtr secmodel,
                                        const char *type,
                                        const char *label)
{
    char *t = NULL, *l = NULL;

    if (type == NULL || label == NULL)
        return -1;

    if (VIR_STRDUP(t, type) < 0)
        goto no_memory;

    if (VIR_STRDUP(l, label) < 0)
        goto no_memory;

    if (VIR_EXPAND_N(secmodel->labels, secmodel->nlabels, 1) < 0)
        goto no_memory;

    secmodel->labels[secmodel->nlabels - 1].type = t;
    secmodel->labels[secmodel->nlabels - 1].label = l;

    return 0;

570
 no_memory:
571 572 573 574 575
    VIR_FREE(l);
    VIR_FREE(t);
    return -1;
}

576 577 578
/**
 * virCapabilitiesSupportsGuestArch:
 * @caps: capabilities to query
579
 * @arch: Architecture to search for
580 581 582 583 584 585
 *
 * Returns non-zero if the capabilities support the
 * requested architecture
 */
extern int
virCapabilitiesSupportsGuestArch(virCapsPtr caps,
586
                                 virArch arch)
587
{
588
    size_t i;
589
    for (i = 0; i < caps->nguests; i++) {
590
        if (caps->guests[i]->arch.id == arch)
591 592 593 594 595
            return 1;
    }
    return 0;
}

596 597 598 599 600 601 602 603 604 605 606 607 608

/**
 * virCapabilitiesSupportsGuestOSType:
 * @caps: capabilities to query
 * @ostype: OS type to search for (eg 'hvm', 'xen')
 *
 * Returns non-zero if the capabilities support the
 * requested operating system type
 */
extern int
virCapabilitiesSupportsGuestOSType(virCapsPtr caps,
                                   const char *ostype)
{
609
    size_t i;
610
    for (i = 0; i < caps->nguests; i++) {
611 612 613 614 615 616 617
        if (STREQ(caps->guests[i]->ostype, ostype))
            return 1;
    }
    return 0;
}


618
/**
619
 * virCapabilitiesSupportsGuestOSTypeArch:
620 621
 * @caps: capabilities to query
 * @ostype: OS type to search for (eg 'hvm', 'xen')
622
 * @arch: Architecture to search for
623 624 625 626 627
 *
 * Returns non-zero if the capabilities support the
 * requested operating system type
 */
extern int
628 629
virCapabilitiesSupportsGuestOSTypeArch(virCapsPtr caps,
                                       const char *ostype,
630
                                       virArch arch)
631
{
632
    size_t i;
633
    for (i = 0; i < caps->nguests; i++) {
634
        if (STREQ(caps->guests[i]->ostype, ostype) &&
635
            caps->guests[i]->arch.id == arch)
636 637 638 639 640 641
            return 1;
    }
    return 0;
}


642 643 644 645 646 647 648 649
/**
 * virCapabilitiesDefaultGuestArch:
 * @caps: capabilities to query
 * @ostype: OS type to search for
 *
 * Returns the first architecture able to run the
 * requested operating system type
 */
650
extern virArch
651
virCapabilitiesDefaultGuestArch(virCapsPtr caps,
652 653
                                const char *ostype,
                                const char *domain)
654
{
655
    size_t i, j;
656 657

    /* First try to find one matching host arch */
658
    for (i = 0; i < caps->nguests; i++) {
659
        if (STREQ(caps->guests[i]->ostype, ostype)) {
660
            for (j = 0; j < caps->guests[i]->arch.ndomains; j++) {
661 662 663
                if (STREQ(caps->guests[i]->arch.domains[j]->type, domain) &&
                    caps->guests[i]->arch.id == caps->host.arch)
                    return caps->guests[i]->arch.id;
664 665
            }
        }
666
    }
667 668

    /* Otherwise find the first match */
669
    for (i = 0; i < caps->nguests; i++) {
670
        if (STREQ(caps->guests[i]->ostype, ostype)) {
671
            for (j = 0; j < caps->guests[i]->arch.ndomains; j++) {
672 673 674 675 676 677 678
                if (STREQ(caps->guests[i]->arch.domains[j]->type, domain))
                    return caps->guests[i]->arch.id;
            }
        }
    }

    return VIR_ARCH_NONE;
679 680 681 682 683 684 685
}

/**
 * virCapabilitiesDefaultGuestMachine:
 * @caps: capabilities to query
 * @ostype: OS type to search for
 * @arch: architecture to search for
686
 * @domain: domain type to search for
687 688
 *
 * Returns the first machine variant associated with
689 690
 * the requested operating system type, architecture
 * and domain type
691 692 693 694
 */
extern const char *
virCapabilitiesDefaultGuestMachine(virCapsPtr caps,
                                   const char *ostype,
695
                                   virArch arch,
696
                                   const char *domain)
697
{
698
    size_t i;
699

700
    for (i = 0; i < caps->nguests; i++) {
701
        virCapsGuestPtr guest = caps->guests[i];
702
        size_t j;
703

704 705
        if (!STREQ(guest->ostype, ostype) ||
            guest->arch.id != arch)
706 707 708
            continue;

        for (j = 0; j < guest->arch.ndomains; j++) {
709
            virCapsGuestDomainPtr dom = guest->arch.domains[j];
710 711 712 713 714 715 716 717 718 719 720

            if (!STREQ(dom->type, domain))
                continue;

            if (!dom->info.nmachines)
                break;

            return dom->info.machines[0]->name;
        }

        if (guest->arch.defaultInfo.nmachines)
721
            return caps->guests[i]->arch.defaultInfo.machines[0]->name;
722
    }
723

724 725 726 727
    return NULL;
}

/**
728
 * virCapabilitiesDefaultGuestEmulator:
729 730 731 732 733 734 735 736 737 738 739 740
 * @caps: capabilities to query
 * @ostype: OS type to search for ('xen', 'hvm')
 * @arch: architecture to search for
 * @domain: domain type ('xen', 'qemu', 'kvm')
 *
 * Returns the first emulator path associated with
 * the requested operating system type, architecture
 * and domain type
 */
extern const char *
virCapabilitiesDefaultGuestEmulator(virCapsPtr caps,
                                    const char *ostype,
741
                                    virArch arch,
742 743
                                    const char *domain)
{
744
    size_t i, j;
745
    for (i = 0; i < caps->nguests; i++) {
746 747
        char *emulator;
        if (STREQ(caps->guests[i]->ostype, ostype) &&
748
            caps->guests[i]->arch.id == arch) {
749
            emulator = caps->guests[i]->arch.defaultInfo.emulator;
750
            for (j = 0; j < caps->guests[i]->arch.ndomains; j++) {
751 752 753 754 755 756 757 758 759 760 761
                if (STREQ(caps->guests[i]->arch.domains[j]->type, domain)) {
                    if (caps->guests[i]->arch.domains[j]->info.emulator)
                        emulator = caps->guests[i]->arch.domains[j]->info.emulator;
                }
            }
            return emulator;
        }
    }
    return NULL;
}

762
static int
763
virCapabilitiesFormatNUMATopology(virBufferPtr buf,
764 765 766
                                  size_t ncells,
                                  virCapsHostNUMACellPtr *cells)
{
767 768
    size_t i;
    size_t j;
769
    char *siblings;
770

771 772 773 774
    virBufferAddLit(buf, "<topology>\n");
    virBufferAdjustIndent(buf, 2);
    virBufferAsprintf(buf, "<cells num='%zu'>\n", ncells);
    virBufferAdjustIndent(buf, 2);
775
    for (i = 0; i < ncells; i++) {
776 777
        virBufferAsprintf(buf, "<cell id='%d'>\n", cells[i]->num);
        virBufferAdjustIndent(buf, 2);
778 779 780

        /* Print out the numacell memory total if it is available */
        if (cells[i]->mem)
781
            virBufferAsprintf(buf, "<memory unit='KiB'>%llu</memory>\n",
782 783
                              cells[i]->mem);

M
Michal Privoznik 已提交
784 785 786 787 788 789
        for (j = 0; j < cells[i]->npageinfo; j++) {
            virBufferAsprintf(buf, "<pages unit='KiB' size='%u'>%zu</pages>\n",
                              cells[i]->pageinfo[j].size,
                              cells[i]->pageinfo[j].avail);
        }

790 791 792 793 794 795 796 797 798 799 800 801
        if (cells[i]->nsiblings) {
            virBufferAddLit(buf, "<distances>\n");
            virBufferAdjustIndent(buf, 2);
            for (j = 0; j < cells[i]->nsiblings; j++) {
                virBufferAsprintf(buf, "<sibling id='%d' value='%d'/>\n",
                                  cells[i]->siblings[j].node,
                                  cells[i]->siblings[j].distance);
            }
            virBufferAdjustIndent(buf, -2);
            virBufferAddLit(buf, "</distances>\n");
        }

802 803
        virBufferAsprintf(buf, "<cpus num='%d'>\n", cells[i]->ncpus);
        virBufferAdjustIndent(buf, 2);
804
        for (j = 0; j < cells[i]->ncpus; j++) {
805
            virBufferAsprintf(buf, "<cpu id='%d'", cells[i]->cpus[j].id);
806 807

            if (cells[i]->cpus[j].siblings) {
808
                if (!(siblings = virBitmapFormat(cells[i]->cpus[j].siblings)))
809 810
                    return -1;

811
                virBufferAsprintf(buf,
812 813 814 815 816 817
                                  " socket_id='%d' core_id='%d' siblings='%s'",
                                  cells[i]->cpus[j].socket_id,
                                  cells[i]->cpus[j].core_id,
                                  siblings);
                VIR_FREE(siblings);
            }
818
            virBufferAddLit(buf, "/>\n");
819
        }
820 821 822 823
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</cpus>\n");
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</cell>\n");
824
    }
825 826 827 828
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</cells>\n");
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</topology>\n");
829
    return 0;
830
}
831 832 833 834 835 836 837 838 839 840 841 842

/**
 * virCapabilitiesFormatXML:
 * @caps: capabilities to format
 *
 * Convert the capabilities object into an XML representation
 *
 * Returns the XML document as a string
 */
char *
virCapabilitiesFormatXML(virCapsPtr caps)
{
843
    virBuffer buf = VIR_BUFFER_INITIALIZER;
844
    size_t i, j, k;
845
    char host_uuid[VIR_UUID_STRING_BUFLEN];
846

847 848 849 850
    virBufferAddLit(&buf, "<capabilities>\n\n");
    virBufferAdjustIndent(&buf, 2);
    virBufferAddLit(&buf, "<host>\n");
    virBufferAdjustIndent(&buf, 2);
851 852
    if (virUUIDIsValid(caps->host.host_uuid)) {
        virUUIDFormat(caps->host.host_uuid, host_uuid);
853
        virBufferAsprintf(&buf, "<uuid>%s</uuid>\n", host_uuid);
854
    }
855 856 857
    virBufferAddLit(&buf, "<cpu>\n");
    virBufferAdjustIndent(&buf, 2);

858
    if (caps->host.arch)
859
        virBufferAsprintf(&buf, "<arch>%s</arch>\n",
860
                          virArchToString(caps->host.arch));
861
    if (caps->host.nfeatures) {
862 863
        virBufferAddLit(&buf, "<features>\n");
        virBufferAdjustIndent(&buf, 2);
864
        for (i = 0; i < caps->host.nfeatures; i++) {
865
            virBufferAsprintf(&buf, "<%s/>\n",
866
                              caps->host.features[i]);
867
        }
868 869
        virBufferAdjustIndent(&buf, -2);
        virBufferAddLit(&buf, "</features>\n");
870
    }
871
    virCPUDefFormatBuf(&buf, caps->host.cpu, 0);
872

M
Michal Privoznik 已提交
873 874 875 876 877
    for (i = 0; i < caps->host.nPagesSize; i++) {
        virBufferAsprintf(&buf, "<pages unit='KiB' size='%u'/>\n",
                          caps->host.pagesSize[i]);
    }

878 879
    virBufferAdjustIndent(&buf, -2);
    virBufferAddLit(&buf, "</cpu>\n");
880

881 882 883 884
    /* The PM query was successful. */
    if (caps->host.powerMgmt) {
        /* The host supports some PM features. */
        unsigned int pm = caps->host.powerMgmt;
885 886
        virBufferAddLit(&buf, "<power_management>\n");
        virBufferAdjustIndent(&buf, 2);
887 888
        while (pm) {
            int bit = ffs(pm) - 1;
889
            virBufferAsprintf(&buf, "<%s/>\n",
890 891
                              virCapsHostPMTargetTypeToString(bit));
            pm &= ~(1U << bit);
892
        }
893 894
        virBufferAdjustIndent(&buf, -2);
        virBufferAddLit(&buf, "</power_management>\n");
895 896
    } else {
        /* The host does not support any PM feature. */
897
        virBufferAddLit(&buf, "<power_management/>\n");
898 899
    }

900
    if (caps->host.offlineMigrate) {
901 902
        virBufferAddLit(&buf, "<migration_features>\n");
        virBufferAdjustIndent(&buf, 2);
903
        if (caps->host.liveMigrate)
904
            virBufferAddLit(&buf, "<live/>\n");
905
        if (caps->host.nmigrateTrans) {
906 907
            virBufferAddLit(&buf, "<uri_transports>\n");
            virBufferAdjustIndent(&buf, 2);
908
            for (i = 0; i < caps->host.nmigrateTrans; i++) {
909
                virBufferAsprintf(&buf, "<uri_transport>%s</uri_transport>\n",
910
                                      caps->host.migrateTrans[i]);
911
            }
912 913
            virBufferAdjustIndent(&buf, -2);
            virBufferAddLit(&buf, "</uri_transports>\n");
914
        }
915 916
        virBufferAdjustIndent(&buf, -2);
        virBufferAddLit(&buf, "</migration_features>\n");
917 918
    }

919
    if (caps->host.nnumaCell &&
920
        virCapabilitiesFormatNUMATopology(&buf, caps->host.nnumaCell,
921 922
                                          caps->host.numaCell) < 0)
        return NULL;
923

924
    for (i = 0; i < caps->host.nsecModels; i++) {
925 926 927
        virBufferAddLit(&buf, "<secmodel>\n");
        virBufferAdjustIndent(&buf, 2);
        virBufferAsprintf(&buf, "<model>%s</model>\n",
928
                          caps->host.secModels[i].model);
929
        virBufferAsprintf(&buf, "<doi>%s</doi>\n",
930
                          caps->host.secModels[i].doi);
931
        for (j = 0; j < caps->host.secModels[i].nlabels; j++) {
932
            virBufferAsprintf(&buf, "<baselabel type='%s'>%s</baselabel>\n",
933 934 935
                              caps->host.secModels[i].labels[j].type,
                              caps->host.secModels[i].labels[j].label);
        }
936 937
        virBufferAdjustIndent(&buf, -2);
        virBufferAddLit(&buf, "</secmodel>\n");
938 939
    }

940 941
    virBufferAdjustIndent(&buf, -2);
    virBufferAddLit(&buf, "</host>\n\n");
942 943


944
    for (i = 0; i < caps->nguests; i++) {
945 946 947
        virBufferAddLit(&buf, "<guest>\n");
        virBufferAdjustIndent(&buf, 2);
        virBufferAsprintf(&buf, "<os_type>%s</os_type>\n",
948
                          caps->guests[i]->ostype);
949
        if (caps->guests[i]->arch.id)
950
            virBufferAsprintf(&buf, "<arch name='%s'>\n",
951
                              virArchToString(caps->guests[i]->arch.id));
952 953
        virBufferAdjustIndent(&buf, 2);
        virBufferAsprintf(&buf, "<wordsize>%d</wordsize>\n",
954 955
                          caps->guests[i]->arch.wordsize);
        if (caps->guests[i]->arch.defaultInfo.emulator)
956
            virBufferAsprintf(&buf, "<emulator>%s</emulator>\n",
957 958
                              caps->guests[i]->arch.defaultInfo.emulator);
            if (caps->guests[i]->arch.defaultInfo.loader)
959
                virBufferAsprintf(&buf, "<loader>%s</loader>\n",
960
                                  caps->guests[i]->arch.defaultInfo.loader);
961

962
        for (j = 0; j < caps->guests[i]->arch.defaultInfo.nmachines; j++) {
963
            virCapsGuestMachinePtr machine = caps->guests[i]->arch.defaultInfo.machines[j];
964
            virBufferAddLit(&buf, "<machine");
965
            if (machine->canonical)
966
                virBufferAsprintf(&buf, " canonical='%s'", machine->canonical);
967
            if (machine->maxCpus > 0)
968 969
                virBufferAsprintf(&buf, " maxCpus='%d'", machine->maxCpus);
            virBufferAsprintf(&buf, ">%s</machine>\n", machine->name);
970 971
        }

972
        for (j = 0; j < caps->guests[i]->arch.ndomains; j++) {
973
            virBufferAsprintf(&buf, "<domain type='%s'>\n",
974
                                  caps->guests[i]->arch.domains[j]->type);
975
            virBufferAdjustIndent(&buf, 2);
976
            if (caps->guests[i]->arch.domains[j]->info.emulator)
977
                virBufferAsprintf(&buf, "<emulator>%s</emulator>\n",
978 979
                                  caps->guests[i]->arch.domains[j]->info.emulator);
            if (caps->guests[i]->arch.domains[j]->info.loader)
980
                virBufferAsprintf(&buf, "<loader>%s</loader>\n",
981
                                  caps->guests[i]->arch.domains[j]->info.loader);
982

983
            for (k = 0; k < caps->guests[i]->arch.domains[j]->info.nmachines; k++) {
984
                virCapsGuestMachinePtr machine = caps->guests[i]->arch.domains[j]->info.machines[k];
985
                virBufferAddLit(&buf, "<machine");
986
                if (machine->canonical)
987
                    virBufferAsprintf(&buf, " canonical='%s'", machine->canonical);
988
                if (machine->maxCpus > 0)
989 990
                    virBufferAsprintf(&buf, " maxCpus='%d'", machine->maxCpus);
                virBufferAsprintf(&buf, ">%s</machine>\n", machine->name);
991
            }
992 993
            virBufferAdjustIndent(&buf, -2);
            virBufferAddLit(&buf, "</domain>\n");
994 995
        }

996 997
        virBufferAdjustIndent(&buf, -2);
        virBufferAddLit(&buf, "</arch>\n");
998 999

        if (caps->guests[i]->nfeatures) {
1000 1001
            virBufferAddLit(&buf, "<features>\n");
            virBufferAdjustIndent(&buf, 2);
1002

1003
            for (j = 0; j < caps->guests[i]->nfeatures; j++) {
1004 1005
                if (STREQ(caps->guests[i]->features[j]->name, "pae") ||
                    STREQ(caps->guests[i]->features[j]->name, "nonpae") ||
1006
                    STREQ(caps->guests[i]->features[j]->name, "ia64_be") ||
1007 1008
                    STREQ(caps->guests[i]->features[j]->name, "cpuselection") ||
                    STREQ(caps->guests[i]->features[j]->name, "deviceboot")) {
1009
                    virBufferAsprintf(&buf, "<%s/>\n",
1010
                                      caps->guests[i]->features[j]->name);
1011
                } else {
1012
                    virBufferAsprintf(&buf, "<%s default='%s' toggle='%s'/>\n",
1013 1014 1015
                                      caps->guests[i]->features[j]->name,
                                      caps->guests[i]->features[j]->defaultOn ? "on" : "off",
                                      caps->guests[i]->features[j]->toggle ? "yes" : "no");
1016 1017 1018
                }
            }

1019 1020
            virBufferAdjustIndent(&buf, -2);
            virBufferAddLit(&buf, "</features>\n");
1021
        }
1022 1023
        virBufferAdjustIndent(&buf, -2);
        virBufferAddLit(&buf, "</guest>\n\n");
1024
    }
1025 1026
    virBufferAdjustIndent(&buf, -2);
    virBufferAddLit(&buf, "</capabilities>\n");
1027

1028
    if (virBufferCheckError(&buf) < 0)
1029
        return NULL;
1030

1031
    return virBufferContentAndReset(&buf);
1032
}
1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059

/* get the maximum ID of cpus in the host */
static unsigned int
virCapabilitiesGetHostMaxcpu(virCapsPtr caps)
{
    unsigned int maxcpu = 0;
    size_t node;
    size_t cpu;

    for (node = 0; node < caps->host.nnumaCell; node++) {
        virCapsHostNUMACellPtr cell = caps->host.numaCell[node];

        for (cpu = 0; cpu < cell->ncpus; cpu++) {
            if (cell->cpus[cpu].id > maxcpu)
                maxcpu = cell->cpus[cpu].id;
        }
    }

    return maxcpu;
}

/* set cpus of a numa node in the bitmask */
static int
virCapabilitiesGetCpusForNode(virCapsPtr caps,
                              size_t node,
                              virBitmapPtr cpumask)
{
1060
    virCapsHostNUMACellPtr cell = NULL;
1061
    size_t cpu;
1062
    size_t i;
1063
    /* The numa node numbers can be non-contiguous. Ex: 0,1,16,17. */
1064 1065 1066
    for (i = 0; i < caps->host.nnumaCell; i++) {
        if (caps->host.numaCell[i]->num == node) {
            cell = caps->host.numaCell[i];
1067 1068 1069
            break;
        }
    }
1070

1071
    for (cpu = 0; cell && cpu < cell->ncpus; cpu++) {
1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104
        if (virBitmapSetBit(cpumask, cell->cpus[cpu].id) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Cpu '%u' in node '%zu' is out of range "
                             "of the provided bitmap"),
                           cell->cpus[cpu].id, node);
            return -1;
        }
    }

    return 0;
}

virBitmapPtr
virCapabilitiesGetCpusForNodemask(virCapsPtr caps,
                                  virBitmapPtr nodemask)
{
    virBitmapPtr ret = NULL;
    unsigned int maxcpu = virCapabilitiesGetHostMaxcpu(caps);
    ssize_t node = -1;

    if (!(ret = virBitmapNew(maxcpu + 1)))
        return NULL;


    while ((node = virBitmapNextSetBit(nodemask, node)) >= 0) {
        if (virCapabilitiesGetCpusForNode(caps, node, ret) < 0) {
            virBitmapFree(ret);
            return NULL;
        }
    }

    return ret;
}