node_device_conf.c 66.2 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,
210
                            virNodeDeviceObjPtr *dev)
211
{
212
    size_t i;
213

214
    virNodeDeviceObjUnlock(*dev);
215

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

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

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

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

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

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

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
        virPCIDeviceAddress addr = {0};
1168
        if (virPCIDeviceAddressParseXML(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 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305
static int
virNodeDevPCICapabilityParseXML(xmlXPathContextPtr ctxt,
                                xmlNodePtr node,
                                virNodeDevCapDataPtr data)
{
    char *maxFuncsStr = virXMLPropString(node, "maxCount");
    char *type = virXMLPropString(node, "type");
    xmlNodePtr *addresses = NULL;
    xmlNodePtr orignode = ctxt->node;
    int ret = -1;
    size_t i = 0;

    ctxt->node = node;

    if (!type) {
        virReportError(VIR_ERR_XML_ERROR, "%s", _("Missing capability type"));
        goto out;
    }

    if (STREQ(type, "phys_function")) {
        xmlNodePtr address = virXPathNode("./address[1]", ctxt);

        if (VIR_ALLOC(data->pci_dev.physical_function) < 0)
            goto out;

        if (!address) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("Missing address in 'phys_function' capability"));
            goto out;
        }

        if (virPCIDeviceAddressParseXML(address,
                                        data->pci_dev.physical_function) < 0)
            goto out;
1306 1307

        data->pci_dev.flags |= VIR_NODE_DEV_CAP_FLAG_PCI_PHYSICAL_FUNCTION;
1308
    } else if (STREQ(type, "virt_functions")) {
1309 1310 1311 1312
        int naddresses;

        if ((naddresses = virXPathNodeSet("./address", ctxt, &addresses)) < 0)
            goto out;
1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359

        if (maxFuncsStr &&
            virStrToLong_uip(maxFuncsStr, NULL, 10,
                             &data->pci_dev.max_virtual_functions) < 0) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("Malformed 'maxCount' parameter"));
            goto out;
        }

        if (VIR_ALLOC_N(data->pci_dev.virtual_functions, naddresses) < 0)
            goto out;

        for (i = 0; i < naddresses; i++) {
            virPCIDeviceAddressPtr addr = NULL;

            if (VIR_ALLOC(addr) < 0)
                goto out;

            if (virPCIDeviceAddressParseXML(addresses[i], addr) < 0) {
                VIR_FREE(addr);
                goto out;
            }

            if (VIR_APPEND_ELEMENT(data->pci_dev.virtual_functions,
                                   data->pci_dev.num_virtual_functions,
                                   addr) < 0)
                goto out;
        }

        data->pci_dev.flags |= VIR_NODE_DEV_CAP_FLAG_PCI_VIRTUAL_FUNCTION;
    } else {
        int hdrType = virPCIHeaderTypeFromString(type);

        if (hdrType > 0 && !data->pci_dev.hdrType)
            data->pci_dev.hdrType = hdrType;
    }

    ret = 0;
 out:
    VIR_FREE(addresses);
    VIR_FREE(maxFuncsStr);
    VIR_FREE(type);
    ctxt->node = orignode;
    return ret;
}


1360
static int
1361
virNodeDevCapPCIDevParseXML(xmlXPathContextPtr ctxt,
1362 1363
                            virNodeDeviceDefPtr def,
                            xmlNodePtr node,
1364
                            virNodeDevCapDataPtr data)
