node_device_conf.c 52.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 * node_device_conf.c: config handling for node devices
 *
 * 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
18
 * License along with this library.  If not, see
O
Osier Yang 已提交
19
 * <http://www.gnu.org/licenses/>.
20 21 22 23 24 25 26 27 28
 *
 * Author: David F. Lively <dlively@virtualiron.com>
 */

#include <config.h>

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

29
#include "virerror.h"
30
#include "datatypes.h"
31
#include "viralloc.h"
32 33

#include "node_device_conf.h"
34
#include "viralloc.h"
35
#include "virxml.h"
36
#include "virutil.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 54
              "storage",
              "fc_host",
              "vports")
55 56 57

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

60
static int
61
virNodeDevCapsDefParseString(const char *xpath,
62
                             xmlXPathContextPtr ctxt,
63
                             char **string)
64 65 66
{
    char *s;

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

    *string = s;
    return 0;
}

74 75 76 77 78 79 80 81 82 83
int virNodeDeviceHasCap(const virNodeDeviceObjPtr dev, const char *cap)
{
    virNodeDevCapsDefPtr caps = dev->def->caps;
    while (caps) {
        if (STREQ(cap, virNodeDevCapTypeToString(caps->type)))
            return 1;
        caps = caps->next;
    }
    return 0;
}
84

85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104

