node_device_conf.c 63.3 KB
Newer Older
1 2 3
/*
 * node_device_conf.c: config handling for node devices
 *
4
 * Copyright (C) 2009-2015 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
{
    virNodeDevCapsDefPtr caps = dev->def->caps;
    while (caps) {
79
        if (STREQ(cap, virNodeDevCapTypeToString(caps->data.type)))
80
            return 1;
81
        else if (caps->data.type == VIR_NODE_DEV_CAP_SCSI_HOST)
82 83 84 85 86 87 88
            if ((STREQ(cap, "fc_host") &&
                (caps->data.scsi_host.flags &
                 VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST)) ||
                (STREQ(cap, "vports") &&
                (caps->data.scsi_host.flags &
                 VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS)))
                return 1;
89 90 91 92
        caps = caps->next;
    }
    return 0;
}
93

94 95

virNodeDeviceObjPtr
E
Eric Blake 已提交
96
virNodeDeviceFindBySysfsPath(virNodeDeviceObjListPtr devs,
97 98
                             const char *sysfs_path)
{
99
    size_t i;
100 101 102 103 104 105 106 107 108 109 110 111 112 113

    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 已提交
114
virNodeDeviceObjPtr virNodeDeviceFindByName(virNodeDeviceObjListPtr devs,
115 116
                                            const char *name)
{
117
    size_t i;
118

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

    return NULL;
}


void virNodeDeviceDefFree(virNodeDeviceDefPtr def)
{
    virNodeDevCapsDefPtr caps;

    if (!def)
        return;

    VIR_FREE(def->name);
    VIR_FREE(def->parent);
139
    VIR_FREE(def->driver);
140 141
    VIR_FREE(def->sysfs_path);
    VIR_FREE(def->parent_sysfs_path);
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161

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

162 163
    virMutexDestroy(&dev->lock);

164 165 166 167 168
    VIR_FREE(dev);
}

void virNodeDeviceObjListFree(virNodeDeviceObjListPtr devs)
{
169
    size_t i;
170
    for (i = 0; i < devs->count; i++)
171 172 173 174 175
        virNodeDeviceObjFree(devs->objs[i]);
    VIR_FREE(devs->objs);
    devs->count = 0;
}

176
virNodeDeviceObjPtr virNodeDeviceAssignDef(virNodeDeviceObjListPtr devs,
E
Eric Blake 已提交
177
                                           virNodeDeviceDefPtr def)
178 179 180 181 182 183 184 185 186
{
    virNodeDeviceObjPtr device;

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

187
    if (VIR_ALLOC(device) < 0)
188 189
        return NULL;

190
    if (virMutexInit(&device->lock) < 0) {
191 192
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("cannot initialize mutex"));
193 194 195
        VIR_FREE(device);
        return NULL;
    }
196
    virNodeDeviceObjLock(device);
197

198
    if (VIR_APPEND_ELEMENT_COPY(devs->objs, devs->count, device) < 0) {
199
        virNodeDeviceObjUnlock(device);
200 201 202
        virNodeDeviceObjFree(device);
        return NULL;
    }
203
    device->def = def;
204 205 206 207 208 209

    return device;

}

void virNodeDeviceObjRemove(virNodeDeviceObjListPtr devs,
E
Eric Blake 已提交
210
                            virNodeDeviceObjPtr dev)
211
{
212
    size_t i;
213

214 215
    virNodeDeviceObjUnlock(dev);

216
    for (i = 0; i < devs->count; i++) {
217
        virNodeDeviceObjLock(dev);
218
        if (devs->objs[i] == dev) {
219
            virNodeDeviceObjUnlock(dev);
220 221
            virNodeDeviceObjFree(devs->objs[i]);

222
            VIR_DELETE_ELEMENT(devs->objs, i, devs->count);
223 224
            break;
        }
225
        virNodeDeviceObjUnlock(dev);
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 261 262 263 264 265
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 已提交
266
char *virNodeDeviceDefFormat(const virNodeDeviceDef *def)
267 268
{
    virBuffer buf = VIR_BUFFER_INITIALIZER;
269
    virNodeDevCapsDefPtr caps;
270
    size_t i = 0;
271 272

    virBufferAddLit(&buf, "<device>\n");
273 274 275 276 277
    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);
278
    if (def->driver) {
279 280 281 282 283
        virBufferAddLit(&buf, "<driver>\n");
        virBufferAdjustIndent(&buf, 2);
        virBufferEscapeString(&buf, "<name>%s</name>\n", def->driver);
        virBufferAdjustIndent(&buf, -2);
        virBufferAddLit(&buf, "</driver>\n");
284
    }
285 286 287

    for (caps = def->caps; caps; caps = caps->next) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
288
        virNodeDevCapDataPtr data = &caps->data;
289

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

            virBufferAddLit(&buf, "<firmware>\n");
            virBufferAdjustIndent(&buf, 2);
316
            if (data->system.firmware.vendor_name)
317
                virBufferEscapeString(&buf, "<vendor>%s</vendor>\n",
318 319
                                      data->system.firmware.vendor_name);
            if (data->system.firmware.version)
320
                virBufferEscapeString(&buf, "<version>%s</version>\n",
321 322
                                      data->system.firmware.version);
            if (data->system.firmware.release_date)
323
                virBufferEscapeString(&buf, "<release_date>%s</release_date>\n",
324
                                      data->system.firmware.release_date);
325 326
            virBufferAdjustIndent(&buf, -2);
            virBufferAddLit(&buf, "</firmware>\n");
327 328
            break;
        case VIR_NODE_DEV_CAP_PCI_DEV:
329
            virBufferAsprintf(&buf, "<domain>%d</domain>\n",
330
                              data->pci_dev.domain);
331 332
            virBufferAsprintf(&buf, "<bus>%d</bus>\n", data->pci_dev.bus);
            virBufferAsprintf(&buf, "<slot>%d</slot>\n",
333
                              data->pci_dev.slot);
334
            virBufferAsprintf(&buf, "<function>%d</function>\n",
335
                              data->pci_dev.function);
336
            virBufferAsprintf(&buf, "<product id='0x%04x'",
337 338 339 340 341 342
                                  data->pci_dev.product);
            if (data->pci_dev.product_name)
                virBufferEscapeString(&buf, ">%s</product>\n",
                                      data->pci_dev.product_name);
            else
                virBufferAddLit(&buf, " />\n");
343
            virBufferAsprintf(&buf, "<vendor id='0x%04x'",
344 345 346 347 348 349
                                  data->pci_dev.vendor);
            if (data->pci_dev.vendor_name)
                virBufferEscapeString(&buf, ">%s</vendor>\n",
                                      data->pci_dev.vendor_name);
            else
                virBufferAddLit(&buf, " />\n");
350
            if (data->pci_dev.flags & VIR_NODE_DEV_CAP_FLAG_PCI_PHYSICAL_FUNCTION) {
351 352
                virBufferAddLit(&buf, "<capability type='phys_function'>\n");
                virBufferAdjustIndent(&buf, 2);
353
                virBufferAsprintf(&buf,
354
                                  "<address domain='0x%.4x' bus='0x%.2x' "
355 356 357 358 359
                                  "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);
360 361
                virBufferAdjustIndent(&buf, -2);
                virBufferAddLit(&buf, "</capability>\n");
362 363
            }
            if (data->pci_dev.flags & VIR_NODE_DEV_CAP_FLAG_PCI_VIRTUAL_FUNCTION) {
364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383
                virBufferAddLit(&buf, "<capability type='virt_functions'");
                if (data->pci_dev.max_virtual_functions)
                    virBufferAsprintf(&buf, " maxCount='%u'",
                                      data->pci_dev.max_virtual_functions);
                if (data->pci_dev.num_virtual_functions == 0) {
                    virBufferAddLit(&buf, "/>\n");
                } else {
                    virBufferAddLit(&buf, ">\n");
                    virBufferAdjustIndent(&buf, 2);
                    for (i = 0; i < data->pci_dev.num_virtual_functions; i++) {
                        virBufferAsprintf(&buf,
                                          "<address domain='0x%.4x' bus='0x%.2x' "
                                          "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);
                    }
                    virBufferAdjustIndent(&buf, -2);
                    virBufferAddLit(&buf, "</capability>\n");
384 385
                }
            }
386
            if (data->pci_dev.nIommuGroupDevices) {
387
                virBufferAsprintf(&buf, "<iommuGroup number='%d'>\n",
388
                                  data->pci_dev.iommuGroupNumber);
389
                virBufferAdjustIndent(&buf, 2);
390 391
                for (i = 0; i < data->pci_dev.nIommuGroupDevices; i++) {
                    virBufferAsprintf(&buf,
392
                                      "<address domain='0x%.4x' bus='0x%.2x' "
393 394 395 396 397 398
                                      "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);
                }
399 400
                virBufferAdjustIndent(&buf, -2);
                virBufferAddLit(&buf, "</iommuGroup>\n");
401
            }
402 403 404
            if (data->pci_dev.numa_node >= 0)
                virBufferAsprintf(&buf, "<numa node='%d'/>\n",
                                  data->pci_dev.numa_node);
405 406 407 408 409 410

            if (data->pci_dev.hdrType) {
                virBufferAsprintf(&buf, "<capability type='%s'/>\n",
                                  virPCIHeaderTypeToString(data->pci_dev.hdrType));
            }

411 412
            if (data->pci_dev.flags & VIR_NODE_DEV_CAP_FLAG_PCIE)
                virPCIEDeviceInfoFormat(&buf, data->pci_dev.pci_express);
413 414
            break;
        case VIR_NODE_DEV_CAP_USB_DEV:
415 416
            virBufferAsprintf(&buf, "<bus>%d</bus>\n", data->usb_dev.bus);
            virBufferAsprintf(&buf, "<device>%d</device>\n",
417
                              data->usb_dev.device);
418
            virBufferAsprintf(&buf, "<product id='0x%04x'",
419 420 421 422 423 424
                                  data->usb_dev.product);
            if (data->usb_dev.product_name)
                virBufferEscapeString(&buf, ">%s</product>\n",
                                      data->usb_dev.product_name);
            else
                virBufferAddLit(&buf, " />\n");
425
            virBufferAsprintf(&buf, "<vendor id='0x%04x'",
426 427 428 429 430 431 432 433
                                  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:
434
            virBufferAsprintf(&buf, "<number>%d</number>\n",
435
                              data->usb_if.number);
436
            virBufferAsprintf(&buf, "<class>%d</class>\n",
437
                              data->usb_if._class);
438
            virBufferAsprintf(&buf, "<subclass>%d</subclass>\n",
439
                              data->usb_if.subclass);
440
            virBufferAsprintf(&buf, "<protocol>%d</protocol>\n",
441 442
                              data->usb_if.protocol);
            if (data->usb_if.description)
443
                virBufferEscapeString(&buf,
444
                                  "<description>%s</description>\n",
445 446 447
                                  data->usb_if.description);
            break;
        case VIR_NODE_DEV_CAP_NET:
448
            virBufferEscapeString(&buf, "<interface>%s</interface>\n",
449
                              data->net.ifname);
450
            if (data->net.address)
451
                virBufferEscapeString(&buf, "<address>%s</address>\n",
452
                                  data->net.address);
453
            virInterfaceLinkFormat(&buf, &data->net.lnk);
454 455
            if (data->net.features) {
                for (i = 0; i < VIR_NET_DEV_FEAT_LAST; i++) {
J
Ján Tomko 已提交
456
                    if (virBitmapIsBitSet(data->net.features, i)) {
457 458 459 460 461
                        virBufferAsprintf(&buf, "<feature name='%s'/>\n",
                                          virNetDevFeatureTypeToString(i));
                    }
                }
            }
462 463 464
            if (data->net.subtype != VIR_NODE_DEV_CAP_NET_LAST) {
                const char *subtyp =
                    virNodeDevNetCapTypeToString(data->net.subtype);
465
                virBufferEscapeString(&buf, "<capability type='%s'/>\n",
466
                                      subtyp);
467 468 469
            }
            break;
        case VIR_NODE_DEV_CAP_SCSI_HOST:
470
            virBufferAsprintf(&buf, "<host>%d</host>\n",
471
                              data->scsi_host.host);
J
John Ferlan 已提交
472 473 474
            if (data->scsi_host.unique_id != -1)
                virBufferAsprintf(&buf, "<unique_id>%d</unique_id>\n",
                                  data->scsi_host.unique_id);
475
            if (data->scsi_host.flags & VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST) {
476 477 478
                virBufferAddLit(&buf, "<capability type='fc_host'>\n");
                virBufferAdjustIndent(&buf, 2);
                virBufferEscapeString(&buf, "<wwnn>%s</wwnn>\n",
479
                                      data->scsi_host.wwnn);
480
                virBufferEscapeString(&buf, "<wwpn>%s</wwpn>\n",
481
                                      data->scsi_host.wwpn);
482
                virBufferEscapeString(&buf, "<fabric_wwn>%s</fabric_wwn>\n",
O
Osier Yang 已提交
483
                                      data->scsi_host.fabric_wwn);
484 485
                virBufferAdjustIndent(&buf, -2);
                virBufferAddLit(&buf, "</capability>\n");
486 487
            }
            if (data->scsi_host.flags & VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS) {
488 489 490
                virBufferAddLit(&buf, "<capability type='vport_ops'>\n");
                virBufferAdjustIndent(&buf, 2);
                virBufferAsprintf(&buf, "<max_vports>%d</max_vports>\n",
491
                                  data->scsi_host.max_vports);
492
                virBufferAsprintf(&buf, "<vports>%d</vports>\n",
493
                                  data->scsi_host.vports);
494 495
                virBufferAdjustIndent(&buf, -2);
                virBufferAddLit(&buf, "</capability>\n");
496 497
            }

498
            break;
D
David Allan 已提交
499 500

        case VIR_NODE_DEV_CAP_SCSI_TARGET:
501
            virBufferEscapeString(&buf, "<target>%s</target>\n",
502
                                  data->scsi_target.name);
D
David Allan 已提交
503 504
            break;

505
        case VIR_NODE_DEV_CAP_SCSI:
506 507 508
            virBufferAsprintf(&buf, "<host>%d</host>\n", data->scsi.host);
            virBufferAsprintf(&buf, "<bus>%d</bus>\n", data->scsi.bus);
            virBufferAsprintf(&buf, "<target>%d</target>\n",
509
                              data->scsi.target);
510
            virBufferAsprintf(&buf, "<lun>%d</lun>\n", data->scsi.lun);
511
            if (data->scsi.type)
512
                virBufferEscapeString(&buf, "<type>%s</type>\n",
513
                                      data->scsi.type);
514 515
            break;
        case VIR_NODE_DEV_CAP_STORAGE:
516 517
            virBufferEscapeString(&buf, "<block>%s</block>\n",
                                  data->storage.block);
518
            if (data->storage.bus)
519 520
                virBufferEscapeString(&buf, "<bus>%s</bus>\n",
                                      data->storage.bus);
521
            if (data->storage.drive_type)
522 523
                virBufferEscapeString(&buf, "<drive_type>%s</drive_type>\n",
                                      data->storage.drive_type);
524
            if (data->storage.model)
525 526
                virBufferEscapeString(&buf, "<model>%s</model>\n",
                                      data->storage.model);
527
            if (data->storage.vendor)
528 529
                virBufferEscapeString(&buf, "<vendor>%s</vendor>\n",
                                      data->storage.vendor);
530
            if (data->storage.serial)
531 532
                virBufferEscapeString(&buf, "<serial>%s</serial>\n",
                                      data->storage.serial);
533 534 535
            if (data->storage.flags & VIR_NODE_DEV_CAP_STORAGE_REMOVABLE) {
                int avl = data->storage.flags &
                    VIR_NODE_DEV_CAP_STORAGE_REMOVABLE_MEDIA_AVAILABLE;
536 537 538
                virBufferAddLit(&buf, "<capability type='removable'>\n");
                virBufferAdjustIndent(&buf, 2);
                virBufferAsprintf(&buf, "<media_available>%d"
539
                                  "</media_available>\n", avl ? 1 : 0);
540
                virBufferAsprintf(&buf, "<media_size>%llu</media_size>\n",
541
                                  data->storage.removable_media_size);
542 543
                if (data->storage.media_label)
                    virBufferEscapeString(&buf,
544 545
                                          "<media_label>%s</media_label>\n",
                                          data->storage.media_label);
546
                if (data->storage.logical_block_size > 0)
547
                    virBufferAsprintf(&buf, "<logical_block_size>%llu"
548 549 550
                                      "</logical_block_size>\n",
                                      data->storage.logical_block_size);
                if (data->storage.num_blocks > 0)
551
                    virBufferAsprintf(&buf,
552
                                      "<num_blocks>%llu</num_blocks>\n",
553
                                      data->storage.num_blocks);
554 555
                virBufferAdjustIndent(&buf, -2);
                virBufferAddLit(&buf, "</capability>\n");
556
            } else {
557
                virBufferAsprintf(&buf, "<size>%llu</size>\n",
558
                                  data->storage.size);
559
                if (data->storage.logical_block_size > 0)
560
                    virBufferAsprintf(&buf, "<logical_block_size>%llu"
561 562 563
                                      "</logical_block_size>\n",
                                      data->storage.logical_block_size);
                if (data->storage.num_blocks > 0)
564
                    virBufferAsprintf(&buf, "<num_blocks>%llu</num_blocks>\n",
565
                                      data->storage.num_blocks);
566 567
            }
            if (data->storage.flags & VIR_NODE_DEV_CAP_STORAGE_HOTPLUGGABLE)
568
                virBufferAddLit(&buf, "<capability type='hotpluggable' />\n");
569
            break;
570
        case VIR_NODE_DEV_CAP_SCSI_GENERIC:
571
            virBufferEscapeString(&buf, "<char>%s</char>\n",
572 573
                                  data->sg.path);
            break;
574 575
        case VIR_NODE_DEV_CAP_FC_HOST:
        case VIR_NODE_DEV_CAP_VPORTS:
576 577 578 579
        case VIR_NODE_DEV_CAP_LAST:
            break;
        }

580 581
        virBufferAdjustIndent(&buf, -2);
        virBufferAddLit(&buf, "</capability>\n");
582 583
    }

584
    virBufferAdjustIndent(&buf, -2);
585 586
    virBufferAddLit(&buf, "</device>\n");

587 588
    if (virBufferCheckError(&buf) < 0)
        return NULL;
589 590 591 592

    return virBufferContentAndReset(&buf);
}

593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627
/**
 * 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;
}

628
static int
629
virNodeDevCapsDefParseULong(const char *xpath,
630 631 632 633 634 635 636 637 638
                            xmlXPathContextPtr ctxt,
                            unsigned *value,
                            virNodeDeviceDefPtr def,
                            const char *missing_error_fmt,
                            const char *invalid_error_fmt)
{
    int ret;
    unsigned long val;

639
    ret = virXPathULong(xpath, ctxt, &val);
640
    if (ret < 0) {
641 642 643
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       ret == -1 ? missing_error_fmt : invalid_error_fmt,
                       def->name);
644 645 646 647 648 649 650 651
        return -1;
    }

    *value = val;
    return 0;
}

static int
652
virNodeDevCapsDefParseULongLong(const char *xpath,
653 654 655 656 657 658 659 660 661
                                xmlXPathContextPtr ctxt,
                                unsigned long long *value,
                                virNodeDeviceDefPtr def,
                                const char *missing_error_fmt,
                                const char *invalid_error_fmt)
{
    int ret;
    unsigned long long val;

662
    ret = virXPathULongLong(xpath, ctxt, &val);
663
    if (ret < 0) {
664 665 666
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       ret == -1 ? missing_error_fmt : invalid_error_fmt,
                       def->name);
667 668 669 670 671 672 673 674
        return -1;
    }

    *value = val;
    return 0;
}

static int
675
virNodeDevCapStorageParseXML(xmlXPathContextPtr ctxt,
676 677
                             virNodeDeviceDefPtr def,
                             xmlNodePtr node,
678
                             virNodeDevCapDataPtr data)
679 680
{
    xmlNodePtr orignode, *nodes = NULL;
681 682
    size_t i;
    int n, ret = -1;
683 684 685 686 687
    unsigned long long val;

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

688
    data->storage.block = virXPathString("string(./block[1])", ctxt);
689
    if (!data->storage.block) {
690 691 692
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("no block device path supplied for '%s'"),
                       def->name);
693 694 695
        goto out;
    }

696 697 698 699 700
    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);
701

702
    if ((n = virXPathNodeSet("./capability", ctxt, &nodes)) < 0)
703 704
        goto out;

705
    for (i = 0; i < n; i++) {
706 707 708
        char *type = virXMLPropString(nodes[i], "type");

        if (!type) {
709 710 711
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("missing storage capability type for '%s'"),
                           def->name);
712 713 714
            goto out;
        }

715
        if (STREQ(type, "hotpluggable")) {
716
            data->storage.flags |= VIR_NODE_DEV_CAP_STORAGE_HOTPLUGGABLE;
717
        } else if (STREQ(type, "removable")) {
718 719 720 721 722 723 724
            xmlNodePtr orignode2;

            data->storage.flags |= VIR_NODE_DEV_CAP_STORAGE_REMOVABLE;

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

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

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

730
            val = 0;
731
            if (virNodeDevCapsDefParseULongLong("number(./media_size[1])", ctxt, &val, def,
732 733 734 735 736 737 738 739 740 741
                                                _("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 {
742 743 744
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown storage capability type '%s' for '%s'"),
                           type, def->name);
745 746 747 748 749 750 751 752 753
            VIR_FREE(type);
            goto out;
        }

        VIR_FREE(type);
    }

    if (!(data->storage.flags & VIR_NODE_DEV_CAP_STORAGE_REMOVABLE)) {
        val = 0;
754
        if (virNodeDevCapsDefParseULongLong("number(./size[1])", ctxt, &val, def,
755 756 757 758 759 760 761
                                            _("no size supplied for '%s'"),
                                            _("invalid size supplied for '%s'")) < 0)
            goto out;
        data->storage.size = val;
    }

    ret = 0;
762
 out:
763 764 765 766 767 768
    VIR_FREE(nodes);
    ctxt->node = orignode;
    return ret;
}

static int
769
virNodeDevCapSCSIParseXML(xmlXPathContextPtr ctxt,
770 771
                          virNodeDeviceDefPtr def,
                          xmlNodePtr node,
772
                          virNodeDevCapDataPtr data)
773 774 775 776 777 778 779
{
    xmlNodePtr orignode;
    int ret = -1;

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

780
    if (virNodeDevCapsDefParseULong("number(./host[1])", ctxt,
781 782 783 784 785
                                    &data->scsi.host, def,
                                    _("no SCSI host ID supplied for '%s'"),
                                    _("invalid SCSI host ID supplied for '%s'")) < 0)
        goto out;

786
    if (virNodeDevCapsDefParseULong("number(./bus[1])", ctxt,
787 788 789 790 791
                                    &data->scsi.bus, def,
                                    _("no SCSI bus ID supplied for '%s'"),
                                    _("invalid SCSI bus ID supplied for '%s'")) < 0)
        goto out;

792
    if (virNodeDevCapsDefParseULong("number(./target[1])", ctxt,
793 794 795 796 797
                                    &data->scsi.target, def,
                                    _("no SCSI target ID supplied for '%s'"),
                                    _("invalid SCSI target ID supplied for '%s'")) < 0)
        goto out;

798
    if (virNodeDevCapsDefParseULong("number(./lun[1])", ctxt,
799 800 801 802 803
                                    &data->scsi.lun, def,
                                    _("no SCSI LUN ID supplied for '%s'"),
                                    _("invalid SCSI LUN ID supplied for '%s'")) < 0)
        goto out;

804
    data->scsi.type = virXPathString("string(./type[1])", ctxt);
805 806

    ret = 0;
807
 out:
808 809 810 811
    ctxt->node = orignode;
    return ret;
}

D
David Allan 已提交
812 813

static int
814
virNodeDevCapSCSITargetParseXML(xmlXPathContextPtr ctxt,
D
David Allan 已提交
815 816
                                virNodeDeviceDefPtr def,
                                xmlNodePtr node,
817
                                virNodeDevCapDataPtr data)
D
David Allan 已提交
818 819 820 821 822 823 824
{
    xmlNodePtr orignode;
    int ret = -1;

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

825
    data->scsi_target.name = virXPathString("string(./target[1])", ctxt);
D
David Allan 已提交
826
    if (!data->scsi_target.name) {
827 828 829
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("no target name supplied for '%s'"),
                       def->name);
D
David Allan 已提交
830 831 832 833 834
        goto out;
    }

    ret = 0;

835
 out:
D
David Allan 已提交
836 837 838 839 840
    ctxt->node = orignode;
    return ret;
}


841
static int
842
virNodeDevCapSCSIHostParseXML(xmlXPathContextPtr ctxt,
843 844
                              virNodeDeviceDefPtr def,
                              xmlNodePtr node,
845
                              virNodeDevCapDataPtr data,
846 847
                              int create,
                              const char *virt_type)
848
{
849
    xmlNodePtr orignode, *nodes = NULL;
850 851
    int ret = -1, n = 0;
    size_t i;
852
    char *type = NULL;
853 854 855 856

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

J
John Ferlan 已提交
857 858 859 860 861 862 863 864 865 866 867 868 869 870
    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;
        }
871 872
    }

873
    if ((n = virXPathNodeSet("./capability", ctxt, &nodes)) < 0)
874
        goto out;
875

876
    for (i = 0; i < n; i++) {
877 878 879
        type = virXMLPropString(nodes[i], "type");

        if (!type) {
880 881 882
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("missing SCSI host capability type for '%s'"),
                           def->name);
883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898
            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];

899
            if (virNodeDevCapsDefParseString("string(./wwnn[1])",
900
                                             ctxt,
901 902
                                             &data->scsi_host.wwnn) < 0) {
                if (virRandomGenerateWWN(&data->scsi_host.wwnn, virt_type) < 0) {
903 904 905 906
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("no WWNN supplied for '%s', and "
                                     "auto-generation failed"),
                                   def->name);
907 908
                    goto out;
                }
909 910
            }

911
            if (virNodeDevCapsDefParseString("string(./wwpn[1])",
912
                                             ctxt,
913 914
                                             &data->scsi_host.wwpn) < 0) {
                if (virRandomGenerateWWN(&data->scsi_host.wwpn, virt_type) < 0) {
915 916 917 918
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("no WWPN supplied for '%s', and "
                                     "auto-generation failed"),
                                   def->name);
919 920
                    goto out;
                }
921 922 923 924 925
            }

            ctxt->node = orignode2;

        } else {
926 927 928
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown SCSI host capability type '%s' for '%s'"),
                           type, def->name);
929 930 931 932 933
            goto out;
        }

        VIR_FREE(type);
    }
934 935

    ret = 0;
936

937
 out:
938
    VIR_FREE(type);
939
    ctxt->node = orignode;
940
    VIR_FREE(nodes);
941 942 943
    return ret;
}

944

945
static int
946
virNodeDevCapNetParseXML(xmlXPathContextPtr ctxt,
947 948
                         virNodeDeviceDefPtr def,
                         xmlNodePtr node,
949
                         virNodeDevCapDataPtr data)
950
{
951
    xmlNodePtr orignode, lnk;
952 953
    size_t i = -1;
    int ret = -1, n = -1;
954
    char *tmp = NULL;
955
    xmlNodePtr *nodes = NULL;
956 957 958 959

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

960
    data->net.ifname = virXPathString("string(./interface[1])", ctxt);
961
    if (!data->net.ifname) {
962 963 964
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("no network interface supplied for '%s'"),
                       def->name);
965 966 967
        goto out;
    }

968
    data->net.address = virXPathString("string(./address[1])", ctxt);
969

970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992
    if ((n = virXPathNodeSet("./feature", ctxt, &nodes)) < 0)
        goto out;

    if (n > 0) {
        if (!(data->net.features = virBitmapNew(VIR_NET_DEV_FEAT_LAST)))
            goto out;
    }

    for (i = 0; i < n; i++) {
        int val;
        if (!(tmp = virXMLPropString(nodes[i], "name"))) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("missing network device feature name"));
            goto out;
        }

        if ((val = virNetDevFeatureTypeFromString(tmp)) < 0) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("unknown network device feature '%s'"),
                           tmp);
            goto out;
        }
        ignore_value(virBitmapSetBit(data->net.features, val));
993
        VIR_FREE(tmp);
994 995
    }

996 997
    data->net.subtype = VIR_NODE_DEV_CAP_NET_LAST;

998
    tmp = virXPathString("string(./capability/@type)", ctxt);
999 1000 1001 1002
    if (tmp) {
        int val = virNodeDevNetCapTypeFromString(tmp);
        VIR_FREE(tmp);
        if (val < 0) {
1003
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1004 1005
                           _("invalid network type supplied for '%s'"),
                           def->name);
1006 1007 1008 1009 1010
            goto out;
        }
        data->net.subtype = val;
    }

1011 1012 1013 1014
    lnk = virXPathNode("./link", ctxt);
    if (lnk && virInterfaceLinkParseXML(lnk, &data->net.lnk) < 0)
        goto out;

1015
    ret = 0;
1016
 out:
1017
    ctxt->node = orignode;
1018 1019
    VIR_FREE(nodes);
    VIR_FREE(tmp);
1020 1021 1022 1023
    return ret;
}

static int
1024
virNodeDevCapUSBInterfaceParseXML(xmlXPathContextPtr ctxt,
1025 1026
                                  virNodeDeviceDefPtr def,
                                  xmlNodePtr node,
1027
                                  virNodeDevCapDataPtr data)
1028 1029 1030 1031 1032 1033 1034
{
    xmlNodePtr orignode;
    int ret = -1;

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

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

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

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

1053
    if (virNodeDevCapsDefParseULong("number(./protocol[1])", ctxt,
1054 1055 1056 1057 1058
                                    &data->usb_if.protocol, def,
                                    _("no USB interface protocol supplied for '%s'"),
                                    _("invalid USB interface protocol supplied for '%s'")) < 0)
        goto out;

1059
    data->usb_if.description = virXPathString("string(./description[1])", ctxt);
1060 1061

    ret = 0;
1062
 out:
1063 1064 1065 1066 1067
    ctxt->node = orignode;
    return ret;
}

static int
1068
virNodeDevCapsDefParseHexId(const char *xpath,
1069 1070 1071 1072 1073 1074 1075 1076 1077
                            xmlXPathContextPtr ctxt,
                            unsigned *value,
                            virNodeDeviceDefPtr def,
                            const char *missing_error_fmt,
                            const char *invalid_error_fmt)
{
    int ret;
    unsigned long val;

1078
    ret = virXPathULongHex(xpath, ctxt, &val);
1079
    if (ret < 0) {
1080 1081 1082
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       ret == -1 ? missing_error_fmt : invalid_error_fmt,
                       def->name);
1083 1084 1085 1086 1087 1088 1089 1090
        return -1;
    }

    *value = val;
    return 0;
}

static int
1091
virNodeDevCapUSBDevParseXML(xmlXPathContextPtr ctxt,
1092 1093
                            virNodeDeviceDefPtr def,
                            xmlNodePtr node,
1094
                            virNodeDevCapDataPtr data)
1095 1096 1097 1098 1099 1100 1101
{
    xmlNodePtr orignode;
    int ret = -1;

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

1102
    if (virNodeDevCapsDefParseULong("number(./bus[1])", ctxt,
1103 1104 1105 1106 1107
                                    &data->usb_dev.bus, def,
                                    _("no USB bus number supplied for '%s'"),
                                    _("invalid USB bus number supplied for '%s'")) < 0)
        goto out;

1108
    if (virNodeDevCapsDefParseULong("number(./device[1])", ctxt,
1109 1110 1111 1112 1113
                                    &data->usb_dev.device, def,
                                    _("no USB device number supplied for '%s'"),
                                    _("invalid USB device number supplied for '%s'")) < 0)
        goto out;

1114
    if (virNodeDevCapsDefParseHexId("string(./vendor[1]/@id)", ctxt,
1115 1116 1117 1118 1119
                                    &data->usb_dev.vendor, def,
                                    _("no USB vendor ID supplied for '%s'"),
                                    _("invalid USB vendor ID supplied for '%s'")) < 0)
        goto out;

1120
    if (virNodeDevCapsDefParseHexId("string(./product[1]/@id)", ctxt,
1121 1122 1123 1124 1125
                                    &data->usb_dev.product, def,
                                    _("no USB product ID supplied for '%s'"),
                                    _("invalid USB product ID supplied for '%s'")) < 0)
        goto out;

1126 1127
    data->usb_dev.vendor_name  = virXPathString("string(./vendor[1])", ctxt);
    data->usb_dev.product_name = virXPathString("string(./product[1])", ctxt);
1128 1129

    ret = 0;
1130
 out:
1131 1132 1133 1134
    ctxt->node = orignode;
    return ret;
}

1135
static int
1136
virNodeDevCapPCIDevIommuGroupParseXML(xmlXPathContextPtr ctxt,
1137
                                      xmlNodePtr iommuGroupNode,
1138
                                      virNodeDevCapDataPtr data)
1139 1140 1141 1142
{
    xmlNodePtr origNode = ctxt->node;
    xmlNodePtr *addrNodes = NULL;
    char *numberStr = NULL;
1143 1144
    int nAddrNodes, ret = -1;
    size_t i;
1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165
    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;

1166
    for (i = 0; i < nAddrNodes; i++) {
1167
        virDevicePCIAddress addr = { 0, 0, 0, 0, 0 };
1168
        if (virDevicePCIAddressParseXML(addrNodes[i], &addr) < 0)
1169
            goto cleanup;
1170
        if (VIR_ALLOC(pciAddr) < 0)
1171 1172 1173 1174 1175 1176 1177
            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,
1178
                               pciAddr) < 0)
1179 1180 1181 1182
            goto cleanup;
    }

    ret = 0;
1183
 cleanup:
1184
    ctxt->node = origNode;
1185
    VIR_FREE(numberStr);
1186 1187 1188 1189 1190
    VIR_FREE(addrNodes);
    VIR_FREE(pciAddr);
    return ret;
}

1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270
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;
}

1271

1272
static int
1273
virNodeDevCapPCIDevParseXML(xmlXPathContextPtr ctxt,
1274 1275
                            virNodeDeviceDefPtr def,
                            xmlNodePtr node,
1276
                            virNodeDevCapDataPtr data)
1277
{
1278
    xmlNodePtr orignode, iommuGroupNode, pciExpress;
1279
    int ret = -1;
1280
    virPCIEDeviceInfoPtr pci_express = NULL;
1281
    char *tmp = NULL;
1282 1283 1284 1285

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

1286
    if (virNodeDevCapsDefParseULong("number(./domain[1])", ctxt,
1287 1288 1289 1290 1291
                                    &data->pci_dev.domain, def,
                                    _("no PCI domain ID supplied for '%s'"),
                                    _("invalid PCI domain ID supplied for '%s'")) < 0)
        goto out;

1292
    if (virNodeDevCapsDefParseULong("number(./bus[1])", ctxt,
1293 1294 1295 1296 1297
                                    &data->pci_dev.bus, def,
                                    _("no PCI bus ID supplied for '%s'"),
                                    _("invalid PCI bus ID supplied for '%s'")) < 0)
        goto out;

1298
    if (virNodeDevCapsDefParseULong("number(./slot[1])", ctxt,
1299 1300 1301 1302 1303
                                    &data->pci_dev.slot, def,
                                    _("no PCI slot ID supplied for '%s'"),
                                    _("invalid PCI slot ID supplied for '%s'")) < 0)
        goto out;

1304
    if (virNodeDevCapsDefParseULong("number(./function[1])", ctxt,
1305 1306 1307 1308 1309
                                    &data->pci_dev.function, def,
                                    _("no PCI function ID supplied for '%s'"),
                                    _("invalid PCI function ID supplied for '%s'")) < 0)
        goto out;

1310
    if (virNodeDevCapsDefParseHexId("string(./vendor[1]/@id)", ctxt,
1311 1312 1313 1314 1315
                                    &data->pci_dev.vendor, def,
                                    _("no PCI vendor ID supplied for '%s'"),
                                    _("invalid PCI vendor ID supplied for '%s'")) < 0)
        goto out;

1316
    if (virNodeDevCapsDefParseHexId("string(./product[1]/@id)", ctxt,
1317 1318 1319 1320 1321
                                    &data->pci_dev.product, def,
                                    _("no PCI product ID supplied for '%s'"),
                                    _("invalid PCI product ID supplied for '%s'")) < 0)
        goto out;

1322 1323
    data->pci_dev.vendor_name  = virXPathString("string(./vendor[1])", ctxt);
    data->pci_dev.product_name = virXPathString("string(./product[1])", ctxt);
1324

1325
    if ((iommuGroupNode = virXPathNode("./iommuGroup[1]", ctxt))) {
1326
        if (virNodeDevCapPCIDevIommuGroupParseXML(ctxt, iommuGroupNode,
1327 1328 1329 1330
                                                  data) < 0) {
            goto out;
        }
    }
1331

1332 1333
    /* The default value is -1 since zero is valid NUMA node number */
    data->pci_dev.numa_node = -1;
