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

#include <config.h>

#include <unistd.h>
#include <errno.h>

30
#include "virerror.h"
31
#include "datatypes.h"
32
#include "viralloc.h"
33
#include "virstring.h"
34
#include "node_device_conf.h"
35
#include "device_conf.h"
36
#include "virxml.h"
37
#include "virbuffer.h"
38
#include "viruuid.h"
39
#include "virrandom.h"
40

41
#define VIR_FROM_THIS VIR_FROM_NODEDEV
42 43 44 45 46 47 48 49

VIR_ENUM_IMPL(virNodeDevCap, VIR_NODE_DEV_CAP_LAST,
              "system",
              "pci",
              "usb_device",
              "usb",
              "net",
              "scsi_host",
D
David Allan 已提交
50
              "scsi_target",
51
              "scsi",
52 53
              "storage",
              "fc_host",
54 55
              "vports",
              "scsi_generic")
56 57 58

VIR_ENUM_IMPL(virNodeDevNetCap, VIR_NODE_DEV_CAP_NET_LAST,
              "80203",
59
              "80211")
60

61 62 63
VIR_ENUM_IMPL(virPCIELinkSpeed, VIR_PCIE_LINK_SPEED_LAST,
              "", "2.5", "5", "8")

64
static int
65
virNodeDevCapsDefParseString(const char *xpath,
66
                             xmlXPathContextPtr ctxt,
67
                             char **string)
68 69 70
{
    char *s;

71
    if (!(s = virXPathString(xpath, ctxt)))
72 73 74 75 76 77
        return -1;

    *string = s;
    return 0;
}

E
Eric Blake 已提交
78
int virNodeDeviceHasCap(const virNodeDeviceObj *dev, const char *cap)
79 80 81 82 83 84 85 86 87
{
    virNodeDevCapsDefPtr caps = dev->def->caps;
    while (caps) {
        if (STREQ(cap, virNodeDevCapTypeToString(caps->type)))
            return 1;
        caps = caps->next;
    }
    return 0;
}
88

89 90

virNodeDeviceObjPtr
E
Eric Blake 已提交
91
virNodeDeviceFindBySysfsPath(virNodeDeviceObjListPtr devs,
92 93
                             const char *sysfs_path)
{
94
    size_t i;
95 96 97 98 99 100 101 102 103 104 105 106 107 108

    for (i = 0; i < devs->count; i++) {
        virNodeDeviceObjLock(devs->objs[i]);
        if ((devs->objs[i]->def->sysfs_path != NULL) &&
            (STREQ(devs->objs[i]->def->sysfs_path, sysfs_path))) {
            return devs->objs[i];
        }
        virNodeDeviceObjUnlock(devs->objs[i]);
    }

    return NULL;
}


E
Eric Blake 已提交
109
virNodeDeviceObjPtr virNodeDeviceFindByName(virNodeDeviceObjListPtr devs,
110 111
                                            const char *name)
{
112
    size_t i;
113

114 115
    for (i = 0; i < devs->count; i++) {
        virNodeDeviceObjLock(devs->objs[i]);
116 117
        if (STREQ(devs->objs[i]->def->name, name))
            return devs->objs[i];
118 119
        virNodeDeviceObjUnlock(devs->objs[i]);
    }
120 121 122 123 124 125 126 127 128 129 130 131 132 133

    return NULL;
}


void virNodeDeviceDefFree(virNodeDeviceDefPtr def)
{
    virNodeDevCapsDefPtr caps;

    if (!def)
        return;

    VIR_FREE(def->name);
    VIR_FREE(def->parent);
134
    VIR_FREE(def->driver);
135 136
    VIR_FREE(def->sysfs_path);
    VIR_FREE(def->parent_sysfs_path);
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156

    caps = def->caps;
    while (caps) {
        virNodeDevCapsDefPtr next = caps->next;
        virNodeDevCapsDefFree(caps);
        caps = next;
    }

    VIR_FREE(def);
}

void virNodeDeviceObjFree(virNodeDeviceObjPtr dev)
{
    if (!dev)
        return;

    virNodeDeviceDefFree(dev->def);
    if (dev->privateFree)
        (*dev->privateFree)(dev->privateData);

157 158
    virMutexDestroy(&dev->lock);

159 160 161 162 163
    VIR_FREE(dev);
}

void virNodeDeviceObjListFree(virNodeDeviceObjListPtr devs)
{
164
    size_t i;
165
    for (i = 0; i < devs->count; i++)
166 167 168 169 170
        virNodeDeviceObjFree(devs->objs[i]);
    VIR_FREE(devs->objs);
    devs->count = 0;
}

171
virNodeDeviceObjPtr virNodeDeviceAssignDef(virNodeDeviceObjListPtr devs,
E
Eric Blake 已提交
172
                                           virNodeDeviceDefPtr def)
173 174 175 176 177 178 179 180 181
{
    virNodeDeviceObjPtr device;

    if ((device = virNodeDeviceFindByName(devs, def->name))) {
        virNodeDeviceDefFree(device->def);
        device->def = def;
        return device;
    }

182
    if (VIR_ALLOC(device) < 0)
183 184
        return NULL;

185
    if (virMutexInit(&device->lock) < 0) {
186 187
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("cannot initialize mutex"));
188 189 190
        VIR_FREE(device);
        return NULL;
    }
191
    virNodeDeviceObjLock(device);
192

193
    if (VIR_APPEND_ELEMENT_COPY(devs->objs, devs->count, device) < 0){
194
        virNodeDeviceObjUnlock(device);
195 196 197
        virNodeDeviceObjFree(device);
        return NULL;
    }
198
    device->def = def;
199 200 201 202 203 204

    return device;

}

void virNodeDeviceObjRemove(virNodeDeviceObjListPtr devs,
E
Eric Blake 已提交
205
                            virNodeDeviceObjPtr dev)
206
{
207
    size_t i;
208

209 210
    virNodeDeviceObjUnlock(dev);

211
    for (i = 0; i < devs->count; i++) {
212
        virNodeDeviceObjLock(dev);
213
        if (devs->objs[i] == dev) {
214
            virNodeDeviceObjUnlock(dev);
215 216
            virNodeDeviceObjFree(devs->objs[i]);

217
            VIR_DELETE_ELEMENT(devs->objs, i, devs->count);
218 219
            break;
        }
220
        virNodeDeviceObjUnlock(dev);
221 222 223
    }
}

224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
static void
virPCIELinkFormat(virBufferPtr buf,
                  virPCIELinkPtr lnk,
                  const char *attrib)
{
    if (!lnk)
        return;

    virBufferAsprintf(buf, "<link validity='%s'", attrib);
    if (lnk->port >= 0)
        virBufferAsprintf(buf, " port='%d'", lnk->port);
    if (lnk->speed)
        virBufferAsprintf(buf, " speed='%s'",
                          virPCIELinkSpeedTypeToString(lnk->speed));
    virBufferAsprintf(buf, " width='%d'", lnk->width);
    virBufferAddLit(buf, "/>\n");
}

static void
virPCIEDeviceInfoFormat(virBufferPtr buf,
                        virPCIEDeviceInfoPtr info)
{
    if (!info->link_cap && !info->link_sta) {
        virBufferAddLit(buf, "<pci-express/>\n");
        return;
    }

    virBufferAddLit(buf, "<pci-express>\n");
    virBufferAdjustIndent(buf, 2);

    virPCIELinkFormat(buf, info->link_cap, "cap");
    virPCIELinkFormat(buf, info->link_sta, "sta");

    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</pci-express>\n");
}