virNodeDeviceObjPtr
virNodeDeviceFindBySysfsPath(const virNodeDeviceObjListPtr devs,
                             const char *sysfs_path)
{
    unsigned int i;

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


105 106 107 108 109
virNodeDeviceObjPtr virNodeDeviceFindByName(const virNodeDeviceObjListPtr devs,
                                            const char *name)
{
    unsigned int i;

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

    return NULL;
}


void virNodeDeviceDefFree(virNodeDeviceDefPtr def)
{
    virNodeDevCapsDefPtr caps;

    if (!def)
        return;

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

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

153 154
    virMutexDestroy(&dev->lock);

155 156 157 158 159 160 161 162 163 164 165 166
    VIR_FREE(dev);
}

void virNodeDeviceObjListFree(virNodeDeviceObjListPtr devs)
{
    unsigned int i;
    for (i = 0 ; i < devs->count ; i++)
        virNodeDeviceObjFree(devs->objs[i]);
    VIR_FREE(devs->objs);
    devs->count = 0;
}

167
virNodeDeviceObjPtr virNodeDeviceAssignDef(virNodeDeviceObjListPtr devs,
168 169 170 171 172 173 174 175 176 177 178
                                           const virNodeDeviceDefPtr def)
{
    virNodeDeviceObjPtr device;

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

    if (VIR_ALLOC(device) < 0) {
179
        virReportOOMError();
180 181 182
        return NULL;
    }

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

    if (VIR_REALLOC_N(devs->objs, devs->count+1) < 0) {
        device->def = NULL;
194
        virNodeDeviceObjUnlock(device);
195
        virNodeDeviceObjFree(device);
196
        virReportOOMError();
197 198 199 200 201 202 203 204 205 206 207 208 209
        return NULL;
    }
    devs->objs[devs->count++] = device;

    return device;

}

void virNodeDeviceObjRemove(virNodeDeviceObjListPtr devs,
                            const virNodeDeviceObjPtr dev)
{
    unsigned int i;

210 211
    virNodeDeviceObjUnlock(dev);

212
    for (i = 0; i < devs->count; i++) {
213
        virNodeDeviceObjLock(dev);
214
        if (devs->objs[i] == dev) {
215
            virNodeDeviceObjUnlock(dev);
216 217 218 219 220 221 222 223 224 225 226 227 228
            virNodeDeviceObjFree(devs->objs[i]);

            if (i < (devs->count - 1))
                memmove(devs->objs + i, devs->objs + i + 1,
                        sizeof(*(devs->objs)) * (devs->count - (i + 1)));

            if (VIR_REALLOC_N(devs->objs, devs->count - 1) < 0) {
                ; /* Failure to reduce memory allocation isn't fatal */
            }
            devs->count--;

            break;
        }
229
        virNodeDeviceObjUnlock(dev);
230 231 232
    }
}

233
char *virNodeDeviceDefFormat(const virNodeDeviceDefPtr def)
234 235
{
    virBuffer buf = VIR_BUFFER_INITIALIZER;
236
    virNodeDevCapsDefPtr caps;
237
    unsigned int i = 0;
238 239 240

    virBufferAddLit(&buf, "<device>\n");
    virBufferEscapeString(&buf, "  <name>%s</name>\n", def->name);
241
    if (def->parent) {
242
        virBufferEscapeString(&buf, "  <parent>%s</parent>\n", def->parent);
243
    }
244 245 246 247 248
    if (def->driver) {
        virBufferAddLit(&buf, "  <driver>\n");
        virBufferEscapeString(&buf, "    <name>%s</name>\n", def->driver);
        virBufferAddLit(&buf, "  </driver>\n");
    }
249 250 251 252 253

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

254
        virBufferAsprintf(&buf, "  <capability type='%s'>\n",
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
                          virNodeDevCapTypeToString(caps->type));
        switch (caps->type) {
        case VIR_NODE_DEV_CAP_SYSTEM:
            if (data->system.product_name)
                virBufferEscapeString(&buf, "    <product>%s</product>\n",
                                      data->system.product_name);
            virBufferAddLit(&buf, "    <hardware>\n");
            if (data->system.hardware.vendor_name)
                virBufferEscapeString(&buf, "      <vendor>%s</vendor>\n",
                                      data->system.hardware.vendor_name);
            if (data->system.hardware.version)
                virBufferEscapeString(&buf, "      <version>%s</version>\n",
                                      data->system.hardware.version);
            if (data->system.hardware.serial)
                virBufferEscapeString(&buf, "      <serial>%s</serial>\n",
                                      data->system.hardware.serial);
            virUUIDFormat(data->system.hardware.uuid, uuidstr);
272
            virBufferAsprintf(&buf, "      <uuid>%s</uuid>\n", uuidstr);
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
            virBufferAddLit(&buf, "    </hardware>\n");
            virBufferAddLit(&buf, "    <firmware>\n");
            if (data->system.firmware.vendor_name)
                virBufferEscapeString(&buf, "      <vendor>%s</vendor>\n",
                                      data->system.firmware.vendor_name);
            if (data->system.firmware.version)
                virBufferEscapeString(&buf, "      <version>%s</version>\n",
                                      data->system.firmware.version);
            if (data->system.firmware.release_date)
                virBufferEscapeString(&buf,
                                      "      <release_date>%s</release_date>\n",
                                      data->system.firmware.release_date);
            virBufferAddLit(&buf, "    </firmware>\n");
            break;
        case VIR_NODE_DEV_CAP_PCI_DEV:
288
            virBufferAsprintf(&buf, "    <domain>%d</domain>\n",
289
                              data->pci_dev.domain);
290 291
            virBufferAsprintf(&buf, "    <bus>%d</bus>\n", data->pci_dev.bus);
            virBufferAsprintf(&buf, "    <slot>%d</slot>\n",
292
                              data->pci_dev.slot);
293
            virBufferAsprintf(&buf, "    <function>%d</function>\n",
294
                              data->pci_dev.function);
295
            virBufferAsprintf(&buf, "    <product id='0x%04x'",
296 297 298 299 300 301
                                  data->pci_dev.product);
            if (data->pci_dev.product_name)
                virBufferEscapeString(&buf, ">%s</product>\n",
                                      data->pci_dev.product_name);
            else
                virBufferAddLit(&buf, " />\n");
302
            virBufferAsprintf(&buf, "    <vendor id='0x%04x'",
303 304 305 306 307 308
                                  data->pci_dev.vendor);
            if (data->pci_dev.vendor_name)
                virBufferEscapeString(&buf, ">%s</vendor>\n",
                                      data->pci_dev.vendor_name);
            else
                virBufferAddLit(&buf, " />\n");
309 310
            if (data->pci_dev.flags & VIR_NODE_DEV_CAP_FLAG_PCI_PHYSICAL_FUNCTION) {
                virBufferAddLit(&buf, "    <capability type='phys_function'>\n");
311
                virBufferAsprintf(&buf,
312 313 314 315 316 317 318 319 320 321 322
                                  "      <address domain='0x%.4x' bus='0x%.2x' "
                                  "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);
                virBufferAddLit(&buf, "    </capability>\n");
            }
            if (data->pci_dev.flags & VIR_NODE_DEV_CAP_FLAG_PCI_VIRTUAL_FUNCTION) {
                virBufferAddLit(&buf, "    <capability type='virt_functions'>\n");
                for (i = 0 ; i < data->pci_dev.num_virtual_functions ; i++) {
323
                    virBufferAsprintf(&buf,
324 325 326 327 328 329 330 331 332
                                      "      <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);
                }
                virBufferAddLit(&buf, "    </capability>\n");
            }
333 334
            break;
        case VIR_NODE_DEV_CAP_USB_DEV:
335 336
            virBufferAsprintf(&buf, "    <bus>%d</bus>\n", data->usb_dev.bus);
            virBufferAsprintf(&buf, "    <device>%d</device>\n",
337
                              data->usb_dev.device);
338
            virBufferAsprintf(&buf, "    <product id='0x%04x'",
339 340 341 342 343 344
                                  data->usb_dev.product);
            if (data->usb_dev.product_name)
                virBufferEscapeString(&buf, ">%s</product>\n",
                                      data->usb_dev.product_name);
            else
                virBufferAddLit(&buf, " />\n");
345
            virBufferAsprintf(&buf, "    <vendor id='0x%04x'",
346 347 348 349 350 351 352 353
                                  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:
354
            virBufferAsprintf(&buf, "    <number>%d</number>\n",
355
                              data->usb_if.number);
356
            virBufferAsprintf(&buf, "    <class>%d</class>\n",
357
                              data->usb_if._class);
358
            virBufferAsprintf(&buf, "    <subclass>%d</subclass>\n",
359
                              data->usb_if.subclass);
360
            virBufferAsprintf(&buf, "    <protocol>%d</protocol>\n",
361 362
                              data->usb_if.protocol);
            if (data->usb_if.description)
363 364
                virBufferEscapeString(&buf,
                                  "    <description>%s</description>\n",
365 366 367
                                  data->usb_if.description);
            break;
        case VIR_NODE_DEV_CAP_NET:
368
            virBufferEscapeString(&buf, "    <interface>%s</interface>\n",
369
                              data->net.ifname);
370
            if (data->net.address)
371
                virBufferEscapeString(&buf, "    <address>%s</address>\n",
372 373 374 375
                                  data->net.address);
            if (data->net.subtype != VIR_NODE_DEV_CAP_NET_LAST) {
                const char *subtyp =
                    virNodeDevNetCapTypeToString(data->net.subtype);
376 377
                virBufferEscapeString(&buf, "    <capability type='%s'/>\n",
                                      subtyp);
378 379 380
            }
            break;
        case VIR_NODE_DEV_CAP_SCSI_HOST:
381
            virBufferAsprintf(&buf, "    <host>%d</host>\n",
382
                              data->scsi_host.host);
383 384
            if (data->scsi_host.flags & VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST) {
                virBufferAddLit(&buf, "    <capability type='fc_host'>\n");
385 386 387 388
                virBufferEscapeString(&buf, "      <wwnn>%s</wwnn>\n",
                                      data->scsi_host.wwnn);
                virBufferEscapeString(&buf, "      <wwpn>%s</wwpn>\n",
                                      data->scsi_host.wwpn);
O
Osier Yang 已提交
389 390
                virBufferEscapeString(&buf, "      <fabric_wwn>%s</fabric_wwn>\n",
                                      data->scsi_host.fabric_wwn);
391 392 393 394 395 396
                virBufferAddLit(&buf, "    </capability>\n");
            }
            if (data->scsi_host.flags & VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS) {
                virBufferAddLit(&buf, "    <capability type='vport_ops' />\n");
            }

397
            break;
D
David Allan 已提交
398 399

        case VIR_NODE_DEV_CAP_SCSI_TARGET:
400 401
            virBufferEscapeString(&buf, "    <target>%s</target>\n",
                                  data->scsi_target.name);
D
David Allan 已提交
402 403
            break;

404
        case VIR_NODE_DEV_CAP_SCSI:
405 406 407
            virBufferAsprintf(&buf, "    <host>%d</host>\n", data->scsi.host);
            virBufferAsprintf(&buf, "    <bus>%d</bus>\n", data->scsi.bus);
            virBufferAsprintf(&buf, "    <target>%d</target>\n",
408
                              data->scsi.target);
409
            virBufferAsprintf(&buf, "    <lun>%d</lun>\n", data->scsi.lun);
410
            if (data->scsi.type)
411 412
                virBufferEscapeString(&buf, "    <type>%s</type>\n",
                                      data->scsi.type);
413 414
            break;
        case VIR_NODE_DEV_CAP_STORAGE:
415
            virBufferEscapeString(&buf, "    <block>%s</block>\n",
416
                              data->storage.block);
417
            if (data->storage.bus)
418
                virBufferEscapeString(&buf, "    <bus>%s</bus>\n",
419 420
                                  data->storage.bus);
            if (data->storage.drive_type)
421
                virBufferEscapeString(&buf, "    <drive_type>%s</drive_type>\n",
422 423
                                  data->storage.drive_type);
            if (data->storage.model)
424
                virBufferEscapeString(&buf, "    <model>%s</model>\n",
425 426
                                  data->storage.model);
            if (data->storage.vendor)
427
                virBufferEscapeString(&buf, "    <vendor>%s</vendor>\n",
428
                                  data->storage.vendor);
429
            if (data->storage.serial)
430
                virBufferAsprintf(&buf, "    <serial>%s</serial>\n",
431
                                  data->storage.serial);
432 433 434 435
            if (data->storage.flags & VIR_NODE_DEV_CAP_STORAGE_REMOVABLE) {
                int avl = data->storage.flags &
                    VIR_NODE_DEV_CAP_STORAGE_REMOVABLE_MEDIA_AVAILABLE;
                virBufferAddLit(&buf, "    <capability type='removable'>\n");
436
                virBufferAsprintf(&buf,
437 438
                                  "      <media_available>%d"
                                  "</media_available>\n", avl ? 1 : 0);
439
                virBufferAsprintf(&buf, "      <media_size>%llu</media_size>\n",
440
                                  data->storage.removable_media_size);
441 442 443 444 445
                if (data->storage.media_label)
                    virBufferEscapeString(&buf,
                                      "      <media_label>%s</media_label>\n",
                                      data->storage.media_label);

446
                if (data->storage.logical_block_size > 0)
447
                    virBufferAsprintf(&buf, "      <logical_block_size>%llu"
448 449 450
                                      "</logical_block_size>\n",
                                      data->storage.logical_block_size);
                if (data->storage.num_blocks > 0)
451
                    virBufferAsprintf(&buf,
452 453
                                      "      <num_blocks>%llu</num_blocks>\n",
                                      data->storage.num_blocks);
454 455
                virBufferAddLit(&buf, "    </capability>\n");
            } else {
456
                virBufferAsprintf(&buf, "    <size>%llu</size>\n",
457
                                  data->storage.size);
458
                if (data->storage.logical_block_size > 0)
459
                    virBufferAsprintf(&buf, "    <logical_block_size>%llu"
460 461 462
                                      "</logical_block_size>\n",
                                      data->storage.logical_block_size);
                if (data->storage.num_blocks > 0)
463
                    virBufferAsprintf(&buf,
464 465
                                      "    <num_blocks>%llu</num_blocks>\n",
                                      data->storage.num_blocks);
466 467 468 469 470
            }
            if (data->storage.flags & VIR_NODE_DEV_CAP_STORAGE_HOTPLUGGABLE)
                virBufferAddLit(&buf,
                                "    <capability type='hotpluggable' />\n");
            break;
471 472
        case VIR_NODE_DEV_CAP_FC_HOST:
        case VIR_NODE_DEV_CAP_VPORTS:
473
        case VIR_NODE_DEV_CAP_LAST:
474
        default:
475 476 477 478 479 480 481 482 483 484 485 486 487 488
            break;
        }

        virBufferAddLit(&buf, "  </capability>\n");
    }

    virBufferAddLit(&buf, "</device>\n");

    if (virBufferError(&buf))
        goto no_memory;

    return virBufferContentAndReset(&buf);

 no_memory:
489
    virReportOOMError();
490
    virBufferFreeAndReset(&buf);
491 492 493
    return NULL;
}

494
static int
495
virNodeDevCapsDefParseULong(const char *xpath,
496 497 498 499 500 501 502 503 504
                            xmlXPathContextPtr ctxt,
                            unsigned *value,
                            virNodeDeviceDefPtr def,
                            const char *missing_error_fmt,
                            const char *invalid_error_fmt)
{
    int ret;
    unsigned long val;

505
    ret = virXPathULong(xpath, ctxt, &val);
506
    if (ret < 0) {
507 508 509
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       ret == -1 ? missing_error_fmt : invalid_error_fmt,
                       def->name);
510 511 512 513 514 515 516 517
        return -1;
    }

    *value = val;
    return 0;
}

static int
518
virNodeDevCapsDefParseULongLong(const char *xpath,
519 520 521 522 523 524 525 526 527
                                xmlXPathContextPtr ctxt,
                                unsigned long long *value,
                                virNodeDeviceDefPtr def,
                                const char *missing_error_fmt,
                                const char *invalid_error_fmt)
{
    int ret;
    unsigned long long val;

528
    ret = virXPathULongLong(xpath, ctxt, &val);
529
    if (ret < 0) {
530 531 532
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       ret == -1 ? missing_error_fmt : invalid_error_fmt,
                       def->name);
533 534 535 536 537 538 539 540
        return -1;
    }

    *value = val;
    return 0;
}

static int
541
virNodeDevCapStorageParseXML(xmlXPathContextPtr ctxt,
542 543 544 545 546 547 548 549 550 551 552
                             virNodeDeviceDefPtr def,
                             xmlNodePtr node,
                             union _virNodeDevCapData *data)
{
    xmlNodePtr orignode, *nodes = NULL;
    int i, n, ret = -1;
    unsigned long long val;

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

553
    data->storage.block = virXPathString("string(./block[1])", ctxt);
554
    if (!data->storage.block) {
555 556 557
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("no block device path supplied for '%s'"),
                       def->name);
558 559 560
        goto out;
    }

561 562 563 564 565
    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);