1334 1335 1336 1337 1338
    if (virNodeDevCapsDefParseIntOptional("number(./numa[1]/@node)", ctxt,
                                          &data->pci_dev.numa_node, def,
                                          _("invalid NUMA node ID supplied for '%s'")) < 0)
        goto out;

1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350
    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;
    }

1351
    ret = 0;
1352
 out:
1353
    VIR_FREE(tmp);
1354
    virPCIEDeviceInfoFree(pci_express);
1355 1356 1357 1358 1359
    ctxt->node = orignode;
    return ret;
}

static int
1360
virNodeDevCapSystemParseXML(xmlXPathContextPtr ctxt,
1361 1362
                            virNodeDeviceDefPtr def,
                            xmlNodePtr node,
1363
                            virNodeDevCapDataPtr data)
1364 1365 1366 1367 1368 1369 1370 1371
{
    xmlNodePtr orignode;
    int ret = -1;
    char *tmp;

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

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

1374 1375 1376
    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);
1377

1378
    tmp = virXPathString("string(./hardware/uuid[1])", ctxt);
1379
    if (!tmp) {
1380 1381
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("no system UUID supplied for '%s'"), def->name);
1382 1383 1384 1385
        goto out;
    }

    if (virUUIDParse(tmp, data->system.hardware.uuid) < 0) {
1386 1387
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("malformed uuid element for '%s'"), def->name);
1388 1389 1390 1391 1392
        VIR_FREE(tmp);
        goto out;
    }
    VIR_FREE(tmp);

