node_device_conf.c 62.1 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
static int
62
virNodeDevCapsDefParseString(const char *xpath,
63
                             xmlXPathContextPtr ctxt,
64
                             char **string)
65 66 67
{
    char *s;

68
    if (!(s = virXPathString(xpath, ctxt)))
69 70 71 72 73 74
        return -1;

    *string = s;
    return 0;
}

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

86 87

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

    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 已提交
106
virNodeDeviceObjPtr virNodeDeviceFindByName(virNodeDeviceObjListPtr devs,
107 108
                                            const char *name)
{
109
    size_t i;
110

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

    return NULL;
}


void virNodeDeviceDefFree(virNodeDeviceDefPtr def)
{
    virNodeDevCapsDefPtr caps;

    if (!def)
        return;

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

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

154 155
    virMutexDestroy(&dev->lock);

156 157 158 159 160
    VIR_FREE(dev);
}

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

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

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

179
    if (VIR_ALLOC(device) < 0)
180 181
        return NULL;

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

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

    return device;

}

void virNodeDeviceObjRemove(virNodeDeviceObjListPtr devs,
E
Eric Blake 已提交
202
                            virNodeDeviceObjPtr dev)
203
{
204
    size_t i;
205

206 207
    virNodeDeviceObjUnlock(dev);

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

214
            VIR_DELETE_ELEMENT(devs->objs, i, devs->count);
215 216
            break;
        }
217
        virNodeDeviceObjUnlock(dev);
218 219 220
    }
}

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
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 已提交
258
char *virNodeDeviceDefFormat(const virNodeDeviceDef *def)
259 260
{
    virBuffer buf = VIR_BUFFER_INITIALIZER;
261
    virNodeDevCapsDefPtr caps;
262
    size_t i = 0;
263 264

    virBufferAddLit(&buf, "<device>\n");
265 266 267 268 269
    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);
270
    if (def->driver) {
271 272 273 274 275
        virBufferAddLit(&buf, "<driver>\n");
        virBufferAdjustIndent(&buf, 2);
        virBufferEscapeString(&buf, "<name>%s</name>\n", def->driver);
        virBufferAdjustIndent(&buf, -2);
        virBufferAddLit(&buf, "</driver>\n");
276
    }
277 278 279 280 281

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

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

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

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

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

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

    return virBufferContentAndReset(&buf);
}

563 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
/**
 * 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;
}

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

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

    *value = val;
    return 0;
}

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

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

    *value = val;
    return 0;
}

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

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

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

666 667 668 669 670
    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);
671

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

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

        if (!type) {
679 680 681
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("missing storage capability type for '%s'"),
                           def->name);
682 683 684
            goto out;
        }

685
        if (STREQ(type, "hotpluggable")) {
686
            data->storage.flags |= VIR_NODE_DEV_CAP_STORAGE_HOTPLUGGABLE;
687
        } else if (STREQ(type, "removable")) {
688 689 690 691 692 693 694
            xmlNodePtr orignode2;

            data->storage.flags |= VIR_NODE_DEV_CAP_STORAGE_REMOVABLE;

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

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

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

700
            val = 0;
701
            if (virNodeDevCapsDefParseULongLong("number(./media_size[1])", ctxt, &val, def,
702 703 704 705 706 707 708 709 710 711
                                                _("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 {
712 713 714
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown storage capability type '%s' for '%s'"),
                           type, def->name);
715 716 717 718 719 720 721 722 723
            VIR_FREE(type);
            goto out;
        }

        VIR_FREE(type);
    }

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

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

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

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

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

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

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

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

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

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

D
David Allan 已提交
782 783

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

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

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

    ret = 0;

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


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

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

J
John Ferlan 已提交
827 828 829 830 831 832 833 834 835 836 837 838 839 840
    if (create == EXISTING_DEVICE) {
        if (virNodeDevCapsDefParseULong("number(./host[1])", ctxt,
                                        &data->scsi_host.host, def,
                                        _("no SCSI host ID supplied for '%s'"),
                                        _("invalid SCSI host ID supplied for '%s'")) < 0) {
            goto out;
        }
        /* Optional unique_id value */
        data->scsi_host.unique_id = -1;
        if (virNodeDevCapsDefParseIntOptional("number(./unique_id[1])", ctxt,
                                              &data->scsi_host.unique_id, def,
                                              _("invalid unique_id supplied for '%s'")) < 0) {
            goto out;
        }