566

567
    if ((n = virXPathNodeSet("./capability", ctxt, &nodes)) < 0) {
568 569 570 571 572 573 574
        goto out;
    }

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

        if (!type) {
575 576 577
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("missing storage capability type for '%s'"),
                           def->name);
578 579 580 581 582 583 584 585 586 587 588 589 590
            goto out;
        }

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

            data->storage.flags |= VIR_NODE_DEV_CAP_STORAGE_REMOVABLE;

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

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

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

596
            val = 0;
597
            if (virNodeDevCapsDefParseULongLong("number(./media_size[1])", ctxt, &val, def,
598 599 600 601 602 603 604 605 606 607
                                                _("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 {
608 609 610
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown storage capability type '%s' for '%s'"),
                           type, def->name);
611 612 613 614 615 616 617 618 619
            VIR_FREE(type);
            goto out;
        }

        VIR_FREE(type);
    }

    if (!(data->storage.flags & VIR_NODE_DEV_CAP_STORAGE_REMOVABLE)) {
        val = 0;
620
        if (virNodeDevCapsDefParseULongLong("number(./size[1])", ctxt, &val, def,
621 622 623 624 625 626 627 628 629 630 631 632 633 634
                                            _("no size supplied for '%s'"),
                                            _("invalid size supplied for '%s'")) < 0)
            goto out;
        data->storage.size = val;
    }

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