1365
{
1366
    xmlNodePtr orignode, iommuGroupNode, pciExpress;
1367 1368
    xmlNodePtr *nodes = NULL;
    int n = 0;
1369
    int ret = -1;
1370
    virPCIEDeviceInfoPtr pci_express = NULL;
1371
    char *tmp = NULL;
1372
    size_t i = 0;
1373 1374 1375 1376

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

1377
    if (virNodeDevCapsDefParseULong("number(./domain[1])", ctxt,
1378 1379 1380 1381 1382
                                    &data->pci_dev.domain, def,
                                    _("no PCI domain ID supplied for '%s'"),
                                    _("invalid PCI domain ID supplied for '%s'")) < 0)
        goto out;

1383
    if (virNodeDevCapsDefParseULong("number(./bus[1])", ctxt,
1384 1385 1386 1387 1388
                                    &data->pci_dev.bus, def,
                                    _("no PCI bus ID supplied for '%s'"),
                                    _("invalid PCI bus ID supplied for '%s'")) < 0)
        goto out;

1389
    if (virNodeDevCapsDefParseULong("number(./slot[1])", ctxt,
1390 1391 1392 1393 1394
                                    &data->pci_dev.slot, def,
                                    _("no PCI slot ID supplied for '%s'"),
                                    _("invalid PCI slot ID supplied for '%s'")) < 0)
        goto out;

1395
    if (virNodeDevCapsDefParseULong("number(./function[1])", ctxt,
1396 1397 1398 1399 1400
                                    &data->pci_dev.function, def,
                                    _("no PCI function ID supplied for '%s'"),
                                    _("invalid PCI function ID supplied for '%s'")) < 0)
        goto out;

1401
    if (virNodeDevCapsDefParseHexId("string(./vendor[1]/@id)", ctxt,
1402 1403 1404 1405 1406
                                    &data->pci_dev.vendor, def,
                                    _("no PCI vendor ID supplied for '%s'"),
                                    _("invalid PCI vendor ID supplied for '%s'")) < 0)
        goto out;

1407
    if (virNodeDevCapsDefParseHexId("string(./product[1]/@id)", ctxt,
1408 1409 1410 1411 1412
                                    &data->pci_dev.product, def,
                                    _("no PCI product ID supplied for '%s'"),
                                    _("invalid PCI product ID supplied for '%s'")) < 0)
        goto out;

1413 1414
    data->pci_dev.vendor_name  = virXPathString("string(./vendor[1])", ctxt);
    data->pci_dev.product_name = virXPathString("string(./product[1])", ctxt);
1415

1416 1417 1418 1419 1420 1421 1422 1423 1424
    if ((n = virXPathNodeSet("./capability", ctxt, &nodes)) < 0)
        goto out;

    for (i = 0; i < n; i++) {
        if (virNodeDevPCICapabilityParseXML(ctxt, nodes[i], data) < 0)
            goto out;
    }
    VIR_FREE(nodes);

1425
    if ((iommuGroupNode = virXPathNode("./iommuGroup[1]", ctxt))) {
1426
        if (virNodeDevCapPCIDevIommuGroupParseXML(ctxt, iommuGroupNode,
1427 1428 1429 1430
                                                  data) < 0) {
            goto out;
        }
    }
1431

1432 1433
    /* The default value is -1 since zero is valid NUMA node number */
    data->pci_dev.numa_node = -1;
1434 1435 1436 1437 1438
    if (virNodeDevCapsDefParseIntOptional("number(./numa[1]/@node)", ctxt,
                                          &data->pci_dev.numa_node, def,
                                          _("invalid NUMA node ID supplied for '%s'")) < 0)
        goto out;

1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450
    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;
    }

1451
    ret = 0;
1452
 out:
1453
    VIR_FREE(nodes);
1454
    VIR_FREE(tmp);
1455
    virPCIEDeviceInfoFree(pci_express);
1456 1457 1458 1459 1460
    ctxt->node = orignode;
    return ret;
}

static int
1461
virNodeDevCapSystemParseXML(xmlXPathContextPtr ctxt,
1462 1463
                            virNodeDeviceDefPtr def,
                            xmlNodePtr node,
1464
                            virNodeDevCapDataPtr data)
1465 1466 1467 1468 1469 1470 1471 1472
{
    xmlNodePtr orignode;
    int ret = -1;
    char *tmp;

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

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

1475 1476 1477
    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);
1478

1479
    tmp = virXPathString("string(./hardware/uuid[1])", ctxt);