841 842
    }

843
    if ((n = virXPathNodeSet("./capability", ctxt, &nodes)) < 0)
844
        goto out;
845

846
    for (i = 0; i < n; i++) {
847 848 849
        type = virXMLPropString(nodes[i], "type");

        if (!type) {
850 851 852
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("missing SCSI host capability type for '%s'"),
                           def->name);
853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868
            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];

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

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

            ctxt->node = orignode2;

        } else {
896 897 898
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown SCSI host capability type '%s' for '%s'"),
                           type, def->name);
899 900 901 902 903
            goto out;
        }

        VIR_FREE(type);
    }
904 905

    ret = 0;
906

907
 out:
908
    VIR_FREE(type);
909
    ctxt->node = orignode;
910
    VIR_FREE(nodes);
911 912 913
    return ret;
}

914

915
static int
916
virNodeDevCapNetParseXML(xmlXPathContextPtr ctxt,
917 918 919 920
                         virNodeDeviceDefPtr def,
                         xmlNodePtr node,
                         union _virNodeDevCapData *data)
{
921
    xmlNodePtr orignode, lnk;
922 923 924 925 926 927
    int ret = -1;
    char *tmp;

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

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

936
    data->net.address = virXPathString("string(./address[1])", ctxt);
937 938 939

    data->net.subtype = VIR_NODE_DEV_CAP_NET_LAST;

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

953 954 955 956
    lnk = virXPathNode("./link", ctxt);
    if (lnk && virInterfaceLinkParseXML(lnk, &data->net.lnk) < 0)
        goto out;

957
    ret = 0;
958
 out:
959 960 961 962 963
    ctxt->node = orignode;
    return ret;
}

static int
964
virNodeDevCapUSBInterfaceParseXML(xmlXPathContextPtr ctxt,
965 966 967 968 969 970 971 972 973 974
                                  virNodeDeviceDefPtr def,
                                  xmlNodePtr node,
                                  union _virNodeDevCapData *data)
{
    xmlNodePtr orignode;
    int ret = -1;

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

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

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

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

993
    if (virNodeDevCapsDefParseULong("number(./protocol[1])", ctxt,
994 995 996 997 998
                                    &data->usb_if.protocol, def,
                                    _("no USB interface protocol supplied for '%s'"),
                                    _("invalid USB interface protocol supplied for '%s'")) < 0)
        goto out;

999
    data->usb_if.description = virXPathString("string(./description[1])", ctxt);
1000 1001

    ret = 0;
1002
 out:
1003 1004 1005 1006 1007
    ctxt->node = orignode;
    return ret;
}

static int
1008
virNodeDevCapsDefParseHexId(const char *xpath,
1009 1010 1011 1012 1013 1014 1015 1016 1017
                            xmlXPathContextPtr ctxt,
                            unsigned *value,
                            virNodeDeviceDefPtr def,
                            const char *missing_error_fmt,
                            const char *invalid_error_fmt)
{
    int ret;
    unsigned long val;

1018
    ret = virXPathULongHex(xpath, ctxt, &val);
1019
    if (ret < 0) {
1020 1021 1022
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       ret == -1 ? missing_error_fmt : invalid_error_fmt,
                       def->name);
1023 1024 1025 1026 1027 1028 1029 1030
        return -1;
    }

    *value = val;
    return 0;
}

static int
1031
virNodeDevCapUSBDevParseXML(xmlXPathContextPtr ctxt,
1032 1033 1034 1035 1036 1037 1038 1039 1040 1041
                            virNodeDeviceDefPtr def,
                            xmlNodePtr node,
                            union _virNodeDevCapData *data)
{
    xmlNodePtr orignode;
    int ret = -1;

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

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

1048
    if (virNodeDevCapsDefParseULong("number(./device[1])", ctxt,
1049 1050 1051 1052 1053
                                    &data->usb_dev.device, def,
                                    _("no USB device number supplied for '%s'"),
                                    _("invalid USB device number supplied for '%s'")) < 0)
        goto out;

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

1060
    if (virNodeDevCapsDefParseHexId("string(./product[1]/@id)", ctxt,
1061 1062 1063 1064 1065
                                    &data->usb_dev.product, def,
                                    _("no USB product ID supplied for '%s'"),
                                    _("invalid USB product ID supplied for '%s'")) < 0)
        goto out;

1066 1067
    data->usb_dev.vendor_name  = virXPathString("string(./vendor[1])", ctxt);
    data->usb_dev.product_name = virXPathString("string(./product[1])", ctxt);
1068 1069