static int
635
virNodeDevCapScsiParseXML(xmlXPathContextPtr ctxt,
636 637 638 639 640 641 642 643 644 645
                          virNodeDeviceDefPtr def,
                          xmlNodePtr node,
                          union _virNodeDevCapData *data)
{
    xmlNodePtr orignode;
    int ret = -1;

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

646
    if (virNodeDevCapsDefParseULong("number(./host[1])", ctxt,
647 648 649 650 651
                                    &data->scsi.host, def,
                                    _("no SCSI host ID supplied for '%s'"),
                                    _("invalid SCSI host ID supplied for '%s'")) < 0)
        goto out;

652
    if (virNodeDevCapsDefParseULong("number(./bus[1])", ctxt,
653 654 655 656 657
                                    &data->scsi.bus, def,
                                    _("no SCSI bus ID supplied for '%s'"),
                                    _("invalid SCSI bus ID supplied for '%s'")) < 0)
        goto out;

658
    if (virNodeDevCapsDefParseULong("number(./target[1])", ctxt,
659 660 661 662 663
                                    &data->scsi.target, def,
                                    _("no SCSI target ID supplied for '%s'"),
                                    _("invalid SCSI target ID supplied for '%s'")) < 0)
        goto out;

664
    if (virNodeDevCapsDefParseULong("number(./lun[1])", ctxt,
665 666 667 668 669
                                    &data->scsi.lun, def,
                                    _("no SCSI LUN ID supplied for '%s'"),
                                    _("invalid SCSI LUN ID supplied for '%s'")) < 0)
        goto out;

670
    data->scsi.type = virXPathString("string(./type[1])", ctxt);
671 672 673 674 675 676 677

    ret = 0;
out:
    ctxt->node = orignode;
    return ret;
}

D
David Allan 已提交
678 679

static int
680
virNodeDevCapScsiTargetParseXML(xmlXPathContextPtr ctxt,
D
David Allan 已提交
681 682 683 684 685 686 687 688 689 690
                                virNodeDeviceDefPtr def,
                                xmlNodePtr node,
                                union _virNodeDevCapData *data)
{
    xmlNodePtr orignode;
    int ret = -1;

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

691
    data->scsi_target.name = virXPathString("string(./name[1])", ctxt);
D
David Allan 已提交
692
    if (!data->scsi_target.name) {
693 694 695
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("no target name supplied for '%s'"),
                       def->name);
D
David Allan 已提交
696 697 698 699 700 701 702 703 704 705 706
        goto out;
    }

    ret = 0;

out:
    ctxt->node = orignode;
    return ret;
}


707
static int
708
virNodeDevCapScsiHostParseXML(xmlXPathContextPtr ctxt,
709 710
                              virNodeDeviceDefPtr def,
                              xmlNodePtr node,
711
                              union _virNodeDevCapData *data,
712 713
                              int create,
                              const char *virt_type)
714
{
715 716 717
    xmlNodePtr orignode, *nodes = NULL;
    int ret = -1, n = 0, i;
    char *type = NULL;
718 719 720 721

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

722
    if (create == EXISTING_DEVICE &&
723
        virNodeDevCapsDefParseULong("number(./host[1])", ctxt,
724 725
                                    &data->scsi_host.host, def,
                                    _("no SCSI host ID supplied for '%s'"),
726 727 728 729
                                    _("invalid SCSI host ID supplied for '%s'")) < 0) {
        goto out;
    }

730
    if ((n = virXPathNodeSet("./capability", ctxt, &nodes)) < 0) {
731
        goto out;
732 733 734 735 736 737
    }

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

        if (!type) {
738 739 740
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("missing SCSI host capability type for '%s'"),
                           def->name);
741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756
            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];

757
            if (virNodeDevCapsDefParseString("string(./wwnn[1])",
758
                                             ctxt,
759 760
                                             &data->scsi_host.wwnn) < 0) {
                if (virRandomGenerateWWN(&data->scsi_host.wwnn, virt_type) < 0) {
761 762 763 764
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("no WWNN supplied for '%s', and "
                                     "auto-generation failed"),
                                   def->name);
765 766
                    goto out;
                }
767 768
            }

769
            if (virNodeDevCapsDefParseString("string(./wwpn[1])",
770
                                             ctxt,
771 772
                                             &data->scsi_host.wwpn) < 0) {
                if (virRandomGenerateWWN(&data->scsi_host.wwpn, virt_type) < 0) {
773 774 775 776
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("no WWPN supplied for '%s', and "
                                     "auto-generation failed"),
                                   def->name);
777 778
                    goto out;
                }