1480
    if (!tmp) {
1481 1482
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("no system UUID supplied for '%s'"), def->name);
1483 1484 1485 1486
        goto out;
    }

    if (virUUIDParse(tmp, data->system.hardware.uuid) < 0) {
1487 1488
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("malformed uuid element for '%s'"), def->name);
1489 1490 1491 1492 1493
        VIR_FREE(tmp);
        goto out;
    }
    VIR_FREE(tmp);

1494 1495 1496
    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);
1497 1498

    ret = 0;
1499
 out:
1500 1501 1502 1503 1504
    ctxt->node = orignode;
    return ret;
}

static virNodeDevCapsDefPtr
1505
virNodeDevCapsDefParseXML(xmlXPathContextPtr ctxt,
1506
                          virNodeDeviceDefPtr def,
1507
                          xmlNodePtr node,
1508 1509
                          int create,
                          const char *virt_type)
1510 1511 1512
{
    virNodeDevCapsDefPtr caps;
    char *tmp;
1513
    int val, ret = -1;
1514

1515
    if (VIR_ALLOC(caps) < 0)
1516 1517 1518 1519
        return NULL;

    tmp = virXMLPropString(node, "type");
    if (!tmp) {
1520 1521
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing capability type"));
1522 1523 1524 1525
        goto error;
    }

    if ((val = virNodeDevCapTypeFromString(tmp)) < 0) {
1526
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1527
                       _("unknown capability type '%s'"), tmp);
1528 1529 1530
        VIR_FREE(tmp);
        goto error;
    }
1531
    caps->data.type = val;
1532 1533
    VIR_FREE(tmp);

1534
    switch (caps->data.type) {
1535
    case VIR_NODE_DEV_CAP_SYSTEM:
1536
        ret = virNodeDevCapSystemParseXML(ctxt, def, node, &caps->data);
1537 1538
        break;
    case VIR_NODE_DEV_CAP_PCI_DEV:
1539
        ret = virNodeDevCapPCIDevParseXML(ctxt, def, node, &caps->data);
1540 1541
        break;
    case VIR_NODE_DEV_CAP_USB_DEV:
1542
        ret = virNodeDevCapUSBDevParseXML(ctxt, def, node, &caps->data);
1543 1544
        break;
    case VIR_NODE_DEV_CAP_USB_INTERFACE:
1545
        ret = virNodeDevCapUSBInterfaceParseXML(ctxt, def, node, &caps->data);
1546 1547
        break;
    case VIR_NODE_DEV_CAP_NET:
1548
        ret = virNodeDevCapNetParseXML(ctxt, def, node, &caps->data);
1549 1550
        break;
    case VIR_NODE_DEV_CAP_SCSI_HOST:
1551
        ret = virNodeDevCapSCSIHostParseXML(ctxt, def, node,
1552 1553 1554
                                            &caps->data,
                                            create,
                                            virt_type);
1555
        break;
D
David Allan 已提交
1556
    case VIR_NODE_DEV_CAP_SCSI_TARGET:
1557
        ret = virNodeDevCapSCSITargetParseXML(ctxt, def, node, &caps->data);
D
David Allan 已提交
1558
        break;
1559
    case VIR_NODE_DEV_CAP_SCSI:
1560
        ret = virNodeDevCapSCSIParseXML(ctxt, def, node, &caps->data);
1561 1562
        break;
    case VIR_NODE_DEV_CAP_STORAGE:
1563
        ret = virNodeDevCapStorageParseXML(ctxt, def, node, &caps->data);
1564
        break;
1565 1566 1567 1568
    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:
1569 1570
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown capability type '%d' for '%s'"),
1571
                       caps->data.type, def->name);
1572 1573 1574 1575 1576 1577 1578 1579
        ret = -1;
        break;
    }

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

1580
 error:
1581 1582 1583 1584 1585
    virNodeDevCapsDefFree(caps);
    return NULL;
}

static virNodeDeviceDefPtr
1586 1587 1588
virNodeDeviceDefParseXML(xmlXPathContextPtr ctxt,
                         int create,
                         const char *virt_type)