1393 1394 1395
    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);
1396 1397

    ret = 0;
1398
 out:
1399 1400 1401 1402 1403
    ctxt->node = orignode;
    return ret;
}

static virNodeDevCapsDefPtr
1404
virNodeDevCapsDefParseXML(xmlXPathContextPtr ctxt,
1405
                          virNodeDeviceDefPtr def,
1406
                          xmlNodePtr node,
1407 1408
                          int create,
                          const char *virt_type)
1409 1410 1411
{
    virNodeDevCapsDefPtr caps;
    char *tmp;
1412
    int val, ret = -1;
1413

1414
    if (VIR_ALLOC(caps) < 0)
1415 1416 1417 1418
        return NULL;

    tmp = virXMLPropString(node, "type");
    if (!tmp) {
1419 1420
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing capability type"));
1421 1422 1423 1424
        goto error;
    }

    if ((val = virNodeDevCapTypeFromString(tmp)) < 0) {
1425
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1426
                       _("unknown capability type '%s'"), tmp);
1427 1428 1429
        VIR_FREE(tmp);
        goto error;
    }
1430
    caps->data.type = val;
1431 1432
    VIR_FREE(tmp);

1433
    switch (caps->data.type) {
1434
    case VIR_NODE_DEV_CAP_SYSTEM:
1435
        ret = virNodeDevCapSystemParseXML(ctxt, def, node, &caps->data);
1436 1437
        break;
    case VIR_NODE_DEV_CAP_PCI_DEV:
1438
        ret = virNodeDevCapPCIDevParseXML(ctxt, def, node, &caps->data);
1439 1440
        break;
    case VIR_NODE_DEV_CAP_USB_DEV:
1441
        ret = virNodeDevCapUSBDevParseXML(ctxt, def, node, &caps->data);
1442 1443
        break;
    case VIR_NODE_DEV_CAP_USB_INTERFACE:
1444
        ret = virNodeDevCapUSBInterfaceParseXML(ctxt, def, node, &caps->data);
1445 1446
        break;
    case VIR_NODE_DEV_CAP_NET:
1447
        ret = virNodeDevCapNetParseXML(ctxt, def, node, &caps->data);
1448 1449
        break;
    case VIR_NODE_DEV_CAP_SCSI_HOST:
1450
        ret = virNodeDevCapSCSIHostParseXML(ctxt, def, node,
1451 1452 1453
                                            &caps->data,
                                            create,
                                            virt_type);
1454
        break;
D
David Allan 已提交
1455
    case VIR_NODE_DEV_CAP_SCSI_TARGET:
1456
        ret = virNodeDevCapSCSITargetParseXML(ctxt, def, node, &caps->data);
D
David Allan 已提交
1457
        break;
1458
    case VIR_NODE_DEV_CAP_SCSI:
1459
        ret = virNodeDevCapSCSIParseXML(ctxt, def, node, &caps->data);
1460 1461
        break;
    case VIR_NODE_DEV_CAP_STORAGE:
1462
        ret = virNodeDevCapStorageParseXML(ctxt, def, node, &caps->data);
1463
        break;
1464 1465 1466 1467
    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:
1468 1469
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown capability type '%d' for '%s'"),
1470
                       caps->data.type, def->name);
