libvirt/src/conf/node_device_conf.c

2891 lines
94 KiB
C
Raw Normal View History

/*
* node_device_conf.c: config handling for node devices
*
* Copyright (C) 2009-2015 Red Hat, Inc.
* 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
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <unistd.h>
#include "virerror.h"
#include "datatypes.h"
2012-12-12 18:06:53 +00:00
#include "viralloc.h"
#include "virstring.h"
#include "node_device_conf.h"
#include "device_conf.h"
2012-12-13 18:13:21 +00:00
#include "virxml.h"
#include "virbuffer.h"
2012-12-13 18:01:25 +00:00
#include "viruuid.h"
#include "virrandom.h"
#include "virlog.h"
#include "virfcp.h"
#define VIR_FROM_THIS VIR_FROM_NODEDEV
VIR_LOG_INIT("conf.node_device_conf");
VIR_ENUM_IMPL(virNodeDevDevnode,
VIR_NODE_DEV_DEVNODE_LAST,
"dev",
"link",
);
VIR_ENUM_IMPL(virNodeDevCap,
VIR_NODE_DEV_CAP_LAST,
"system",
"pci",
"usb_device",
"usb",
"net",
"scsi_host",
"scsi_target",
"scsi",
"storage",
"fc_host",
"vports",
"scsi_generic",
"drm",
"mdev_types",
"mdev",
"ccw",
"css",
"vdpa",
"ap_card",
"ap_queue",
"ap_matrix",
);
VIR_ENUM_IMPL(virNodeDevNetCap,
VIR_NODE_DEV_CAP_NET_LAST,
"80203",
"80211",
);
VIR_ENUM_IMPL(virNodeDevDRM,
VIR_NODE_DEV_DRM_LAST,
"primary",
"control",
"render",
);
static int
virNodeDevCapsDefParseString(const char *xpath,
xmlXPathContextPtr ctxt,
char **string)
{
char *s;
if (!(s = virXPathString(xpath, ctxt)))
return -1;
*string = s;
return 0;
}
void
virNodeDeviceDefFree(virNodeDeviceDefPtr def)
{
virNodeDevCapsDefPtr caps;
if (!def)
return;
g_free(def->name);
g_free(def->parent);
g_free(def->parent_wwnn);
g_free(def->parent_wwpn);
g_free(def->parent_fabric_wwn);
g_free(def->driver);
g_free(def->sysfs_path);
g_free(def->parent_sysfs_path);
g_free(def->devnode);
g_strfreev(def->devlinks);
caps = def->caps;
while (caps) {
virNodeDevCapsDefPtr next = caps->next;
virNodeDevCapsDefFree(caps);
caps = next;
}
g_free(def);
}
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");
}
static void
virNodeDeviceCapSystemDefFormat(virBufferPtr buf,
const virNodeDevCapData *data)
{
char uuidstr[VIR_UUID_STRING_BUFLEN];
if (data->system.product_name)
virBufferEscapeString(buf, "<product>%s</product>\n",
data->system.product_name);
virBufferAddLit(buf, "<hardware>\n");
virBufferAdjustIndent(buf, 2);
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);
virBufferAsprintf(buf, "<uuid>%s</uuid>\n", uuidstr);
virBufferAdjustIndent(buf, -2);
virBufferAddLit(buf, "</hardware>\n");
virBufferAddLit(buf, "<firmware>\n");
virBufferAdjustIndent(buf, 2);
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);
virBufferAdjustIndent(buf, -2);
virBufferAddLit(buf, "</firmware>\n");
}
static void
virNodeDeviceCapMdevTypesFormat(virBufferPtr buf,
virMediatedDeviceTypePtr *mdev_types,
const size_t nmdev_types)
{
size_t i;
if (nmdev_types > 0) {
virBufferAddLit(buf, "<capability type='mdev_types'>\n");
virBufferAdjustIndent(buf, 2);
for (i = 0; i < nmdev_types; i++) {
virMediatedDeviceTypePtr type = mdev_types[i];
virBufferEscapeString(buf, "<type id='%s'>\n", type->id);
virBufferAdjustIndent(buf, 2);
if (type->name)
virBufferEscapeString(buf, "<name>%s</name>\n",
type->name);
virBufferEscapeString(buf, "<deviceAPI>%s</deviceAPI>\n",
type->device_api);
virBufferAsprintf(buf,
"<availableInstances>%u</availableInstances>\n",
type->available_instances);
virBufferAdjustIndent(buf, -2);
virBufferAddLit(buf, "</type>\n");
}
virBufferAdjustIndent(buf, -2);
virBufferAddLit(buf, "</capability>\n");
}
}
static void
virNodeDeviceCapPCIDefFormat(virBufferPtr buf,
const virNodeDevCapData *data)
{
size_t i;
if (data->pci_dev.klass >= 0)
virBufferAsprintf(buf, "<class>0x%.6x</class>\n", data->pci_dev.klass);
virBufferAsprintf(buf, "<domain>%d</domain>\n",
data->pci_dev.domain);
virBufferAsprintf(buf, "<bus>%d</bus>\n", data->pci_dev.bus);
virBufferAsprintf(buf, "<slot>%d</slot>\n",
data->pci_dev.slot);
virBufferAsprintf(buf, "<function>%d</function>\n",
data->pci_dev.function);
virBufferAsprintf(buf, "<product id='0x%04x'",
data->pci_dev.product);
if (data->pci_dev.product_name)
virBufferEscapeString(buf, ">%s</product>\n",
data->pci_dev.product_name);
else
virBufferAddLit(buf, "/>\n");
virBufferAsprintf(buf, "<vendor id='0x%04x'",
data->pci_dev.vendor);
if (data->pci_dev.vendor_name)
virBufferEscapeString(buf, ">%s</vendor>\n",
data->pci_dev.vendor_name);
else
virBufferAddLit(buf, "/>\n");
if (data->pci_dev.flags & VIR_NODE_DEV_CAP_FLAG_PCI_PHYSICAL_FUNCTION) {
virBufferAddLit(buf, "<capability type='phys_function'>\n");
virBufferAdjustIndent(buf, 2);
virBufferAsprintf(buf,
"<address domain='0x%04x' bus='0x%02x' "
"slot='0x%02x' function='0x%d'/>\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);
virBufferAdjustIndent(buf, -2);
virBufferAddLit(buf, "</capability>\n");
}
if (data->pci_dev.flags & VIR_NODE_DEV_CAP_FLAG_PCI_VIRTUAL_FUNCTION) {
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%04x' bus='0x%02x' "
"slot='0x%02x' function='0x%d'/>\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");
}
}
if (data->pci_dev.hdrType) {
virBufferAsprintf(buf, "<capability type='%s'/>\n",
virPCIHeaderTypeToString(data->pci_dev.hdrType));
}
if (data->pci_dev.flags & VIR_NODE_DEV_CAP_FLAG_PCI_MDEV) {
virNodeDeviceCapMdevTypesFormat(buf,
data->pci_dev.mdev_types,
data->pci_dev.nmdev_types);
}
if (data->pci_dev.nIommuGroupDevices) {
virBufferAsprintf(buf, "<iommuGroup number='%d'>\n",
data->pci_dev.iommuGroupNumber);
virBufferAdjustIndent(buf, 2);
for (i = 0; i < data->pci_dev.nIommuGroupDevices; i++) {
virBufferAsprintf(buf,
"<address domain='0x%04x' bus='0x%02x' "
"slot='0x%02x' function='0x%d'/>\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);
}
virBufferAdjustIndent(buf, -2);
virBufferAddLit(buf, "</iommuGroup>\n");
}
if (data->pci_dev.numa_node >= 0)
virBufferAsprintf(buf, "<numa node='%d'/>\n",
data->pci_dev.numa_node);
if (data->pci_dev.flags & VIR_NODE_DEV_CAP_FLAG_PCIE)
virPCIEDeviceInfoFormat(buf, data->pci_dev.pci_express);
}
static void
virNodeDeviceCapUSBDevDefFormat(virBufferPtr buf,
const virNodeDevCapData *data)
{
virBufferAsprintf(buf, "<bus>%d</bus>\n", data->usb_dev.bus);
virBufferAsprintf(buf, "<device>%d</device>\n",
data->usb_dev.device);
virBufferAsprintf(buf, "<product id='0x%04x'",
data->usb_dev.product);
if (data->usb_dev.product_name)
virBufferEscapeString(buf, ">%s</product>\n",
data->usb_dev.product_name);
else
virBufferAddLit(buf, " />\n");
virBufferAsprintf(buf, "<vendor id='0x%04x'",
data->usb_dev.vendor);
if (data->usb_dev.vendor_name)
virBufferEscapeString(buf, ">%s</vendor>\n",
data->usb_dev.vendor_name);
else
virBufferAddLit(buf, " />\n");
}
static void
virNodeDeviceCapUSBInterfaceDefFormat(virBufferPtr buf,
const virNodeDevCapData *data)
{
virBufferAsprintf(buf, "<number>%d</number>\n",
data->usb_if.number);
virBufferAsprintf(buf, "<class>%d</class>\n",
data->usb_if.klass);
virBufferAsprintf(buf, "<subclass>%d</subclass>\n",
data->usb_if.subclass);
virBufferAsprintf(buf, "<protocol>%d</protocol>\n",
data->usb_if.protocol);
if (data->usb_if.description)
virBufferEscapeString(buf,
"<description>%s</description>\n",
data->usb_if.description);
}
static void
virNodeDeviceCapNetDefFormat(virBufferPtr buf,
const virNodeDevCapData *data)
{
size_t i;
virBufferEscapeString(buf, "<interface>%s</interface>\n",
data->net.ifname);
if (data->net.address)
virBufferEscapeString(buf, "<address>%s</address>\n",
data->net.address);
virInterfaceLinkFormat(buf, &data->net.lnk);
if (data->net.features) {
for (i = 0; i < VIR_NET_DEV_FEAT_LAST; i++) {
if (virBitmapIsBitSet(data->net.features, i)) {
virBufferAsprintf(buf, "<feature name='%s'/>\n",
virNetDevFeatureTypeToString(i));
}
}
}
if (data->net.subtype != VIR_NODE_DEV_CAP_NET_LAST) {
const char *subtyp =
virNodeDevNetCapTypeToString(data->net.subtype);
virBufferEscapeString(buf, "<capability type='%s'/>\n",
subtyp);
}
}
static void
virNodeDeviceCapSCSIHostDefFormat(virBufferPtr buf,
const virNodeDevCapData *data)
{
virBufferAsprintf(buf, "<host>%d</host>\n",
data->scsi_host.host);
if (data->scsi_host.unique_id != -1)
virBufferAsprintf(buf, "<unique_id>%d</unique_id>\n",
data->scsi_host.unique_id);
if (data->scsi_host.flags & VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST) {
virBufferAddLit(buf, "<capability type='fc_host'>\n");
virBufferAdjustIndent(buf, 2);
virBufferEscapeString(buf, "<wwnn>%s</wwnn>\n",
data->scsi_host.wwnn);
virBufferEscapeString(buf, "<wwpn>%s</wwpn>\n",
data->scsi_host.wwpn);
virBufferEscapeString(buf, "<fabric_wwn>%s</fabric_wwn>\n",
data->scsi_host.fabric_wwn);
virBufferAdjustIndent(buf, -2);
virBufferAddLit(buf, "</capability>\n");
}
if (data->scsi_host.flags & VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS) {
virBufferAddLit(buf, "<capability type='vport_ops'>\n");
virBufferAdjustIndent(buf, 2);
virBufferAsprintf(buf, "<max_vports>%d</max_vports>\n",
data->scsi_host.max_vports);
virBufferAsprintf(buf, "<vports>%d</vports>\n",
data->scsi_host.vports);
virBufferAdjustIndent(buf, -2);
virBufferAddLit(buf, "</capability>\n");
}
}
static void
virNodeDeviceCapSCSIDefFormat(virBufferPtr buf,
const virNodeDevCapData *data)
{
virBufferAsprintf(buf, "<host>%d</host>\n", data->scsi.host);
virBufferAsprintf(buf, "<bus>%d</bus>\n", data->scsi.bus);
virBufferAsprintf(buf, "<target>%d</target>\n",
data->scsi.target);
virBufferAsprintf(buf, "<lun>%d</lun>\n", data->scsi.lun);
if (data->scsi.type)
virBufferEscapeString(buf, "<type>%s</type>\n",
data->scsi.type);
}
static void
virNodeDeviceCapStorageDefFormat(virBufferPtr buf,
const virNodeDevCapData *data)
{
virBufferEscapeString(buf, "<block>%s</block>\n",
data->storage.block);
if (data->storage.bus)
virBufferEscapeString(buf, "<bus>%s</bus>\n",
data->storage.bus);
if (data->storage.drive_type)
virBufferEscapeString(buf, "<drive_type>%s</drive_type>\n",
data->storage.drive_type);
if (data->storage.model)
virBufferEscapeString(buf, "<model>%s</model>\n",
data->storage.model);
if (data->storage.vendor)
virBufferEscapeString(buf, "<vendor>%s</vendor>\n",
data->storage.vendor);
if (data->storage.serial)
virBufferEscapeString(buf, "<serial>%s</serial>\n",
data->storage.serial);
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");
virBufferAdjustIndent(buf, 2);
virBufferAsprintf(buf, "<media_available>%d"
"</media_available>\n", avl ? 1 : 0);
virBufferAsprintf(buf, "<media_size>%llu</media_size>\n",
data->storage.removable_media_size);
if (data->storage.media_label)
virBufferEscapeString(buf,
"<media_label>%s</media_label>\n",
data->storage.media_label);
if (data->storage.logical_block_size > 0)
virBufferAsprintf(buf, "<logical_block_size>%llu"
"</logical_block_size>\n",
data->storage.logical_block_size);
if (data->storage.num_blocks > 0)
virBufferAsprintf(buf,
"<num_blocks>%llu</num_blocks>\n",
data->storage.num_blocks);
virBufferAdjustIndent(buf, -2);
virBufferAddLit(buf, "</capability>\n");
} else {
virBufferAsprintf(buf, "<size>%llu</size>\n",
data->storage.size);
if (data->storage.logical_block_size > 0)
virBufferAsprintf(buf, "<logical_block_size>%llu"
"</logical_block_size>\n",
data->storage.logical_block_size);
if (data->storage.num_blocks > 0)
virBufferAsprintf(buf, "<num_blocks>%llu</num_blocks>\n",
data->storage.num_blocks);
}
if (data->storage.flags & VIR_NODE_DEV_CAP_STORAGE_HOTPLUGGABLE)
virBufferAddLit(buf, "<capability type='hotpluggable'/>\n");
}
static void
virNodeDeviceCapMdevDefFormat(virBufferPtr buf,
const virNodeDevCapData *data)
{
size_t i;
virBufferEscapeString(buf, "<type id='%s'/>\n", data->mdev.type);
virBufferAsprintf(buf, "<iommuGroup number='%u'/>\n",
data->mdev.iommuGroupNumber);
for (i = 0; i < data->mdev.nattributes; i++) {
virMediatedDeviceAttrPtr attr = data->mdev.attributes[i];
virBufferAsprintf(buf, "<attr name='%s' value='%s'/>\n",
attr->name, attr->value);
}
}
static void
virNodeDeviceCapVDPADefFormat(virBufferPtr buf,
const virNodeDevCapData *data)
{
virBufferEscapeString(buf, "<chardev>%s</chardev>\n", data->vdpa.chardev);
}
static void
virNodeDeviceCapCCWDefFormat(virBufferPtr buf,
const virNodeDevCapData *data)
{
virBufferAsprintf(buf, "<cssid>0x%x</cssid>\n",
data->ccw_dev.cssid);
virBufferAsprintf(buf, "<ssid>0x%x</ssid>\n",
data->ccw_dev.ssid);
virBufferAsprintf(buf, "<devno>0x%04x</devno>\n",
data->ccw_dev.devno);
if (data->ccw_dev.flags & VIR_NODE_DEV_CAP_FLAG_CSS_MDEV)
virNodeDeviceCapMdevTypesFormat(buf,
data->ccw_dev.mdev_types,
data->ccw_dev.nmdev_types);
}
char *
virNodeDeviceDefFormat(const virNodeDeviceDef *def)
{
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
virNodeDevCapsDefPtr caps;
size_t i = 0;
virBufferAddLit(&buf, "<device>\n");
virBufferAdjustIndent(&buf, 2);
virBufferEscapeString(&buf, "<name>%s</name>\n", def->name);
virBufferEscapeString(&buf, "<path>%s</path>\n", def->sysfs_path);
if (def->devnode)
virBufferEscapeString(&buf, "<devnode type='dev'>%s</devnode>\n",
def->devnode);
if (def->devlinks) {
for (i = 0; def->devlinks[i]; i++)
virBufferEscapeString(&buf, "<devnode type='link'>%s</devnode>\n",
def->devlinks[i]);
}
if (def->parent)
virBufferEscapeString(&buf, "<parent>%s</parent>\n", def->parent);
if (def->driver) {
virBufferAddLit(&buf, "<driver>\n");
virBufferAdjustIndent(&buf, 2);
virBufferEscapeString(&buf, "<name>%s</name>\n", def->driver);
virBufferAdjustIndent(&buf, -2);
virBufferAddLit(&buf, "</driver>\n");
}
for (caps = def->caps; caps; caps = caps->next) {
virNodeDevCapDataPtr data = &caps->data;
virBufferAsprintf(&buf, "<capability type='%s'>\n",
virNodeDevCapTypeToString(caps->data.type));
virBufferAdjustIndent(&buf, 2);
switch (caps->data.type) {
case VIR_NODE_DEV_CAP_SYSTEM:
virNodeDeviceCapSystemDefFormat(&buf, data);
break;
case VIR_NODE_DEV_CAP_PCI_DEV:
virNodeDeviceCapPCIDefFormat(&buf, data);
break;
case VIR_NODE_DEV_CAP_USB_DEV:
virNodeDeviceCapUSBDevDefFormat(&buf, data);
break;
case VIR_NODE_DEV_CAP_USB_INTERFACE:
virNodeDeviceCapUSBInterfaceDefFormat(&buf, data);
break;
case VIR_NODE_DEV_CAP_NET:
virNodeDeviceCapNetDefFormat(&buf, data);
break;
case VIR_NODE_DEV_CAP_SCSI_HOST:
virNodeDeviceCapSCSIHostDefFormat(&buf, data);
break;
case VIR_NODE_DEV_CAP_SCSI_TARGET:
virBufferEscapeString(&buf, "<target>%s</target>\n",
data->scsi_target.name);
if (data->scsi_target.flags & VIR_NODE_DEV_CAP_FLAG_FC_RPORT) {
virBufferAddLit(&buf, "<capability type='fc_remote_port'>\n");
virBufferAdjustIndent(&buf, 2);
virBufferAsprintf(&buf, "<rport>%s</rport>\n",
data->scsi_target.rport);
virBufferAsprintf(&buf, "<wwpn>%s</wwpn>\n",
data->scsi_target.wwpn);
virBufferAdjustIndent(&buf, -2);
virBufferAddLit(&buf, "</capability>\n");
}
break;
case VIR_NODE_DEV_CAP_SCSI:
virNodeDeviceCapSCSIDefFormat(&buf, data);
break;
case VIR_NODE_DEV_CAP_STORAGE:
virNodeDeviceCapStorageDefFormat(&buf, data);
break;
case VIR_NODE_DEV_CAP_SCSI_GENERIC:
virBufferEscapeString(&buf, "<char>%s</char>\n",
data->sg.path);
break;
case VIR_NODE_DEV_CAP_DRM:
virBufferEscapeString(&buf, "<type>%s</type>\n", virNodeDevDRMTypeToString(data->drm.type));
break;
case VIR_NODE_DEV_CAP_MDEV:
virNodeDeviceCapMdevDefFormat(&buf, data);
break;
case VIR_NODE_DEV_CAP_CCW_DEV:
case VIR_NODE_DEV_CAP_CSS_DEV:
virNodeDeviceCapCCWDefFormat(&buf, data);
break;
case VIR_NODE_DEV_CAP_VDPA:
virNodeDeviceCapVDPADefFormat(&buf, data);
break;
case VIR_NODE_DEV_CAP_AP_CARD:
virBufferAsprintf(&buf, "<ap-adapter>0x%02x</ap-adapter>\n",
data->ap_card.ap_adapter);
break;
case VIR_NODE_DEV_CAP_AP_QUEUE:
virBufferAsprintf(&buf, "<ap-adapter>0x%02x</ap-adapter>\n",
data->ap_queue.ap_adapter);
virBufferAsprintf(&buf, "<ap-domain>0x%04x</ap-domain>\n",
data->ap_queue.ap_domain);
break;
case VIR_NODE_DEV_CAP_AP_MATRIX:
if (data->ap_matrix.flags & VIR_NODE_DEV_CAP_FLAG_AP_MATRIX_MDEV)
virNodeDeviceCapMdevTypesFormat(&buf,
data->ap_matrix.mdev_types,
data->ap_matrix.nmdev_types);
case VIR_NODE_DEV_CAP_MDEV_TYPES:
case VIR_NODE_DEV_CAP_FC_HOST:
case VIR_NODE_DEV_CAP_VPORTS:
case VIR_NODE_DEV_CAP_LAST:
break;
}
virBufferAdjustIndent(&buf, -2);
virBufferAddLit(&buf, "</capability>\n");
}
virBufferAdjustIndent(&buf, -2);
virBufferAddLit(&buf, "</device>\n");
return virBufferContentAndReset(&buf);
}
/**
* 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;
}
static int
virNodeDevCapsDefParseULong(const char *xpath,
xmlXPathContextPtr ctxt,
unsigned *value,
virNodeDeviceDefPtr def,
const char *missing_error_fmt,
const char *invalid_error_fmt)
{
int ret;
unsigned long val;
ret = virXPathULong(xpath, ctxt, &val);
if (ret < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
ret == -1 ? missing_error_fmt : invalid_error_fmt,
def->name);
return -1;
}
*value = val;
return 0;
}
static int
virNodeDevCapsDefParseULongLong(const char *xpath,
xmlXPathContextPtr ctxt,
unsigned long long *value,
virNodeDeviceDefPtr def,
const char *missing_error_fmt,
const char *invalid_error_fmt)
{
int ret;
unsigned long long val;
ret = virXPathULongLong(xpath, ctxt, &val);
if (ret < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
ret == -1 ? missing_error_fmt : invalid_error_fmt,
def->name);
return -1;
}
*value = val;
return 0;
}
static int
virNodeDevCapDRMParseXML(xmlXPathContextPtr ctxt,
virNodeDeviceDefPtr def,
xmlNodePtr node,
virNodeDevCapDRMPtr drm)
{
VIR_XPATH_NODE_AUTORESTORE(ctxt)
int val;
g_autofree char *type = NULL;
ctxt->node = node;
type = virXPathString("string(./type[1])", ctxt);
if ((val = virNodeDevDRMTypeFromString(type)) < 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("unknown drm type '%s' for '%s'"), type, def->name);
return -1;
}
drm->type = val;
return 0;
}
static int
virNodeDevCapMdevTypesParseXML(xmlXPathContextPtr ctxt,
virMediatedDeviceTypePtr **mdev_types,
size_t *nmdev_types)
{
int ret = -1;
xmlNodePtr orignode = NULL;
g_autofree xmlNodePtr *nodes = NULL;
int ntypes = -1;
virMediatedDeviceTypePtr type = NULL;
size_t i;
if ((ntypes = virXPathNodeSet("./type", ctxt, &nodes)) < 0)
goto cleanup;
if (nmdev_types == 0) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("missing <type> element in <capability> element"));
goto cleanup;
}
orignode = ctxt->node;
for (i = 0; i < ntypes; i++) {
ctxt->node = nodes[i];
type = g_new0(virMediatedDeviceType, 1);
if (!(type->id = virXPathString("string(./@id[1])", ctxt))) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("missing 'id' attribute for mediated device's "
"<type> element"));
goto cleanup;
}
if (!(type->device_api = virXPathString("string(./deviceAPI[1])", ctxt))) {
virReportError(VIR_ERR_XML_ERROR,
_("missing device API for mediated device type '%s'"),
type->id);
goto cleanup;
}
if (virXPathUInt("number(./availableInstances)", ctxt,
&type->available_instances) < 0) {
virReportError(VIR_ERR_XML_ERROR,
_("missing number of available instances for "
"mediated device type '%s'"),
type->id);
goto cleanup;
}
type->name = virXPathString("string(./name)", ctxt);
if (VIR_APPEND_ELEMENT(*mdev_types,
*nmdev_types, type) < 0)
goto cleanup;
}
ret = 0;
cleanup:
virMediatedDeviceTypeFree(type);
ctxt->node = orignode;
return ret;
}
static int
virNodeDevAPMatrixCapabilityParseXML(xmlXPathContextPtr ctxt,
xmlNodePtr node,
virNodeDevCapAPMatrixPtr apm_dev)
{
g_autofree char *type = virXMLPropString(node, "type");
VIR_XPATH_NODE_AUTORESTORE(ctxt)
ctxt->node = node;
if (!type) {
virReportError(VIR_ERR_XML_ERROR, "%s", _("Missing capability type"));
return -1;
}
if (STREQ(type, "mdev_types")) {
if (virNodeDevCapMdevTypesParseXML(ctxt,
&apm_dev->mdev_types,
&apm_dev->nmdev_types) < 0)
return -1;
apm_dev->flags |= VIR_NODE_DEV_CAP_FLAG_AP_MATRIX_MDEV;
}
return 0;
}
static int
virNodeDevCSSCapabilityParseXML(xmlXPathContextPtr ctxt,
xmlNodePtr node,
virNodeDevCapCCWPtr ccw_dev)
{
g_autofree char *type = virXMLPropString(node, "type");
VIR_XPATH_NODE_AUTORESTORE(ctxt)
ctxt->node = node;
if (!type) {
virReportError(VIR_ERR_XML_ERROR, "%s", _("Missing capability type"));
return -1;
}
if (STREQ(type, "mdev_types")) {
if (virNodeDevCapMdevTypesParseXML(ctxt,
&ccw_dev->mdev_types,
&ccw_dev->nmdev_types) < 0)
return -1;
ccw_dev->flags |= VIR_NODE_DEV_CAP_FLAG_CSS_MDEV;
}
return 0;
}
static int
virNodeDevCapCCWParseXML(xmlXPathContextPtr ctxt,
virNodeDeviceDefPtr def,
xmlNodePtr node,
virNodeDevCapCCWPtr ccw_dev)
{
VIR_XPATH_NODE_AUTORESTORE(ctxt)
g_autofree xmlNodePtr *nodes = NULL;
int n = 0;
size_t i = 0;
g_autofree char *cssid = NULL;
g_autofree char *ssid = NULL;
g_autofree char *devno = NULL;
ctxt->node = node;
if (!(cssid = virXPathString("string(./cssid[1])", ctxt))) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("missing cssid value for '%s'"), def->name);
return -1;
}
if (virStrToLong_uip(cssid, NULL, 0, &ccw_dev->cssid) < 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("invalid cssid value '%s' for '%s'"),
cssid, def->name);
return -1;
}
if (!(ssid = virXPathString("string(./ssid[1])", ctxt))) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("missing ssid value for '%s'"), def->name);
return -1;
}
if (virStrToLong_uip(ssid, NULL, 0, &ccw_dev->ssid) < 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("invalid ssid value '%s' for '%s'"),
cssid, def->name);
return -1;
}
if (!(devno = virXPathString("string(./devno[1])", ctxt))) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("missing devno value for '%s'"), def->name);
return -1;
}
if (virStrToLong_uip(devno, NULL, 16, &ccw_dev->devno) < 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("invalid devno value '%s' for '%s'"),
devno, def->name);
return -1;
}
if ((n = virXPathNodeSet("./capability", ctxt, &nodes)) < 0)
return -1;
for (i = 0; i < n; i++) {
if (virNodeDevCSSCapabilityParseXML(ctxt, nodes[i], ccw_dev) < 0)
return -1;
}
return 0;
}
static int
virNodeDevCapAPAdapterParseXML(xmlXPathContextPtr ctxt,
virNodeDeviceDefPtr def,
unsigned int *ap_adapter)
{
g_autofree char *adapter = NULL;
if (!(adapter = virXPathString("string(./ap-adapter[1])", ctxt))) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("missing ap-adapter value for '%s'"), def->name);
return -1;
}
if (virStrToLong_uip(adapter, NULL, 0, ap_adapter) < 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("invalid ap-adapter value '%s' for '%s'"),
adapter, def->name);
return -1;
}
return 0;
}
static int
virNodeDevCapAPCardParseXML(xmlXPathContextPtr ctxt,
virNodeDeviceDefPtr def,
xmlNodePtr node,
virNodeDevCapAPCardPtr ap_card)
{
VIR_XPATH_NODE_AUTORESTORE(ctxt)
ctxt->node = node;
return virNodeDevCapAPAdapterParseXML(ctxt, def, &ap_card->ap_adapter);
}
static int
virNodeDevCapAPQueueParseXML(xmlXPathContextPtr ctxt,
virNodeDeviceDefPtr def,
xmlNodePtr node,
virNodeDevCapAPQueuePtr ap_queue)
{
int ret = -1;
VIR_XPATH_NODE_AUTORESTORE(ctxt)
g_autofree char *dom = NULL;
ctxt->node = node;
ret = virNodeDevCapAPAdapterParseXML(ctxt, def, &ap_queue->ap_adapter);
if (ret < 0)
return ret;
if (!(dom = virXPathString("string(./ap-domain[1])", ctxt))) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("missing ap-domain value for '%s'"), def->name);
return -1;
}
if (virStrToLong_uip(dom, NULL, 0, &ap_queue->ap_domain) < 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("invalid ap-domain value '%s' for '%s'"),
dom, def->name);
return -1;
}
if (ap_queue->ap_domain > 255) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("ap-domain value '%s' is out of range for '%s'"),
dom, def->name);
return -1;
}
return 0;
}
static int
virNodeDevCapAPMatrixParseXML(xmlXPathContextPtr ctxt,
virNodeDeviceDefPtr def G_GNUC_UNUSED,
xmlNodePtr node,
virNodeDevCapAPMatrixPtr ap_matrix)
{
VIR_XPATH_NODE_AUTORESTORE(ctxt)
g_autofree xmlNodePtr *nodes = NULL;
int n = 0;
size_t i = 0;
ctxt->node = node;
if ((n = virXPathNodeSet("./capability", ctxt, &nodes)) < 0)
return -1;
for (i = 0; i < n; i++) {
if (virNodeDevAPMatrixCapabilityParseXML(ctxt, nodes[i], ap_matrix) < 0)
return -1;
}
return 0;
}
static int
virNodeDevCapStorageParseXML(xmlXPathContextPtr ctxt,
virNodeDeviceDefPtr def,
xmlNodePtr node,
virNodeDevCapStoragePtr storage)
{
VIR_XPATH_NODE_AUTORESTORE(ctxt)
g_autofree xmlNodePtr *nodes = NULL;
size_t i;
int n;
unsigned long long val;
ctxt->node = node;
storage->block = virXPathString("string(./block[1])", ctxt);
if (!storage->block) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("no block device path supplied for '%s'"),
def->name);
return -1;
}
storage->bus = virXPathString("string(./bus[1])", ctxt);
storage->drive_type = virXPathString("string(./drive_type[1])", ctxt);
storage->model = virXPathString("string(./model[1])", ctxt);
storage->vendor = virXPathString("string(./vendor[1])", ctxt);
storage->serial = virXPathString("string(./serial[1])", ctxt);
if ((n = virXPathNodeSet("./capability", ctxt, &nodes)) < 0)
return -1;
for (i = 0; i < n; i++) {
g_autofree char *type = virXMLPropString(nodes[i], "type");
if (!type) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("missing storage capability type for '%s'"),
def->name);
return -1;
}
if (STREQ(type, "hotpluggable")) {
storage->flags |= VIR_NODE_DEV_CAP_STORAGE_HOTPLUGGABLE;
} else if (STREQ(type, "removable")) {
xmlNodePtr orignode2;
storage->flags |= VIR_NODE_DEV_CAP_STORAGE_REMOVABLE;
orignode2 = ctxt->node;
ctxt->node = nodes[i];
if (virXPathBoolean("count(./media_available[. = '1']) > 0", ctxt))
storage->flags |= VIR_NODE_DEV_CAP_STORAGE_REMOVABLE_MEDIA_AVAILABLE;
storage->media_label = virXPathString("string(./media_label[1])", ctxt);
val = 0;
if (virNodeDevCapsDefParseULongLong("number(./media_size[1])", ctxt, &val, def,
_("no removable media size supplied for '%s'"),
_("invalid removable media size supplied for '%s'")) < 0) {
return -1;
}
storage->removable_media_size = val;
ctxt->node = orignode2;
} else {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("unknown storage capability type '%s' for '%s'"),
type, def->name);
return -1;
}
}
if (!(storage->flags & VIR_NODE_DEV_CAP_STORAGE_REMOVABLE)) {
val = 0;
if (virNodeDevCapsDefParseULongLong("number(./size[1])", ctxt, &val, def,
_("no size supplied for '%s'"),
_("invalid size supplied for '%s'")) < 0)
return -1;
storage->size = val;
}
return 0;
}
static int
virNodeDevCapSCSIParseXML(xmlXPathContextPtr ctxt,
virNodeDeviceDefPtr def,
xmlNodePtr node,
virNodeDevCapSCSIPtr scsi)
{
VIR_XPATH_NODE_AUTORESTORE(ctxt)
ctxt->node = node;
if (virNodeDevCapsDefParseULong("number(./host[1])", ctxt,
&scsi->host, def,
_("no SCSI host ID supplied for '%s'"),
_("invalid SCSI host ID supplied for '%s'")) < 0)
return -1;
if (virNodeDevCapsDefParseULong("number(./bus[1])", ctxt,
&scsi->bus, def,
_("no SCSI bus ID supplied for '%s'"),
_("invalid SCSI bus ID supplied for '%s'")) < 0)
return -1;
if (virNodeDevCapsDefParseULong("number(./target[1])", ctxt,
&scsi->target, def,
_("no SCSI target ID supplied for '%s'"),
_("invalid SCSI target ID supplied for '%s'")) < 0)
return -1;
if (virNodeDevCapsDefParseULong("number(./lun[1])", ctxt,
&scsi->lun, def,
_("no SCSI LUN ID supplied for '%s'"),
_("invalid SCSI LUN ID supplied for '%s'")) < 0)
return -1;
scsi->type = virXPathString("string(./type[1])", ctxt);
return 0;
}
static int
virNodeDevCapSCSITargetParseXML(xmlXPathContextPtr ctxt,
virNodeDeviceDefPtr def,
xmlNodePtr node,
virNodeDevCapSCSITargetPtr scsi_target)
{
VIR_XPATH_NODE_AUTORESTORE(ctxt)
g_autofree xmlNodePtr *nodes = NULL;
int n = 0;
size_t i;
ctxt->node = node;
scsi_target->name = virXPathString("string(./target[1])", ctxt);
if (!scsi_target->name) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("no target name supplied for '%s'"),
def->name);
return -1;
}
if ((n = virXPathNodeSet("./capability", ctxt, &nodes)) < 0)
return -1;
for (i = 0; i < n; ++i) {
g_autofree char *type = NULL;
type = virXMLPropString(nodes[i], "type");
if (!type) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("missing type for SCSI target capability for '%s'"),
def->name);
return -1;
}
if (STREQ(type, "fc_remote_port")) {
scsi_target->flags |= VIR_NODE_DEV_CAP_FLAG_FC_RPORT;
ctxt->node = nodes[i];
if (virNodeDevCapsDefParseString("string(./rport[1])",
ctxt,
&scsi_target->rport) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("missing rport name for '%s'"), def->name);
return -1;
}
if (virNodeDevCapsDefParseString("string(./wwpn[1])",
ctxt, &scsi_target->wwpn) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("missing wwpn identifier for '%s'"),
def->name);
return -1;
}
} else {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("unknown SCSI target capability type '%s' for '%s'"),
type, def->name);
return -1;
}
}
return 0;
}
static int
virNodeDevCapSCSIHostParseXML(xmlXPathContextPtr ctxt,
virNodeDeviceDefPtr def,
xmlNodePtr node,
virNodeDevCapSCSIHostPtr scsi_host,
int create,
const char *virt_type)
{
VIR_XPATH_NODE_AUTORESTORE(ctxt)
g_autofree xmlNodePtr *nodes = NULL;
int n = 0;
size_t i;
ctxt->node = node;
if (create == EXISTING_DEVICE) {
if (virNodeDevCapsDefParseULong("number(./host[1])", ctxt,
&scsi_host->host, def,
_("no SCSI host ID supplied for '%s'"),
_("invalid SCSI host ID supplied for '%s'")) < 0) {
return -1;
}
/* Optional unique_id value */
scsi_host->unique_id = -1;
if (virNodeDevCapsDefParseIntOptional("number(./unique_id[1])", ctxt,
&scsi_host->unique_id, def,
_("invalid unique_id supplied for '%s'")) < 0) {
return -1;
}
}
if ((n = virXPathNodeSet("./capability", ctxt, &nodes)) < 0)
return -1;
for (i = 0; i < n; i++) {
g_autofree char *type = NULL;
type = virXMLPropString(nodes[i], "type");
if (!type) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("missing SCSI host capability type for '%s'"),
def->name);
return -1;
}
if (STREQ(type, "vport_ops")) {
scsi_host->flags |= VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS;
} else if (STREQ(type, "fc_host")) {
scsi_host->flags |= VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST;
ctxt->node = nodes[i];
if (virNodeDevCapsDefParseString("string(./wwnn[1])",
ctxt,
&scsi_host->wwnn) < 0) {
if (virRandomGenerateWWN(&scsi_host->wwnn, virt_type) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("no WWNN supplied for '%s', and "
"auto-generation failed"),
def->name);
return -1;
}
}
if (virNodeDevCapsDefParseString("string(./wwpn[1])",
ctxt,
&scsi_host->wwpn) < 0) {
if (virRandomGenerateWWN(&scsi_host->wwpn, virt_type) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("no WWPN supplied for '%s', and "
"auto-generation failed"),
def->name);
return -1;
}
}
if (virNodeDevCapsDefParseString("string(./fabric_wwn[1])",
ctxt,
&scsi_host->fabric_wwn) < 0)
VIR_DEBUG("No fabric_wwn defined for '%s'", def->name);
} else {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("unknown SCSI host capability type '%s' for '%s'"),
type, def->name);
return -1;
}
}
return 0;
}
static int
virNodeDevCapNetParseXML(xmlXPathContextPtr ctxt,
virNodeDeviceDefPtr def,
xmlNodePtr node,
virNodeDevCapNetPtr net)
{
VIR_XPATH_NODE_AUTORESTORE(ctxt)
xmlNodePtr lnk;
size_t i = -1;
int n = -1;
g_autofree char *type = NULL;
g_autofree xmlNodePtr *nodes = NULL;
ctxt->node = node;
net->ifname = virXPathString("string(./interface[1])", ctxt);
if (!net->ifname) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("no network interface supplied for '%s'"),
def->name);
return -1;
}
net->address = virXPathString("string(./address[1])", ctxt);
if ((n = virXPathNodeSet("./feature", ctxt, &nodes)) < 0)
return -1;
if (n > 0)
net->features = virBitmapNew(VIR_NET_DEV_FEAT_LAST);
for (i = 0; i < n; i++) {
g_autofree char *tmp = NULL;
int val;
if (!(tmp = virXMLPropString(nodes[i], "name"))) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("missing network device feature name"));
return -1;
}
if ((val = virNetDevFeatureTypeFromString(tmp)) < 0) {
virReportError(VIR_ERR_XML_ERROR,
_("unknown network device feature '%s'"),
tmp);
return -1;
}
ignore_value(virBitmapSetBit(net->features, val));
}
net->subtype = VIR_NODE_DEV_CAP_NET_LAST;
type = virXPathString("string(./capability/@type)", ctxt);
if (type) {
int val = virNodeDevNetCapTypeFromString(type);
if (val < 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("invalid network type supplied for '%s'"),
def->name);
return -1;
}
net->subtype = val;
}
lnk = virXPathNode("./link", ctxt);
if (lnk && virInterfaceLinkParseXML(lnk, &net->lnk) < 0)
return -1;
return 0;
}
static int
virNodeDevCapUSBInterfaceParseXML(xmlXPathContextPtr ctxt,
virNodeDeviceDefPtr def,
xmlNodePtr node,
virNodeDevCapUSBIfPtr usb_if)
{
VIR_XPATH_NODE_AUTORESTORE(ctxt)
ctxt->node = node;
if (virNodeDevCapsDefParseULong("number(./number[1])", ctxt,
&usb_if->number, def,
_("no USB interface number supplied for '%s'"),
_("invalid USB interface number supplied for '%s'")) < 0)
return -1;
if (virNodeDevCapsDefParseULong("number(./class[1])", ctxt,
&usb_if->klass, def,
_("no USB interface class supplied for '%s'"),
_("invalid USB interface class supplied for '%s'")) < 0)
return -1;
if (virNodeDevCapsDefParseULong("number(./subclass[1])", ctxt,
&usb_if->subclass, def,
_("no USB interface subclass supplied for '%s'"),
_("invalid USB interface subclass supplied for '%s'")) < 0)
return -1;
if (virNodeDevCapsDefParseULong("number(./protocol[1])", ctxt,
&usb_if->protocol, def,
_("no USB interface protocol supplied for '%s'"),
_("invalid USB interface protocol supplied for '%s'")) < 0)
return -1;
usb_if->description = virXPathString("string(./description[1])", ctxt);
return 0;
}
static int
virNodeDevCapsDefParseHexId(const char *xpath,
xmlXPathContextPtr ctxt,
unsigned *value,
virNodeDeviceDefPtr def,
const char *missing_error_fmt,
const char *invalid_error_fmt)
{
int ret;
unsigned long val;
ret = virXPathULongHex(xpath, ctxt, &val);
if (ret < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
ret == -1 ? missing_error_fmt : invalid_error_fmt,
def->name);
return -1;
}
*value = val;
return 0;
}
static int
virNodeDevCapUSBDevParseXML(xmlXPathContextPtr ctxt,
virNodeDeviceDefPtr def,
xmlNodePtr node,
virNodeDevCapUSBDevPtr usb_dev)
{
VIR_XPATH_NODE_AUTORESTORE(ctxt)
ctxt->node = node;
if (virNodeDevCapsDefParseULong("number(./bus[1])", ctxt,
&usb_dev->bus, def,
_("no USB bus number supplied for '%s'"),
_("invalid USB bus number supplied for '%s'")) < 0)
return -1;
if (virNodeDevCapsDefParseULong("number(./device[1])", ctxt,
&usb_dev->device, def,
_("no USB device number supplied for '%s'"),
_("invalid USB device number supplied for '%s'")) < 0)
return -1;
if (virNodeDevCapsDefParseHexId("string(./vendor[1]/@id)", ctxt,
&usb_dev->vendor, def,
_("no USB vendor ID supplied for '%s'"),
_("invalid USB vendor ID supplied for '%s'")) < 0)
return -1;
if (virNodeDevCapsDefParseHexId("string(./product[1]/@id)", ctxt,
&usb_dev->product, def,
_("no USB product ID supplied for '%s'"),
_("invalid USB product ID supplied for '%s'")) < 0)
return -1;
usb_dev->vendor_name = virXPathString("string(./vendor[1])", ctxt);
usb_dev->product_name = virXPathString("string(./product[1])", ctxt);
return 0;
}
static int
virNodeDevCapPCIDevIommuGroupParseXML(xmlXPathContextPtr ctxt,
xmlNodePtr iommuGroupNode,
virNodeDevCapPCIDevPtr pci_dev)
{
VIR_XPATH_NODE_AUTORESTORE(ctxt)
g_autofree xmlNodePtr *addrNodes = NULL;
g_autofree char *numberStr = NULL;
int nAddrNodes;
size_t i;
ctxt->node = iommuGroupNode;
numberStr = virXMLPropString(iommuGroupNode, "number");
if (!numberStr) {
virReportError(VIR_ERR_XML_ERROR,
"%s", _("missing iommuGroup number attribute"));
return -1;
}
if (virStrToLong_ui(numberStr, NULL, 10,
&pci_dev->iommuGroupNumber) < 0) {
virReportError(VIR_ERR_XML_ERROR,
_("invalid iommuGroup number attribute '%s'"),
numberStr);
return -1;
}
if ((nAddrNodes = virXPathNodeSet("./address", ctxt, &addrNodes)) < 0)
return -1;
for (i = 0; i < nAddrNodes; i++) {
g_autoptr(virPCIDeviceAddress) pciAddr = g_new0(virPCIDeviceAddress, 1);
if (virPCIDeviceAddressParseXML(addrNodes[i], pciAddr) < 0)
return -1;
if (VIR_APPEND_ELEMENT(pci_dev->iommuGroupDevices,
pci_dev->nIommuGroupDevices,
pciAddr) < 0)
return -1;
}
return 0;
}
static int
virPCIEDeviceInfoLinkParseXML(xmlXPathContextPtr ctxt,
xmlNodePtr linkNode,
virPCIELinkPtr lnk)
{
VIR_XPATH_NODE_AUTORESTORE(ctxt)
int speed;
g_autofree char *speedStr = NULL;
g_autofree char *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"));
return -1;
}
if ((speedStr = virXPathString("string(./@speed)", ctxt))) {
if ((speed = virPCIELinkSpeedTypeFromString(speedStr)) < 0) {
virReportError(VIR_ERR_XML_DETAIL,
_("malformed 'speed' attribute: %s"),
speedStr);
return -1;
}
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);
return -1;
}
} else {
lnk->port = -1;
}
return 0;
}
static int
virPCIEDeviceInfoParseXML(xmlXPathContextPtr ctxt,
xmlNodePtr pciExpressNode,
virPCIEDeviceInfoPtr pci_express)
{
VIR_XPATH_NODE_AUTORESTORE(ctxt)
xmlNodePtr lnk;
ctxt->node = pciExpressNode;
if ((lnk = virXPathNode("./link[@validity='cap']", ctxt))) {
pci_express->link_cap = g_new0(virPCIELink, 1);
if (virPCIEDeviceInfoLinkParseXML(ctxt, lnk,
pci_express->link_cap) < 0)
return -1;
}
if ((lnk = virXPathNode("./link[@validity='sta']", ctxt))) {
pci_express->link_sta = g_new0(virPCIELink, 1);
if (virPCIEDeviceInfoLinkParseXML(ctxt, lnk,
pci_express->link_sta) < 0)
return -1;
}
return 0;
}
static int
virNodeDevPCICapSRIOVPhysicalParseXML(xmlXPathContextPtr ctxt,
virNodeDevCapPCIDevPtr pci_dev)
{
xmlNodePtr address = virXPathNode("./address[1]", ctxt);
pci_dev->physical_function = g_new0(virPCIDeviceAddress, 1);
if (!address) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("Missing address in 'phys_function' capability"));
return -1;
}
if (virPCIDeviceAddressParseXML(address,
pci_dev->physical_function) < 0)
return -1;
pci_dev->flags |= VIR_NODE_DEV_CAP_FLAG_PCI_PHYSICAL_FUNCTION;
return 0;
}
static int
virNodeDevPCICapSRIOVVirtualParseXML(xmlXPathContextPtr ctxt,
virNodeDevCapPCIDevPtr pci_dev)
{
g_autofree xmlNodePtr *addresses = NULL;
int naddresses = virXPathNodeSet("./address", ctxt, &addresses);
g_autofree char *maxFuncsStr = virXPathString("string(./@maxCount)", ctxt);
size_t i;
if (naddresses < 0)
return -1;
if (maxFuncsStr &&
virStrToLong_uip(maxFuncsStr, NULL, 10,
&pci_dev->max_virtual_functions) < 0) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("Malformed 'maxCount' parameter"));
return -1;
}
pci_dev->virtual_functions = g_new0(virPCIDeviceAddressPtr, naddresses);
for (i = 0; i < naddresses; i++) {
g_autoptr(virPCIDeviceAddress) addr = NULL;
addr = g_new0(virPCIDeviceAddress, 1);
if (virPCIDeviceAddressParseXML(addresses[i], addr) < 0)
return -1;
if (VIR_APPEND_ELEMENT(pci_dev->virtual_functions,
pci_dev->num_virtual_functions,
addr) < 0)
return -1;
}
pci_dev->flags |= VIR_NODE_DEV_CAP_FLAG_PCI_VIRTUAL_FUNCTION;
return 0;
}
static int
virNodeDevPCICapabilityParseXML(xmlXPathContextPtr ctxt,
xmlNodePtr node,
virNodeDevCapPCIDevPtr pci_dev)
{
g_autofree char *type = virXMLPropString(node, "type");
VIR_XPATH_NODE_AUTORESTORE(ctxt)
ctxt->node = node;
if (!type) {
virReportError(VIR_ERR_XML_ERROR, "%s", _("Missing capability type"));
return -1;
}
if (STREQ(type, "phys_function") &&
virNodeDevPCICapSRIOVPhysicalParseXML(ctxt, pci_dev) < 0) {
return -1;
} else if (STREQ(type, "virt_functions") &&
virNodeDevPCICapSRIOVVirtualParseXML(ctxt, pci_dev) < 0) {
return -1;
} else if (STREQ(type, "mdev_types")) {
if (virNodeDevCapMdevTypesParseXML(ctxt,
&pci_dev->mdev_types,
&pci_dev->nmdev_types) < 0)
return -1;
pci_dev->flags |= VIR_NODE_DEV_CAP_FLAG_PCI_MDEV;
} else {
int hdrType = virPCIHeaderTypeFromString(type);
if (hdrType > 0 && !pci_dev->hdrType)
pci_dev->hdrType = hdrType;
}
return 0;
}
static int
virNodeDevCapPCIDevParseXML(xmlXPathContextPtr ctxt,
virNodeDeviceDefPtr def,
xmlNodePtr node,
virNodeDevCapPCIDevPtr pci_dev)
{
VIR_XPATH_NODE_AUTORESTORE(ctxt)
xmlNodePtr iommuGroupNode;
xmlNodePtr pciExpress;
g_autofree xmlNodePtr *nodes = NULL;
int n = 0;
int ret = -1;
virPCIEDeviceInfoPtr pci_express = NULL;
g_autofree char *tmp = NULL;
size_t i = 0;
ctxt->node = node;
if ((tmp = virXPathString("string(./class[1])", ctxt))) {
if (virStrToLong_i(tmp, NULL, 16, &pci_dev->klass) < 0 ||
pci_dev->klass > 0xffffff) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("invalid PCI class supplied for '%s'"), def->name);
goto out;
}
} else {
pci_dev->klass = -1;
}
if (virNodeDevCapsDefParseULong("number(./domain[1])", ctxt,
&pci_dev->domain, def,
_("no PCI domain ID supplied for '%s'"),
_("invalid PCI domain ID supplied for '%s'")) < 0)
goto out;
if (virNodeDevCapsDefParseULong("number(./bus[1])", ctxt,
&pci_dev->bus, def,
_("no PCI bus ID supplied for '%s'"),
_("invalid PCI bus ID supplied for '%s'")) < 0)
goto out;
if (virNodeDevCapsDefParseULong("number(./slot[1])", ctxt,
&pci_dev->slot, def,
_("no PCI slot ID supplied for '%s'"),
_("invalid PCI slot ID supplied for '%s'")) < 0)
goto out;
if (virNodeDevCapsDefParseULong("number(./function[1])", ctxt,
&pci_dev->function, def,
_("no PCI function ID supplied for '%s'"),
_("invalid PCI function ID supplied for '%s'")) < 0)
goto out;
if (virNodeDevCapsDefParseHexId("string(./vendor[1]/@id)", ctxt,
&pci_dev->vendor, def,
_("no PCI vendor ID supplied for '%s'"),
_("invalid PCI vendor ID supplied for '%s'")) < 0)
goto out;
if (virNodeDevCapsDefParseHexId("string(./product[1]/@id)", ctxt,
&pci_dev->product, def,
_("no PCI product ID supplied for '%s'"),
_("invalid PCI product ID supplied for '%s'")) < 0)
goto out;
pci_dev->vendor_name = virXPathString("string(./vendor[1])", ctxt);
pci_dev->product_name = virXPathString("string(./product[1])", ctxt);
if ((n = virXPathNodeSet("./capability", ctxt, &nodes)) < 0)
goto out;
for (i = 0; i < n; i++) {
if (virNodeDevPCICapabilityParseXML(ctxt, nodes[i], pci_dev) < 0)
goto out;
}
if ((iommuGroupNode = virXPathNode("./iommuGroup[1]", ctxt))) {
if (virNodeDevCapPCIDevIommuGroupParseXML(ctxt, iommuGroupNode,
pci_dev) < 0) {
goto out;
}
}
/* The default value is -1 since zero is valid NUMA node number */
pci_dev->numa_node = -1;
if (virNodeDevCapsDefParseIntOptional("number(./numa[1]/@node)", ctxt,
&pci_dev->numa_node, def,
_("invalid NUMA node ID supplied for '%s'")) < 0)
goto out;
if ((pciExpress = virXPathNode("./pci-express[1]", ctxt))) {
pci_express = g_new0(virPCIEDeviceInfo, 1);
if (virPCIEDeviceInfoParseXML(ctxt, pciExpress, pci_express) < 0)
goto out;
pci_dev->pci_express = g_steal_pointer(&pci_express);
pci_dev->flags |= VIR_NODE_DEV_CAP_FLAG_PCIE;
}
ret = 0;
out:
virPCIEDeviceInfoFree(pci_express);
return ret;
}
static int
virNodeDevCapSystemParseXML(xmlXPathContextPtr ctxt,
virNodeDeviceDefPtr def,
xmlNodePtr node,
virNodeDevCapSystemPtr syscap)
{
virNodeDevCapSystemHardwarePtr hardware = &syscap->hardware;
virNodeDevCapSystemFirmwarePtr firmware = &syscap->firmware;
VIR_XPATH_NODE_AUTORESTORE(ctxt)
g_autofree char *tmp = NULL;
ctxt->node = node;
syscap->product_name = virXPathString("string(./product[1])", ctxt);
hardware->vendor_name = virXPathString("string(./hardware/vendor[1])", ctxt);
hardware->version = virXPathString("string(./hardware/version[1])", ctxt);
hardware->serial = virXPathString("string(./hardware/serial[1])", ctxt);
tmp = virXPathString("string(./hardware/uuid[1])", ctxt);
if (!tmp) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("no system UUID supplied for '%s'"), def->name);
return -1;
}
if (virUUIDParse(tmp, hardware->uuid) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("malformed uuid element for '%s'"), def->name);
return -1;
}
firmware->vendor_name = virXPathString("string(./firmware/vendor[1])", ctxt);
firmware->version = virXPathString("string(./firmware/version[1])", ctxt);
firmware->release_date = virXPathString("string(./firmware/release_date[1])", ctxt);
return 0;
}
static int
virNodeDevCapMdevAttributeParseXML(xmlXPathContextPtr ctxt,
xmlNodePtr node,
virNodeDevCapMdevPtr mdev)
{
VIR_XPATH_NODE_AUTORESTORE(ctxt)
g_autoptr(virMediatedDeviceAttr) attr = virMediatedDeviceAttrNew();
ctxt->node = node;
attr->name = virXPathString("string(./@name)", ctxt);
attr->value = virXPathString("string(./@value)", ctxt);
if (!attr->name || !attr->value) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("mdev attribute missing name or value"));
return -1;
}
return VIR_APPEND_ELEMENT(mdev->attributes,
mdev->nattributes,
attr);
}
static int
virNodeDevCapMdevParseXML(xmlXPathContextPtr ctxt,
virNodeDeviceDefPtr def,
xmlNodePtr node,
virNodeDevCapMdevPtr mdev)
{
VIR_XPATH_NODE_AUTORESTORE(ctxt)
int nattrs = 0;
g_autofree xmlNodePtr *attrs = NULL;
size_t i;
ctxt->node = node;
if (!(mdev->type = virXPathString("string(./type[1]/@id)", ctxt))) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("missing type id attribute for '%s'"), def->name);
return -1;
}
/* 'iommuGroup' is optional, only report an error if the supplied value is
* invalid (-2), not if it's missing (-1) */
if (virXPathUInt("number(./iommuGroup[1]/@number)",
ctxt, &mdev->iommuGroupNumber) < -1) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("invalid iommuGroup number attribute for '%s'"),
def->name);
return -1;
}
if ((nattrs = virXPathNodeSet("./attr", ctxt, &attrs)) < 0)
return -1;
for (i = 0; i < nattrs; i++)
virNodeDevCapMdevAttributeParseXML(ctxt, attrs[i], mdev);
return 0;
}
static virNodeDevCapsDefPtr
virNodeDevCapsDefParseXML(xmlXPathContextPtr ctxt,
virNodeDeviceDefPtr def,
xmlNodePtr node,
int create,
const char *virt_type)
{
virNodeDevCapsDefPtr caps;
g_autofree char *tmp = NULL;
int val, ret = -1;
caps = g_new0(virNodeDevCapsDef, 1);
tmp = virXMLPropString(node, "type");
if (!tmp) {
virReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("missing capability type"));
goto error;
}
if ((val = virNodeDevCapTypeFromString(tmp)) < 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("unknown capability type '%s'"), tmp);
goto error;
}
caps->data.type = val;
switch (caps->data.type) {
case VIR_NODE_DEV_CAP_SYSTEM:
ret = virNodeDevCapSystemParseXML(ctxt, def, node, &caps->data.system);
break;
case VIR_NODE_DEV_CAP_PCI_DEV:
ret = virNodeDevCapPCIDevParseXML(ctxt, def, node, &caps->data.pci_dev);
break;
case VIR_NODE_DEV_CAP_USB_DEV:
ret = virNodeDevCapUSBDevParseXML(ctxt, def, node, &caps->data.usb_dev);
break;
case VIR_NODE_DEV_CAP_USB_INTERFACE:
ret = virNodeDevCapUSBInterfaceParseXML(ctxt, def, node,
&caps->data.usb_if);
break;
case VIR_NODE_DEV_CAP_NET:
ret = virNodeDevCapNetParseXML(ctxt, def, node, &caps->data.net);
break;
case VIR_NODE_DEV_CAP_SCSI_HOST:
ret = virNodeDevCapSCSIHostParseXML(ctxt, def, node,
&caps->data.scsi_host,
create,
virt_type);
break;
case VIR_NODE_DEV_CAP_SCSI_TARGET:
ret = virNodeDevCapSCSITargetParseXML(ctxt, def, node,
&caps->data.scsi_target);
break;
case VIR_NODE_DEV_CAP_SCSI:
ret = virNodeDevCapSCSIParseXML(ctxt, def, node, &caps->data.scsi);
break;
case VIR_NODE_DEV_CAP_STORAGE:
ret = virNodeDevCapStorageParseXML(ctxt, def, node,
&caps->data.storage);
break;
case VIR_NODE_DEV_CAP_DRM:
ret = virNodeDevCapDRMParseXML(ctxt, def, node, &caps->data.drm);
break;
case VIR_NODE_DEV_CAP_MDEV:
ret = virNodeDevCapMdevParseXML(ctxt, def, node, &caps->data.mdev);
break;
case VIR_NODE_DEV_CAP_CCW_DEV:
case VIR_NODE_DEV_CAP_CSS_DEV:
ret = virNodeDevCapCCWParseXML(ctxt, def, node, &caps->data.ccw_dev);
break;
case VIR_NODE_DEV_CAP_AP_CARD:
ret = virNodeDevCapAPCardParseXML(ctxt, def, node,
&caps->data.ap_card);
break;
case VIR_NODE_DEV_CAP_AP_QUEUE:
ret = virNodeDevCapAPQueueParseXML(ctxt, def, node,
&caps->data.ap_queue);
break;
case VIR_NODE_DEV_CAP_AP_MATRIX:
ret = virNodeDevCapAPMatrixParseXML(ctxt, def, node,
&caps->data.ap_matrix);
break;
case VIR_NODE_DEV_CAP_MDEV_TYPES:
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_VDPA:
case VIR_NODE_DEV_CAP_LAST:
virReportError(VIR_ERR_INTERNAL_ERROR,
_("unknown capability type '%d' for '%s'"),
caps->data.type, def->name);
ret = -1;
break;
}
if (ret < 0)
goto error;
return caps;
error:
virNodeDevCapsDefFree(caps);
return NULL;
}
static virNodeDeviceDefPtr
virNodeDeviceDefParseXML(xmlXPathContextPtr ctxt,
int create,
const char *virt_type)
{
virNodeDeviceDefPtr def;
virNodeDevCapsDefPtr *next_cap;
xmlNodePtr *nodes = NULL;
int n, m;
size_t i;
def = g_new0(virNodeDeviceDef, 1);
/* Extract device name */
if (create == EXISTING_DEVICE) {
def->name = virXPathString("string(./name[1])", ctxt);
if (!def->name) {
virReportError(VIR_ERR_NO_NAME, NULL);
goto error;
}
} else {
def->name = g_strdup("new device");
}
def->sysfs_path = virXPathString("string(./path[1])", ctxt);
/* Parse devnodes */
if ((n = virXPathNodeSet("./devnode", ctxt, &nodes)) < 0)
goto error;
def->devlinks = g_new0(char *, n + 1);
for (i = 0, m = 0; i < n; i++) {
xmlNodePtr node = nodes[i];
g_autofree char *tmp = virXMLPropString(node, "type");
int val;
if (!tmp) {
virReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("missing devnode type"));
goto error;
}
val = virNodeDevDevnodeTypeFromString(tmp);
if (val < 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("unknown devnode type '%s'"), tmp);
goto error;
}
switch ((virNodeDevDevnodeType)val) {
case VIR_NODE_DEV_DEVNODE_DEV:
if (!(def->devnode = virXMLNodeContentString(node)))
goto error;
break;
case VIR_NODE_DEV_DEVNODE_LINK:
if (!(def->devlinks[m++] = virXMLNodeContentString(node)))
goto error;
break;
case VIR_NODE_DEV_DEVNODE_LAST:
break;
}
}
/* Extract device parent, if any */
def->parent = virXPathString("string(./parent[1])", ctxt);
nodedev: Add the ability to create vHBA by parent wwnn/wwpn or fabric_wwn https://bugzilla.redhat.com/show_bug.cgi?id=1349696 When creating a vHBA, the process is to feed XML to nodeDeviceCreateXML that lists the <parent> scsi_hostX to use to create the vHBA. However, between reboots, it's possible that the <parent> changes its scsi_hostX to scsi_hostY and saved XML to perform the creation will either fail or create a vHBA using the wrong parent. So add the ability to provide "wwnn" and "wwpn" or "fabric_wwn" to the <parent> instead of a name of the scsi_hostN that is the parent. The allowed XML will thus be: <parent>scsi_host3</parent> (current) or <parent wwnn='$WWNN' wwpn='$WWPN'/> or <parent fabric_wwn='$WWNN'/> Using the wwnn/wwpn or fabric_wwn ensures the same 'scsi_hostN' is selected between hardware reconfigs or host reboots. The fabric_wwn Using the wwnn/wwpn pair will provide the most specific search option, while fabric_wwn will at least ensure usage of the same SAN, but maybe not the same scsi_hostN. This patch will add the new fields to the nodedev.rng for input purposes only since the input XML is essentially thrown away, no need to Format the values since they'd already be printed as part of the scsi_host data block. New API virNodeDeviceGetParentHostByWWNs will take the parent "wwnn" and "wwpn" in order to search the list of devices for matching capability data fields wwnn and wwpn. New API virNodeDeviceGetParentHostByFabricWWN will take the parent "fabric_wwn" in order to search the list of devices for matching capability data field fabric_wwn.
2016-11-17 16:09:09 +00:00
def->parent_wwnn = virXPathString("string(./parent[1]/@wwnn)", ctxt);
def->parent_wwpn = virXPathString("string(./parent[1]/@wwpn)", ctxt);
if (def->parent_wwnn && !def->parent_wwpn) {
virReportError(VIR_ERR_XML_ERROR,
_("when providing parent wwnn='%s', the "
"wwpn must also be provided"),
def->parent_wwnn);
goto error;
}
if (!def->parent_wwnn && def->parent_wwpn) {
virReportError(VIR_ERR_XML_ERROR,
_("when providing parent wwpn='%s', the "
"wwnn must also be provided"),
def->parent_wwpn);
nodedev: Add the ability to create vHBA by parent wwnn/wwpn or fabric_wwn https://bugzilla.redhat.com/show_bug.cgi?id=1349696 When creating a vHBA, the process is to feed XML to nodeDeviceCreateXML that lists the <parent> scsi_hostX to use to create the vHBA. However, between reboots, it's possible that the <parent> changes its scsi_hostX to scsi_hostY and saved XML to perform the creation will either fail or create a vHBA using the wrong parent. So add the ability to provide "wwnn" and "wwpn" or "fabric_wwn" to the <parent> instead of a name of the scsi_hostN that is the parent. The allowed XML will thus be: <parent>scsi_host3</parent> (current) or <parent wwnn='$WWNN' wwpn='$WWPN'/> or <parent fabric_wwn='$WWNN'/> Using the wwnn/wwpn or fabric_wwn ensures the same 'scsi_hostN' is selected between hardware reconfigs or host reboots. The fabric_wwn Using the wwnn/wwpn pair will provide the most specific search option, while fabric_wwn will at least ensure usage of the same SAN, but maybe not the same scsi_hostN. This patch will add the new fields to the nodedev.rng for input purposes only since the input XML is essentially thrown away, no need to Format the values since they'd already be printed as part of the scsi_host data block. New API virNodeDeviceGetParentHostByWWNs will take the parent "wwnn" and "wwpn" in order to search the list of devices for matching capability data fields wwnn and wwpn. New API virNodeDeviceGetParentHostByFabricWWN will take the parent "fabric_wwn" in order to search the list of devices for matching capability data field fabric_wwn.
2016-11-17 16:09:09 +00:00
goto error;
}
def->parent_fabric_wwn = virXPathString("string(./parent[1]/@fabric_wwn)",
ctxt);
/* Parse device capabilities */
VIR_FREE(nodes);
if ((n = virXPathNodeSet("./capability", ctxt, &nodes)) < 0)
goto error;
if (n == 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("no device capabilities for '%s'"),
def->name);
goto error;
}
next_cap = &def->caps;
for (i = 0; i < n; i++) {
*next_cap = virNodeDevCapsDefParseXML(ctxt, def,
nodes[i],
create,
virt_type);
if (!*next_cap)
goto error;
next_cap = &(*next_cap)->next;
}
VIR_FREE(nodes);
return def;
error:
virNodeDeviceDefFree(def);
VIR_FREE(nodes);
return NULL;
}
virNodeDeviceDefPtr
virNodeDeviceDefParseNode(xmlDocPtr xml,
xmlNodePtr root,
int create,
const char *virt_type)
{
g_autoptr(xmlXPathContext) ctxt = NULL;
if (!virXMLNodeNameEqual(root, "device")) {
virReportError(VIR_ERR_XML_ERROR,
_("unexpected root element <%s> "
"expecting <device>"),
root->name);
return NULL;
}
if (!(ctxt = virXMLXPathContextNew(xml)))
return NULL;
ctxt->node = root;
return virNodeDeviceDefParseXML(ctxt, create, virt_type);
}
static virNodeDeviceDefPtr
virNodeDeviceDefParse(const char *str,
const char *filename,
int create,
const char *virt_type)
{
2010-02-24 20:53:16 +00:00
xmlDocPtr xml;
virNodeDeviceDefPtr def = NULL;
if ((xml = virXMLParse(filename, str, _("(node_device_definition)")))) {
def = virNodeDeviceDefParseNode(xml, xmlDocGetRootElement(xml),
create, virt_type);
2010-02-24 20:53:16 +00:00
xmlFreeDoc(xml);
}
return def;
}
virNodeDeviceDefPtr
virNodeDeviceDefParseString(const char *str,
int create,
const char *virt_type)
{
return virNodeDeviceDefParse(str, NULL, create, virt_type);
}
virNodeDeviceDefPtr
virNodeDeviceDefParseFile(const char *filename,
int create,
const char *virt_type)
{
return virNodeDeviceDefParse(NULL, filename, create, virt_type);
}
/*
* Return fc_host dev's WWNN and WWPN
*/
int
virNodeDeviceGetWWNs(virNodeDeviceDefPtr def,
char **wwnn,
char **wwpn)
{
virNodeDevCapsDefPtr cap = NULL;
cap = def->caps;
while (cap != NULL) {
if (cap->data.type == VIR_NODE_DEV_CAP_SCSI_HOST &&
cap->data.scsi_host.flags & VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST) {
*wwnn = g_strdup(cap->data.scsi_host.wwnn);
*wwpn = g_strdup(cap->data.scsi_host.wwpn);
break;
}
cap = cap->next;
}
if (cap == NULL) {
virReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("Device is not a fibre channel HBA"));
return -1;
}
return 0;
}
void
virNodeDevCapsDefFree(virNodeDevCapsDefPtr caps)
{
size_t i = 0;
virNodeDevCapDataPtr data = &caps->data;
switch (caps->data.type) {
case VIR_NODE_DEV_CAP_SYSTEM:
g_free(data->system.product_name);
g_free(data->system.hardware.vendor_name);
g_free(data->system.hardware.version);
g_free(data->system.hardware.serial);
g_free(data->system.firmware.vendor_name);
g_free(data->system.firmware.version);
g_free(data->system.firmware.release_date);
break;
case VIR_NODE_DEV_CAP_PCI_DEV:
g_free(data->pci_dev.product_name);
g_free(data->pci_dev.vendor_name);
g_free(data->pci_dev.physical_function);
for (i = 0; i < data->pci_dev.num_virtual_functions; i++)
g_free(data->pci_dev.virtual_functions[i]);
g_free(data->pci_dev.virtual_functions);
for (i = 0; i < data->pci_dev.nIommuGroupDevices; i++)
g_free(data->pci_dev.iommuGroupDevices[i]);
g_free(data->pci_dev.iommuGroupDevices);
virPCIEDeviceInfoFree(data->pci_dev.pci_express);
for (i = 0; i < data->pci_dev.nmdev_types; i++)
virMediatedDeviceTypeFree(data->pci_dev.mdev_types[i]);
g_free(data->pci_dev.mdev_types);
break;
case VIR_NODE_DEV_CAP_USB_DEV:
g_free(data->usb_dev.product_name);
g_free(data->usb_dev.vendor_name);
break;
case VIR_NODE_DEV_CAP_USB_INTERFACE:
g_free(data->usb_if.description);
break;
case VIR_NODE_DEV_CAP_NET:
g_free(data->net.ifname);
g_free(data->net.address);
virBitmapFree(data->net.features);
break;
case VIR_NODE_DEV_CAP_SCSI_HOST:
g_free(data->scsi_host.wwnn);
g_free(data->scsi_host.wwpn);
g_free(data->scsi_host.fabric_wwn);
break;
case VIR_NODE_DEV_CAP_SCSI_TARGET:
g_free(data->scsi_target.name);
g_free(data->scsi_target.rport);
g_free(data->scsi_target.wwpn);
break;
case VIR_NODE_DEV_CAP_SCSI:
g_free(data->scsi.type);
break;
case VIR_NODE_DEV_CAP_STORAGE:
g_free(data->storage.block);
g_free(data->storage.bus);
g_free(data->storage.drive_type);
g_free(data->storage.model);
g_free(data->storage.vendor);
g_free(data->storage.serial);
g_free(data->storage.media_label);
break;
case VIR_NODE_DEV_CAP_SCSI_GENERIC:
g_free(data->sg.path);
break;
case VIR_NODE_DEV_CAP_MDEV:
g_free(data->mdev.type);
g_free(data->mdev.uuid);
for (i = 0; i < data->mdev.nattributes; i++)
virMediatedDeviceAttrFree(data->mdev.attributes[i]);
g_free(data->mdev.attributes);
break;
case VIR_NODE_DEV_CAP_CSS_DEV:
for (i = 0; i < data->ccw_dev.nmdev_types; i++)
virMediatedDeviceTypeFree(data->ccw_dev.mdev_types[i]);
g_free(data->ccw_dev.mdev_types);
break;
case VIR_NODE_DEV_CAP_AP_MATRIX:
g_free(data->ap_matrix.addr);
for (i = 0; i < data->ap_matrix.nmdev_types; i++)
virMediatedDeviceTypeFree(data->ap_matrix.mdev_types[i]);
g_free(data->ap_matrix.mdev_types);
break;
case VIR_NODE_DEV_CAP_MDEV_TYPES:
case VIR_NODE_DEV_CAP_DRM:
case VIR_NODE_DEV_CAP_FC_HOST:
case VIR_NODE_DEV_CAP_VPORTS:
case VIR_NODE_DEV_CAP_CCW_DEV:
case VIR_NODE_DEV_CAP_VDPA:
case VIR_NODE_DEV_CAP_AP_CARD:
case VIR_NODE_DEV_CAP_AP_QUEUE:
case VIR_NODE_DEV_CAP_LAST:
/* This case is here to shutup the compiler */
break;
}
g_free(caps);
}
2008-12-04 20:53:20 +00:00
int
virNodeDeviceUpdateCaps(virNodeDeviceDefPtr def)
{
virNodeDevCapsDefPtr cap = def->caps;
while (cap) {
switch (cap->data.type) {
case VIR_NODE_DEV_CAP_SCSI_HOST:
virNodeDeviceGetSCSIHostCaps(&cap->data.scsi_host);
break;
case VIR_NODE_DEV_CAP_SCSI_TARGET:
virNodeDeviceGetSCSITargetCaps(def->sysfs_path,
&cap->data.scsi_target);
break;
case VIR_NODE_DEV_CAP_NET:
if (virNetDevGetLinkInfo(cap->data.net.ifname,
&cap->data.net.lnk) < 0)
return -1;
virBitmapFree(cap->data.net.features);
if (virNetDevGetFeatures(cap->data.net.ifname,
&cap->data.net.features) < 0)
return -1;
break;
case VIR_NODE_DEV_CAP_PCI_DEV:
if (virNodeDeviceGetPCIDynamicCaps(def->sysfs_path,
&cap->data.pci_dev) < 0)
return -1;
break;
case VIR_NODE_DEV_CAP_CSS_DEV:
if (virNodeDeviceGetCSSDynamicCaps(def->sysfs_path,
&cap->data.ccw_dev) < 0)
return -1;
break;
case VIR_NODE_DEV_CAP_AP_MATRIX:
if (virNodeDeviceGetAPMatrixDynamicCaps(def->sysfs_path,
&cap->data.ap_matrix) < 0)
return -1;
break;
/* all types that (supposedly) don't require any updates
* relative to what's in the cache.
*/
case VIR_NODE_DEV_CAP_DRM:
case VIR_NODE_DEV_CAP_SYSTEM:
case VIR_NODE_DEV_CAP_USB_DEV:
case VIR_NODE_DEV_CAP_USB_INTERFACE:
case VIR_NODE_DEV_CAP_SCSI:
case VIR_NODE_DEV_CAP_STORAGE:
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_MDEV_TYPES:
case VIR_NODE_DEV_CAP_MDEV:
case VIR_NODE_DEV_CAP_CCW_DEV:
case VIR_NODE_DEV_CAP_VDPA:
case VIR_NODE_DEV_CAP_AP_CARD:
case VIR_NODE_DEV_CAP_AP_QUEUE:
case VIR_NODE_DEV_CAP_LAST:
break;
}
cap = cap->next;
}
return 0;
}
/**
* virNodeDeviceCapsListExport:
* @def: node device definition
* @list: pointer to an array to store all supported capabilities by a device
*
* Takes the definition, scans through all the capabilities that the device
* supports (including the nested caps) and populates a newly allocated list
* with them. Caller is responsible for freeing the list.
* If NULL is passed to @list, only the number of caps will be returned.
*
* Returns the number of capabilities the device supports, -1 on error.
*/
int
virNodeDeviceCapsListExport(virNodeDeviceDefPtr def,
virNodeDevCapType **list)
{
virNodeDevCapsDefPtr caps = NULL;
g_autofree virNodeDevCapType *tmp = NULL;
bool want_list = !!list;
int ncaps = 0;
#define MAYBE_ADD_CAP(cap) \
do { \
if (want_list) \
tmp[ncaps] = cap; \
} while (0)
if (virNodeDeviceUpdateCaps(def) < 0)
return -1;
if (want_list)
tmp = g_new0(virNodeDevCapType, VIR_NODE_DEV_CAP_LAST - 1);
for (caps = def->caps; caps; caps = caps->next) {
unsigned int flags;
MAYBE_ADD_CAP(caps->data.type);
ncaps++;
/* check nested caps for a given type as well */
if (caps->data.type == VIR_NODE_DEV_CAP_SCSI_HOST) {
flags = caps->data.scsi_host.flags;
if (flags & VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST) {
MAYBE_ADD_CAP(VIR_NODE_DEV_CAP_FC_HOST);
ncaps++;
}
if (flags & VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS) {
MAYBE_ADD_CAP(VIR_NODE_DEV_CAP_VPORTS);
ncaps++;
}
}
if (caps->data.type == VIR_NODE_DEV_CAP_PCI_DEV) {
flags = caps->data.pci_dev.flags;
if (flags & VIR_NODE_DEV_CAP_FLAG_PCI_MDEV) {
MAYBE_ADD_CAP(VIR_NODE_DEV_CAP_MDEV_TYPES);
ncaps++;
}
}
if (caps->data.type == VIR_NODE_DEV_CAP_CSS_DEV) {
flags = caps->data.ccw_dev.flags;
if (flags & VIR_NODE_DEV_CAP_FLAG_CSS_MDEV) {
MAYBE_ADD_CAP(VIR_NODE_DEV_CAP_MDEV_TYPES);
ncaps++;
}
}
if (caps->data.type == VIR_NODE_DEV_CAP_AP_MATRIX) {
flags = caps->data.ap_matrix.flags;
if (flags & VIR_NODE_DEV_CAP_FLAG_AP_MATRIX_MDEV) {
MAYBE_ADD_CAP(VIR_NODE_DEV_CAP_MDEV_TYPES);
ncaps++;
}
}
}
#undef MAYBE_ADD_CAP
if (want_list)
*list = g_steal_pointer(&tmp);
return ncaps;
}
#ifdef __linux__
int
virNodeDeviceGetSCSIHostCaps(virNodeDevCapSCSIHostPtr scsi_host)
{
g_autofree char *tmp = NULL;
int ret = -1;
if ((scsi_host->unique_id =
virSCSIHostGetUniqueId(NULL, scsi_host->host)) < 0) {
VIR_DEBUG("Failed to read unique_id for host%d", scsi_host->host);
scsi_host->unique_id = -1;
}
VIR_DEBUG("Checking if host%d is an FC HBA", scsi_host->host);
if (virVHBAPathExists(NULL, scsi_host->host)) {
scsi_host->flags |= VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST;
if (!(tmp = virVHBAGetConfig(NULL, scsi_host->host, "port_name"))) {
VIR_WARN("Failed to read WWPN for host%d", scsi_host->host);
goto cleanup;
}
VIR_FREE(scsi_host->wwpn);
scsi_host->wwpn = g_steal_pointer(&tmp);
if (!(tmp = virVHBAGetConfig(NULL, scsi_host->host, "node_name"))) {
VIR_WARN("Failed to read WWNN for host%d", scsi_host->host);
goto cleanup;
}
VIR_FREE(scsi_host->wwnn);
scsi_host->wwnn = g_steal_pointer(&tmp);
if ((tmp = virVHBAGetConfig(NULL, scsi_host->host, "fabric_name"))) {
VIR_FREE(scsi_host->fabric_wwn);
scsi_host->fabric_wwn = g_steal_pointer(&tmp);
}
}
if (virVHBAIsVportCapable(NULL, scsi_host->host)) {
scsi_host->flags |= VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS;
if (!(tmp = virVHBAGetConfig(NULL, scsi_host->host,
"max_npiv_vports"))) {
VIR_WARN("Failed to read max_npiv_vports for host%d",
scsi_host->host);
goto cleanup;
}
if (virStrToLong_i(tmp, NULL, 10, &scsi_host->max_vports) < 0) {
VIR_WARN("Failed to parse value of max_npiv_vports '%s'", tmp);
goto cleanup;
}
if (!(tmp = virVHBAGetConfig(NULL, scsi_host->host,
"npiv_vports_inuse"))) {
VIR_WARN("Failed to read npiv_vports_inuse for host%d",
scsi_host->host);
goto cleanup;
}
if (virStrToLong_i(tmp, NULL, 10, &scsi_host->vports) < 0) {
VIR_WARN("Failed to parse value of npiv_vports_inuse '%s'", tmp);
goto cleanup;
}
}
ret = 0;
cleanup:
if (ret < 0) {
/* Clear the two flags in case of producing confusing XML output */
scsi_host->flags &= ~(VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST |
VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS);
VIR_FREE(scsi_host->wwnn);
VIR_FREE(scsi_host->wwpn);
VIR_FREE(scsi_host->fabric_wwn);
}
return ret;
}
int
virNodeDeviceGetSCSITargetCaps(const char *sysfsPath,
virNodeDevCapSCSITargetPtr scsi_target)
{
int ret = -1;
g_autofree char *dir = NULL;
g_autofree char *rport = NULL;
VIR_DEBUG("Checking if '%s' is an FC remote port", scsi_target->name);
/* /sys/devices/[...]/host0/rport-0:0-0/target0:0:0 -> rport-0:0-0 */
dir = g_path_get_dirname(sysfsPath);
rport = g_path_get_basename(dir);
if (!virFCIsCapableRport(rport))
goto cleanup;
VIR_FREE(scsi_target->rport);
scsi_target->rport = g_steal_pointer(&rport);
if (virFCReadRportValue(scsi_target->rport, "port_name",
&scsi_target->wwpn) < 0) {
VIR_WARN("Failed to read port_name for '%s'", scsi_target->rport);
goto cleanup;
}
scsi_target->flags |= VIR_NODE_DEV_CAP_FLAG_FC_RPORT;
ret = 0;
cleanup:
if (ret < 0) {
VIR_FREE(scsi_target->rport);
VIR_FREE(scsi_target->wwpn);
scsi_target->flags &= ~VIR_NODE_DEV_CAP_FLAG_FC_RPORT;
}
return ret;
}
static int
virNodeDeviceGetPCISRIOVCaps(const char *sysfsPath,
virNodeDevCapPCIDevPtr pci_dev)
{
size_t i;
int ret;
/* this could be a refresh, so clear out the old data */
for (i = 0; i < pci_dev->num_virtual_functions; i++)
VIR_FREE(pci_dev->virtual_functions[i]);
VIR_FREE(pci_dev->virtual_functions);
VIR_FREE(pci_dev->physical_function);
pci_dev->num_virtual_functions = 0;
pci_dev->max_virtual_functions = 0;
pci_dev->flags &= ~VIR_NODE_DEV_CAP_FLAG_PCI_VIRTUAL_FUNCTION;
pci_dev->flags &= ~VIR_NODE_DEV_CAP_FLAG_PCI_PHYSICAL_FUNCTION;
ret = virPCIGetPhysicalFunction(sysfsPath,
&pci_dev->physical_function);
if (ret < 0)
return ret;
if (pci_dev->physical_function)
pci_dev->flags |= VIR_NODE_DEV_CAP_FLAG_PCI_PHYSICAL_FUNCTION;
ret = virPCIGetVirtualFunctions(sysfsPath, &pci_dev->virtual_functions,
&pci_dev->num_virtual_functions,
&pci_dev->max_virtual_functions);
if (ret < 0)
return ret;
if (pci_dev->num_virtual_functions > 0 ||
pci_dev->max_virtual_functions > 0)
pci_dev->flags |= VIR_NODE_DEV_CAP_FLAG_PCI_VIRTUAL_FUNCTION;
return ret;
}
static int
virNodeDeviceGetPCIIOMMUGroupCaps(virNodeDevCapPCIDevPtr pci_dev)
{
size_t i;
int tmpGroup;
virPCIDeviceAddress addr;
/* this could be a refresh, so clear out the old data */
for (i = 0; i < pci_dev->nIommuGroupDevices; i++)
VIR_FREE(pci_dev->iommuGroupDevices[i]);
VIR_FREE(pci_dev->iommuGroupDevices);
pci_dev->nIommuGroupDevices = 0;
pci_dev->iommuGroupNumber = 0;
addr.domain = pci_dev->domain;
addr.bus = pci_dev->bus;
addr.slot = pci_dev->slot;
addr.function = pci_dev->function;
tmpGroup = virPCIDeviceAddressGetIOMMUGroupNum(&addr);
if (tmpGroup == -1) {
/* error was already reported */
return -1;
}
if (tmpGroup == -2)
/* -2 return means there is no iommu_group data */
return 0;
if (tmpGroup >= 0) {
if (virPCIDeviceAddressGetIOMMUGroupAddresses(&addr, &pci_dev->iommuGroupDevices,
&pci_dev->nIommuGroupDevices) < 0)
return -1;
pci_dev->iommuGroupNumber = tmpGroup;
}
return 0;
}
static int
virNodeDeviceGetMdevTypesCaps(const char *sysfspath,
virMediatedDeviceTypePtr **mdev_types,
size_t *nmdev_types)
{
virMediatedDeviceTypePtr *types = NULL;
size_t ntypes = 0;
size_t i;
/* this could be a refresh, so clear out the old data */
for (i = 0; i < *nmdev_types; i++)
conf: Fix segfault when parsing mdev types Commit f1b0890 introduced a potential crash due to incorrect operator precedence when accessing an element from a pointer to an array. Backtrace below: #0 virNodeDeviceGetMdevTypesCaps (sysfspath=0x7fff801661e0 "/sys/devices/pci0000:00/0000:00:02.0", mdev_types=0x7fff801c9b40, nmdev_types=0x7fff801c9b48) at ../src/conf/node_device_conf.c:2676 #1 0x00007ffff7caf53d in virNodeDeviceGetPCIDynamicCaps (sysfsPath=0x7fff801661e0 "/sys/devices/pci0000:00/0000:00:02.0", pci_dev=0x7fff801c9ac8) at ../src/conf/node_device_conf.c:2705 #2 0x00007ffff7cae38f in virNodeDeviceUpdateCaps (def=0x7fff80168a10) at ../src/conf/node_device_conf.c:2342 #3 0x00007ffff7cb11c0 in virNodeDeviceObjMatch (obj=0x7fff84002e50, flags=0) at ../src/conf/virnodedeviceobj.c:850 #4 0x00007ffff7cb153d in virNodeDeviceObjListExportCallback (payload=0x7fff84002e50, name=0x7fff801cbc20 "pci_0000_00_02_0", opaque=0x7fffe2ffc6a0) at ../src/conf/virnodedeviceobj.c:909 #5 0x00007ffff7b69146 in virHashForEach (table=0x7fff9814b700 = {...}, iter=0x7ffff7cb149e <virNodeDeviceObjListExportCallback>, opaque=0x7fffe2ffc6a0) at ../src/util/virhash.c:394 #6 0x00007ffff7cb1694 in virNodeDeviceObjListExport (conn=0x7fff98013170, devs=0x7fff98154430, devices=0x7fffe2ffc798, filter=0x7ffff7cf47a1 <virConnectListAllNodeDevicesCheckACL>, flags=0) at ../src/conf/virnodedeviceobj.c:943 #7 0x00007fffe00694b2 in nodeConnectListAllNodeDevices (conn=0x7fff98013170, devices=0x7fffe2ffc798, flags=0) at ../src/node_device/node_device_driver.c:228 #8 0x00007ffff7e703aa in virConnectListAllNodeDevices (conn=0x7fff98013170, devices=0x7fffe2ffc798, flags=0) at ../src/libvirt-nodedev.c:130 #9 0x000055555557f796 in remoteDispatchConnectListAllNodeDevices (server=0x555555627080, client=0x5555556bf050, msg=0x5555556c0000, rerr=0x7fffe2ffc8a0, args=0x7fffd4008470, ret=0x7fffd40084e0) at src/remote/remote_daemon_dispatch_stubs.h:1613 #10 0x000055555557f6f9 in remoteDispatchConnectListAllNodeDevicesHelper (server=0x555555627080, client=0x5555556bf050, msg=0x5555556c0000, rerr=0x7fffe2ffc8a0, args=0x7fffd4008470, ret=0x7fffd40084e0) at src/remote/remote_daemon_dispatch_stubs.h:1591 #11 0x00007ffff7ce9542 in virNetServerProgramDispatchCall (prog=0x555555690c10, server=0x555555627080, client=0x5555556bf050, msg=0x5555556c0000) at ../src/rpc/virnetserverprogram.c:428 #12 0x00007ffff7ce90bd in virNetServerProgramDispatch (prog=0x555555690c10, server=0x555555627080, client=0x5555556bf050, msg=0x5555556c0000) at ../src/rpc/virnetserverprogram.c:302 #13 0x00007ffff7cf042b in virNetServerProcessMsg (srv=0x555555627080, client=0x5555556bf050, prog=0x555555690c10, msg=0x5555556c0000) at ../src/rpc/virnetserver.c:137 #14 0x00007ffff7cf04eb in virNetServerHandleJob (jobOpaque=0x5555556b66b0, opaque=0x555555627080) at ../src/rpc/virnetserver.c:154 #15 0x00007ffff7bd912f in virThreadPoolWorker (opaque=0x55555562bc70) at ../src/util/virthreadpool.c:163 #16 0x00007ffff7bd8645 in virThreadHelper (data=0x55555562bc90) at ../src/util/virthread.c:233 #17 0x00007ffff6d90432 in start_thread () at /lib64/libpthread.so.0 #18 0x00007ffff75c5913 in clone () at /lib64/libc.so.6 Signed-off-by: Jonathon Jongsma <jjongsma@redhat.com> Reviewed-by: Ján Tomko <jtomko@redhat.com> Signed-off-by: Ján Tomko <jtomko@redhat.com>
2020-12-02 17:52:39 +00:00
virMediatedDeviceTypeFree((*mdev_types)[i]);
VIR_FREE(*mdev_types);
*nmdev_types = 0;
if (virMediatedDeviceGetMdevTypes(sysfspath, &types, &ntypes) < 0)
return -1;
*mdev_types = g_steal_pointer(&types);
*nmdev_types = ntypes;
return 0;
}
/* virNodeDeviceGetPCIDynamicCaps() get info that is stored in sysfs
* about devices related to this device, i.e. things that can change
* without this device itself changing. These must be refreshed
* anytime full XML of the device is requested, because they can
* change with no corresponding notification from the kernel/udev.
*/
int
virNodeDeviceGetPCIDynamicCaps(const char *sysfsPath,
virNodeDevCapPCIDevPtr pci_dev)
{
if (virNodeDeviceGetPCISRIOVCaps(sysfsPath, pci_dev) < 0 ||
virNodeDeviceGetPCIIOMMUGroupCaps(pci_dev) < 0)
return -1;
pci_dev->flags &= ~VIR_NODE_DEV_CAP_FLAG_PCI_MDEV;
if (virNodeDeviceGetMdevTypesCaps(sysfsPath,
&pci_dev->mdev_types,
&pci_dev->nmdev_types) < 0)
return -1;
if (pci_dev->nmdev_types > 0)
pci_dev->flags |= VIR_NODE_DEV_CAP_FLAG_PCI_MDEV;
return 0;
}
/* virNodeDeviceGetCSSDynamicCaps() get info that is stored in sysfs
* about devices related to this device, i.e. things that can change
* without this device itself changing. These must be refreshed
* anytime full XML of the device is requested, because they can
* change with no corresponding notification from the kernel/udev.
*/
int
virNodeDeviceGetCSSDynamicCaps(const char *sysfsPath,
virNodeDevCapCCWPtr ccw_dev)
{
ccw_dev->flags &= ~VIR_NODE_DEV_CAP_FLAG_CSS_MDEV;
if (virNodeDeviceGetMdevTypesCaps(sysfsPath,
&ccw_dev->mdev_types,
&ccw_dev->nmdev_types) < 0)
return -1;
if (ccw_dev->nmdev_types > 0)
ccw_dev->flags |= VIR_NODE_DEV_CAP_FLAG_CSS_MDEV;
return 0;
}
/* virNodeDeviceGetAPMatrixDynamicCaps() get info that is stored in sysfs
* about devices related to this device, i.e. things that can change
* without this device itself changing. These must be refreshed
* anytime full XML of the device is requested, because they can
* change with no corresponding notification from the kernel/udev.
*/
int
virNodeDeviceGetAPMatrixDynamicCaps(const char *sysfsPath,
virNodeDevCapAPMatrixPtr ap_matrix)
{
ap_matrix->flags &= ~VIR_NODE_DEV_CAP_FLAG_AP_MATRIX_MDEV;
if (virNodeDeviceGetMdevTypesCaps(sysfsPath,
&ap_matrix->mdev_types,
&ap_matrix->nmdev_types) < 0)
return -1;
if (ap_matrix->nmdev_types > 0)
ap_matrix->flags |= VIR_NODE_DEV_CAP_FLAG_AP_MATRIX_MDEV;
return 0;
}
#else
int
virNodeDeviceGetSCSIHostCaps(virNodeDevCapSCSIHostPtr scsi_host G_GNUC_UNUSED)
{
return -1;
}
int
virNodeDeviceGetPCIDynamicCaps(const char *sysfsPath G_GNUC_UNUSED,
virNodeDevCapPCIDevPtr pci_dev G_GNUC_UNUSED)
{
return -1;
}
int virNodeDeviceGetSCSITargetCaps(const char *sysfsPath G_GNUC_UNUSED,
virNodeDevCapSCSITargetPtr scsi_target G_GNUC_UNUSED)
{
return -1;
}
int
virNodeDeviceGetCSSDynamicCaps(const char *sysfsPath G_GNUC_UNUSED,
virNodeDevCapCCWPtr ccw_dev G_GNUC_UNUSED)
{
return -1;
}
int
virNodeDeviceGetAPMatrixDynamicCaps(const char *sysfsPath G_GNUC_UNUSED,
virNodeDevCapAPMatrixPtr ap_matrix G_GNUC_UNUSED)
{
return -1;
}
#endif /* __linux__ */