    ret = 0;
1070
 out:
1071 1072 1073 1074
    ctxt->node = orignode;
    return ret;
}

1075
static int
1076
virNodeDevCapPCIDevIommuGroupParseXML(xmlXPathContextPtr ctxt,
1077 1078 1079 1080 1081 1082
                                      xmlNodePtr iommuGroupNode,
                                      union _virNodeDevCapData *data)
{
    xmlNodePtr origNode = ctxt->node;
    xmlNodePtr *addrNodes = NULL;
    char *numberStr = NULL;
1083 1084
    int nAddrNodes, ret = -1;
    size_t i;
1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105
    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;

1106
    for (i = 0; i < nAddrNodes; i++) {
1107
        virDevicePCIAddress addr = { 0, 0, 0, 0, 0 };
1108
        if (virDevicePCIAddressParseXML(addrNodes[i], &addr) < 0)
1109
            goto cleanup;
1110
        if (VIR_ALLOC(pciAddr) < 0)
1111 1112 1113 1114 1115 1116 1117
            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,
1118
                               pciAddr) < 0)
1119 1120 1121 1122
            goto cleanup;
    }

    ret = 0;
1123
 cleanup:
1124
    ctxt->node = origNode;
1125
    VIR_FREE(numberStr);
1126 1127 1128 1129 1130
    VIR_FREE(addrNodes);
    VIR_FREE(pciAddr);
    return ret;
}

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 1206 1207 1208 1209 1210
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;
}

1211

1212
static int
1213
virNodeDevCapPCIDevParseXML(xmlXPathContextPtr ctxt,
1214 1215 1216 1217
                            virNodeDeviceDefPtr def,
                            xmlNodePtr node,
                            union _virNodeDevCapData *data)
{
1218
    xmlNodePtr orignode, iommuGroupNode, pciExpress;
1219
    int ret = -1;
1220
    virPCIEDeviceInfoPtr pci_express = NULL;
1221 1222 1223 1224

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

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

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

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

1243
    if (virNodeDevCapsDefParseULong("number(./function[1])", ctxt,
1244 1245 1246 1247 1248
                                    &data->pci_dev.function, def,
                                    _("no PCI function ID supplied for '%s'"),
                                    _("invalid PCI function ID supplied for '%s'")) < 0)
        goto out;

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

1255
    if (virNodeDevCapsDefParseHexId("string(./product[1]/@id)", ctxt,
1256 1257 1258 1259 1260
                                    &data->pci_dev.product, def,
                                    _("no PCI product ID supplied for '%s'"),
                                    _("invalid PCI product ID supplied for '%s'")) < 0)
        goto out;

1261 1262
    data->pci_dev.vendor_name  = virXPathString("string(./vendor[1])", ctxt);
    data->pci_dev.product_name = virXPathString("string(./product[1])", ctxt);
1263

1264
    if ((iommuGroupNode = virXPathNode("./iommuGroup[1]", ctxt))) {
1265
        if (virNodeDevCapPCIDevIommuGroupParseXML(ctxt, iommuGroupNode,
1266 1267 1268 1269
                                                  data) < 0) {
            goto out;
        }
    }
1270

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

1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289
    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;
    }

1290
    ret = 0;
1291
 out:
1292
    virPCIEDeviceInfoFree(pci_express);
1293 1294 1295 1296 1297
    ctxt->node = orignode;
    return ret;
}

static int
1298
virNodeDevCapSystemParseXML(xmlXPathContextPtr ctxt,
1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309
                            virNodeDeviceDefPtr def,
                            xmlNodePtr node,
                            union _virNodeDevCapData *data)
{
    xmlNodePtr orignode;
    int ret = -1;
    char *tmp;

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

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

1312 1313 1314
    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);