1471 1472 1473 1474 1475 1476 1477 1478
        ret = -1;
        break;
    }

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

1479
 error:
1480 1481 1482 1483 1484
    virNodeDevCapsDefFree(caps);
    return NULL;
}

static virNodeDeviceDefPtr
1485 1486 1487
virNodeDeviceDefParseXML(xmlXPathContextPtr ctxt,
                         int create,
                         const char *virt_type)
1488 1489 1490 1491
{
    virNodeDeviceDefPtr def;
    virNodeDevCapsDefPtr *next_cap;
    xmlNodePtr *nodes;
1492 1493
    int n;
    size_t i;
1494

1495
    if (VIR_ALLOC(def) < 0)
1496 1497 1498
        return NULL;

    /* Extract device name */
1499
    if (create == EXISTING_DEVICE) {
1500
        def->name = virXPathString("string(./name[1])", ctxt);
1501 1502

        if (!def->name) {
1503
            virReportError(VIR_ERR_NO_NAME, NULL);
1504 1505
            goto error;
        }
1506
    } else {
1507
        if (VIR_STRDUP(def->name, "new device") < 0)
1508
            goto error;
1509 1510 1511
    }

    /* Extract device parent, if any */
1512
    def->parent = virXPathString("string(./parent[1])", ctxt);
1513 1514 1515

    /* Parse device capabilities */
    nodes = NULL;
1516
    if ((n = virXPathNodeSet("./capability", ctxt, &nodes)) < 0)
1517 1518 1519
        goto error;

    if (n == 0) {
1520 1521 1522
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("no device capabilities for '%s'"),
                       def->name);
1523 1524 1525 1526
        goto error;
    }

    next_cap = &def->caps;