779 780 781 782 783
            }

            ctxt->node = orignode2;

        } else {
784 785 786
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown SCSI host capability type '%s' for '%s'"),
                           type, def->name);
787 788 789 790 791
            goto out;
        }

        VIR_FREE(type);
    }
792 793

    ret = 0;
794

795
out:
796
    VIR_FREE(type);
797
    ctxt->node = orignode;
798
    VIR_FREE(nodes);
799 800 801
    return ret;
}

802

803
static int
804
virNodeDevCapNetParseXML(xmlXPathContextPtr ctxt,
805 806 807 808 809 810 811 812 813 814 815
                         virNodeDeviceDefPtr def,
                         xmlNodePtr node,
                         union _virNodeDevCapData *data)
{
    xmlNodePtr orignode;
    int ret = -1;
    char *tmp;

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

816
    data->net.ifname = virXPathString("string(./interface[1])", ctxt);
817
    if (!data->net.ifname) {
818 819 820
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("no network interface supplied for '%s'"),
                       def->name);
821 822 823
        goto out;
    }

824
    data->net.address = virXPathString("string(./address[1])", ctxt);
825 826 827

    data->net.subtype = VIR_NODE_DEV_CAP_NET_LAST;

828
    tmp = virXPathString("string(./capability/@type)", ctxt);
829 830 831 832
    if (tmp) {
        int val = virNodeDevNetCapTypeFromString(tmp);
        VIR_FREE(tmp);
        if (val < 0) {
833 834 835
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("invalid network type supplied for '%s'"),
                           def->name);
836 837 838 839 840 841 842 843 844 845 846 847
            goto out;
        }
        data->net.subtype = val;
    }

    ret = 0;
out:
    ctxt->node = orignode;
    return ret;
}

static int
848
virNodeDevCapUsbInterfaceParseXML(xmlXPathContextPtr ctxt,
849 850 851 852 853 854 855 856 857 858
                                  virNodeDeviceDefPtr def,
                                  xmlNodePtr node,
                                  union _virNodeDevCapData *data)
{
    xmlNodePtr orignode;
    int ret = -1;

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

859
    if (virNodeDevCapsDefParseULong("number(./number[1])", ctxt,
860 861 862 863 864
                                    &data->usb_if.number, def,
                                    _("no USB interface number supplied for '%s'"),
                                    _("invalid USB interface number supplied for '%s'")) < 0)
        goto out;

865
    if (virNodeDevCapsDefParseULong("number(./class[1])", ctxt,
866 867 868 869 870
                                    &data->usb_if._class, def,
                                    _("no USB interface class supplied for '%s'"),
                                    _("invalid USB interface class supplied for '%s'")) < 0)
        goto out;

871
    if (virNodeDevCapsDefParseULong("number(./subclass[1])", ctxt,
872 873 874 875 876
                                    &data->usb_if.subclass, def,
                                    _("no USB interface subclass supplied for '%s'"),
                                    _("invalid USB interface subclass supplied for '%s'")) < 0)
        goto out;

877
    if (virNodeDevCapsDefParseULong("number(./protocol[1])", ctxt,
878 879 880 881 882
                                    &data->usb_if.protocol, def,
                                    _("no USB interface protocol supplied for '%s'"),
                                    _("invalid USB interface protocol supplied for '%s'")) < 0)
        goto out;

883
    data->usb_if.description = virXPathString("string(./description[1])", ctxt);
884 885 886 887 888 889 890 891

    ret = 0;
out:
    ctxt->node = orignode;
    return ret;
}

static int
892
virNodeDevCapsDefParseHexId(const char *xpath,
893 894 895 896 897 898 899 900 901
                            xmlXPathContextPtr ctxt,
                            unsigned *value,
                            virNodeDeviceDefPtr def,
                            const char *missing_error_fmt,
                            const char *invalid_error_fmt)
{
    int ret;
    unsigned long val;

902
    ret = virXPathULongHex(xpath, ctxt, &val);
903
    if (ret < 0) {
904 905 906
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       ret == -1 ? missing_error_fmt : invalid_error_fmt,
                       def->name);
907 908 909 910 911 912 913 914
        return -1;
    }

    *value = val;
    return 0;
}

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

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

926
    if (virNodeDevCapsDefParseULong("number(./bus[1])", ctxt,
927 928 929 930 931
                                    &data->usb_dev.bus, def,
                                    _("no USB bus number supplied for '%s'"),
                                    _("invalid USB bus number supplied for '%s'")) < 0)
        goto out;

932
    if (virNodeDevCapsDefParseULong("number(./device[1])", ctxt,
933 934 935 936 937
                                    &data->usb_dev.device, def,
                                    _("no USB device number supplied for '%s'"),
                                    _("invalid USB device number supplied for '%s'")) < 0)
        goto out;

938
    if (virNodeDevCapsDefParseHexId("string(./vendor[1]/@id)", ctxt,
939 940 941 942 943
                                    &data->usb_dev.vendor, def,
                                    _("no USB vendor ID supplied for '%s'"),
                                    _("invalid USB vendor ID supplied for '%s'")) < 0)
        goto out;

944
    if (virNodeDevCapsDefParseHexId("string(./product[1]/@id)", ctxt,
945 946 947 948 949
                                    &data->usb_dev.product, def,
                                    _("no USB product ID supplied for '%s'"),
                                    _("invalid USB product ID supplied for '%s'")) < 0)
        goto out;

950 951
    data->usb_dev.vendor_name  = virXPathString("string(./vendor[1])", ctxt);
    data->usb_dev.product_name = virXPathString("string(./product[1])", ctxt);
952 953 954 955 956 957 958 959

    ret = 0;
out:
    ctxt->node = orignode;
    return ret;
}

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

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

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

977
    if (virNodeDevCapsDefParseULong("number(./bus[1])", ctxt,
978 979 980 981 982
                                    &data->pci_dev.bus, def,
                                    _("no PCI bus ID supplied for '%s'"),
                                    _("invalid PCI bus ID supplied for '%s'")) < 0)
        goto out;