1315

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

    if (virUUIDParse(tmp, data->system.hardware.uuid) < 0) {
1324 1325
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("malformed uuid element for '%s'"), def->name);
1326 1327 1328 1329 1330
        VIR_FREE(tmp);
        goto out;
    }
    VIR_FREE(tmp);

1331 1332 1333
    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);
1334 1335

    ret = 0;
1336
 out:
1337 1338 1339 1340 1341
    ctxt->node = orignode;
    return ret;
}

static virNodeDevCapsDefPtr
1342
virNodeDevCapsDefParseXML(xmlXPathContextPtr ctxt,
1343
                          virNodeDeviceDefPtr def,
1344
                          xmlNodePtr node,
1345 1346
                          int create,
                          const char *virt_type)
1347 1348 1349
{
    virNodeDevCapsDefPtr caps;
    char *tmp;
1350
    int val, ret = -1;
1351

1352
    if (VIR_ALLOC(caps) < 0)
1353 1354 1355 1356
        return NULL;

    tmp = virXMLPropString(node, "type");
    if (!tmp) {
1357 1358
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing capability type"));
1359 1360 1361 1362
        goto error;
    }

    if ((val = virNodeDevCapTypeFromString(tmp)) < 0) {
1363
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1364
                       _("unknown capability type '%s'"), tmp);
1365 1366 1367 1368 1369 1370 1371 1372
        VIR_FREE(tmp);
        goto error;
    }
    caps->type = val;
    VIR_FREE(tmp);

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

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

1417
 error:
1418 1419 1420 1421 1422
    virNodeDevCapsDefFree(caps);
    return NULL;
}

static virNodeDeviceDefPtr
1423 1424 1425
virNodeDeviceDefParseXML(xmlXPathContextPtr ctxt,
                         int create,
                         const char *virt_type)
1426 1427 1428 1429
{
    virNodeDeviceDefPtr def;
    virNodeDevCapsDefPtr *next_cap;
    xmlNodePtr *nodes;
1430 1431
    int n;
    size_t i;
1432

1433
    if (VIR_ALLOC(def) < 0)
1434 1435 1436
        return NULL;

    /* Extract device name */
1437
    if (create == EXISTING_DEVICE) {
1438
        def->name = virXPathString("string(./name[1])", ctxt);
1439 1440

        if (!def->name) {
1441
            virReportError(VIR_ERR_NO_NAME, NULL);
1442 1443
            goto error;
        }
1444
    } else {
1445
        if (VIR_STRDUP(def->name, "new device") < 0)
1446
            goto error;
1447 1448 1449
    }

    /* Extract device parent, if any */
1450
    def->parent = virXPathString("string(./parent[1])", ctxt);
1451 1452 1453

    /* Parse device capabilities */
    nodes = NULL;
1454
    if ((n = virXPathNodeSet("./capability", ctxt, &nodes)) < 0)
1455 1456 1457
        goto error;

    if (n == 0) {
1458 1459 1460
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("no device capabilities for '%s'"),
                       def->name);
1461 1462 1463 1464
        goto error;
    }

    next_cap = &def->caps;
1465
    for (i = 0; i < n; i++) {
1466 1467 1468 1469
        *next_cap = virNodeDevCapsDefParseXML(ctxt, def,
                                              nodes[i],
                                              create,
                                              virt_type);
1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485
        if (!*next_cap) {
            VIR_FREE(nodes);
            goto error;
        }

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

    return def;

 error:
    virNodeDeviceDefFree(def);
    return NULL;
}

1486
virNodeDeviceDefPtr
1487
virNodeDeviceDefParseNode(xmlDocPtr xml,
1488
                          xmlNodePtr root,
1489 1490
                          int create,
                          const char *virt_type)