1527
    for (i = 0; i < n; i++) {
1528 1529 1530 1531
        *next_cap = virNodeDevCapsDefParseXML(ctxt, def,
                                              nodes[i],
                                              create,
                                              virt_type);
1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547
        if (!*next_cap) {
            VIR_FREE(nodes);
            goto error;
        }

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

    return def;

 error:
    virNodeDeviceDefFree(def);
    return NULL;
}

1548
virNodeDeviceDefPtr
1549
virNodeDeviceDefParseNode(xmlDocPtr xml,
1550
                          xmlNodePtr root,
1551 1552
                          int create,
                          const char *virt_type)
1553 1554 1555 1556 1557
{
    xmlXPathContextPtr ctxt = NULL;
    virNodeDeviceDefPtr def = NULL;

    if (!xmlStrEqual(root->name, BAD_CAST "device")) {
1558 1559 1560 1561
        virReportError(VIR_ERR_XML_ERROR,
                       _("unexpected root element <%s> "
                         "expecting <device>"),
                       root->name);
1562 1563 1564 1565 1566
        return NULL;
    }

    ctxt = xmlXPathNewContext(xml);
    if (ctxt == NULL) {
1567
        virReportOOMError();
1568 1569 1570 1571
        goto cleanup;
    }

    ctxt->node = root;
1572
    def = virNodeDeviceDefParseXML(ctxt, create, virt_type);
1573

1574
 cleanup:
1575 1576 1577 1578
    xmlXPathFreeContext(ctxt);
    return def;
}

