node_device_conf.c 63.6 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(./name[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 ((tmp = virXPathString("string(./capability[1]/@type)", ctxt))) {
        int hdrType = virPCIHeaderTypeFromString(tmp);

        if (hdrType <= 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unknown PCI header type '%s'"), tmp);
            goto out;
        }

        data->pci_dev.hdrType = hdrType;
    }

1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362
    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;
    }

1363
    ret = 0;
1364
 out:
1365
    VIR_FREE(tmp);
1366
    virPCIEDeviceInfoFree(pci_express);
1367 1368 1369 1370 1371
    ctxt->node = orignode;
    return ret;
}

static int
1372
virNodeDevCapSystemParseXML(xmlXPathContextPtr ctxt,
1373 1374
                            virNodeDeviceDefPtr def,
                            xmlNodePtr node,
1375
                            virNodeDevCapDataPtr data)
1376 1377 1378 1379 1380 1381 1382 1383
{
    xmlNodePtr orignode;
    int ret = -1;
    char *tmp;

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

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

1386 1387 1388
    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);
1389

1390
    tmp = virXPathString("string(./hardware/uuid[1])", ctxt);
1391
    if (!tmp) {
1392 1393
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("no system UUID supplied for '%s'"), def->name);
1394 1395 1396 1397
        goto out;
    }

    if (virUUIDParse(tmp, data->system.hardware.uuid) < 0) {
1398 1399
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("malformed uuid element for '%s'"), def->name);
1400 1401 1402 1403 1404
        VIR_FREE(tmp);
        goto out;
    }
    VIR_FREE(tmp);

1405 1406 1407
    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);
1408 1409

    ret = 0;
1410
 out:
1411 1412 1413 1414 1415
    ctxt->node = orignode;
    return ret;
}

static virNodeDevCapsDefPtr
1416
virNodeDevCapsDefParseXML(xmlXPathContextPtr ctxt,
1417
                          virNodeDeviceDefPtr def,
1418
                          xmlNodePtr node,
1419 1420
                          int create,
                          const char *virt_type)
1421 1422 1423
{
    virNodeDevCapsDefPtr caps;
    char *tmp;
1424
    int val, ret = -1;
1425

1426
    if (VIR_ALLOC(caps) < 0)
1427 1428 1429 1430
        return NULL;

    tmp = virXMLPropString(node, "type");
    if (!tmp) {
1431 1432
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing capability type"));
1433 1434 1435 1436
        goto error;
    }

    if ((val = virNodeDevCapTypeFromString(tmp)) < 0) {
1437
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1438
                       _("unknown capability type '%s'"), tmp);
1439 1440 1441
        VIR_FREE(tmp);
        goto error;
    }
1442
    caps->data.type = val;
1443 1444
    VIR_FREE(tmp);

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

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

1491
 error:
1492 1493 1494 1495 1496
    virNodeDevCapsDefFree(caps);
    return NULL;
}

static virNodeDeviceDefPtr
1497 1498 1499
virNodeDeviceDefParseXML(xmlXPathContextPtr ctxt,
                         int create,
                         const char *virt_type)
1500 1501 1502 1503
{
    virNodeDeviceDefPtr def;
    virNodeDevCapsDefPtr *next_cap;
    xmlNodePtr *nodes;
1504 1505
    int n;
    size_t i;
1506

1507
    if (VIR_ALLOC(def) < 0)
1508 1509 1510
        return NULL;

    /* Extract device name */
1511
    if (create == EXISTING_DEVICE) {
1512
        def->name = virXPathString("string(./name[1])", ctxt);
1513 1514

        if (!def->name) {
1515
            virReportError(VIR_ERR_NO_NAME, NULL);
1516 1517
            goto error;
        }
1518
    } else {
1519
        if (VIR_STRDUP(def->name, "new device") < 0)
1520
            goto error;
1521 1522 1523
    }

    /* Extract device parent, if any */
1524
    def->parent = virXPathString("string(./parent[1])", ctxt);
1525 1526 1527

    /* Parse device capabilities */
    nodes = NULL;
1528
    if ((n = virXPathNodeSet("./capability", ctxt, &nodes)) < 0)
1529 1530 1531
        goto error;

    if (n == 0) {
1532 1533 1534
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("no device capabilities for '%s'"),
                       def->name);
1535 1536 1537 1538
        goto error;
    }

    next_cap = &def->caps;