E
Eric Blake 已提交
261
char *virNodeDeviceDefFormat(const virNodeDeviceDef *def)
262 263
{
    virBuffer buf = VIR_BUFFER_INITIALIZER;
264
    virNodeDevCapsDefPtr caps;
265
    size_t i = 0;
266 267

    virBufferAddLit(&buf, "<device>\n");
268 269 270 271 272
    virBufferAdjustIndent(&buf, 2);
    virBufferEscapeString(&buf, "<name>%s</name>\n", def->name);
    virBufferEscapeString(&buf, "<path>%s</path>\n", def->sysfs_path);
    if (def->parent)
        virBufferEscapeString(&buf, "<parent>%s</parent>\n", def->parent);
273
    if (def->driver) {
274 275 276 277 278
        virBufferAddLit(&buf, "<driver>\n");
        virBufferAdjustIndent(&buf, 2);
        virBufferEscapeString(&buf, "<name>%s</name>\n", def->driver);
        virBufferAdjustIndent(&buf, -2);
        virBufferAddLit(&buf, "</driver>\n");
279
    }
280 281 282 283 284

    for (caps = def->caps; caps; caps = caps->next) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        union _virNodeDevCapData *data = &caps->data;

285
        virBufferAsprintf(&buf, "<capability type='%s'>\n",
286
                          virNodeDevCapTypeToString(caps->type));
287
        virBufferAdjustIndent(&buf, 2);
288 289 290
        switch (caps->type) {
        case VIR_NODE_DEV_CAP_SYSTEM:
            if (data->system.product_name)
291
                virBufferEscapeString(&buf, "<product>%s</product>\n",
292
                                      data->system.product_name);
293 294
            virBufferAddLit(&buf, "<hardware>\n");
            virBufferAdjustIndent(&buf, 2);
295
            if (data->system.hardware.vendor_name)
296
                virBufferEscapeString(&buf, "<vendor>%s</vendor>\n",
297 298
                                      data->system.hardware.vendor_name);
            if (data->system.hardware.version)
299
                virBufferEscapeString(&buf, "<version>%s</version>\n",
300 301
                                      data->system.hardware.version);
            if (data->system.hardware.serial)
302
                virBufferEscapeString(&buf, "<serial>%s</serial>\n",
303 304
                                      data->system.hardware.serial);
            virUUIDFormat(data->system.hardware.uuid, uuidstr);
305 306 307 308 309 310
            virBufferAsprintf(&buf, "<uuid>%s</uuid>\n", uuidstr);
            virBufferAdjustIndent(&buf, -2);
            virBufferAddLit(&buf, "</hardware>\n");

            virBufferAddLit(&buf, "<firmware>\n");
            virBufferAdjustIndent(&buf, 2);
311
            if (data->system.firmware.vendor_name)
312
                virBufferEscapeString(&buf, "<vendor>%s</vendor>\n",
313 314
                                      data->system.firmware.vendor_name);
            if (data->system.firmware.version)
315
                virBufferEscapeString(&buf, "<version>%s</version>\n",
316 317
                                      data->system.firmware.version);
            if (data->system.firmware.release_date)
318
                virBufferEscapeString(&buf, "<release_date>%s</release_date>\n",
319
                                      data->system.firmware.release_date);
320 321
            virBufferAdjustIndent(&buf, -2);
            virBufferAddLit(&buf, "</firmware>\n");
322 323
            break;
        case VIR_NODE_DEV_CAP_PCI_DEV:
324
            virBufferAsprintf(&buf, "<domain>%d</domain>\n",
325
                              data->pci_dev.domain);
326 327
            virBufferAsprintf(&buf, "<bus>%d</bus>\n", data->pci_dev.bus);
            virBufferAsprintf(&buf, "<slot>%d</slot>\n",
328
                              data->pci_dev.slot);
329
            virBufferAsprintf(&buf, "<function>%d</function>\n",
330
                              data->pci_dev.function);
331
            virBufferAsprintf(&buf, "<product id='0x%04x'",
332 333 334 335 336 337
                                  data->pci_dev.product);
            if (data->pci_dev.product_name)
                virBufferEscapeString(&buf, ">%s</product>\n",
                                      data->pci_dev.product_name);
            else
                virBufferAddLit(&buf, " />\n");
338
            virBufferAsprintf(&buf, "<vendor id='0x%04x'",
339 340 341 342 343 344
                                  data->pci_dev.vendor);
            if (data->pci_dev.vendor_name)
                virBufferEscapeString(&buf, ">%s</vendor>\n",
                                      data->pci_dev.vendor_name);
            else
                virBufferAddLit(&buf, " />\n");
345
            if (data->pci_dev.flags & VIR_NODE_DEV_CAP_FLAG_PCI_PHYSICAL_FUNCTION) {
346 347
                virBufferAddLit(&buf, "<capability type='phys_function'>\n");
                virBufferAdjustIndent(&buf, 2);
348
                virBufferAsprintf(&buf,
349
                                  "<address domain='0x%.4x' bus='0x%.2x' "
350 351 352 353 354
                                  "slot='0x%.2x' function='0x%.1x'/>\n",
                                  data->pci_dev.physical_function->domain,
                                  data->pci_dev.physical_function->bus,
                                  data->pci_dev.physical_function->slot,
                                  data->pci_dev.physical_function->function);
355 356
                virBufferAdjustIndent(&buf, -2);
                virBufferAddLit(&buf, "</capability>\n");
357 358
            }
            if (data->pci_dev.flags & VIR_NODE_DEV_CAP_FLAG_PCI_VIRTUAL_FUNCTION) {
359 360
                virBufferAddLit(&buf, "<capability type='virt_functions'>\n");
                virBufferAdjustIndent(&buf, 2);
361
                for (i = 0; i < data->pci_dev.num_virtual_functions; i++) {
362
                    virBufferAsprintf(&buf,
363
                                      "<address domain='0x%.4x' bus='0x%.2x' "
364 365 366 367 368 369
                                      "slot='0x%.2x' function='0x%.1x'/>\n",
                                      data->pci_dev.virtual_functions[i]->domain,
                                      data->pci_dev.virtual_functions[i]->bus,
                                      data->pci_dev.virtual_functions[i]->slot,
                                      data->pci_dev.virtual_functions[i]->function);
                }
370 371
                virBufferAdjustIndent(&buf, -2);
                virBufferAddLit(&buf, "</capability>\n");
372
            }
373
            if (data->pci_dev.nIommuGroupDevices) {
374
                virBufferAsprintf(&buf, "<iommuGroup number='%d'>\n",
375
                                  data->pci_dev.iommuGroupNumber);
376
                virBufferAdjustIndent(&buf, 2);
377 378
                for (i = 0; i < data->pci_dev.nIommuGroupDevices; i++) {
                    virBufferAsprintf(&buf,
379
                                      "<address domain='0x%.4x' bus='0x%.2x' "
380 381 382 383 384 385
                                      "slot='0x%.2x' function='0x%.1x'/>\n",
                                      data->pci_dev.iommuGroupDevices[i]->domain,
                                      data->pci_dev.iommuGroupDevices[i]->bus,
                                      data->pci_dev.iommuGroupDevices[i]->slot,
                                      data->pci_dev.iommuGroupDevices[i]->function);
                }
386 387
                virBufferAdjustIndent(&buf, -2);
                virBufferAddLit(&buf, "</iommuGroup>\n");
388
            }
389 390 391
            if (data->pci_dev.numa_node >= 0)
                virBufferAsprintf(&buf, "<numa node='%d'/>\n",
                                  data->pci_dev.numa_node);
392 393
            if (data->pci_dev.flags & VIR_NODE_DEV_CAP_FLAG_PCIE)
                virPCIEDeviceInfoFormat(&buf, data->pci_dev.pci_express);
394 395
            break;
        case VIR_NODE_DEV_CAP_USB_DEV:
396 397
            virBufferAsprintf(&buf, "<bus>%d</bus>\n", data->usb_dev.bus);
            virBufferAsprintf(&buf, "<device>%d</device>\n",
398
                              data->usb_dev.device);
399
            virBufferAsprintf(&buf, "<product id='0x%04x'",
400 401 402 403 404 405
                                  data->usb_dev.product);
            if (data->usb_dev.product_name)
                virBufferEscapeString(&buf, ">%s</product>\n",
                                      data->usb_dev.product_name);
            else
                virBufferAddLit(&buf, " />\n");
406
            virBufferAsprintf(&buf, "<vendor id='0x%04x'",
407 408 409 410 411 412 413 414
                                  data->usb_dev.vendor);
            if (data->usb_dev.vendor_name)
                virBufferEscapeString(&buf, ">%s</vendor>\n",
                                      data->usb_dev.vendor_name);
            else
                virBufferAddLit(&buf, " />\n");
            break;
        case VIR_NODE_DEV_CAP_USB_INTERFACE:
415
            virBufferAsprintf(&buf, "<number>%d</number>\n",
416
                              data->usb_if.number);
417
            virBufferAsprintf(&buf, "<class>%d</class>\n",
418
                              data->usb_if._class);
419
            virBufferAsprintf(&buf, "<subclass>%d</subclass>\n",
420
                              data->usb_if.subclass);
421
            virBufferAsprintf(&buf, "<protocol>%d</protocol>\n",
422 423
                              data->usb_if.protocol);
            if (data->usb_if.description)
424
                virBufferEscapeString(&buf,
425
                                  "<description>%s</description>\n",
426 427 428
                                  data->usb_if.description);
            break;
        case VIR_NODE_DEV_CAP_NET:
429
            virBufferEscapeString(&buf, "<interface>%s</interface>\n",
430
                              data->net.ifname);
431
            if (data->net.address)
432
                virBufferEscapeString(&buf, "<address>%s</address>\n",
433
                                  data->net.address);
434
            virInterfaceLinkFormat(&buf, &data->net.lnk);
435 436 437
            if (data->net.subtype != VIR_NODE_DEV_CAP_NET_LAST) {
                const char *subtyp =
                    virNodeDevNetCapTypeToString(data->net.subtype);
438
                virBufferEscapeString(&buf, "<capability type='%s'/>\n",
439
                                      subtyp);
440 441 442
            }
            break;
        case VIR_NODE_DEV_CAP_SCSI_HOST:
443
            virBufferAsprintf(&buf, "<host>%d</host>\n",
444
                              data->scsi_host.host);
445
            if (data->scsi_host.flags & VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST) {
446 447 448
                virBufferAddLit(&buf, "<capability type='fc_host'>\n");
                virBufferAdjustIndent(&buf, 2);
                virBufferEscapeString(&buf, "<wwnn>%s</wwnn>\n",
449
                                      data->scsi_host.wwnn);
450
                virBufferEscapeString(&buf, "<wwpn>%s</wwpn>\n",
451
                                      data->scsi_host.wwpn);
452
                virBufferEscapeString(&buf, "<fabric_wwn>%s</fabric_wwn>\n",
O
Osier Yang 已提交
453
                                      data->scsi_host.fabric_wwn);
454 455
                virBufferAdjustIndent(&buf, -2);
                virBufferAddLit(&buf, "</capability>\n");
456 457
            }
            if (data->scsi_host.flags & VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS) {
458 459 460
                virBufferAddLit(&buf, "<capability type='vport_ops'>\n");
                virBufferAdjustIndent(&buf, 2);
                virBufferAsprintf(&buf, "<max_vports>%d</max_vports>\n",
461
                                  data->scsi_host.max_vports);
462
                virBufferAsprintf(&buf, "<vports>%d</vports>\n",
463
                                  data->scsi_host.vports);
464 465
                virBufferAdjustIndent(&buf, -2);
                virBufferAddLit(&buf, "</capability>\n");
466 467
            }

468
            break;
D
David Allan 已提交
469 470

        case VIR_NODE_DEV_CAP_SCSI_TARGET:
471
            virBufferEscapeString(&buf, "<target>%s</target>\n",
472
                                  data->scsi_target.name);
D
David Allan 已提交
473 474
            break;

475
        case VIR_NODE_DEV_CAP_SCSI:
476 477 478
            virBufferAsprintf(&buf, "<host>%d</host>\n", data->scsi.host);
            virBufferAsprintf(&buf, "<bus>%d</bus>\n", data->scsi.bus);
            virBufferAsprintf(&buf, "<target>%d</target>\n",
479
                              data->scsi.target);
480
            virBufferAsprintf(&buf, "<lun>%d</lun>\n", data->scsi.lun);
481
            if (data->scsi.type)
482
                virBufferEscapeString(&buf, "<type>%s</type>\n",
483
                                      data->scsi.type);
484 485
            break;
        case VIR_NODE_DEV_CAP_STORAGE:
486 487
            virBufferEscapeString(&buf, "<block>%s</block>\n",
                                  data->storage.block);
488
            if (data->storage.bus)
489 490
                virBufferEscapeString(&buf, "<bus>%s</bus>\n",
                                      data->storage.bus);
491
            if (data->storage.drive_type)
492 493
                virBufferEscapeString(&buf, "<drive_type>%s</drive_type>\n",
                                      data->storage.drive_type);
494
            if (data->storage.model)
495 496
                virBufferEscapeString(&buf, "<model>%s</model>\n",
                                      data->storage.model);
497
            if (data->storage.vendor)
498 499
                virBufferEscapeString(&buf, "<vendor>%s</vendor>\n",
                                      data->storage.vendor);
500
            if (data->storage.serial)
501
                virBufferAsprintf(&buf, "<serial>%s</serial>\n",
502
                                  data->storage.serial);
503 504 505
            if (data->storage.flags & VIR_NODE_DEV_CAP_STORAGE_REMOVABLE) {
                int avl = data->storage.flags &
                    VIR_NODE_DEV_CAP_STORAGE_REMOVABLE_MEDIA_AVAILABLE;
506 507 508
                virBufferAddLit(&buf, "<capability type='removable'>\n");
                virBufferAdjustIndent(&buf, 2);
                virBufferAsprintf(&buf, "<media_available>%d"
509
                                  "</media_available>\n", avl ? 1 : 0);
510
                virBufferAsprintf(&buf, "<media_size>%llu</media_size>\n",
511
                                  data->storage.removable_media_size);
512 513
                if (data->storage.media_label)
                    virBufferEscapeString(&buf,
514 515
                                          "<media_label>%s</media_label>\n",
                                          data->storage.media_label);
516
                if (data->storage.logical_block_size > 0)
517
                    virBufferAsprintf(&buf, "<logical_block_size>%llu"
518 519 520
                                      "</logical_block_size>\n",
                                      data->storage.logical_block_size);
                if (data->storage.num_blocks > 0)
521
                    virBufferAsprintf(&buf,
522
                                      "<num_blocks>%llu</num_blocks>\n",
523
                                      data->storage.num_blocks);
524 525
                virBufferAdjustIndent(&buf, -2);
                virBufferAddLit(&buf, "</capability>\n");
526
            } else {
527
                virBufferAsprintf(&buf, "<size>%llu</size>\n",
528
                                  data->storage.size);
529
                if (data->storage.logical_block_size > 0)
530
                    virBufferAsprintf(&buf, "<logical_block_size>%llu"
531 532 533
                                      "</logical_block_size>\n",
                                      data->storage.logical_block_size);
                if (data->storage.num_blocks > 0)
534
                    virBufferAsprintf(&buf, "<num_blocks>%llu</num_blocks>\n",
535
                                      data->storage.num_blocks);
536 537
            }
            if (data->storage.flags & VIR_NODE_DEV_CAP_STORAGE_HOTPLUGGABLE)
538
                virBufferAddLit(&buf, "<capability type='hotpluggable' />\n");
539
            break;
540
        case VIR_NODE_DEV_CAP_SCSI_GENERIC:
541
            virBufferEscapeString(&buf, "<char>%s</char>\n",
542 543
                                  data->sg.path);
            break;
544 545
        case VIR_NODE_DEV_CAP_FC_HOST:
        case VIR_NODE_DEV_CAP_VPORTS:
546
        case VIR_NODE_DEV_CAP_LAST:
547
        default:
548 549 550
            break;
        }

551 552
        virBufferAdjustIndent(&buf, -2);
        virBufferAddLit(&buf, "</capability>\n");
553 554
    }