1579
static virNodeDeviceDefPtr
1580
virNodeDeviceDefParse(const char *str,
1581
                      const char *filename,
1582 1583
                      int create,
                      const char *virt_type)
1584
{
J
Jiri Denemark 已提交
1585
    xmlDocPtr xml;
1586 1587
    virNodeDeviceDefPtr def = NULL;

1588
    if ((xml = virXMLParse(filename, str, _("(node_device_definition)")))) {
1589 1590
        def = virNodeDeviceDefParseNode(xml, xmlDocGetRootElement(xml),
                                        create, virt_type);
J
Jiri Denemark 已提交
1591
        xmlFreeDoc(xml);
1592 1593
    }

1594 1595 1596
    return def;
}

1597
virNodeDeviceDefPtr
1598
virNodeDeviceDefParseString(const char *str,
1599 1600
                            int create,
                            const char *virt_type)
1601
{
1602
    return virNodeDeviceDefParse(str, NULL, create, virt_type);
1603 1604 1605
}

virNodeDeviceDefPtr
1606
virNodeDeviceDefParseFile(const char *filename,
1607 1608
                          int create,
                          const char *virt_type)
1609
{
1610
    return virNodeDeviceDefParse(NULL, filename, create, virt_type);
1611 1612
}

1613 1614 1615 1616
/*
 * Return fc_host dev's WWNN and WWPN
 */