1589 1590 1591 1592
{
    virNodeDeviceDefPtr def;
    virNodeDevCapsDefPtr *next_cap;
    xmlNodePtr *nodes;
1593 1594
    int n;
    size_t i;
1595

1596
    if (VIR_ALLOC(def) < 0)
1597 1598 1599
        return NULL;

    /* Extract device name */
1600
    if (create == EXISTING_DEVICE) {
1601
        def->name = virXPathString("string(./name[1])", ctxt);
1602 1603

        if (!def->name) {
1604
            virReportError(VIR_ERR_NO_NAME, NULL);
1605 1606
            goto error;
        }
1607
    } else {
1608
        if (VIR_STRDUP(def->name, "new device") < 0)
1609
            goto error;
1610 1611 1612
    }

    /* Extract device parent, if any */
1613
    def->parent = virXPathString("string(./parent[1])", ctxt);
1614 1615 1616

    /* Parse device capabilities */
    nodes = NULL;
1617
    if ((n = virXPathNodeSet("./capability", ctxt, &nodes)) < 0)
1618 1619 1620
        goto error;

    if (n == 0) {
1621 1622 1623
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("no device capabilities for '%s'"),
                       def->name);
1624 1625 1626 1627
        goto error;
    }

    next_cap = &def->caps;
1628
    for (i = 0; i < n; i++) {
1629 1630 1631 1632
        *next_cap = virNodeDevCapsDefParseXML(ctxt, def,
                                              nodes[i],
                                              create,
                                              virt_type);
1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648
        if (!*next_cap) {
            VIR_FREE(nodes);
            goto error;
        }

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

    return def;

 error:
    virNodeDeviceDefFree(def);
    return NULL;
}

1649
virNodeDeviceDefPtr
1650
virNodeDeviceDefParseNode(xmlDocPtr xml,
1651
                          xmlNodePtr root,
1652 1653
                          int create,
                          const char *virt_type)
1654 1655 1656 1657 1658
{
    xmlXPathContextPtr ctxt = NULL;
    virNodeDeviceDefPtr def = NULL;

    if (!xmlStrEqual(root->name, BAD_CAST "device")) {
1659 1660 1661 1662
        virReportError(VIR_ERR_XML_ERROR,
                       _("unexpected root element <%s> "
                         "expecting <device>"),
                       root->name);
1663 1664 1665 1666 1667
        return NULL;
    }

    ctxt = xmlXPathNewContext(xml);
    if (ctxt == NULL) {
1668
        virReportOOMError();
1669 1670 1671 1672
        goto cleanup;
    }

    ctxt->node = root;
1673
    def = virNodeDeviceDefParseXML(ctxt, create, virt_type);
1674

1675
 cleanup:
1676 1677 1678 1679
    xmlXPathFreeContext(ctxt);
    return def;
}

1680
static virNodeDeviceDefPtr
1681
virNodeDeviceDefParse(const char *str,
1682
                      const char *filename,
1683 1684
                      int create,
                      const char *virt_type)
1685
{
J
Jiri Denemark 已提交
1686
    xmlDocPtr xml;
1687 1688
    virNodeDeviceDefPtr def = NULL;

1689
    if ((xml = virXMLParse(filename, str, _("(node_device_definition)")))) {
1690 1691
        def = virNodeDeviceDefParseNode(xml, xmlDocGetRootElement(xml),
                                        create, virt_type);
J
Jiri Denemark 已提交
1692
        xmlFreeDoc(xml);
1693 1694
    }

1695 1696 1697
    return def;
}

1698
virNodeDeviceDefPtr
1699
virNodeDeviceDefParseString(const char *str,
1700 1701
                            int create,
                            const char *virt_type)
1702
{
1703
    return virNodeDeviceDefParse(str, NULL, create, virt_type);
1704 1705 1706
}

virNodeDeviceDefPtr
1707
virNodeDeviceDefParseFile(const char *filename,
1708 1709
                          int create,
                          const char *virt_type)