555
    virBufferAdjustIndent(&buf, -2);
556 557
    virBufferAddLit(&buf, "</device>\n");

558 559
    if (virBufferCheckError(&buf) < 0)
        return NULL;
560 561 562 563

    return virBufferContentAndReset(&buf);
}

564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598
/**
 * virNodeDevCapsDefParseIntOptional:
 * @xpath:  XPath to evaluate
 * @ctxt:   Context
 * @value:  Where to store parsed value
 * @def:    Node device which is parsed
 * @invalid_error_fmt:  error message to print on invalid format
 *
 * Returns: -1 on error (invalid int format under @xpath)
 *           0 if @xpath was not found (@value is untouched)
 *           1 on success
 */
static int
virNodeDevCapsDefParseIntOptional(const char *xpath,
                                  xmlXPathContextPtr ctxt,
                                  int *value,
                                  virNodeDeviceDefPtr def,
                                  const char *invalid_error_fmt)
{
    int ret;
    int val;

    ret = virXPathInt(xpath, ctxt, &val);
    if (ret < -1) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       invalid_error_fmt,
                       def->name);
        return -1;
    } else if (ret == -1) {
        return 0;
    }
    *value = val;
    return 1;
}

599
static int
600
virNodeDevCapsDefParseULong(const char *xpath,
601 602 603 604 605 606 607 608 609
                            xmlXPathContextPtr ctxt,
                            unsigned *value,
                            virNodeDeviceDefPtr def,
                            const char *missing_error_fmt,
                            const char *invalid_error_fmt)
{
    int ret;
    unsigned long val;

610
    ret = virXPathULong(xpath, ctxt, &val);
611
    if (ret < 0) {
612 613 614
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       ret == -1 ? missing_error_fmt : invalid_error_fmt,
                       def->name);
615 616 617 618 619 620 621 622
        return -1;
    }

    *value = val;
    return 0;
}

static int
623
virNodeDevCapsDefParseULongLong(const char *xpath,
624 625 626 627 628 629 630 631 632
                                xmlXPathContextPtr ctxt,
                                unsigned long long *value,
                                virNodeDeviceDefPtr def,
                                const char *missing_error_fmt,
                                const char *invalid_error_fmt)
{
    int ret;
    unsigned long long val;

633
    ret = virXPathULongLong(xpath, ctxt, &val);
634
    if (ret < 0) {
635 636 637
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       ret == -1 ? missing_error_fmt : invalid_error_fmt,
                       def->name);
638 639 640 641 642 643 644 645
        return -1;
    }

    *value = val;
    return 0;
}

static int
646
virNodeDevCapStorageParseXML(xmlXPathContextPtr ctxt,
647 648 649 650 651
                             virNodeDeviceDefPtr def,
                             xmlNodePtr node,
                             union _virNodeDevCapData *data)
{
    xmlNodePtr orignode, *nodes = NULL;
652 653
    size_t i;
    int n, ret = -1;
654 655 656 657 658
    unsigned long long val;