1491 1492 1493 1494 1495
{
    xmlXPathContextPtr ctxt = NULL;
    virNodeDeviceDefPtr def = NULL;

    if (!xmlStrEqual(root->name, BAD_CAST "device")) {
1496 1497 1498 1499
        virReportError(VIR_ERR_XML_ERROR,
                       _("unexpected root element <%s> "
                         "expecting <device>"),
                       root->name);
1500 1501 1502 1503 1504
        return NULL;
    }

    ctxt = xmlXPathNewContext(xml);
    if (ctxt == NULL) {
1505
        virReportOOMError();
1506 1507 1508 1509
        goto cleanup;
    }

    ctxt->node = root;
1510
    def = virNodeDeviceDefParseXML(ctxt, create, virt_type);
1511

1512
 cleanup:
1513 1514 1515 1516
    xmlXPathFreeContext(ctxt);
    return def;
}

1517
static virNodeDeviceDefPtr
1518
virNodeDeviceDefParse(const char *str,
1519
                      const char *filename,
1520 1521
                      int create,
                      const char *virt_type)
1522
{
J
Jiri Denemark 已提交
1523
    xmlDocPtr xml;
1524 1525
    virNodeDeviceDefPtr def = NULL;

1526
    if ((xml = virXMLParse(filename, str, _("(node_device_definition)")))) {
1527 1528
        def = virNodeDeviceDefParseNode(xml, xmlDocGetRootElement(xml),
                                        create, virt_type);
J
Jiri Denemark 已提交
1529
        xmlFreeDoc(xml);
1530 1531
    }

1532 1533 1534
    return def;
}

1535
virNodeDeviceDefPtr
1536
virNodeDeviceDefParseString(const char *str,
1537 1538
                            int create,
                            const char *virt_type)
1539
{
1540
    return virNodeDeviceDefParse(str, NULL, create, virt_type);
1541 1542 1543
}

virNodeDeviceDefPtr
1544
virNodeDeviceDefParseFile(const char *filename,
1545 1546
                          int create,
                          const char *virt_type)
1547
{
1548
    return virNodeDeviceDefParse(NULL, filename, create, virt_type);
1549 1550
}

1551 1552 1553 1554
/*
 * Return fc_host dev's WWNN and WWPN
 */
int
1555
virNodeDeviceGetWWNs(virNodeDeviceDefPtr def,
1556 1557 1558 1559
                     char **wwnn,
                     char **wwpn)
{
    virNodeDevCapsDefPtr cap = NULL;
1560
    int ret = -1;
1561 1562 1563 1564 1565

    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) {
1566 1567 1568 1569 1570 1571
            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;
            }
1572 1573 1574 1575 1576 1577 1578
            break;
        }

        cap = cap->next;
    }

    if (cap == NULL) {
1579 1580
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Device is not a fibre channel HBA"));
1581
        goto cleanup;
1582 1583
    }

1584
    ret = 0;
1585
 cleanup:
1586 1587 1588 1589 1590 1591 1592
    return ret;
}

/*
 * Return the NPIV dev's parent device name
 */
int
E
Eric Blake 已提交
1593
virNodeDeviceGetParentHost(virNodeDeviceObjListPtr devs,
1594 1595 1596 1597 1598 1599 1600 1601 1602 1603
                           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) {
1604 1605 1606
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not find parent device for '%s'"),
                       dev_name);
1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623
        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) {
1624 1625 1626 1627
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Parent device %s is not capable "
                         "of vport operations"),
                       parent->def->name);
1628 1629 1630 1631 1632
        ret = -1;
    }

    virNodeDeviceObjUnlock(parent);

1633
 out:
1634 1635
    return ret;
}
1636

1637 1638
void virNodeDevCapsDefFree(virNodeDevCapsDefPtr caps)
{
1639
    size_t i = 0;
1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654
    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);
1655
        VIR_FREE(data->pci_dev.physical_function);
1656
        for (i = 0; i < data->pci_dev.num_virtual_functions; i++)
1657
            VIR_FREE(data->pci_dev.virtual_functions[i]);
1658
        VIR_FREE(data->pci_dev.virtual_functions);
1659
        for (i = 0; i < data->pci_dev.nIommuGroupDevices; i++)
1660
            VIR_FREE(data->pci_dev.iommuGroupDevices[i]);
1661
        VIR_FREE(data->pci_dev.iommuGroupDevices);
1662
        virPCIEDeviceInfoFree(data->pci_dev.pci_express);
1663 1664 1665 1666 1667 1668 1669 1670 1671
        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:
1672
        VIR_FREE(data->net.ifname);