983
    if (virNodeDevCapsDefParseULong("number(./slot[1])", ctxt,
984 985 986 987 988
                                    &data->pci_dev.slot, def,
                                    _("no PCI slot ID supplied for '%s'"),
                                    _("invalid PCI slot ID supplied for '%s'")) < 0)
        goto out;

989
    if (virNodeDevCapsDefParseULong("number(./function[1])", ctxt,
990 991 992 993 994
                                    &data->pci_dev.function, def,
                                    _("no PCI function ID supplied for '%s'"),
                                    _("invalid PCI function ID supplied for '%s'")) < 0)
        goto out;

995
    if (virNodeDevCapsDefParseHexId("string(./vendor[1]/@id)", ctxt,
996 997 998 999 1000
                                    &data->pci_dev.vendor, def,
                                    _("no PCI vendor ID supplied for '%s'"),
                                    _("invalid PCI vendor ID supplied for '%s'")) < 0)
        goto out;

1001
    if (virNodeDevCapsDefParseHexId("string(./product[1]/@id)", ctxt,
1002 1003 1004 1005 1006
                                    &data->pci_dev.product, def,
                                    _("no PCI product ID supplied for '%s'"),
                                    _("invalid PCI product ID supplied for '%s'")) < 0)
        goto out;

1007 1008
    data->pci_dev.vendor_name  = virXPathString("string(./vendor[1])", ctxt);
    data->pci_dev.product_name = virXPathString("string(./product[1])", ctxt);
1009 1010 1011 1012 1013 1014 1015 1016

    ret = 0;
out:
    ctxt->node = orignode;
    return ret;
}

static int
1017
virNodeDevCapSystemParseXML(xmlXPathContextPtr ctxt,
1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028
                            virNodeDeviceDefPtr def,
                            xmlNodePtr node,
                            union _virNodeDevCapData *data)
{
    xmlNodePtr orignode;
    int ret = -1;
    char *tmp;

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

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

1031 1032 1033
    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);
1034

1035
    tmp = virXPathString("string(./hardware/uuid[1])", ctxt);
1036
    if (!tmp) {
1037 1038
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("no system UUID supplied for '%s'"), def->name);
1039 1040 1041 1042
        goto out;
    }

    if (virUUIDParse(tmp, data->system.hardware.uuid) < 0) {
1043 1044
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("malformed uuid element for '%s'"), def->name);
1045 1046 1047 1048 1049
        VIR_FREE(tmp);
        goto out;
    }
    VIR_FREE(tmp);

1050 1051 1052
    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);
1053 1054 1055 1056 1057 1058 1059 1060

    ret = 0;
out:
    ctxt->node = orignode;
    return ret;
}

static virNodeDevCapsDefPtr
1061
virNodeDevCapsDefParseXML(xmlXPathContextPtr ctxt,
1062
                          virNodeDeviceDefPtr def,
1063
                          xmlNodePtr node,
1064 1065
                          int create,
                          const char *virt_type)
1066 1067 1068 1069 1070 1071
{
    virNodeDevCapsDefPtr caps;
    char *tmp;
    int val, ret;

    if (VIR_ALLOC(caps) < 0) {
1072
        virReportOOMError();
1073 1074 1075 1076 1077
        return NULL;
    }

    tmp = virXMLPropString(node, "type");
    if (!tmp) {
1078 1079
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing capability type"));
1080 1081 1082 1083
        goto error;
    }

    if ((val = virNodeDevCapTypeFromString(tmp)) < 0) {
1084 1085
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown capability type '%s'"), tmp);
1086 1087 1088 1089 1090 1091 1092 1093
        VIR_FREE(tmp);
        goto error;
    }
    caps->type = val;
    VIR_FREE(tmp);

    switch (caps->type) {
    case VIR_NODE_DEV_CAP_SYSTEM:
1094
        ret = virNodeDevCapSystemParseXML(ctxt, def, node, &caps->data);
1095 1096
        break;
    case VIR_NODE_DEV_CAP_PCI_DEV:
1097
        ret = virNodeDevCapPciDevParseXML(ctxt, def, node, &caps->data);
1098 1099
        break;
    case VIR_NODE_DEV_CAP_USB_DEV:
1100
        ret = virNodeDevCapUsbDevParseXML(ctxt, def, node, &caps->data);
1101 1102
        break;
    case VIR_NODE_DEV_CAP_USB_INTERFACE:
1103
        ret = virNodeDevCapUsbInterfaceParseXML(ctxt, def, node, &caps->data);
1104 1105
        break;
    case VIR_NODE_DEV_CAP_NET:
1106
        ret = virNodeDevCapNetParseXML(ctxt, def, node, &caps->data);
1107 1108
        break;
    case VIR_NODE_DEV_CAP_SCSI_HOST:
1109 1110 1111 1112
        ret = virNodeDevCapScsiHostParseXML(ctxt, def, node,
                                            &caps->data,
                                            create,
                                            virt_type);
1113
        break;
D
David Allan 已提交
1114
    case VIR_NODE_DEV_CAP_SCSI_TARGET:
1115
        ret = virNodeDevCapScsiTargetParseXML(ctxt, def, node, &caps->data);
D
David Allan 已提交
1116
        break;
1117
    case VIR_NODE_DEV_CAP_SCSI:
1118
        ret = virNodeDevCapScsiParseXML(ctxt, def, node, &caps->data);
1119 1120
        break;
    case VIR_NODE_DEV_CAP_STORAGE:
1121
        ret = virNodeDevCapStorageParseXML(ctxt, def, node, &caps->data);
1122 1123
        break;
    default:
1124 1125 1126
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown capability type '%d' for '%s'"),
                       caps->type, def->name);
1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140
        ret = -1;
        break;
    }

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

error:
    virNodeDevCapsDefFree(caps);
    return NULL;
}

static virNodeDeviceDefPtr
1141 1142 1143
virNodeDeviceDefParseXML(xmlXPathContextPtr ctxt,
                         int create,
                         const char *virt_type)