    orignode = ctxt->node;
    ctxt->node = node;

659
    data->storage.block = virXPathString("string(./block[1])", ctxt);
660
    if (!data->storage.block) {
661 662 663
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("no block device path supplied for '%s'"),
                       def->name);
664 665 666
        goto out;
    }

667 668 669 670 671
    data->storage.bus        = virXPathString("string(./bus[1])", ctxt);
    data->storage.drive_type = virXPathString("string(./drive_type[1])", ctxt);
    data->storage.model      = virXPathString("string(./model[1])", ctxt);
    data->storage.vendor     = virXPathString("string(./vendor[1])", ctxt);
    data->storage.serial     = virXPathString("string(./serial[1])", ctxt);
672

673
    if ((n = virXPathNodeSet("./capability", ctxt, &nodes)) < 0) {
674 675 676
        goto out;
    }

677
    for (i = 0; i < n; i++) {
678 679 680
        char *type = virXMLPropString(nodes[i], "type");

        if (!type) {
681 682 683
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("missing storage capability type for '%s'"),
                           def->name);
684 685 686 687 688 689 690 691 692 693 694 695 696
            goto out;
        }

        if (STREQ(type, "hotpluggable"))
            data->storage.flags |= VIR_NODE_DEV_CAP_STORAGE_HOTPLUGGABLE;
        else if (STREQ(type, "removable")) {
            xmlNodePtr orignode2;

            data->storage.flags |= VIR_NODE_DEV_CAP_STORAGE_REMOVABLE;

            orignode2 = ctxt->node;
            ctxt->node = nodes[i];

697
            if (virXPathBoolean("count(./media_available[. = '1']) > 0", ctxt))
698 699
                data->storage.flags |= VIR_NODE_DEV_CAP_STORAGE_REMOVABLE_MEDIA_AVAILABLE;

700
            data->storage.media_label = virXPathString("string(./media_label[1])", ctxt);
701

702
            val = 0;
703
            if (virNodeDevCapsDefParseULongLong("number(./media_size[1])", ctxt, &val, def,
704 705 706 707 708 709 710 711 712 713
                                                _("no removable media size supplied for '%s'"),
                                                _("invalid removable media size supplied for '%s'")) < 0) {
                ctxt->node = orignode2;
                VIR_FREE(type);
                goto out;
            }
            data->storage.removable_media_size = val;

            ctxt->node = orignode2;
        } else {
714 715 716
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown storage capability type '%s' for '%s'"),
                           type, def->name);
717 718 719 720 721 722 723 724 725
            VIR_FREE(type);
            goto out;
        }

        VIR_FREE(type);
    }

    if (!(data->storage.flags & VIR_NODE_DEV_CAP_STORAGE_REMOVABLE)) {
        val = 0;
726
        if (virNodeDevCapsDefParseULongLong("number(./size[1])", ctxt, &val, def,
727 728 729 730 731 732 733
                                            _("no size supplied for '%s'"),
                                            _("invalid size supplied for '%s'")) < 0)
            goto out;
        data->storage.size = val;
    }

    ret = 0;
734
 out:
735 736 737 738 739 740
    VIR_FREE(nodes);
    ctxt->node = orignode;
    return ret;
}

static int
741
virNodeDevCapSCSIParseXML(xmlXPathContextPtr ctxt,
742 743 744 745 746 747 748 749 750 751
                          virNodeDeviceDefPtr def,
                          xmlNodePtr node,
                          union _virNodeDevCapData *data)
{
    xmlNodePtr orignode;
    int ret = -1;

    orignode = ctxt->node;
    ctxt->node = node;

752
    if (virNodeDevCapsDefParseULong("number(./host[1])", ctxt,
753 754 755 756 757
                                    &data->scsi.host, def,
                                    _("no SCSI host ID supplied for '%s'"),
                                    _("invalid SCSI host ID supplied for '%s'")) < 0)
        goto out;

758
    if (virNodeDevCapsDefParseULong("number(./bus[1])", ctxt,
759 760 761 762 763
                                    &data->scsi.bus, def,
                                    _("no SCSI bus ID supplied for '%s'"),
                                    _("invalid SCSI bus ID supplied for '%s'")) < 0)
        goto out;

764
    if (virNodeDevCapsDefParseULong("number(./target[1])", ctxt,
765 766 767 768 769
                                    &data->scsi.target, def,
                                    _("no SCSI target ID supplied for '%s'"),
                                    _("invalid SCSI target ID supplied for '%s'")) < 0)
        goto out;

770
    if (virNodeDevCapsDefParseULong("number(./lun[1])", ctxt,
771 772 773 774 775
                                    &data->scsi.lun, def,
                                    _("no SCSI LUN ID supplied for '%s'"),
                                    _("invalid SCSI LUN ID supplied for '%s'")) < 0)
        goto out;

776
    data->scsi.type = virXPathString("string(./type[1])", ctxt);
777 778

    ret = 0;
779
 out:
780 781 782 783
    ctxt->node = orignode;
    return ret;
}

D
David Allan 已提交
784 785

static int
786
virNodeDevCapSCSITargetParseXML(xmlXPathContextPtr ctxt,
D
David Allan 已提交
787 788 789 790 791 792 793 794 795 796
                                virNodeDeviceDefPtr def,
                                xmlNodePtr node,
                                union _virNodeDevCapData *data)
{
    xmlNodePtr orignode;
    int ret = -1;

    orignode = ctxt->node;
    ctxt->node = node;

797
    data->scsi_target.name = virXPathString("string(./name[1])", ctxt);
D
David Allan 已提交
798
    if (!data->scsi_target.name) {
799 800 801
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("no target name supplied for '%s'"),
                       def->name);
D
David Allan 已提交
802 803 804 805 806
        goto out;
    }

    ret = 0;

807
 out:
D
David Allan 已提交
808 809 810 811 812
    ctxt->node = orignode;
    return ret;
}


813
static int
814
virNodeDevCapSCSIHostParseXML(xmlXPathContextPtr ctxt,
815 816
                              virNodeDeviceDefPtr def,
                              xmlNodePtr node,
817
                              union _virNodeDevCapData *data,
818 819
                              int create,
                              const char *virt_type)
820
{
821
    xmlNodePtr orignode, *nodes = NULL;
822 823
    int ret = -1, n = 0;
    size_t i;
824
    char *type = NULL;
825 826 827 828

    orignode = ctxt->node;
    ctxt->node = node;

829
    if (create == EXISTING_DEVICE &&
830
        virNodeDevCapsDefParseULong("number(./host[1])", ctxt,
831 832
                                    &data->scsi_host.host, def,
                                    _("no SCSI host ID supplied for '%s'"),
833 834 835 836
                                    _("invalid SCSI host ID supplied for '%s'")) < 0) {
        goto out;
    }

837
    if ((n = virXPathNodeSet("./capability", ctxt, &nodes)) < 0) {
838
        goto out;
839 840
    }

841
    for (i = 0; i < n; i++) {
842 843 844
        type = virXMLPropString(nodes[i], "type");

        if (!type) {
845 846 847
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("missing SCSI host capability type for '%s'"),
                           def->name);
848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863
            goto out;
        }

        if (STREQ(type, "vport_ops")) {

            data->scsi_host.flags |= VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS;

        } else if (STREQ(type, "fc_host")) {

            xmlNodePtr orignode2;

            data->scsi_host.flags |= VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST;

            orignode2 = ctxt->node;
            ctxt->node = nodes[i];

864
            if (virNodeDevCapsDefParseString("string(./wwnn[1])",
865
                                             ctxt,
866 867
                                             &data->scsi_host.wwnn) < 0) {
                if (virRandomGenerateWWN(&data->scsi_host.wwnn, virt_type) < 0) {
868 869 870 871
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("no WWNN supplied for '%s', and "
                                     "auto-generation failed"),
                                   def->name);
872 873
                    goto out;
                }
874 875
            }

876
            if (virNodeDevCapsDefParseString("string(./wwpn[1])",
877
                                             ctxt,
878 879
                                             &data->scsi_host.wwpn) < 0) {
                if (virRandomGenerateWWN(&data->scsi_host.wwpn, virt_type) < 0) {
880 881 882 883
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("no WWPN supplied for '%s', and "
                                     "auto-generation failed"),
                                   def->name);
884 885
                    goto out;
                }
886 887 888 889 890
            }

            ctxt->node = orignode2;

        } else {
891 892 893
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown SCSI host capability type '%s' for '%s'"),
                           type, def->name);
894 895 896 897 898
            goto out;
        }

        VIR_FREE(type);
    }
899 900

    ret = 0;
901

902
 out:
903
    VIR_FREE(type);
904
    ctxt->node = orignode;
905
    VIR_FREE(nodes);
906 907 908
    return ret;
}

909