1710
{
1711
    return virNodeDeviceDefParse(NULL, filename, create, virt_type);
1712 1713
}

1714 1715 1716 1717
/*
 * Return fc_host dev's WWNN and WWPN
 */
int
1718
virNodeDeviceGetWWNs(virNodeDeviceDefPtr def,
1719 1720 1721 1722
                     char **wwnn,
                     char **wwpn)
{
    virNodeDevCapsDefPtr cap = NULL;
1723
    int ret = -1;
1724 1725 1726

    cap = def->caps;
    while (cap != NULL) {
1727
        if (cap->data.type == VIR_NODE_DEV_CAP_SCSI_HOST &&
1728
            cap->data.scsi_host.flags & VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST) {
1729 1730 1731 1732 1733 1734
            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;
            }
1735 1736 1737 1738 1739 1740 1741
            break;
        }

        cap = cap->next;
    }

    if (cap == NULL) {
1742 1743
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Device is not a fibre channel HBA"));
1744
        goto cleanup;
1745 1746
    }

1747
    ret = 0;
1748
 cleanup:
1749 1750 1751 1752 1753 1754 1755
    return ret;
}

/*
 * Return the NPIV dev's parent device name
 */
int
E
Eric Blake 已提交
1756
virNodeDeviceGetParentHost(virNodeDeviceObjListPtr devs,
1757 1758 1759 1760 1761 1762 1763 1764 1765 1766
                           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) {
1767 1768 1769
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not find parent device for '%s'"),
                       dev_name);
1770 1771 1772 1773 1774 1775
        ret = -1;
        goto out;
    }

    cap = parent->def->caps;
    while (cap != NULL) {
1776
        if (cap->data.type == VIR_NODE_DEV_CAP_SCSI_HOST &&
1777 1778 1779 1780 1781 1782 1783 1784 1785 1786
            (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) {
1787 1788 1789 1790
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Parent device %s is not capable "
                         "of vport operations"),
                       parent->def->name);
1791 1792 1793 1794 1795
        ret = -1;
    }

    virNodeDeviceObjUnlock(parent);

1796
 out:
1797 1798
    return ret;
}
1799

1800 1801
void virNodeDevCapsDefFree(virNodeDevCapsDefPtr caps)
{
1802
    size_t i = 0;
1803
    virNodeDevCapDataPtr data = &caps->data;
1804

1805
    switch (caps->data.type) {
1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817
    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);
1818
        VIR_FREE(data->pci_dev.physical_function);
1819
        for (i = 0; i < data->pci_dev.num_virtual_functions; i++)
1820
            VIR_FREE(data->pci_dev.virtual_functions[i]);
1821
        VIR_FREE(data->pci_dev.virtual_functions);
1822
        for (i = 0; i < data->pci_dev.nIommuGroupDevices; i++)
1823
            VIR_FREE(data->pci_dev.iommuGroupDevices[i]);
1824
        VIR_FREE(data->pci_dev.iommuGroupDevices);
1825
        virPCIEDeviceInfoFree(data->pci_dev.pci_express);
1826 1827 1828 1829 1830 1831 1832 1833 1834
        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:
1835
        VIR_FREE(data->net.ifname);
1836
        VIR_FREE(data->net.address);
1837 1838
        virBitmapFree(data->net.features);
        data->net.features = NULL;
1839 1840
        break;
    case VIR_NODE_DEV_CAP_SCSI_HOST:
1841 1842
        VIR_FREE(data->scsi_host.wwnn);
        VIR_FREE(data->scsi_host.wwpn);
O
Osier Yang 已提交
1843
        VIR_FREE(data->scsi_host.fabric_wwn);
1844
        break;
D
David Allan 已提交
1845 1846 1847
    case VIR_NODE_DEV_CAP_SCSI_TARGET:
        VIR_FREE(data->scsi_target.name);
        break;
1848 1849 1850 1851
    case VIR_NODE_DEV_CAP_SCSI:
        VIR_FREE(data->scsi.type);
        break;
    case VIR_NODE_DEV_CAP_STORAGE:
1852
        VIR_FREE(data->storage.block);
1853 1854 1855 1856
        VIR_FREE(data->storage.bus);
        VIR_FREE(data->storage.drive_type);
        VIR_FREE(data->storage.model);
        VIR_FREE(data->storage.vendor);
1857
        VIR_FREE(data->storage.serial);
1858
        VIR_FREE(data->storage.media_label);
1859
        break;
1860 1861 1862
    case VIR_NODE_DEV_CAP_SCSI_GENERIC:
        VIR_FREE(data->sg.path);
        break;
1863 1864
    case VIR_NODE_DEV_CAP_FC_HOST:
    case VIR_NODE_DEV_CAP_VPORTS:
1865 1866 1867 1868 1869 1870 1871 1872
    case VIR_NODE_DEV_CAP_LAST:
        /* This case is here to shutup the compiler */
        break;
    }

    VIR_FREE(caps);
}