1539
    for (i = 0; i < n; i++) {
1540 1541 1542 1543
        *next_cap = virNodeDevCapsDefParseXML(ctxt, def,
                                              nodes[i],
                                              create,
                                              virt_type);
1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559
        if (!*next_cap) {
            VIR_FREE(nodes);
            goto error;
        }

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

    return def;

 error:
    virNodeDeviceDefFree(def);
    return NULL;
}

1560
virNodeDeviceDefPtr
1561
virNodeDeviceDefParseNode(xmlDocPtr xml,
1562
                          xmlNodePtr root,
1563 1564
                          int create,
                          const char *virt_type)
1565 1566 1567 1568 1569
{
    xmlXPathContextPtr ctxt = NULL;
    virNodeDeviceDefPtr def = NULL;

    if (!xmlStrEqual(root->name, BAD_CAST "device")) {
1570 1571 1572 1573
        virReportError(VIR_ERR_XML_ERROR,
                       _("unexpected root element <%s> "
                         "expecting <device>"),
                       root->name);
1574 1575 1576 1577 1578
        return NULL;
    }

    ctxt = xmlXPathNewContext(xml);
    if (ctxt == NULL) {
1579
        virReportOOMError();
1580 1581 1582 1583
        goto cleanup;
    }

    ctxt->node = root;
1584
    def = virNodeDeviceDefParseXML(ctxt, create, virt_type);
1585

1586
 cleanup:
1587 1588 1589 1590
    xmlXPathFreeContext(ctxt);
    return def;
}

1591
static virNodeDeviceDefPtr
1592
virNodeDeviceDefParse(const char *str,
1593
                      const char *filename,
1594 1595
                      int create,
                      const char *virt_type)
1596
{
J
Jiri Denemark 已提交
1597
    xmlDocPtr xml;
1598 1599
    virNodeDeviceDefPtr def = NULL;

1600
    if ((xml = virXMLParse(filename, str, _("(node_device_definition)")))) {
1601 1602
        def = virNodeDeviceDefParseNode(xml, xmlDocGetRootElement(xml),
                                        create, virt_type);
J
Jiri Denemark 已提交
1603
        xmlFreeDoc(xml);
1604 1605
    }

1606 1607 1608
    return def;
}

1609
virNodeDeviceDefPtr
1610
virNodeDeviceDefParseString(const char *str,
1611 1612
                            int create,
                            const char *virt_type)
1613
{
1614
    return virNodeDeviceDefParse(str, NULL, create, virt_type);
1615 1616 1617
}

virNodeDeviceDefPtr
1618
virNodeDeviceDefParseFile(const char *filename,
1619 1620
                          int create,
                          const char *virt_type)
1621
{
1622
    return virNodeDeviceDefParse(NULL, filename, create, virt_type);
1623 1624
}

1625 1626 1627 1628
/*
 * Return fc_host dev's WWNN and WWPN
 */
int
1629
virNodeDeviceGetWWNs(virNodeDeviceDefPtr def,
1630 1631 1632 1633
                     char **wwnn,
                     char **wwpn)
{
    virNodeDevCapsDefPtr cap = NULL;
1634
    int ret = -1;
1635 1636 1637

    cap = def->caps;
    while (cap != NULL) {
1638
        if (cap->data.type == VIR_NODE_DEV_CAP_SCSI_HOST &&
1639
            cap->data.scsi_host.flags & VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST) {
1640 1641 1642 1643 1644 1645
            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;
            }
1646 1647 1648 1649 1650 1651 1652
            break;
        }

        cap = cap->next;
    }

    if (cap == NULL) {
1653 1654
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Device is not a fibre channel HBA"));
1655
        goto cleanup;
1656 1657
    }

1658
    ret = 0;
1659
 cleanup:
1660 1661 1662 1663 1664 1665 1666
    return ret;
}

/*
 * Return the NPIV dev's parent device name
 */