910
static int
911
virNodeDevCapNetParseXML(xmlXPathContextPtr ctxt,
912 913 914 915
                         virNodeDeviceDefPtr def,
                         xmlNodePtr node,
                         union _virNodeDevCapData *data)
{
916
    xmlNodePtr orignode, lnk;
917 918 919 920 921 922
    int ret = -1;
    char *tmp;

    orignode = ctxt->node;
    ctxt->node = node;

923
    data->net.ifname = virXPathString("string(./interface[1])", ctxt);
924
    if (!data->net.ifname) {
925 926 927
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("no network interface supplied for '%s'"),
                       def->name);
928 929 930
        goto out;
    }

931
    data->net.address = virXPathString("string(./address[1])", ctxt);
932 933 934

    data->net.subtype = VIR_NODE_DEV_CAP_NET_LAST;

935
    tmp = virXPathString("string(./capability/@type)", ctxt);
936 937 938 939
    if (tmp) {
        int val = virNodeDevNetCapTypeFromString(tmp);
        VIR_FREE(tmp);
        if (val < 0) {
940
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
941 942
                           _("invalid network type supplied for '%s'"),
                           def->name);
943 944 945 946 947
            goto out;
        }
        data->net.subtype = val;
    }

948 949 950 951
    lnk = virXPathNode("./link", ctxt);
    if (lnk && virInterfaceLinkParseXML(lnk, &data->net.lnk) < 0)
        goto out;

952
    ret = 0;
953
 out:
954 955 956 957 958
    ctxt->node = orignode;
    return ret;
}

static int
959
virNodeDevCapUSBInterfaceParseXML(xmlXPathContextPtr ctxt,
960 961 962 963 964 965 966 967 968 969
                                  virNodeDeviceDefPtr def,
                                  xmlNodePtr node,
                                  union _virNodeDevCapData *data)
{
    xmlNodePtr orignode;
    int ret = -1;

    orignode = ctxt->node;
    ctxt->node = node;

970
    if (virNodeDevCapsDefParseULong("number(./number[1])", ctxt,
971 972 973 974 975
                                    &data->usb_if.number, def,
                                    _("no USB interface number supplied for '%s'"),
                                    _("invalid USB interface number supplied for '%s'")) < 0)
        goto out;

976
    if (virNodeDevCapsDefParseULong("number(./class[1])", ctxt,
977 978 979 980 981
                                    &data->usb_if._class, def,
                                    _("no USB interface class supplied for '%s'"),
                                    _("invalid USB interface class supplied for '%s'")) < 0)
        goto out;

982
    if (virNodeDevCapsDefParseULong("number(./subclass[1])", ctxt,
983 984 985 986 987
                                    &data->usb_if.subclass, def,
                                    _("no USB interface subclass supplied for '%s'"),
                                    _("invalid USB interface subclass supplied for '%s'")) < 0)
        goto out;

988
    if (virNodeDevCapsDefParseULong("number(./protocol[1])", ctxt,
989 990 991 992 993
                                    &data->usb_if.protocol, def,
                                    _("no USB interface protocol supplied for '%s'"),
                                    _("invalid USB interface protocol supplied for '%s'")) < 0)
        goto out;

994
    data->usb_if.description = virXPathString("string(./description[1])", ctxt);
995 996

    ret = 0;
997
 out:
998 999 1000 1001 1002
    ctxt->node = orignode;
    return ret;
}

static int
1003
virNodeDevCapsDefParseHexId(const char *xpath,
1004 1005 1006 1007 1008 1009 1010 1011 1012
                            xmlXPathContextPtr ctxt,
                            unsigned *value,
                            virNodeDeviceDefPtr def,
                            const char *missing_error_fmt,
                            const char *invalid_error_fmt)
{
    int ret;
    unsigned long val;

1013
    ret = virXPathULongHex(xpath, ctxt, &val);
1014
    if (ret < 0) {
1015 1016 1017
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       ret == -1 ? missing_error_fmt : invalid_error_fmt,
                       def->name);
1018 1019 1020 1021 1022 1023 1024 1025
        return -1;
    }

    *value = val;
    return 0;
}

static int
1026
virNodeDevCapUSBDevParseXML(xmlXPathContextPtr ctxt,
1027 1028 1029 1030 1031 1032 1033 1034 1035 1036
                            virNodeDeviceDefPtr def,
                            xmlNodePtr node,
                            union _virNodeDevCapData *data)
{
    xmlNodePtr orignode;
    int ret = -1;

    orignode = ctxt->node;
    ctxt->node = node;

1037
    if (virNodeDevCapsDefParseULong("number(./bus[1])", ctxt,
1038 1039 1040 1041 1042
                                    &data->usb_dev.bus, def,
                                    _("no USB bus number supplied for '%s'"),
                                    _("invalid USB bus number supplied for '%s'")) < 0)
        goto out;

1043
    if (virNodeDevCapsDefParseULong("number(./device[1])", ctxt,
1044 1045 1046 1047 1048
                                    &data->usb_dev.device, def,
                                    _("no USB device number supplied for '%s'"),
                                    _("invalid USB device number supplied for '%s'")) < 0)
        goto out;

1049
    if (virNodeDevCapsDefParseHexId("string(./vendor[1]/@id)", ctxt,
1050 1051 1052 1053 1054
                                    &data->usb_dev.vendor, def,
                                    _("no USB vendor ID supplied for '%s'"),
                                    _("invalid USB vendor ID supplied for '%s'")) < 0)
        goto out;

1055
    if (virNodeDevCapsDefParseHexId("string(./product[1]/@id)", ctxt,
1056 1057 1058 1059 1060
                                    &data->usb_dev.product, def,
                                    _("no USB product ID supplied for '%s'"),
                                    _("invalid USB product ID supplied for '%s'")) < 0)
        goto out;

1061 1062
    data->usb_dev.vendor_name  = virXPathString("string(./vendor[1])", ctxt);
    data->usb_dev.product_name = virXPathString("string(./product[1])", ctxt);
1063 1064

    ret = 0;
1065
 out:
1066 1067 1068 1069
    ctxt->node = orignode;
    return ret;
}

1070
static int
1071
virNodeDevCapPCIDevIommuGroupParseXML(xmlXPathContextPtr ctxt,
1072 1073 1074 1075 1076 1077
                                      xmlNodePtr iommuGroupNode,
                                      union _virNodeDevCapData *data)
{
    xmlNodePtr origNode = ctxt->node;
    xmlNodePtr *addrNodes = NULL;
    char *numberStr = NULL;
1078 1079
    int nAddrNodes, ret = -1;
    size_t i;
1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100
    virPCIDeviceAddressPtr pciAddr = NULL;

    ctxt->node = iommuGroupNode;

    numberStr = virXMLPropString(iommuGroupNode, "number");
    if (!numberStr) {
        virReportError(VIR_ERR_XML_ERROR,
                       "%s", _("missing iommuGroup number attribute"));
        goto cleanup;
    }
    if (virStrToLong_ui(numberStr, NULL, 10,
                        &data->pci_dev.iommuGroupNumber) < 0) {
        virReportError(VIR_ERR_XML_ERROR,
                       _("invalid iommuGroup number attribute '%s'"),
                       numberStr);
        goto cleanup;
    }

    if ((nAddrNodes = virXPathNodeSet("./address", ctxt, &addrNodes)) < 0)
        goto cleanup;

1101
    for (i = 0; i < nAddrNodes; i++) {
1102
        virDevicePCIAddress addr = { 0, 0, 0, 0, 0 };
1103
        if (virDevicePCIAddressParseXML(addrNodes[i], &addr) < 0)
1104
            goto cleanup;
1105
        if (VIR_ALLOC(pciAddr) < 0)
1106 1107 1108 1109 1110 1111 1112
            goto cleanup;
        pciAddr->domain = addr.domain;
        pciAddr->bus = addr.bus;
        pciAddr->slot = addr.slot;
        pciAddr->function = addr.function;
        if (VIR_APPEND_ELEMENT(data->pci_dev.iommuGroupDevices,
                               data->pci_dev.nIommuGroupDevices,
1113
                               pciAddr) < 0)
1114 1115 1116 1117
            goto cleanup;
    }

    ret = 0;
1118
 cleanup:
1119
    ctxt->node = origNode;
1120
    VIR_FREE(numberStr);
1121 1122 1123 1124 1125
    VIR_FREE(addrNodes);
    VIR_FREE(pciAddr);
    return ret;
}