int
1617
virNodeDeviceGetWWNs(virNodeDeviceDefPtr def,
1618 1619 1620 1621
                     char **wwnn,
                     char **wwpn)
{
    virNodeDevCapsDefPtr cap = NULL;
1622
    int ret = -1;
1623 1624 1625

    cap = def->caps;
    while (cap != NULL) {
1626
        if (cap->data.type == VIR_NODE_DEV_CAP_SCSI_HOST &&
1627
            cap->data.scsi_host.flags & VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST) {
1628 1629 1630 1631 1632 1633
            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;
            }
1634 1635 1636 1637 1638 1639 1640
            break;
        }

        cap = cap->next;
    }

    if (cap == NULL) {
1641 1642
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Device is not a fibre channel HBA"));
1643
        goto cleanup;
1644 1645
    }

1646
    ret = 0;
1647
 cleanup:
1648 1649 1650 1651 1652 1653 1654
    return ret;
}

/*
 * Return the NPIV dev's parent device name
 */
int
E
Eric Blake 已提交
1655
virNodeDeviceGetParentHost(virNodeDeviceObjListPtr devs,
1656 1657 1658 1659 1660 1661 1662 1663 1664 1665
                           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) {
1666 1667 1668
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not find parent device for '%s'"),
                       dev_name);