1144 1145 1146 1147 1148 1149 1150
{
    virNodeDeviceDefPtr def;
    virNodeDevCapsDefPtr *next_cap;
    xmlNodePtr *nodes;
    int n, i;

    if (VIR_ALLOC(def) < 0) {
1151
        virReportOOMError();
1152 1153 1154 1155
        return NULL;
    }

    /* Extract device name */
1156
    if (create == EXISTING_DEVICE) {
1157
        def->name = virXPathString("string(./name[1])", ctxt);
1158 1159

        if (!def->name) {
1160
            virReportError(VIR_ERR_NO_NAME, NULL);
1161 1162
            goto error;
        }
1163 1164 1165
    } else {
        def->name = strdup("new device");

1166
        if (!def->name) {
1167
            virReportOOMError();
1168 1169
            goto error;
        }
1170 1171 1172
    }

    /* Extract device parent, if any */
1173
    def->parent = virXPathString("string(./parent[1])", ctxt);
1174 1175 1176

    /* Parse device capabilities */
    nodes = NULL;
1177 1178 1179 1180 1181
    if ((n = virXPathNodeSet("./capability", ctxt, &nodes)) < 0) {
        goto error;
    }

    if (n == 0) {
1182 1183 1184
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("no device capabilities for '%s'"),
                       def->name);
1185 1186 1187 1188 1189
        goto error;
    }

    next_cap = &def->caps;
    for (i = 0 ; i < n ; i++) {
1190 1191 1192 1193
        *next_cap = virNodeDevCapsDefParseXML(ctxt, def,
                                              nodes[i],
                                              create,
                                              virt_type);
1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209
        if (!*next_cap) {
            VIR_FREE(nodes);
            goto error;
        }

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

    return def;

 error:
    virNodeDeviceDefFree(def);
    return NULL;
}

1210
virNodeDeviceDefPtr
1211
virNodeDeviceDefParseNode(xmlDocPtr xml,
1212
                          xmlNodePtr root,
1213 1214
                          int create,
                          const char *virt_type)
1215 1216 1217 1218 1219
{
    xmlXPathContextPtr ctxt = NULL;
    virNodeDeviceDefPtr def = NULL;

    if (!xmlStrEqual(root->name, BAD_CAST "device")) {
1220 1221 1222 1223
        virReportError(VIR_ERR_XML_ERROR,
                       _("unexpected root element <%s> "
                         "expecting <device>"),
                       root->name);
1224 1225 1226 1227 1228
        return NULL;
    }

    ctxt = xmlXPathNewContext(xml);
    if (ctxt == NULL) {
1229
        virReportOOMError();
1230 1231 1232 1233
        goto cleanup;
    }

    ctxt->node = root;
1234
    def = virNodeDeviceDefParseXML(ctxt, create, virt_type);
1235 1236 1237 1238 1239 1240

cleanup:
    xmlXPathFreeContext(ctxt);
    return def;
}

1241
static virNodeDeviceDefPtr
1242
virNodeDeviceDefParse(const char *str,
1243
                      const char *filename,
1244 1245
                      int create,
                      const char *virt_type)
1246
{
J
Jiri Denemark 已提交
1247
    xmlDocPtr xml;
1248 1249
    virNodeDeviceDefPtr def = NULL;

1250
    if ((xml = virXMLParse(filename, str, _("(node_device_definition)")))) {
1251 1252
        def = virNodeDeviceDefParseNode(xml, xmlDocGetRootElement(xml),
                                        create, virt_type);
J
Jiri Denemark 已提交
1253
        xmlFreeDoc(xml);
1254 1255
    }

1256 1257 1258
    return def;
}

1259
virNodeDeviceDefPtr
1260
virNodeDeviceDefParseString(const char *str,
1261 1262
                            int create,
                            const char *virt_type)
1263
{
1264
    return virNodeDeviceDefParse(str, NULL, create, virt_type);
1265 1266 1267
}

virNodeDeviceDefPtr
1268
virNodeDeviceDefParseFile(const char *filename,
1269 1270
                          int create,
                          const char *virt_type)
1271
{
1272
    return virNodeDeviceDefParse(NULL, filename, create, virt_type);
1273 1274
}

1275 1276 1277 1278
/*
 * Return fc_host dev's WWNN and WWPN
 */
int
1279
virNodeDeviceGetWWNs(virNodeDeviceDefPtr def,
1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298
                     char **wwnn,
                     char **wwpn)
{
    virNodeDevCapsDefPtr cap = NULL;
    int ret = 0;

    cap = def->caps;
    while (cap != NULL) {
        if (cap->type == VIR_NODE_DEV_CAP_SCSI_HOST &&
            cap->data.scsi_host.flags & VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST) {
            *wwnn = strdup(cap->data.scsi_host.wwnn);
            *wwpn = strdup(cap->data.scsi_host.wwpn);
            break;
        }

        cap = cap->next;
    }

    if (cap == NULL) {
1299 1300
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Device is not a fibre channel HBA"));
1301
        ret = -1;
1302
    } else if (*wwnn == NULL || *wwpn == NULL) {
1303
        /* Free the other one, if allocated... */
1304 1305
        VIR_FREE(*wwnn);
        VIR_FREE(*wwpn);
1306
        ret = -1;
1307
        virReportOOMError();
1308 1309 1310 1311 1312 1313 1314 1315 1316
    }

    return ret;
}

/*
 * Return the NPIV dev's parent device name
 */
int
1317
virNodeDeviceGetParentHost(const virNodeDeviceObjListPtr devs,
1318 1319 1320 1321 1322 1323 1324 1325 1326 1327
                           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) {
1328 1329 1330
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not find parent device for '%s'"),
                       dev_name);
1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347
        ret = -1;
        goto out;
    }

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

        cap = cap->next;
    }

    if (cap == NULL) {
1348 1349 1350 1351
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Parent device %s is not capable "
                         "of vport operations"),
                       parent->def->name);
1352 1353 1354 1355 1356 1357 1358 1359
        ret = -1;
    }

    virNodeDeviceObjUnlock(parent);

out:
    return ret;
}
1360