1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205
static int
virPCIEDeviceInfoLinkParseXML(xmlXPathContextPtr ctxt,
                              xmlNodePtr linkNode,
                              virPCIELinkPtr lnk)
{
    xmlNodePtr origNode = ctxt->node;
    int ret = -1, speed;
    char *speedStr = NULL, *portStr = NULL;

    ctxt->node = linkNode;

    if (virXPathUInt("number(./@width)", ctxt, &lnk->width) < 0) {
        virReportError(VIR_ERR_XML_DETAIL, "%s",
                       _("mandatory attribute 'width' is missing or malformed"));
        goto cleanup;
    }

    if ((speedStr = virXPathString("string(./@speed)", ctxt))) {
        if ((speed = virPCIELinkSpeedTypeFromString(speedStr)) < 0) {
            virReportError(VIR_ERR_XML_DETAIL,
                           _("malformed 'speed' attribute: %s"),
                           speedStr);
            goto cleanup;
        }
        lnk->speed = speed;
    }

    if ((portStr = virXPathString("string(./@port)", ctxt))) {
        if (virStrToLong_i(portStr, NULL, 10, &lnk->port) < 0) {
            virReportError(VIR_ERR_XML_DETAIL,
                           _("malformed 'port' attribute: %s"),
                           portStr);
            goto cleanup;
        }
    } else {
        lnk->port = -1;
    }

    ret = 0;
 cleanup:
    VIR_FREE(portStr);
    VIR_FREE(speedStr);
    ctxt->node = origNode;
    return ret;
}

static int
virPCIEDeviceInfoParseXML(xmlXPathContextPtr ctxt,
                          xmlNodePtr pciExpressNode,
                          virPCIEDeviceInfoPtr pci_express)
{
    xmlNodePtr lnk, origNode = ctxt->node;
    int ret = -1;

    ctxt->node = pciExpressNode;

    if ((lnk = virXPathNode("./link[@validity='cap']", ctxt))) {
        if (VIR_ALLOC(pci_express->link_cap) < 0)
            goto cleanup;

        if (virPCIEDeviceInfoLinkParseXML(ctxt, lnk,
                                          pci_express->link_cap) < 0)
            goto cleanup;
    }

    if ((lnk = virXPathNode("./link[@validity='sta']", ctxt))) {
        if (VIR_ALLOC(pci_express->link_sta) < 0)
            goto cleanup;

        if (virPCIEDeviceInfoLinkParseXML(ctxt, lnk,
                                          pci_express->link_sta) < 0)
            goto cleanup;
    }

    ret = 0;
 cleanup:
    ctxt->node = origNode;
    return ret;
}

1206

1207
static int
1208
virNodeDevCapPCIDevParseXML(xmlXPathContextPtr ctxt,
1209 1210 1211 1212
                            virNodeDeviceDefPtr def,
                            xmlNodePtr node,
                            union _virNodeDevCapData *data)
{
1213
    xmlNodePtr orignode, iommuGroupNode, pciExpress;
1214
    int ret = -1;
1215
    virPCIEDeviceInfoPtr pci_express = NULL;
1216 1217 1218 1219

    orignode = ctxt->node;
    ctxt->node = node;

1220
    if (virNodeDevCapsDefParseULong("number(./domain[1])", ctxt,
1221 1222 1223 1224 1225
                                    &data->pci_dev.domain, def,
                                    _("no PCI domain ID supplied for '%s'"),
                                    _("invalid PCI domain ID supplied for '%s'")) < 0)
        goto out;

1226
    if (virNodeDevCapsDefParseULong("number(./bus[1])", ctxt,
1227 1228 1229 1230 1231
                                    &data->pci_dev.bus, def,
                                    _("no PCI bus ID supplied for '%s'"),
                                    _("invalid PCI bus ID supplied for '%s'")) < 0)
        goto out;

1232
    if (virNodeDevCapsDefParseULong("number(./slot[1])", ctxt,
1233 1234 1235 1236 1237
                                    &data->pci_dev.slot, def,
                                    _("no PCI slot ID supplied for '%s'"),
                                    _("invalid PCI slot ID supplied for '%s'")) < 0)
        goto out;

1238
    if (virNodeDevCapsDefParseULong("number(./function[1])", ctxt,
1239 1240 1241 1242 1243
                                    &data->pci_dev.function, def,
                                    _("no PCI function ID supplied for '%s'"),
                                    _("invalid PCI function ID supplied for '%s'")) < 0)
        goto out;

1244
    if (virNodeDevCapsDefParseHexId("string(./vendor[1]/@id)", ctxt,
1245 1246 1247 1248 1249
                                    &data->pci_dev.vendor, def,
                                    _("no PCI vendor ID supplied for '%s'"),
                                    _("invalid PCI vendor ID supplied for '%s'")) < 0)
        goto out;

1250
    if (virNodeDevCapsDefParseHexId("string(./product[1]/@id)", ctxt,
1251 1252 1253 1254 1255
                                    &data->pci_dev.product, def,
                                    _("no PCI product ID supplied for '%s'"),
                                    _("invalid PCI product ID supplied for '%s'")) < 0)
        goto out;

1256 1257
    data->pci_dev.vendor_name  = virXPathString("string(./vendor[1])", ctxt);
    data->pci_dev.product_name = virXPathString("string(./product[1])", ctxt);
1258

1259
    if ((iommuGroupNode = virXPathNode("./iommuGroup[1]", ctxt))) {
1260
        if (virNodeDevCapPCIDevIommuGroupParseXML(ctxt, iommuGroupNode,
1261 1262 1263 1264
                                                  data) < 0) {
            goto out;
        }
    }
1265

1266 1267
    /* The default value is -1 since zero is valid NUMA node number */
    data->pci_dev.numa_node = -1;
1268 1269 1270 1271 1272
    if (virNodeDevCapsDefParseIntOptional("number(./numa[1]/@node)", ctxt,
                                          &data->pci_dev.numa_node, def,
                                          _("invalid NUMA node ID supplied for '%s'")) < 0)
        goto out;

1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284
    if ((pciExpress = virXPathNode("./pci-express[1]", ctxt))) {
        if (VIR_ALLOC(pci_express) < 0)
            goto out;

        if (virPCIEDeviceInfoParseXML(ctxt, pciExpress, pci_express) < 0)
            goto out;

        data->pci_dev.pci_express = pci_express;
        pci_express = NULL;
        data->pci_dev.flags |= VIR_NODE_DEV_CAP_FLAG_PCIE;
    }

1285
    ret = 0;
1286
 out:
1287
    VIR_FREE(pci_express);
1288 1289 1290 1291 1292
    ctxt->node = orignode;
    return ret;
}

static int
1293
virNodeDevCapSystemParseXML(xmlXPathContextPtr ctxt,
1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304
                            virNodeDeviceDefPtr def,
                            xmlNodePtr node,
                            union _virNodeDevCapData *data)
{
    xmlNodePtr orignode;
    int ret = -1;
    char *tmp;

    orignode = ctxt->node;
    ctxt->node = node;

1305
    data->system.product_name = virXPathString("string(./product[1])", ctxt);
1306

1307 1308 1309
    data->system.hardware.vendor_name = virXPathString("string(./hardware/vendor[1])", ctxt);
    data->system.hardware.version     = virXPathString("string(./hardware/version[1])", ctxt);
    data->system.hardware.serial      = virXPathString("string(./hardware/serial[1])", ctxt);
1310

1311
    tmp = virXPathString("string(./hardware/uuid[1])", ctxt);
1312
    if (!tmp) {
1313 1314
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("no system UUID supplied for '%s'"), def->name);
1315 1316 1317 1318
        goto out;
    }

    if (virUUIDParse(tmp, data->system.hardware.uuid) < 0) {
1319 1320
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("malformed uuid element for '%s'"), def->name);
1321 1322 1323 1324 1325
        VIR_FREE(tmp);
        goto out;
    }
    VIR_FREE(tmp);

1326 1327 1328
    data->system.firmware.vendor_name  = virXPathString("string(./firmware/vendor[1])", ctxt);
    data->system.firmware.version      = virXPathString("string(./firmware/version[1])", ctxt);
    data->system.firmware.release_date = virXPathString("string(./firmware/release_date[1])", ctxt);
1329 1330

    ret = 0;
1331
 out:
1332 1333 1334 1335 1336
    ctxt->node = orignode;
    return ret;
}

static virNodeDevCapsDefPtr
1337
virNodeDevCapsDefParseXML(xmlXPathContextPtr ctxt,
1338
                          virNodeDeviceDefPtr def,
1339
                          xmlNodePtr node,
1340 1341
                          int create,
                          const char *virt_type)