1669 1670 1671 1672 1673 1674
        ret = -1;
        goto out;
    }

    cap = parent->def->caps;
    while (cap != NULL) {
1675
        if (cap->data.type == VIR_NODE_DEV_CAP_SCSI_HOST &&
1676 1677 1678 1679 1680 1681 1682 1683 1684 1685
            (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) {
1686 1687 1688 1689
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Parent device %s is not capable "
                         "of vport operations"),
                       parent->def->name);
1690 1691 1692 1693 1694
        ret = -1;
    }

    virNodeDeviceObjUnlock(parent);

1695
 out:
1696 1697
    return ret;
}
1698

1699 1700
void virNodeDevCapsDefFree(virNodeDevCapsDefPtr caps)
{
1701
    size_t i = 0;
1702
    virNodeDevCapDataPtr data = &caps->data;
1703

1704
    switch (caps->data.type) {
1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716
    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);
1717
        VIR_FREE(data->pci_dev.physical_function);
1718
        for (i = 0; i < data->pci_dev.num_virtual_functions; i++)
1719
            VIR_FREE(data->pci_dev.virtual_functions[i]);
1720
        VIR_FREE(data->pci_dev.virtual_functions);
1721
        for (i = 0; i < data->pci_dev.nIommuGroupDevices; i++)
1722
            VIR_FREE(data->pci_dev.iommuGroupDevices[i]);
1723
        VIR_FREE(data->pci_dev.iommuGroupDevices);
1724
        virPCIEDeviceInfoFree(data->pci_dev.pci_express);
1725 1726 1727 1728 1729 1730 1731 1732 1733
        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:
1734
        VIR_FREE(data->net.ifname);
1735
        VIR_FREE(data->net.address);
1736 1737
        virBitmapFree(data->net.features);
        data->net.features = NULL;
1738 1739
        break;
    case VIR_NODE_DEV_CAP_SCSI_HOST:
1740 1741
        VIR_FREE(data->scsi_host.wwnn);
        VIR_FREE(data->scsi_host.wwpn);
O
Osier Yang 已提交
1742
        VIR_FREE(data->scsi_host.fabric_wwn);
1743
        break;
D
David Allan 已提交
1744 1745 1746
    case VIR_NODE_DEV_CAP_SCSI_TARGET:
        VIR_FREE(data->scsi_target.name);
        break;
1747 1748 1749 1750
    case VIR_NODE_DEV_CAP_SCSI:
        VIR_FREE(data->scsi.type);
        break;
    case VIR_NODE_DEV_CAP_STORAGE:
1751
        VIR_FREE(data->storage.block);
1752 1753 1754 1755
        VIR_FREE(data->storage.bus);
        VIR_FREE(data->storage.drive_type);
        VIR_FREE(data->storage.model);
        VIR_FREE(data->storage.vendor);
1756
        VIR_FREE(data->storage.serial);
1757
        VIR_FREE(data->storage.media_label);
1758
        break;
1759 1760 1761
    case VIR_NODE_DEV_CAP_SCSI_GENERIC:
        VIR_FREE(data->sg.path);
        break;
1762 1763
    case VIR_NODE_DEV_CAP_FC_HOST:
    case VIR_NODE_DEV_CAP_VPORTS:
1764 1765 1766 1767 1768 1769 1770 1771
    case VIR_NODE_DEV_CAP_LAST:
        /* This case is here to shutup the compiler */
        break;
    }

    VIR_FREE(caps);
}

D
Daniel P. Berrange 已提交
1772

1773 1774
void virNodeDeviceObjLock(virNodeDeviceObjPtr obj)
{
1775
    virMutexLock(&obj->lock);
1776 1777 1778 1779
}

void virNodeDeviceObjUnlock(virNodeDeviceObjPtr obj)
{
1780
    virMutexUnlock(&obj->lock);
D
Daniel P. Berrange 已提交
1781
}
1782 1783 1784 1785 1786 1787 1788 1789

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

    for (cap = devobj->def->caps; cap; cap = cap->next) {
1790
        if (type == cap->data.type)
1791
            return true;
1792

1793
        if (cap->data.type == VIR_NODE_DEV_CAP_SCSI_HOST) {
1794
            if (type == VIR_NODE_DEV_CAP_FC_HOST &&
1795 1796 1797 1798
                (cap->data.scsi_host.flags &
                 VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST))
                return true;

1799
            if (type == VIR_NODE_DEV_CAP_VPORTS &&
1800 1801 1802 1803
                (cap->data.scsi_host.flags &
                 VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS))
                return true;
        }
1804 1805 1806 1807 1808
    }

    return false;
}

1809 1810
#define MATCH(FLAG) ((flags & (VIR_CONNECT_LIST_NODE_DEVICES_CAP_ ## FLAG)) && \
                     virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_ ## FLAG))
1811 1812 1813 1814 1815
static bool
virNodeDeviceMatch(virNodeDeviceObjPtr devobj,
                   unsigned int flags)
{
    /* filter by cap type */
1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828
    if (flags & VIR_CONNECT_LIST_NODE_DEVICES_FILTERS_CAP) {
        if (!(MATCH(SYSTEM)        ||
              MATCH(PCI_DEV)       ||
              MATCH(USB_DEV)       ||
              MATCH(USB_INTERFACE) ||
              MATCH(NET)           ||
              MATCH(SCSI_HOST)     ||
              MATCH(SCSI_TARGET)   ||
              MATCH(SCSI)          ||
              MATCH(STORAGE)       ||
              MATCH(FC_HOST)       ||
              MATCH(VPORTS)        ||
              MATCH(SCSI_GENERIC)))
1829 1830 1831 1832 1833 1834 1835 1836
            return false;
    }

    return true;
}
#undef MATCH

int
1837 1838 1839 1840 1841
virNodeDeviceObjListExport(virConnectPtr conn,
                           virNodeDeviceObjList devobjs,
                           virNodeDevicePtr **devices,
                           virNodeDeviceObjListFilter filter,
                           unsigned int flags)
1842 1843 1844 1845 1846
{
    virNodeDevicePtr *tmp_devices = NULL;
    virNodeDevicePtr device = NULL;
    int ndevices = 0;
    int ret = -1;
1847
    size_t i;
1848

1849 1850
    if (devices && VIR_ALLOC_N(tmp_devices, devobjs.count + 1) < 0)
        goto cleanup;
1851 1852 1853 1854

    for (i = 0; i < devobjs.count; i++) {
        virNodeDeviceObjPtr devobj = devobjs.objs[i];
        virNodeDeviceObjLock(devobj);
1855 1856
        if ((!filter || filter(conn, devobj->def)) &&
            virNodeDeviceMatch(devobj, flags)) {
1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878
            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;

1879
 cleanup:
1880
    if (tmp_devices) {
1881 1882
        for (i = 0; i < ndevices; i++)
            virObjectUnref(tmp_devices[i]);
1883 1884 1885 1886 1887
    }

    VIR_FREE(tmp_devices);
    return ret;
}