1361 1362
void virNodeDevCapsDefFree(virNodeDevCapsDefPtr caps)
{
1363
    int i = 0;
1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378
    union _virNodeDevCapData *data = &caps->data;

    switch (caps->type) {
    case VIR_NODE_DEV_CAP_SYSTEM:
        VIR_FREE(data->system.product_name);
        VIR_FREE(data->system.hardware.vendor_name);
        VIR_FREE(data->system.hardware.version);
        VIR_FREE(data->system.hardware.serial);
        VIR_FREE(data->system.firmware.vendor_name);
        VIR_FREE(data->system.firmware.version);
        VIR_FREE(data->system.firmware.release_date);
        break;
    case VIR_NODE_DEV_CAP_PCI_DEV:
        VIR_FREE(data->pci_dev.product_name);
        VIR_FREE(data->pci_dev.vendor_name);
1379 1380 1381 1382
        VIR_FREE(data->pci_dev.physical_function);
        for (i = 0 ; i < data->pci_dev.num_virtual_functions ; i++) {
            VIR_FREE(data->pci_dev.virtual_functions[i]);
        }
1383 1384 1385 1386 1387 1388 1389 1390 1391
        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:
1392
        VIR_FREE(data->net.ifname);
1393 1394 1395
        VIR_FREE(data->net.address);
        break;
    case VIR_NODE_DEV_CAP_SCSI_HOST:
1396 1397
        VIR_FREE(data->scsi_host.wwnn);
        VIR_FREE(data->scsi_host.wwpn);
O
Osier Yang 已提交
1398
        VIR_FREE(data->scsi_host.fabric_wwn);
1399
        break;
D
David Allan 已提交
1400 1401 1402
    case VIR_NODE_DEV_CAP_SCSI_TARGET:
        VIR_FREE(data->scsi_target.name);
        break;
1403 1404 1405 1406
    case VIR_NODE_DEV_CAP_SCSI:
        VIR_FREE(data->scsi.type);
        break;
    case VIR_NODE_DEV_CAP_STORAGE:
1407
        VIR_FREE(data->storage.block);
1408 1409 1410 1411
        VIR_FREE(data->storage.bus);
        VIR_FREE(data->storage.drive_type);
        VIR_FREE(data->storage.model);
        VIR_FREE(data->storage.vendor);
1412
        VIR_FREE(data->storage.serial);
1413
        VIR_FREE(data->storage.media_label);
1414
        break;
1415 1416
    case VIR_NODE_DEV_CAP_FC_HOST:
    case VIR_NODE_DEV_CAP_VPORTS:
1417
    case VIR_NODE_DEV_CAP_LAST:
1418
    default:
1419 1420 1421 1422 1423 1424 1425
        /* This case is here to shutup the compiler */
        break;
    }

    VIR_FREE(caps);
}

D
Daniel P. Berrange 已提交
1426

1427 1428
void virNodeDeviceObjLock(virNodeDeviceObjPtr obj)
{
1429
    virMutexLock(&obj->lock);
1430 1431 1432 1433
}

void virNodeDeviceObjUnlock(virNodeDeviceObjPtr obj)
{
1434
    virMutexUnlock(&obj->lock);
D
Daniel P. Berrange 已提交
1435
}
1436 1437 1438 1439 1440 1441 1442 1443 1444 1445

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

    for (cap = devobj->def->caps; cap; cap = cap->next) {
        if (type == cap->type)
            return true;
1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457

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

            if (type == VIR_CONNECT_LIST_NODE_DEVICES_CAP_VPORTS &&
                (cap->data.scsi_host.flags &
                 VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS))
                return true;
        }
1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486
    }

    return false;
}

#define MATCH(FLAG) (flags & (FLAG))
static bool
virNodeDeviceMatch(virNodeDeviceObjPtr devobj,
                   unsigned int flags)
{
    /* filter by cap type */
    if (MATCH(VIR_CONNECT_LIST_NODE_DEVICES_FILTERS_CAP)) {
        if (!((MATCH(VIR_CONNECT_LIST_NODE_DEVICES_CAP_SYSTEM) &&
               virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_SYSTEM))        ||
              (MATCH(VIR_CONNECT_LIST_NODE_DEVICES_CAP_PCI_DEV) &&
               virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_PCI_DEV))       ||
              (MATCH(VIR_CONNECT_LIST_NODE_DEVICES_CAP_USB_DEV) &&
               virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_USB_DEV))       ||
              (MATCH(VIR_CONNECT_LIST_NODE_DEVICES_CAP_USB_INTERFACE) &&
               virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_USB_INTERFACE)) ||
              (MATCH(VIR_CONNECT_LIST_NODE_DEVICES_CAP_NET) &&
               virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_NET))           ||
              (MATCH(VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI_HOST) &&
               virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_SCSI_HOST))     ||
              (MATCH(VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI_TARGET) &&
               virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_SCSI_TARGET))   ||
              (MATCH(VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI) &&
               virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_SCSI))          ||
              (MATCH(VIR_CONNECT_LIST_NODE_DEVICES_CAP_STORAGE) &&
1487 1488 1489 1490 1491
               virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_STORAGE))       ||
              (MATCH(VIR_CONNECT_LIST_NODE_DEVICES_CAP_FC_HOST) &&
               virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_FC_HOST))       ||
              (MATCH(VIR_CONNECT_LIST_NODE_DEVICES_CAP_VPORTS) &&
               virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_VPORTS))))
1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554
            return false;
    }

    return true;
}
#undef MATCH

int
virNodeDeviceList(virConnectPtr conn,
                  virNodeDeviceObjList devobjs,
                  virNodeDevicePtr **devices,
                  unsigned int flags)
{
    virNodeDevicePtr *tmp_devices = NULL;
    virNodeDevicePtr device = NULL;
    int ndevices = 0;
    int ret = -1;
    int i;

    if (devices) {
        if (VIR_ALLOC_N(tmp_devices, devobjs.count + 1) < 0) {
            virReportOOMError();
            goto cleanup;
        }
    }

    for (i = 0; i < devobjs.count; i++) {
        virNodeDeviceObjPtr devobj = devobjs.objs[i];
        virNodeDeviceObjLock(devobj);
        if (virNodeDeviceMatch(devobj, flags)) {
            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;

cleanup:
    if (tmp_devices) {
        for (i = 0; i < ndevices; i++) {
            if (tmp_devices[i])
                virNodeDeviceFree(tmp_devices[i]);
        }
    }

    VIR_FREE(tmp_devices);
    return ret;
}