1342 1343 1344 1345 1346
{
    virNodeDevCapsDefPtr caps;
    char *tmp;
    int val, ret;

1347
    if (VIR_ALLOC(caps) < 0)
1348 1349 1350 1351
        return NULL;

    tmp = virXMLPropString(node, "type");
    if (!tmp) {
1352 1353
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing capability type"));
1354 1355 1356 1357
        goto error;
    }

    if ((val = virNodeDevCapTypeFromString(tmp)) < 0) {
1358
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1359
                       _("unknown capability type '%s'"), tmp);
1360 1361 1362 1363 1364 1365 1366 1367
        VIR_FREE(tmp);
        goto error;
    }
    caps->type = val;
    VIR_FREE(tmp);

    switch (caps->type) {
    case VIR_NODE_DEV_CAP_SYSTEM:
1368
        ret = virNodeDevCapSystemParseXML(ctxt, def, node, &caps->data);
1369 1370
        break;
    case VIR_NODE_DEV_CAP_PCI_DEV:
1371
        ret = virNodeDevCapPCIDevParseXML(ctxt, def, node, &caps->data);
1372 1373
        break;
    case VIR_NODE_DEV_CAP_USB_DEV:
1374
        ret = virNodeDevCapUSBDevParseXML(ctxt, def, node, &caps->data);
1375 1376
        break;
    case VIR_NODE_DEV_CAP_USB_INTERFACE:
1377
        ret = virNodeDevCapUSBInterfaceParseXML(ctxt, def, node, &caps->data);
1378 1379
        break;
    case VIR_NODE_DEV_CAP_NET:
1380
        ret = virNodeDevCapNetParseXML(ctxt, def, node, &caps->data);
1381 1382
        break;
    case VIR_NODE_DEV_CAP_SCSI_HOST:
1383
        ret = virNodeDevCapSCSIHostParseXML(ctxt, def, node,
1384 1385 1386
                                            &caps->data,
                                            create,
                                            virt_type);
1387
        break;
D
David Allan 已提交
1388
    case VIR_NODE_DEV_CAP_SCSI_TARGET:
1389
        ret = virNodeDevCapSCSITargetParseXML(ctxt, def, node, &caps->data);
D
David Allan 已提交
1390
        break;
1391
    case VIR_NODE_DEV_CAP_SCSI:
1392
        ret = virNodeDevCapSCSIParseXML(ctxt, def, node, &caps->data);
1393 1394
        break;
    case VIR_NODE_DEV_CAP_STORAGE:
1395
        ret = virNodeDevCapStorageParseXML(ctxt, def, node, &caps->data);
1396 1397
        break;
    default:
1398 1399 1400
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown capability type '%d' for '%s'"),
                       caps->type, def->name);
1401 1402 1403 1404 1405 1406 1407 1408
        ret = -1;
        break;
    }

    if (ret < 0)
        goto error;
    return caps;

1409
 error:
1410 1411 1412 1413 1414
    virNodeDevCapsDefFree(caps);
    return NULL;
}

static virNodeDeviceDefPtr
1415 1416 1417
virNodeDeviceDefParseXML(xmlXPathContextPtr ctxt,
                         int create,
                         const char *virt_type)
1418 1419 1420 1421
{
    virNodeDeviceDefPtr def;
    virNodeDevCapsDefPtr *next_cap;
    xmlNodePtr *nodes;
1422 1423
    int n;
    size_t i;
1424

1425
    if (VIR_ALLOC(def) < 0)
1426 1427 1428
        return NULL;

    /* Extract device name */
1429
    if (create == EXISTING_DEVICE) {
1430
        def->name = virXPathString("string(./name[1])", ctxt);
1431 1432

        if (!def->name) {
1433
            virReportError(VIR_ERR_NO_NAME, NULL);
1434 1435
            goto error;
        }
1436
    } else {
1437
        if (VIR_STRDUP(def->name, "new device") < 0)
1438
            goto error;
1439 1440 1441
    }

    /* Extract device parent, if any */
1442
    def->parent = virXPathString("string(./parent[1])", ctxt);
1443 1444 1445

    /* Parse device capabilities */
    nodes = NULL;
1446 1447 1448 1449 1450
    if ((n = virXPathNodeSet("./capability", ctxt, &nodes)) < 0) {
        goto error;
    }

    if (n == 0) {
1451 1452 1453
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("no device capabilities for '%s'"),
                       def->name);
1454 1455 1456 1457
        goto error;
    }

    next_cap = &def->caps;
1458
    for (i = 0; i < n; i++) {
1459 1460 1461 1462
        *next_cap = virNodeDevCapsDefParseXML(ctxt, def,
                                              nodes[i],
                                              create,
                                              virt_type);
1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478
        if (!*next_cap) {
            VIR_FREE(nodes);
            goto error;
        }

        next_cap = &(*next_cap)->next;
    }
    VIR_FREE(nodes);

    return def;

 error:
    virNodeDeviceDefFree(def);
    return NULL;
}

1479
virNodeDeviceDefPtr
1480
virNodeDeviceDefParseNode(xmlDocPtr xml,
1481
                          xmlNodePtr root,
1482 1483
                          int create,
                          const char *virt_type)
1484 1485 1486 1487 1488
{
    xmlXPathContextPtr ctxt = NULL;
    virNodeDeviceDefPtr def = NULL;

    if (!xmlStrEqual(root->name, BAD_CAST "device")) {
1489 1490 1491 1492
        virReportError(VIR_ERR_XML_ERROR,
                       _("unexpected root element <%s> "
                         "expecting <device>"),
                       root->name);
1493 1494 1495 1496 1497
        return NULL;
    }

    ctxt = xmlXPathNewContext(xml);
    if (ctxt == NULL) {
1498
        virReportOOMError();
1499 1500 1501 1502
        goto cleanup;
    }

    ctxt->node = root;
1503
    def = virNodeDeviceDefParseXML(ctxt, create, virt_type);
1504

1505
 cleanup:
1506 1507 1508 1509
    xmlXPathFreeContext(ctxt);
    return def;
}

1510
static virNodeDeviceDefPtr
1511
virNodeDeviceDefParse(const char *str,
1512
                      const char *filename,
1513 1514
                      int create,
                      const char *virt_type)
1515
{
J
Jiri Denemark 已提交
1516
    xmlDocPtr xml;
1517 1518
    virNodeDeviceDefPtr def = NULL;

1519
    if ((xml = virXMLParse(filename, str, _("(node_device_definition)")))) {
1520 1521
        def = virNodeDeviceDefParseNode(xml, xmlDocGetRootElement(xml),
                                        create, virt_type);
J
Jiri Denemark 已提交
1522
        xmlFreeDoc(xml);
1523 1524
    }

1525 1526 1527
    return def;
}

1528
virNodeDeviceDefPtr
1529
virNodeDeviceDefParseString(const char *str,
1530 1531
                            int create,
                            const char *virt_type)
1532
{
1533
    return virNodeDeviceDefParse(str, NULL, create, virt_type);
1534 1535 1536
}

virNodeDeviceDefPtr
1537
virNodeDeviceDefParseFile(const char *filename,
1538 1539
                          int create,
                          const char *virt_type)
1540
{
1541
    return virNodeDeviceDefParse(NULL, filename, create, virt_type);
1542 1543
}

1544 1545 1546 1547
/*
 * Return fc_host dev's WWNN and WWPN
 */
int
1548
virNodeDeviceGetWWNs(virNodeDeviceDefPtr def,
1549 1550 1551 1552
                     char **wwnn,
                     char **wwpn)
{
    virNodeDevCapsDefPtr cap = NULL;
1553
    int ret = -1;
1554 1555 1556 1557 1558

    cap = def->caps;
    while (cap != NULL) {
        if (cap->type == VIR_NODE_DEV_CAP_SCSI_HOST &&
            cap->data.scsi_host.flags & VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST) {
1559 1560 1561 1562 1563 1564
            if (VIR_STRDUP(*wwnn, cap->data.scsi_host.wwnn) < 0 ||
                VIR_STRDUP(*wwpn, cap->data.scsi_host.wwpn) < 0) {
                /* Free the other one, if allocated... */
                VIR_FREE(*wwnn);
                goto cleanup;
            }
1565 1566 1567 1568 1569 1570 1571
            break;
        }

        cap = cap->next;
    }

    if (cap == NULL) {
1572 1573
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Device is not a fibre channel HBA"));
1574
        goto cleanup;
1575 1576
    }

1577
    ret = 0;
1578
 cleanup:
1579 1580 1581 1582 1583 1584 1585
    return ret;
}

/*
 * Return the NPIV dev's parent device name
 */
int
E
Eric Blake 已提交
1586
virNodeDeviceGetParentHost(virNodeDeviceObjListPtr devs,
1587 1588 1589 1590 1591 1592 1593 1594 1595 1596
                           const char *dev_name,
                           const char *parent_name,
                           int *parent_host)
{
    virNodeDeviceObjPtr parent = NULL;
    virNodeDevCapsDefPtr cap = NULL;
    int ret = 0;

    parent = virNodeDeviceFindByName(devs, parent_name);
    if (parent == NULL) {
1597 1598 1599
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not find parent device for '%s'"),
                       dev_name);
1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616
        ret = -1;
        goto out;
    }

    cap = parent->def->caps;
    while (cap != NULL) {
        if (cap->type == VIR_NODE_DEV_CAP_SCSI_HOST &&
            (cap->data.scsi_host.flags &
             VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS)) {
                *parent_host = cap->data.scsi_host.host;
                break;
        }

        cap = cap->next;
    }

    if (cap == NULL) {
1617 1618 1619 1620
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Parent device %s is not capable "
                         "of vport operations"),
                       parent->def->name);
1621 1622 1623 1624 1625
        ret = -1;
    }

    virNodeDeviceObjUnlock(parent);