int
E
Eric Blake 已提交
1667
virNodeDeviceGetParentHost(virNodeDeviceObjListPtr devs,
1668 1669 1670 1671 1672 1673 1674 1675 1676 1677
                           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) {
1678 1679 1680
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not find parent device for '%s'"),
                       dev_name);
1681 1682 1683 1684 1685 1686
        ret = -1;
        goto out;
    }

    cap = parent->def->caps;
    while (cap != NULL) {
1687
        if (cap->data.type == VIR_NODE_DEV_CAP_SCSI_HOST &&
1688 1689 1690 1691 1692 1693 1694 1695 1696 1697
            (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) {
1698 1699 1700 1701
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Parent device %s is not capable "
                         "of vport operations"),
                       parent->def->name);
1702 1703 1704 1705 1706
        ret = -1;
    }

    virNodeDeviceObjUnlock(parent);

1707
 out:
1708 1709
    return ret;
}
1710

1711 1712
void virNodeDevCapsDefFree(virNodeDevCapsDefPtr caps)
{
1713
    size_t i = 0;
1714
    virNodeDevCapDataPtr data = &caps->data;
1715

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

    VIR_FREE(caps);
}

D
Daniel P. Berrange 已提交
1784

1785 1786
void virNodeDeviceObjLock(virNodeDeviceObjPtr obj)
{
1787
    virMutexLock(&obj->lock);
1788 1789 1790 1791
}

void virNodeDeviceObjUnlock(virNodeDeviceObjPtr obj)
{
1792
    virMutexUnlock(&obj->lock);
D
Daniel P. Berrange 已提交
1793
}
1794 1795 1796 1797 1798 1799 1800 1801

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

    for (cap = devobj->def->caps; cap; cap = cap->next) {
1802
        if (type == cap->data.type)
1803
            return true;
1804

1805
        if (cap->data.type == VIR_NODE_DEV_CAP_SCSI_HOST) {
1806
            if (type == VIR_NODE_DEV_CAP_FC_HOST &&
1807 1808 1809 1810
                (cap->data.scsi_host.flags &
                 VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST))
                return true;

1811
            if (type == VIR_NODE_DEV_CAP_VPORTS &&
1812 1813 1814 1815
                (cap->data.scsi_host.flags &
                 VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS))
                return true;
        }
1816 1817 1818 1819 1820
    }

    return false;
}

1821 1822
#define MATCH(FLAG) ((flags & (VIR_CONNECT_LIST_NODE_DEVICES_CAP_ ## FLAG)) && \
                     virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_ ## FLAG))
1823 1824 1825 1826 1827
static bool
virNodeDeviceMatch(virNodeDeviceObjPtr devobj,
                   unsigned int flags)
{
    /* filter by cap type */
1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840
    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)))
1841 1842 1843 1844 1845 1846 1847 1848
            return false;
    }

    return true;
}
#undef MATCH

int
1849 1850 1851 1852 1853
virNodeDeviceObjListExport(virConnectPtr conn,
                           virNodeDeviceObjList devobjs,
                           virNodeDevicePtr **devices,
                           virNodeDeviceObjListFilter filter,
                           unsigned int flags)
1854 1855 1856 1857 1858
{
    virNodeDevicePtr *tmp_devices = NULL;
    virNodeDevicePtr device = NULL;
    int ndevices = 0;
    int ret = -1;
1859
    size_t i;
1860

1861 1862
    if (devices && VIR_ALLOC_N(tmp_devices, devobjs.count + 1) < 0)
        goto cleanup;
1863 1864 1865 1866

    for (i = 0; i < devobjs.count; i++) {
        virNodeDeviceObjPtr devobj = devobjs.objs[i];
        virNodeDeviceObjLock(devobj);
1867 1868
        if ((!filter || filter(conn, devobj->def)) &&
            virNodeDeviceMatch(devobj, flags)) {
1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890
            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;

1891
 cleanup:
1892
    if (tmp_devices) {
1893 1894
        for (i = 0; i < ndevices; i++)
            virObjectUnref(tmp_devices[i]);
1895 1896 1897 1898 1899
    }

    VIR_FREE(tmp_devices);
    return ret;
}