D
Daniel P. Berrange 已提交
1873

1874 1875
void virNodeDeviceObjLock(virNodeDeviceObjPtr obj)
{
1876
    virMutexLock(&obj->lock);
1877 1878 1879 1880
}

void virNodeDeviceObjUnlock(virNodeDeviceObjPtr obj)
{
1881
    virMutexUnlock(&obj->lock);
D
Daniel P. Berrange 已提交
1882
}
1883 1884 1885 1886 1887 1888 1889 1890

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

    for (cap = devobj->def->caps; cap; cap = cap->next) {
1891
        if (type == cap->data.type)
1892
            return true;
1893

1894
        if (cap->data.type == VIR_NODE_DEV_CAP_SCSI_HOST) {
1895
            if (type == VIR_NODE_DEV_CAP_FC_HOST &&
1896 1897 1898 1899
                (cap->data.scsi_host.flags &
                 VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST))
                return true;

1900
            if (type == VIR_NODE_DEV_CAP_VPORTS &&
1901 1902 1903 1904
                (cap->data.scsi_host.flags &
                 VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS))
                return true;
        }
1905 1906 1907 1908 1909
    }

    return false;
}

1910 1911
#define MATCH(FLAG) ((flags & (VIR_CONNECT_LIST_NODE_DEVICES_CAP_ ## FLAG)) && \
                     virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_ ## FLAG))
1912 1913 1914 1915 1916
static bool
virNodeDeviceMatch(virNodeDeviceObjPtr devobj,
                   unsigned int flags)
{
    /* filter by cap type */
1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929
    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)))
1930 1931 1932 1933 1934 1935 1936 1937
            return false;
    }

    return true;
}
#undef MATCH

int
1938 1939 1940 1941 1942
virNodeDeviceObjListExport(virConnectPtr conn,
                           virNodeDeviceObjList devobjs,
                           virNodeDevicePtr **devices,
                           virNodeDeviceObjListFilter filter,
                           unsigned int flags)
1943 1944 1945 1946 1947
{
    virNodeDevicePtr *tmp_devices = NULL;
    virNodeDevicePtr device = NULL;
    int ndevices = 0;
    int ret = -1;
1948
    size_t i;
1949

1950 1951
    if (devices && VIR_ALLOC_N(tmp_devices, devobjs.count + 1) < 0)
        goto cleanup;
1952 1953 1954 1955

    for (i = 0; i < devobjs.count; i++) {
        virNodeDeviceObjPtr devobj = devobjs.objs[i];
        virNodeDeviceObjLock(devobj);
1956 1957
        if ((!filter || filter(conn, devobj->def)) &&
            virNodeDeviceMatch(devobj, flags)) {
1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979
            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;

1980
 cleanup:
1981
    if (tmp_devices) {
1982 1983
        for (i = 0; i < ndevices; i++)
            virObjectUnref(tmp_devices[i]);
1984 1985 1986 1987 1988
    }

    VIR_FREE(tmp_devices);
    return ret;
}