1626
 out:
1627 1628
    return ret;
}
1629

1630 1631
void virNodeDevCapsDefFree(virNodeDevCapsDefPtr caps)
{
1632
    size_t i = 0;
1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647
    union _virNodeDevCapData *data = &caps->data;

    switch (caps->type) {
    case VIR_NODE_DEV_CAP_SYSTEM:
        VIR_FREE(data->system.product_name);
        VIR_FREE(data->system.hardware.vendor_name);
        VIR_FREE(data->system.hardware.version);
        VIR_FREE(data->system.hardware.serial);
        VIR_FREE(data->system.firmware.vendor_name);
        VIR_FREE(data->system.firmware.version);
        VIR_FREE(data->system.firmware.release_date);
        break;
    case VIR_NODE_DEV_CAP_PCI_DEV:
        VIR_FREE(data->pci_dev.product_name);
        VIR_FREE(data->pci_dev.vendor_name);
1648
        VIR_FREE(data->pci_dev.physical_function);
1649
        for (i = 0; i < data->pci_dev.num_virtual_functions; i++) {
1650 1651
            VIR_FREE(data->pci_dev.virtual_functions[i]);
        }
1652
        VIR_FREE(data->pci_dev.virtual_functions);
1653 1654 1655
        for (i = 0; i < data->pci_dev.nIommuGroupDevices; i++) {
            VIR_FREE(data->pci_dev.iommuGroupDevices[i]);
        }
1656
        VIR_FREE(data->pci_dev.iommuGroupDevices);
1657 1658 1659 1660 1661 1662 1663 1664 1665
        break;
    case VIR_NODE_DEV_CAP_USB_DEV:
        VIR_FREE(data->usb_dev.product_name);
        VIR_FREE(data->usb_dev.vendor_name);
        break;
    case VIR_NODE_DEV_CAP_USB_INTERFACE:
        VIR_FREE(data->usb_if.description);
        break;
    case VIR_NODE_DEV_CAP_NET:
1666
        VIR_FREE(data->net.ifname);
1667 1668 1669
        VIR_FREE(data->net.address);
        break;
    case VIR_NODE_DEV_CAP_SCSI_HOST:
1670 1671
        VIR_FREE(data->scsi_host.wwnn);
        VIR_FREE(data->scsi_host.wwpn);
O
Osier Yang 已提交
1672
        VIR_FREE(data->scsi_host.fabric_wwn);
1673
        break;
D
David Allan 已提交
1674 1675 1676
    case VIR_NODE_DEV_CAP_SCSI_TARGET:
        VIR_FREE(data->scsi_target.name);
        break;
1677 1678 1679 1680
    case VIR_NODE_DEV_CAP_SCSI:
        VIR_FREE(data->scsi.type);
        break;
    case VIR_NODE_DEV_CAP_STORAGE:
1681
        VIR_FREE(data->storage.block);
1682 1683 1684 1685
        VIR_FREE(data->storage.bus);
        VIR_FREE(data->storage.drive_type);
        VIR_FREE(data->storage.model);
        VIR_FREE(data->storage.vendor);
1686
        VIR_FREE(data->storage.serial);
1687
        VIR_FREE(data->storage.media_label);
1688
        break;
1689 1690 1691
    case VIR_NODE_DEV_CAP_SCSI_GENERIC:
        VIR_FREE(data->sg.path);
        break;
1692 1693
    case VIR_NODE_DEV_CAP_FC_HOST:
    case VIR_NODE_DEV_CAP_VPORTS:
1694
    case VIR_NODE_DEV_CAP_LAST:
1695
    default:
1696 1697 1698 1699 1700 1701 1702
        /* This case is here to shutup the compiler */
        break;
    }

    VIR_FREE(caps);
}

D
Daniel P. Berrange 已提交
1703

1704 1705
void virNodeDeviceObjLock(virNodeDeviceObjPtr obj)
{
1706
    virMutexLock(&obj->lock);
1707 1708 1709 1710
}

void virNodeDeviceObjUnlock(virNodeDeviceObjPtr obj)
{
1711
    virMutexUnlock(&obj->lock);
D
Daniel P. Berrange 已提交
1712
}
1713 1714 1715 1716 1717 1718 1719 1720 1721 1722

static bool
virNodeDeviceCapMatch(virNodeDeviceObjPtr devobj,
                      int type)
{
    virNodeDevCapsDefPtr cap = NULL;

    for (cap = devobj->def->caps; cap; cap = cap->next) {
        if (type == cap->type)
            return true;
1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734

        if (cap->type == VIR_NODE_DEV_CAP_SCSI_HOST) {
            if (type == VIR_CONNECT_LIST_NODE_DEVICES_CAP_FC_HOST &&
                (cap->data.scsi_host.flags &
                 VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST))
                return true;

            if (type == VIR_CONNECT_LIST_NODE_DEVICES_CAP_VPORTS &&
                (cap->data.scsi_host.flags &
                 VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS))
                return true;
        }
1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763
    }

    return false;
}

#define MATCH(FLAG) (flags & (FLAG))
static bool
virNodeDeviceMatch(virNodeDeviceObjPtr devobj,
                   unsigned int flags)
{
    /* filter by cap type */
    if (MATCH(VIR_CONNECT_LIST_NODE_DEVICES_FILTERS_CAP)) {
        if (!((MATCH(VIR_CONNECT_LIST_NODE_DEVICES_CAP_SYSTEM) &&
               virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_SYSTEM))        ||
              (MATCH(VIR_CONNECT_LIST_NODE_DEVICES_CAP_PCI_DEV) &&
               virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_PCI_DEV))       ||
              (MATCH(VIR_CONNECT_LIST_NODE_DEVICES_CAP_USB_DEV) &&
               virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_USB_DEV))       ||
              (MATCH(VIR_CONNECT_LIST_NODE_DEVICES_CAP_USB_INTERFACE) &&
               virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_USB_INTERFACE)) ||
              (MATCH(VIR_CONNECT_LIST_NODE_DEVICES_CAP_NET) &&
               virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_NET))           ||
              (MATCH(VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI_HOST) &&
               virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_SCSI_HOST))     ||
              (MATCH(VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI_TARGET) &&
               virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_SCSI_TARGET))   ||
              (MATCH(VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI) &&
               virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_SCSI))          ||
              (MATCH(VIR_CONNECT_LIST_NODE_DEVICES_CAP_STORAGE) &&
1764 1765 1766 1767
               virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_STORAGE))       ||
              (MATCH(VIR_CONNECT_LIST_NODE_DEVICES_CAP_FC_HOST) &&
               virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_FC_HOST))       ||
              (MATCH(VIR_CONNECT_LIST_NODE_DEVICES_CAP_VPORTS) &&
1768 1769 1770
               virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_VPORTS))        ||
              (MATCH(VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI_GENERIC) &&
               virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_SCSI_GENERIC))))
1771 1772 1773 1774 1775 1776 1777 1778
            return false;
    }

    return true;
}
#undef MATCH

int
1779 1780 1781 1782 1783
virNodeDeviceObjListExport(virConnectPtr conn,
                           virNodeDeviceObjList devobjs,
                           virNodeDevicePtr **devices,
                           virNodeDeviceObjListFilter filter,
                           unsigned int flags)
1784 1785 1786 1787 1788
{
    virNodeDevicePtr *tmp_devices = NULL;
    virNodeDevicePtr device = NULL;
    int ndevices = 0;
    int ret = -1;
1789
    size_t i;
1790

1791 1792
    if (devices && VIR_ALLOC_N(tmp_devices, devobjs.count + 1) < 0)
        goto cleanup;
1793 1794 1795 1796

    for (i = 0; i < devobjs.count; i++) {
        virNodeDeviceObjPtr devobj = devobjs.objs[i];
        virNodeDeviceObjLock(devobj);
1797 1798
        if ((!filter || filter(conn, devobj->def)) &&
            virNodeDeviceMatch(devobj, flags)) {
1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820
            if (devices) {
                if (!(device = virGetNodeDevice(conn,
                                                devobj->def->name))) {
                    virNodeDeviceObjUnlock(devobj);
                    goto cleanup;
                }
                tmp_devices[ndevices] = device;
            }
            ndevices++;
        }
        virNodeDeviceObjUnlock(devobj);
    }

    if (tmp_devices) {
        /* trim the array to the final size */
        ignore_value(VIR_REALLOC_N(tmp_devices, ndevices + 1));
        *devices = tmp_devices;
        tmp_devices = NULL;
    }

    ret = ndevices;

1821
 cleanup:
1822 1823 1824 1825 1826 1827 1828 1829 1830 1831
    if (tmp_devices) {
        for (i = 0; i < ndevices; i++) {
            if (tmp_devices[i])
                virNodeDeviceFree(tmp_devices[i]);
        }
    }

    VIR_FREE(tmp_devices);
    return ret;
}