1673 1674 1675
        VIR_FREE(data->net.address);
        break;
    case VIR_NODE_DEV_CAP_SCSI_HOST:
1676 1677
        VIR_FREE(data->scsi_host.wwnn);
        VIR_FREE(data->scsi_host.wwpn);
O
Osier Yang 已提交
1678
        VIR_FREE(data->scsi_host.fabric_wwn);
1679
        break;
D
David Allan 已提交
1680 1681 1682
    case VIR_NODE_DEV_CAP_SCSI_TARGET:
        VIR_FREE(data->scsi_target.name);
        break;
1683 1684 1685 1686
    case VIR_NODE_DEV_CAP_SCSI:
        VIR_FREE(data->scsi.type);
        break;
    case VIR_NODE_DEV_CAP_STORAGE:
1687
        VIR_FREE(data->storage.block);
1688 1689 1690 1691
        VIR_FREE(data->storage.bus);
        VIR_FREE(data->storage.drive_type);
        VIR_FREE(data->storage.model);
        VIR_FREE(data->storage.vendor);
1692
        VIR_FREE(data->storage.serial);
1693
        VIR_FREE(data->storage.media_label);
1694
        break;
1695 1696 1697
    case VIR_NODE_DEV_CAP_SCSI_GENERIC:
        VIR_FREE(data->sg.path);
        break;
1698 1699
    case VIR_NODE_DEV_CAP_FC_HOST:
    case VIR_NODE_DEV_CAP_VPORTS:
1700 1701 1702 1703 1704 1705 1706 1707
    case VIR_NODE_DEV_CAP_LAST:
        /* This case is here to shutup the compiler */
        break;
    }

    VIR_FREE(caps);
}

D
Daniel P. Berrange 已提交
1708

1709 1710
void virNodeDeviceObjLock(virNodeDeviceObjPtr obj)
{
1711
    virMutexLock(&obj->lock);
1712 1713 1714 1715
}

void virNodeDeviceObjUnlock(virNodeDeviceObjPtr obj)
{
1716
    virMutexUnlock(&obj->lock);
D
Daniel P. Berrange 已提交
1717
}
1718 1719 1720 1721 1722 1723 1724 1725 1726 1727

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;
1728 1729

        if (cap->type == VIR_NODE_DEV_CAP_SCSI_HOST) {
1730
            if (type == VIR_NODE_DEV_CAP_FC_HOST &&
1731 1732 1733 1734
                (cap->data.scsi_host.flags &
                 VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST))
                return true;

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

    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) &&
1769 1770 1771 1772
               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) &&
1773 1774 1775
               virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_VPORTS))        ||
              (MATCH(VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI_GENERIC) &&
               virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_SCSI_GENERIC))))
1776 1777 1778 1779 1780 1781 1782 1783
            return false;
    }

    return true;
}
#undef MATCH

int
1784 1785 1786 1787 1788
virNodeDeviceObjListExport(virConnectPtr conn,
                           virNodeDeviceObjList devobjs,
                           virNodeDevicePtr **devices,
                           virNodeDeviceObjListFilter filter,
                           unsigned int flags)
1789 1790 1791 1792 1793
{
    virNodeDevicePtr *tmp_devices = NULL;
    virNodeDevicePtr device = NULL;
    int ndevices = 0;
    int ret = -1;
1794
    size_t i;
1795

1796 1797
    if (devices && VIR_ALLOC_N(tmp_devices, devobjs.count + 1) < 0)
        goto cleanup;
1798 1799 1800 1801

    for (i = 0; i < devobjs.count; i++) {
        virNodeDeviceObjPtr devobj = devobjs.objs[i];
        virNodeDeviceObjLock(devobj);
1802 1803
        if ((!filter || filter(conn, devobj->def)) &&
            virNodeDeviceMatch(devobj, flags)) {
1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825
            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;

1826
 cleanup:
1827 1828 1829 1830 1831 1832 1833 1834 1835 1836
    if (tmp_devices) {
        for (i = 0; i < ndevices; i++) {
            if (tmp_devices[i])
                virNodeDeviceFree(tmp_devices[i]);
        }
    }

    VIR_FREE(tmp_devices);
    return ret;
}