[libvirt] node device libudev backend second look
by Dave Allan
Attached is a patch against the current head containing an
implementation of node device enumeration using libudev. It is complete
except for the monitor, but I'm submitting it now as I have a few
questions about the implementation that I'd like advice on. They are
marked XXX in comments in the patch.
The other thing that's not clear to me is how the code generates the
tree structure for nodedev-list --tree. I'm setting the parent pointer
to what I think is correct, but the tree output is broken. I can dig
through it until I understand it, but if anyone is familiar with the
implementation and would be willing to take a few minutes to walk me
through it, it would save me a bunch of time.
I think it's also important that people get the code installed on a
variety of systems as soon as possible to shake out the inevitable bugs
that will arise from differing device models and code versions, and I'll
have the final version with the monitor shortly.
Dave
>From efedc8fee8127b32fb5b761ce5035902d168a207 Mon Sep 17 00:00:00 2001
From: David Allan <dallan(a)redhat.com>
Date: Fri, 25 Sep 2009 10:59:28 -0400
Subject: [PATCH 1/1] A second look at the libudev node device backend.
This patch is a very much cleaned up version of the libudev based node device backend with all the device types implemented, although I need some guidance on the USB interface code as I am not especially familiar with the terminology and HAL and udev display the details quite differently. This version of the code uses libudev to retrieve all the device information, so there's no manual mucking about in sysfs except for a little bit of existing code for fibre channel adapters.
There is a lot of detail work in this code, so we should try to get people running it on a wide variety of hardware so we can shake out the differences in implementation between the HAL and libudev backends.
---
configure.in | 47 ++-
daemon/libvirtd.c | 3 +-
src/Makefile.am | 16 +-
src/conf/node_device_conf.c | 15 +-
src/conf/node_device_conf.h | 5 +
src/node_device/node_device_driver.c | 12 +-
src/node_device/node_device_driver.h | 22 +
src/node_device/node_device_hal.h | 19 -
...evice_hal_linux.c => node_device_linux_sysfs.c} | 0
src/node_device/node_device_udev.c | 800 ++++++++++++++++++++
src/node_device/node_device_udev.h | 27 +
src/util/util.c | 28 +
src/util/util.h | 3 +
13 files changed, 967 insertions(+), 30 deletions(-)
rename src/node_device/{node_device_hal_linux.c => node_device_linux_sysfs.c} (100%)
create mode 100644 src/node_device/node_device_udev.c
create mode 100644 src/node_device/node_device_udev.h
diff --git a/configure.in b/configure.in
index 2f9db72..25ed55f 100644
--- a/configure.in
+++ b/configure.in
@@ -1640,7 +1640,7 @@ test "$enable_shared" = no && lt_cv_objdir=.
LV_LIBTOOL_OBJDIR=${lt_cv_objdir-.}
AC_SUBST([LV_LIBTOOL_OBJDIR])
-dnl HAL or DeviceKit library for host device enumeration
+dnl HAL, DeviceKit, or libudev library for host device enumeration
HAL_REQUIRED=0.0
HAL_CFLAGS=
HAL_LIBS=
@@ -1734,8 +1734,46 @@ AM_CONDITIONAL([HAVE_DEVKIT], [test "x$with_devkit" = "xyes"])
AC_SUBST([DEVKIT_CFLAGS])
AC_SUBST([DEVKIT_LIBS])
+UDEV_REQUIRED=143
+UDEV_CFLAGS=
+UDEV_LIBS=
+AC_ARG_WITH([udev],
+ [ --with-udev use libudev for host device enumeration],
+ [],
+ [with_udev=check])
+
+if test "$with_libvirtd" = "no" ; then
+ with_udev=no
+fi
+if test "x$with_udev" = "xyes" -o "x$with_udev" = "xcheck"; then
+ PKG_CHECK_MODULES(UDEV, libudev >= $UDEV_REQUIRED,
+ [with_udev=yes], [
+ if test "x$with_udev" = "xcheck" ; then
+ with_udev=no
+ else
+ AC_MSG_ERROR(
+ [You must install udev-devel >= $UDEV_REQUIRED to compile libvirt])
+ fi
+ ])
+ if test "x$with_udev" = "xyes" ; then
+ AC_DEFINE_UNQUOTED([HAVE_UDEV], 1,
+ [use UDEV for host device enumeration])
+
+ old_CFLAGS=$CFLAGS
+ old_LDFLAGS=$LDFLAGS
+ CFLAGS="$CFLAGS $UDEV_CFLAGS"
+ LDFLAGS="$LDFLAGS $UDEV_LIBS"
+ AC_CHECK_FUNCS([udev_new],,[with_udev=no])
+ CFLAGS="$old_CFLAGS"
+ LDFLAGS="$old_LDFLAGS"
+ fi
+fi
+AM_CONDITIONAL([HAVE_UDEV], [test "x$with_udev" = "xyes"])
+AC_SUBST([UDEV_CFLAGS])
+AC_SUBST([UDEV_LIBS])
+
with_nodedev=no;
-if test "$with_devkit" = "yes" -o "$with_hal" = "yes";
+if test "$with_devkit" = "yes" -o "$with_hal" = "yes" -o "$with_udev" = "yes";
then
with_nodedev=yes
AC_DEFINE_UNQUOTED([WITH_NODE_DEVICES], 1, [with node device driver])
@@ -1900,6 +1938,11 @@ AC_MSG_NOTICE([ devkit: $DEVKIT_CFLAGS $DEVKIT_LIBS])
else
AC_MSG_NOTICE([ devkit: no])
fi
+if test "$with_udev" = "yes" ; then
+AC_MSG_NOTICE([ udev: $UDEV_CFLAGS $UDEV_LIBS])
+else
+AC_MSG_NOTICE([ udev: no])
+fi
if test "$with_netcf" = "yes" ; then
AC_MSG_NOTICE([ netcf: $NETCF_CFLAGS $NETCF_LIBS])
else
diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c
index 78dfb2d..0c03aae 100644
--- a/daemon/libvirtd.c
+++ b/daemon/libvirtd.c
@@ -833,8 +833,7 @@ static struct qemud_server *qemudInitialize(int sigread) {
#ifdef WITH_STORAGE_DIR
storageRegister();
#endif
-#if defined(WITH_NODE_DEVICES) && \
- (defined(HAVE_HAL) || defined(HAVE_DEVKIT))
+#if defined(WITH_NODE_DEVICES)
nodedevRegister();
#endif
secretRegister();
diff --git a/src/Makefile.am b/src/Makefile.am
index d0ef7d1..f6f63a2 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -254,16 +254,20 @@ SECURITY_DRIVER_APPARMOR_SOURCES = \
NODE_DEVICE_DRIVER_SOURCES = \
- node_device/node_device_driver.c node_device/node_device_driver.h
+ node_device/node_device_driver.c \
+ node_device/node_device_driver.h \
+ node_device/node_device_linux_sysfs.c
NODE_DEVICE_DRIVER_HAL_SOURCES = \
node_device/node_device_hal.c \
- node_device/node_device_hal.h \
- node_device/node_device_hal_linux.c
+ node_device/node_device_hal.h
NODE_DEVICE_DRIVER_DEVKIT_SOURCES = \
node_device/node_device_devkit.c
+NODE_DEVICE_DRIVER_UDEV_SOURCES = \
+ node_device/node_device_udev.c
+
#########################
#
@@ -642,6 +646,11 @@ libvirt_driver_nodedev_la_SOURCES += $(NODE_DEVICE_DRIVER_DEVKIT_SOURCES)
libvirt_driver_nodedev_la_CFLAGS += $(DEVKIT_CFLAGS)
libvirt_driver_nodedev_la_LDFLAGS += $(DEVKIT_LIBS)
endif
+if HAVE_UDEV
+libvirt_driver_nodedev_la_SOURCES += $(NODE_DEVICE_DRIVER_UDEV_SOURCES)
+libvirt_driver_nodedev_la_CFLAGS += $(UDEV_CFLAGS)
+libvirt_driver_nodedev_la_LDFLAGS += $(UDEV_LIBS)
+endif
if WITH_DRIVER_MODULES
libvirt_driver_nodedev_la_LDFLAGS += -module -avoid-version
@@ -689,6 +698,7 @@ EXTRA_DIST += \
$(NODE_DEVICE_DRIVER_SOURCES) \
$(NODE_DEVICE_DRIVER_HAL_SOURCES) \
$(NODE_DEVICE_DRIVER_DEVKIT_SOURCES) \
+ $(NODE_DEVICE_DRIVER_UDEV_SOURCES) \
$(SECURITY_DRIVER_SELINUX_SOURCES) \
$(SECURITY_DRIVER_APPARMOR_SOURCES) \
$(SECRET_DRIVER_SOURCES) \
diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c
index f09f814..2322819 100644
--- a/src/conf/node_device_conf.c
+++ b/src/conf/node_device_conf.c
@@ -325,6 +325,9 @@ char *virNodeDeviceDefFormat(virConnectPtr conn,
data->usb_if.subclass);
virBufferVSprintf(&buf, " <protocol>%d</protocol>\n",
data->usb_if.protocol);
+ if (data->usb_if.interface_name)
+ virBufferVSprintf(&buf, " <interface_name>%s</interface_name>\n",
+ data->usb_if.interface_name);
if (data->usb_if.description)
virBufferVSprintf(&buf, " <description>%s</description>\n",
data->usb_if.description);
@@ -394,10 +397,19 @@ char *virNodeDeviceDefFormat(virConnectPtr conn,
"</media_available>\n", avl ? 1 : 0);
virBufferVSprintf(&buf, " <media_size>%llu</media_size>\n",
data->storage.removable_media_size);
- virBufferAddLit(&buf, " </capability>\n");
+ virBufferVSprintf(&buf, " <logical_block_size>%llu"
+ "</logical_block_size>\n",
+ data->storage.logical_block_size);
+ virBufferVSprintf(&buf, " <num_blocks>%llu</num_blocks>\n",
+ data->storage.num_blocks);
} else {
virBufferVSprintf(&buf, " <size>%llu</size>\n",
data->storage.size);
+ virBufferVSprintf(&buf, " <logical_block_size>%llu"
+ "</logical_block_size>\n",
+ data->storage.logical_block_size);
+ virBufferVSprintf(&buf, " <num_blocks>%llu</num_blocks>\n",
+ data->storage.num_blocks);
}
if (data->storage.flags & VIR_NODE_DEV_CAP_STORAGE_HOTPLUGGABLE)
virBufferAddLit(&buf,
@@ -1239,6 +1251,7 @@ void virNodeDevCapsDefFree(virNodeDevCapsDefPtr caps)
VIR_FREE(data->usb_dev.vendor_name);
break;
case VIR_NODE_DEV_CAP_USB_INTERFACE:
+ VIR_FREE(data->usb_if.interface_name);
VIR_FREE(data->usb_if.description);
break;
case VIR_NODE_DEV_CAP_NET:
diff --git a/src/conf/node_device_conf.h b/src/conf/node_device_conf.h
index 29a4d43..95910c5 100644
--- a/src/conf/node_device_conf.h
+++ b/src/conf/node_device_conf.h
@@ -101,6 +101,7 @@ struct _virNodeDevCapsDef {
unsigned function;
unsigned product;
unsigned vendor;
+ unsigned class;
char *product_name;
char *vendor_name;
} pci_dev;
@@ -117,10 +118,12 @@ struct _virNodeDevCapsDef {
unsigned _class; /* "class" is reserved in C */
unsigned subclass;
unsigned protocol;
+ char *interface_name;
char *description;
} usb_if;
struct {
char *address;
+ unsigned address_len;
char *ifname;
enum virNodeDevNetCapType subtype; /* LAST -> no subtype */
} net;
@@ -139,6 +142,8 @@ struct _virNodeDevCapsDef {
} scsi;
struct {
unsigned long long size;
+ unsigned long long num_blocks;
+ unsigned long long logical_block_size;
unsigned long long removable_media_size;
char *block;
char *bus;
diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c
index 14b3098..f3bd45d 100644
--- a/src/node_device/node_device_driver.c
+++ b/src/node_device/node_device_driver.c
@@ -70,9 +70,12 @@ static int update_caps(virNodeDeviceObjPtr dev)
}
-#ifdef __linux__
-static int update_driver_name(virConnectPtr conn,
- virNodeDeviceObjPtr dev)
+#if defined (__linux__) && defined (HAVE_HAL)
+/* XXX Why does this function exist? Are there devices that change
+ * their drivers while running? Under libudev, most devices seem to
+ * provide their driver name as a property "DRIVER" */
+static int update_driver_name_hal_linux(virConnectPtr conn,
+ virNodeDeviceObjPtr dev)
{
char *driver_link = NULL;
char devpath[PATH_MAX];
@@ -754,5 +757,8 @@ int nodedevRegister(void) {
#ifdef HAVE_DEVKIT
return devkitNodeRegister();
#endif
+#ifdef HAVE_UDEV
+ return udevNodeRegister();
+#endif
#endif
}
diff --git a/src/node_device/node_device_driver.h b/src/node_device/node_device_driver.h
index db01624..5be0781 100644
--- a/src/node_device/node_device_driver.h
+++ b/src/node_device/node_device_driver.h
@@ -45,6 +45,9 @@ int halNodeRegister(void);
#ifdef HAVE_DEVKIT
int devkitNodeRegister(void);
#endif
+#ifdef HAVE_UDEV
+int udevNodeRegister(void);
+#endif
void nodeDeviceLock(virDeviceMonitorStatePtr driver);
void nodeDeviceUnlock(virDeviceMonitorStatePtr driver);
@@ -53,4 +56,23 @@ void registerCommonNodeFuncs(virDeviceMonitorPtr mon);
int nodedevRegister(void);
+#ifdef __linux__
+
+#define check_fc_host(d) check_fc_host_linux(d)
+int check_fc_host_linux(union _virNodeDevCapData *d);
+
+#define check_vport_capable(d) check_vport_capable_linux(d)
+int check_vport_capable_linux(union _virNodeDevCapData *d);
+
+#define read_wwn(host, file, wwn) read_wwn_linux(host, file, wwn)
+int read_wwn_linux(int host, const char *file, char **wwn);
+
+#else /* __linux__ */
+
+#define check_fc_host(d)
+#define check_vport_capable(d)
+#define read_wwn(host, file, wwn)
+
+#endif /* __linux__ */
+
#endif /* __VIR_NODE_DEVICE_H__ */
diff --git a/src/node_device/node_device_hal.h b/src/node_device/node_device_hal.h
index c859fe3..8ac8a35 100644
--- a/src/node_device/node_device_hal.h
+++ b/src/node_device/node_device_hal.h
@@ -22,23 +22,4 @@
#ifndef __VIR_NODE_DEVICE_HAL_H__
#define __VIR_NODE_DEVICE_HAL_H__
-#ifdef __linux__
-
-#define check_fc_host(d) check_fc_host_linux(d)
-int check_fc_host_linux(union _virNodeDevCapData *d);
-
-#define check_vport_capable(d) check_vport_capable_linux(d)
-int check_vport_capable_linux(union _virNodeDevCapData *d);
-
-#define read_wwn(host, file, wwn) read_wwn_linux(host, file, wwn)
-int read_wwn_linux(int host, const char *file, char **wwn);
-
-#else /* __linux__ */
-
-#define check_fc_host(d)
-#define check_vport_capable(d)
-#define read_wwn(host, file, wwn)
-
-#endif /* __linux__ */
-
#endif /* __VIR_NODE_DEVICE_HAL_H__ */
diff --git a/src/node_device/node_device_hal_linux.c b/src/node_device/node_device_linux_sysfs.c
similarity index 100%
rename from src/node_device/node_device_hal_linux.c
rename to src/node_device/node_device_linux_sysfs.c
diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c
new file mode 100644
index 0000000..32fde52
--- /dev/null
+++ b/src/node_device/node_device_udev.c
@@ -0,0 +1,800 @@
+/*
+ * node_device_udev.c: node device enumeration - libudev implementation
+ *
+ * Copyright (C) 2009 Red Hat
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Dave Allan <dallan(a)redhat.com>
+ */
+
+#include <config.h>
+#include <libudev.h>
+
+#include "node_device_udev.h"
+#include "virterror_internal.h"
+#include "node_device_conf.h"
+#include "node_device_driver.h"
+#include "driver.h"
+#include "datatypes.h"
+#include "logging.h"
+#include "memory.h"
+#include "util.h"
+#include "buf.h"
+
+#define VIR_FROM_THIS VIR_FROM_NODEDEV
+
+static virDeviceMonitorStatePtr driverState = NULL;
+
+/* This function allocates memory from the heap for the property
+ * value. That memory must be later freed by some other code. */
+static int udevGetDeviceProperty(struct udev_device *udev_device,
+ const char *property_key,
+ char **property_value)
+{
+ const char *udev_value = NULL;
+ int ret = -1;
+
+ udev_value = udev_device_get_property_value(udev_device, property_key);
+ if (udev_value == NULL) {
+ VIR_ERROR(_("udev reports property '%s' does not exist"),
+ property_key);
+ goto out;
+ }
+
+ /* If this allocation is changed, the comment at the beginning
+ * of the function must also be changed. */
+ *property_value = strdup(udev_value);
+ if (*property_value == NULL) {
+ VIR_ERROR(_("Failed to allocate memory for "
+ "property '%s' on device '%s'"),
+ property_key, udev_device_get_sysname(udev_device));
+ goto out;
+ }
+
+ ret = 0;
+
+out:
+ if (ret != 0) {
+ VIR_ERROR(_("Failed to get udev property '%s' for device '%s'"),
+ property_key, udev_device_get_sysname(udev_device));
+ }
+
+ return ret;
+}
+
+
+static int udevGetStringProperty(struct udev_device *udev_device,
+ const char *property_key,
+ char **value)
+{
+ return udevGetDeviceProperty(udev_device, property_key, value);
+}
+
+
+static int udevGetIntProperty(struct udev_device *udev_device,
+ const char *property_key,
+ int *value,
+ int base)
+{
+ char *udev_value = NULL;
+ int ret = 0;
+
+ ret = udevGetDeviceProperty(udev_device, property_key, &udev_value);
+
+ if (ret == 0) {
+ ret = virStrToLong_i(udev_value, NULL, base, value);
+ }
+
+ VIR_FREE(udev_value);
+ return ret;
+}
+
+
+static int udevGetUintProperty(struct udev_device *udev_device,
+ const char *property_key,
+ unsigned int *value,
+ int base)
+{
+ char *udev_value = NULL;
+ int ret = 0;
+
+ ret = udevGetDeviceProperty(udev_device, property_key, &udev_value);
+
+ if (ret == 0) {
+ ret = virStrToLong_ui(udev_value, NULL, base, value);
+ }
+
+ VIR_FREE(udev_value);
+ return ret;
+}
+
+
+static int udevGetStringSysfsAttr(struct udev_device *udev_device,
+ const char *attr_name,
+ char **value)
+{
+ const char *udev_value = NULL;
+ int ret = -1;
+
+ udev_value = udev_device_get_sysattr_value(udev_device, attr_name);
+
+ if (udev_value != NULL) {
+ *value = strdup(udev_value);
+ if (*value != NULL) {
+ ret = 0;
+ }
+ }
+
+ return ret;
+}
+
+
+static int udevGetIntSysfsAttr(struct udev_device *udev_device,
+ const char *attr_name,
+ int *value,
+ int base)
+{
+ const char *udev_value = NULL;
+ int ret = -1;
+
+ udev_value = udev_device_get_sysattr_value(udev_device, attr_name);
+
+ if (udev_value != NULL) {
+ ret = virStrToLong_i(udev_value, NULL, base, value);
+ }
+
+ return ret;
+}
+
+
+static int udevGetUintSysfsAttr(struct udev_device *udev_device,
+ const char *attr_name,
+ unsigned int *value,
+ int base)
+{
+ const char *udev_value = NULL;
+ int ret = -1;
+
+ udev_value = udev_device_get_sysattr_value(udev_device, attr_name);
+
+ if (udev_value != NULL) {
+ ret = virStrToLong_ui(udev_value, NULL, base, value);
+ }
+
+ return ret;
+}
+
+
+static int udevGetUint64SysfsAttr(struct udev_device *udev_device,
+ const char *attr_name,
+ uint64_t *value)
+{
+ const char *udev_value = NULL;
+ int ret = -1;
+
+ udev_value = udev_device_get_sysattr_value(udev_device, attr_name);
+
+ if (udev_value != NULL) {
+ ret = virStrToLong_ull(udev_value, NULL, 0, value);
+ }
+
+ return ret;
+}
+
+
+static void udevLogFunction(struct udev *udev ATTRIBUTE_UNUSED,
+ int priority ATTRIBUTE_UNUSED,
+ const char *file,
+ int line,
+ const char *fn,
+ const char *fmt,
+ va_list args)
+{
+ VIR_ERROR_INT(file, fn, line, fmt, args);
+}
+
+
+static int udevProcessPCI(struct udev_device *device,
+ virNodeDeviceDefPtr def)
+{
+ const char *devpath = NULL;
+ int ret = -1;
+
+ devpath = udev_device_get_devpath(device);
+
+ char *p = strrchr(devpath, '/');
+ if (p) {
+ virStrToLong_ui(p+1, &p, 16, &def->caps->data.pci_dev.domain);
+ virStrToLong_ui(p+1, &p, 16, &def->caps->data.pci_dev.bus);
+ virStrToLong_ui(p+1, &p, 16, &def->caps->data.pci_dev.slot);
+ virStrToLong_ui(p+1, &p, 16, &def->caps->data.pci_dev.function);
+ }
+
+ udevGetUintSysfsAttr(device, "vendor", &def->caps->data.pci_dev.vendor, 0);
+ udevGetUintSysfsAttr(device, "product", &def->caps->data.pci_dev.product, 0);
+
+ /* FIXME: to do the vendor name and product name, we have to
+ * parse /usr/share/hwdata/pci.ids. Look in hal/hald/ids.c
+ */
+
+ ret = 0;
+
+ return ret;
+}
+
+
+static int udevProcessUSBDevice(struct udev_device *device,
+ virNodeDeviceDefPtr def)
+{
+ int ret = 0;
+ udevGetUintProperty(device, "BUSNUM", &def->caps->data.usb_dev.bus, 0);
+ udevGetUintProperty(device, "DEVNUM", &def->caps->data.usb_dev.device, 0);
+ udevGetUintProperty(device, "ID_VENDOR_ID", &def->caps->data.usb_dev.vendor, 16);
+ udevGetStringProperty(device, "ID_VENDOR", &def->caps->data.usb_dev.vendor_name);
+ udevGetUintProperty(device, "ID_MODEL_ID", &def->caps->data.usb_dev.product, 0);
+ udevGetStringProperty(device, "ID_MODEL", &def->caps->data.usb_dev.product_name);
+
+ return ret;
+}
+
+
+/* XXX I don't fully understand the properties here. Advice needed. */
+static int udevProcessUSBInterface(struct udev_device *device,
+ virNodeDeviceDefPtr def)
+{
+ int ret = 0;
+ char *tmp = NULL, *p = NULL;
+
+ udevGetStringProperty(device,
+ "INTERFACE",
+ &def->caps->data.usb_if.interface_name);
+
+ tmp = strdup(def->caps->data.usb_if.interface_name);
+
+ p = strrchr(tmp, '/');
+ if (p) {
+ *p = '\0';
+ virStrToLong_ui(tmp, NULL, 0, &def->caps->data.usb_if.number);
+ virStrToLong_ui(p+1, &p, 0, &def->caps->data.usb_if._class);
+ virStrToLong_ui(p+1, &p, 0, &def->caps->data.usb_if.subclass);
+ }
+
+ VIR_FREE(tmp);
+ return ret;
+}
+
+
+static int udevProcessNetworkInterface(struct udev_device *device,
+ virNodeDeviceDefPtr def)
+{
+ int ret = 0;
+
+ udevGetStringSysfsAttr(device, "address", &def->caps->data.net.address);
+ udevGetUintSysfsAttr(device, "addr_len", &def->caps->data.net.address_len, 0);
+
+ return ret;
+}
+
+
+static int udevProcessSCSIHost(struct udev_device *device ATTRIBUTE_UNUSED,
+ virNodeDeviceDefPtr def)
+{
+ int ret = 0;
+ char *filename = NULL;
+
+ filename = basename(def->name);
+
+ if (STRPREFIX(filename, "host")) {
+ /* XXX There's really no better way to get the host #? */
+ ret = virStrToLong_ui(filename + strlen("host"),
+ NULL,
+ 0,
+ &def->caps->data.scsi_host.host);
+ check_fc_host(&def->caps->data);
+ check_vport_capable(&def->caps->data);
+ }
+
+ return ret;
+}
+
+
+static int udevProcessSCSIDevice(struct udev_device *device ATTRIBUTE_UNUSED,
+ virNodeDeviceDefPtr def)
+{
+ int ret = 0;
+ char *filename = NULL, *p = NULL;
+
+ filename = basename(def->name);
+
+ virStrToLong_ui(filename, &p, 10, &def->caps->data.scsi.host);
+ virStrToLong_ui(p+1, &p, 10, &def->caps->data.scsi.bus);
+ virStrToLong_ui(p+1, &p, 10, &def->caps->data.scsi.target);
+ virStrToLong_ui(p+1, &p, 10, &def->caps->data.scsi.lun);
+
+ return ret;
+}
+
+
+static int udevProcessDisk(struct udev_device *device,
+ virNodeDeviceDefPtr def)
+{
+ int ret = 0;
+
+ def->caps->data.storage.drive_type = strdup("disk");
+ if (def->caps->data.storage.drive_type == NULL) {
+ ret = -1;
+ goto out;
+ }
+
+ udevGetUint64SysfsAttr(device, "size", &def->caps->data.storage.num_blocks);
+ udevGetUint64SysfsAttr(device, "queue/logical_block_size",
+ &def->caps->data.storage.logical_block_size);
+
+ def->caps->data.storage.size = def->caps->data.storage.num_blocks *
+ def->caps->data.storage.logical_block_size;
+
+out:
+ return ret;
+}
+
+
+static int udevProcessCDROM(struct udev_device *device,
+ virNodeDeviceDefPtr def)
+{
+ int tmp_int = 0, ret = 0;
+
+ if ((udevGetIntSysfsAttr(device, "removable", &tmp_int, 0) == 0) &&
+ (tmp_int == 1)) {
+
+ def->caps->data.storage.flags |= VIR_NODE_DEV_CAP_STORAGE_REMOVABLE;
+
+ if ((udevGetIntProperty(device, "ID_CDROM_MEDIA", &tmp_int, 0) == 0) &&
+ (tmp_int == 1)) {
+
+ def->caps->data.storage.flags |=
+ VIR_NODE_DEV_CAP_STORAGE_REMOVABLE_MEDIA_AVAILABLE;
+
+ udevGetUint64SysfsAttr(device, "size", &def->caps->data.storage.num_blocks);
+ udevGetUint64SysfsAttr(device, "queue/logical_block_size",
+ &def->caps->data.storage.logical_block_size);
+
+ /* XXX This calculation is wrong for the qemu virtual
+ * cdrom which reports the size in 512 byte blocks, but
+ * the logical block size as 2048. I don't have a
+ * physical cdrom on a devel system to see how they
+ * behave. */
+ def->caps->data.storage.removable_media_size =
+ def->caps->data.storage.num_blocks *
+ def->caps->data.storage.logical_block_size;
+ }
+ }
+
+ return ret;
+}
+
+
+/* This function exists to deal with the case in which a driver does
+ * not provide a device type in the usual place, but udev told us it's
+ * a storage device, and we can make a good guess at what kind of
+ * storage device it is from other information that is provided. */
+static int udevKludgeStorageType(virNodeDeviceDefPtr def)
+{
+ int ret = -1;
+
+ if (STRPREFIX(def->caps->data.storage.block, "/dev/vd")) {
+ /* virtio disk */
+ def->caps->data.storage.drive_type = strdup("disk");
+ if (def->caps->data.storage.drive_type != NULL) {
+ ret = 0;
+ }
+ }
+
+ return ret;
+}
+
+
+static void udevStripSpaces(char *s)
+{
+ if (s == NULL) {
+ return;
+ }
+
+ while (virFileStripSuffix(s, " ")) {
+ /* do nothing */
+ ;
+ }
+
+ return;
+}
+
+
+static int udevProcessStorage(struct udev_device *device,
+ virNodeDeviceDefPtr def)
+{
+ int ret = -1;
+
+ def->caps->data.storage.block = strdup(udev_device_get_devnode(device));
+ udevGetStringProperty(device, "DEVNAME", &def->caps->data.storage.block);
+ udevGetStringProperty(device, "ID_BUS", &def->caps->data.storage.bus);
+ udevGetStringProperty(device, "ID_SERIAL", &def->caps->data.storage.serial);
+ udevGetStringSysfsAttr(device, "device/vendor", &def->caps->data.storage.vendor);
+ udevStripSpaces(def->caps->data.storage.vendor);
+ udevGetStringSysfsAttr(device, "device/model", &def->caps->data.storage.model);
+ udevStripSpaces(def->caps->data.storage.model);
+ /* XXX Is there an equivalent of the HAL hotpluggable property?
+ * Is the hotpluggable property still relevant? */
+
+ if (udevGetStringProperty(device,
+ "ID_TYPE",
+ &def->caps->data.storage.drive_type) != 0) {
+ /* If udev doesn't have it, perhaps we can guess it. */
+ if (udevKludgeStorageType(def) != 0) {
+ goto out;
+ }
+ }
+
+ /* NB: drive_type has changed from HAL; now it's "cd" instead of "cdrom" */
+ if (STREQ(def->caps->data.storage.drive_type, "cd")) {
+ ret = udevProcessCDROM(device, def);
+ } else if (STREQ(def->caps->data.storage.drive_type, "disk")) {
+ ret = udevProcessDisk(device, def);
+ } else {
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+
+static int udevSetDeviceType(struct udev_device *device,
+ virNodeDeviceDefPtr def)
+{
+ const char *devtype = NULL;
+ int ret = 0;
+
+ if (VIR_ALLOC(def->caps) != 0) {
+ ret = -1;
+ goto out;
+ }
+
+ devtype = udev_device_get_devtype(device);
+
+ if (udevGetUintProperty(device,
+ "PCI_CLASS",
+ &def->caps->data.pci_dev.class,
+ 0) == 0) {
+ def->caps->type = VIR_NODE_DEV_CAP_PCI_DEV;
+ goto out;
+ }
+
+ if (devtype != NULL && STREQ(devtype, "usb_device")) {
+ def->caps->type = VIR_NODE_DEV_CAP_USB_DEV;
+ goto out;
+ }
+
+ if (devtype != NULL && STREQ(devtype, "usb_interface")) {
+ def->caps->type = VIR_NODE_DEV_CAP_USB_INTERFACE;
+ goto out;
+ }
+
+ /* XXX Do some network interfaces set the device type property? */
+ if (udevGetStringProperty(device,
+ "INTERFACE",
+ &def->caps->data.net.ifname) == 0) {
+
+ def->caps->type = VIR_NODE_DEV_CAP_NET;
+ goto out;
+ }
+
+ if (devtype != NULL && STREQ(devtype, "scsi_host")) {
+ def->caps->type = VIR_NODE_DEV_CAP_SCSI_HOST;
+ goto out;
+ }
+
+ if (devtype != NULL && STREQ(devtype, "scsi_device")) {
+ def->caps->type = VIR_NODE_DEV_CAP_SCSI;
+ goto out;
+ }
+
+ if (devtype != NULL && STREQ(devtype, "disk")) {
+ def->caps->type = VIR_NODE_DEV_CAP_STORAGE;
+ goto out;
+ }
+
+ ret = -1;
+
+out:
+ return ret;
+}
+
+
+static int udevGetDeviceDetails(struct udev_device *device,
+ virNodeDeviceDefPtr def)
+{
+ int ret = 0;
+
+ switch (def->caps->type) {
+ case VIR_NODE_DEV_CAP_SYSTEM:
+ /* What do we want to do with system--there's no libudev equivalent. */
+ break;
+ case VIR_NODE_DEV_CAP_PCI_DEV:
+ ret = udevProcessPCI(device, def);
+ break;
+ case VIR_NODE_DEV_CAP_USB_DEV:
+ ret = udevProcessUSBDevice(device, def);
+ break;
+ case VIR_NODE_DEV_CAP_USB_INTERFACE:
+ ret = udevProcessUSBInterface(device, def);
+ break;
+ case VIR_NODE_DEV_CAP_NET:
+ ret = udevProcessNetworkInterface(device, def);
+ break;
+ case VIR_NODE_DEV_CAP_SCSI_HOST:
+ ret = udevProcessSCSIHost(device, def);
+ break;
+ case VIR_NODE_DEV_CAP_SCSI:
+ ret = udevProcessSCSIDevice(device, def);
+ break;
+ case VIR_NODE_DEV_CAP_STORAGE:
+ ret = udevProcessStorage(device, def);
+ break;
+ default:
+ ret = -1;
+ break;
+ }
+
+ return ret;
+}
+
+
+static int udevProcessOneDevice(struct udev_device *device,
+ virNodeDeviceDefPtr def)
+{
+ struct udev_device *parent = NULL;
+ virNodeDeviceObjPtr dev = NULL;
+ const char *parent_name = NULL;
+ int ret = -1;
+
+ def->name = strdup(udev_device_get_syspath(device));
+ udevGetStringProperty(device, "DRIVER", &def->driver);
+
+ /* How to handle parent devices? Shall we change the meaning of
+ * the parent pointer for the udev backend? What does client code
+ * use the parent relationship for? We really want to preserve
+ * the behavior of the HAL backend, but that may be difficult in
+ * practice. */
+ parent = udev_device_get_parent(device);
+ if (parent != NULL) {
+ parent_name = udev_device_get_syspath(parent);
+ if (parent_name != NULL) {
+ def->parent = strdup(parent_name);
+ }
+ }
+
+ if (udevSetDeviceType(device, def) == 0) {
+ ret = udevGetDeviceDetails(device, def);
+ }
+
+ if (ret == 0) {
+ dev = virNodeDeviceAssignDef(NULL, &driverState->devs, def);
+ dev->devicePath = strdup(udev_device_get_devpath(device));
+ virNodeDeviceObjUnlock(dev);
+ } else {
+ virNodeDeviceDefFree(def);
+ }
+
+ return ret;
+}
+
+
+static int udevProcessDeviceListEntry(struct udev *udev,
+ struct udev_list_entry *list_entry)
+{
+ struct udev_device *device;
+ virNodeDeviceDefPtr def = NULL;
+ const char *name = NULL;
+ int ret = -1;
+
+ name = udev_list_entry_get_name(list_entry);
+
+ if (VIR_ALLOC(def) != 0) {
+ goto out;
+ }
+
+ device = udev_device_new_from_syspath(udev, name);
+ if (device != NULL) {
+ udevProcessOneDevice(device, def);
+ udev_device_unref(device);
+ ret = 0;
+ }
+
+out:
+ return ret;
+}
+
+
+static int udevEnumerateDevices(struct udev *udev)
+{
+ struct udev_enumerate *udev_enumerate = NULL;
+ struct udev_list_entry *list_entry = NULL;
+ const char *name = NULL;
+ int ret = 0;
+
+ udev_enumerate = udev_enumerate_new(udev);
+
+ ret = udev_enumerate_scan_devices(udev_enumerate);
+ if (0 != ret) {
+ VIR_ERROR("udev scan devices returned %d\n", ret);
+ goto out;
+ }
+
+ udev_list_entry_foreach(list_entry,
+ udev_enumerate_get_list_entry(udev_enumerate)) {
+
+ udevProcessDeviceListEntry(udev, list_entry);
+ name = udev_list_entry_get_name(list_entry);
+ }
+
+out:
+ udev_enumerate_unref(udev_enumerate);
+ return ret;
+}
+
+
+static int udevDeviceMonitorShutdown(void)
+{
+ int ret = 0;
+
+ struct udev_monitor *udev_monitor = NULL;
+ struct udev *udev = NULL;
+
+ if (driverState) {
+
+ nodeDeviceLock(driverState);
+ udev_monitor = DRV_STATE_UDEV_MONITOR(driverState);
+
+ if (udev_monitor != NULL) {
+ udev = udev_monitor_get_udev(udev_monitor);
+ udev_monitor_unref(udev_monitor);
+ }
+
+ if (udev != NULL) {
+ udev_unref(udev);
+ }
+
+ virNodeDeviceObjListFree(&driverState->devs);
+ nodeDeviceUnlock(driverState);
+ virMutexDestroy(&driverState->lock);
+ VIR_FREE(driverState);
+
+ } else {
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+static int udevDeviceMonitorStartup(int privileged ATTRIBUTE_UNUSED)
+{
+ struct udev *udev = NULL;
+ struct udev_monitor *udev_monitor = NULL;
+ int ret = 0;
+
+ if (VIR_ALLOC(driverState) < 0) {
+ ret = -1;
+ goto out;
+ }
+
+ if (virMutexInit(&driverState->lock) < 0) {
+ VIR_FREE(driverState);
+ ret = -1;
+ goto out;
+ }
+
+ nodeDeviceLock(driverState);
+
+ /*
+ * http://www.kernel.org/pub/linux/utils/kernel/hotplug/libudev/libudev-udev...
+ *
+ * indicates no return value other than success, so we don't check
+ * its return value.
+ */
+ udev = udev_new();
+ udev_set_log_fn(udev, udevLogFunction);
+
+ udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
+ if (udev_monitor == NULL) {
+ ret = -1;
+ goto out;
+ }
+
+ /* udev can be retrieved from udev_monitor */
+ driverState->privateData = udev_monitor;
+ nodeDeviceUnlock(driverState);
+
+ /* Populate with known devices */
+
+ if (udevEnumerateDevices(udev) != 0) {
+ ret = -1;
+ goto out;
+ }
+
+out:
+ if (ret == -1) {
+ udevDeviceMonitorShutdown();
+ }
+ return ret;
+}
+
+
+static int udevDeviceMonitorReload(void)
+{
+ return 0;
+}
+
+
+static int udevDeviceMonitorActive(void)
+{
+ /* Always ready to deal with a shutdown */
+ return 0;
+}
+
+
+static virDrvOpenStatus udevNodeDrvOpen(virConnectPtr conn,
+ virConnectAuthPtr auth ATTRIBUTE_UNUSED,
+ int flags ATTRIBUTE_UNUSED)
+{
+ if (driverState == NULL) {
+ return VIR_DRV_OPEN_DECLINED;
+ }
+
+ conn->devMonPrivateData = driverState;
+
+ return VIR_DRV_OPEN_SUCCESS;
+}
+
+static int udevNodeDrvClose(virConnectPtr conn)
+{
+ conn->devMonPrivateData = NULL;
+ return 0;
+}
+
+static virDeviceMonitor udevDeviceMonitor = {
+ .name = "udevDeviceMonitor",
+ .open = udevNodeDrvOpen,
+ .close = udevNodeDrvClose,
+};
+
+static virStateDriver udevStateDriver = {
+ .initialize = udevDeviceMonitorStartup,
+ .cleanup = udevDeviceMonitorShutdown,
+ .reload = udevDeviceMonitorReload,
+ .active = udevDeviceMonitorActive,
+};
+
+int udevNodeRegister(void)
+{
+ VIR_ERROR0("Registering udev node device backend\n");
+
+ registerCommonNodeFuncs(&udevDeviceMonitor);
+ if (virRegisterDeviceMonitor(&udevDeviceMonitor) < 0) {
+ return -1;
+ }
+
+ return virRegisterStateDriver(&udevStateDriver);
+}
diff --git a/src/node_device/node_device_udev.h b/src/node_device/node_device_udev.h
new file mode 100644
index 0000000..bac628d
--- /dev/null
+++ b/src/node_device/node_device_udev.h
@@ -0,0 +1,27 @@
+/*
+ * node_device_udev.h: node device enumeration - libudev implementation
+ *
+ * Copyright (C) 2009 Red Hat
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Dave Allan <dallan(a)redhat.com>
+ */
+
+#include <libudev.h>
+#include <stdint.h>
+
+#define SYSFS_DATA_SIZE 4096
+#define DRV_STATE_UDEV_MONITOR(ds) ((struct udev_monitor *)((ds)->privateData))
diff --git a/src/util/util.c b/src/util/util.c
index 98f8a14..f63bd39 100644
--- a/src/util/util.c
+++ b/src/util/util.c
@@ -2114,3 +2114,31 @@ void virFileWaitForDevices(virConnectPtr conn)
void virFileWaitForDevices(virConnectPtr conn ATTRIBUTE_UNUSED) {}
#endif
#endif
+
+int virBuildPathInternal(char **path, ...)
+{
+ char *path_component = NULL;
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ va_list ap;
+ int ret = 0;
+
+ va_start(ap, *path);
+
+ path_component = va_arg(ap, char *);
+ virBufferAdd(&buf, path_component, -1);
+
+ while ((path_component = va_arg(ap, char *)) != NULL)
+ {
+ virBufferAddChar(&buf, '/');
+ virBufferAdd(&buf, path_component, -1);
+ }
+
+ va_end(ap);
+
+ *path = virBufferContentAndReset(&buf);
+ if (*path == NULL) {
+ ret = -1;
+ }
+
+ return ret;
+}
diff --git a/src/util/util.h b/src/util/util.h
index 8679636..da410e1 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -248,4 +248,7 @@ char *virFileFindMountPoint(const char *type);
void virFileWaitForDevices(virConnectPtr conn);
+#define virBuildPath(path, ...) virBuildPathInternal(path, __VA_ARGS__, NULL)
+int virBuildPathInternal(char **path, ...) __attribute__ ((sentinel));
+
#endif /* __VIR_UTIL_H__ */
--
1.6.4.4
15 years, 6 months
[libvirt] [RFC PATCH 0/3] Add MAC filtering to qemu
by Gerhard Stenzel
The following series of patches is a prototype implementation of a ebtables based MAC address filter. I hope to have addressed all the previous comments and I am still interested to get more feedback/comments.
At the moment, some defaults are set when libvirtd starts and when a domain is started or destroyed. The plan is to extend this filter capability to the API level and virsh command level. The plan is also to add more filtering features like VLAN filtering and QoS filtering.
Thanks, Gerhard
---
Gerhard Stenzel (3):
add MAC address based port filtering to qemu
add build support for ebtables wrapper
add ebtables wrapper
configure.in | 3
src/Makefile.am | 1
src/libvirt_private.syms | 27 +
src/qemu/qemu.conf | 3
src/qemu/qemu_conf.c | 85 ++++
src/qemu/qemu_conf.h | 8
src/qemu/qemu_driver.c | 44 ++
src/util/ebtables.c | 982 ++++++++++++++++++++++++++++++++++++++++++++++
src/util/ebtables.h | 134 ++++++
9 files changed, 1287 insertions(+), 0 deletions(-)
create mode 100644 src/util/ebtables.c
create mode 100644 src/util/ebtables.h
--
15 years, 6 months
[libvirt] [PATCH 0/5] Misc changes to domain driver stuff
by Daniel P. Berrange
The patches that follow make some changes to the domain driver
infrastructure, and the QEMU driver. The important goal is to
improve the concurrency of the QEMU driver, by allowing multiple
readers on the driver (change mutex to a rwlock) and removing
the O(n) locks on the virDomainObjPtr instances
These have not been heavily tested yet, beyond checking the TCK
passes with QEMU driver. I just send them now for early review,
while I continue to work on the rest of the QEMU monitor related
patches which this series supports.
The CIL object locking test also needs to be extended to understand
the idea of RWlocks instead of just mutexes so it can properly
validate this code
Daniel
15 years, 7 months
[libvirt] [PATCH] LXC complement PATH environment variable of a controller
by Ryota Ozaki
Hi,
lxc controller usually executes 'ip' command to control veths, however
now PATH environment variable of the controller is not set (logging
code resets environment variables all) and the execution will definitely
fail because the controller cannot find the executable.
This patch complements PATH with driver's one. The code is just copied
from qemu_conf.c
Thanks,
ozaki-r
>From c98136628c1ea0964191be976b23ac99d0f7bb7b Mon Sep 17 00:00:00 2001
From: Ryota Ozaki <ozaki.ryota(a)gmail.com>
Date: Wed, 14 Oct 2009 05:09:04 +0900
Subject: [PATCH] LXC complement PATH environment variable of a controller
* src/lxc/lxc_driver.c: without PATH, the controller will definitely
fail to call ip command
---
src/lxc/lxc_driver.c | 13 +++++++++++++
1 files changed, 13 insertions(+), 0 deletions(-)
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
index 0b614e3..783dfcc 100644
--- a/src/lxc/lxc_driver.c
+++ b/src/lxc/lxc_driver.c
@@ -1005,6 +1005,19 @@ static int lxcControllerStart(virConnectPtr conn,
lenv[lenvc++] = envval; ¥
} while (0)
+#define ADD_ENV_COPY(envname) ¥
+ do { ¥
+ char *val = getenv(envname); ¥
+ if (val != NULL) { ¥
+ ADD_ENV_PAIR(envname, val); ¥
+ } ¥
+ } while (0)
+
+ /*
+ * The controller may call ip command, so we have to remain PATH.
+ */
+ ADD_ENV_COPY("PATH");
+
log_level = virLogGetDefaultPriority();
if (virAsprintf(&tmp, "LIBVIRT_DEBUG=%d", log_level) < 0)
goto no_memory;
--
1.6.2.5
15 years, 7 months
[libvirt] [RFC] Support for CPUID masking
by Jiri Denemark
Hi,
We need to provide support for CPU ID masking. Xen and VMware ESX are examples
of current hypervisors which support such masking.
My proposal is to define new 'cpuid' feature advertised in guest
capabilities:
<guest>
...
<features>
<cpuid/>
</feature>
</guest>
When a driver supports cpuid feature, one can use it to mask/check for
specific bits returned by CPU ID as follows:
<domain>
...
<features>
<cpuid>
<mask level='hex' register='eax|ebx|ecx|edx'>MASK</mask>
</cpuid>
</features>
...
</domain>
Where
- level is a hexadecimal number used as an input to CPU ID (i.e. eax
register),
- register is one of eax, ebx, ecx or edx,
- and MASK is a string with the following format:
mmmm:mmmm:mmmm:mmmm:mmmm:mmmm:mmmm:mmmm with m being 1-bit mask for the
corresponding bit in the register.
There are three possibilities of specifying what values can be used for 'm':
- let it be driver-specific,
- define all possible values,
- define a common set of values and allow drivers to specify their own
additional values.
I think the third is the way to go as it lowers the confusion of different
values used by different drivers for the same purpose while maintaining the
flexibility to support driver-specific masks.
The following could be a good set of predefined common values:
- 1 force the bit to be 1
- 0 force the bit to be 0
- x don't care, i.e., use driver's default value
- T require the bit to be 1
- F require the bit to be 0
Some examples of what it could look like follow:
<capabilities>
...
<guest>
<os_type>xen</os_type>
...
<features>
<pae/>
<cpuid/>
</features>
</guest>
...
</capabilities>
<domain type='xen' id='42'>
...
<features>
<pae/>
<acpi/>
<apic/>
<cpuid>
<mask level='1' register='ebx'>
xxxx:xxxx:0000:1010:xxxx:xxxx:xxxx:xxxx
</mask>
<mask level='1' register='ecx'>
xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xx1x:xxxx
</mask>
<mask level='1' register='edx'>
xxx1:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
</mask>
<mask level='80000001' register='ecx'>
xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xx1x
</mask>
<mask level='80000008' register='ecx'>
xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xx00:1001
</mask>
</cpuid>
</features>
...
</domain>
What are your opinions about this?
Thank for all comments.
Jirka
15 years, 7 months
[libvirt] [PATCH] Avoid crash in virBufferEscapeString
by Laine Stump
If virBufferEscapeString is called on a buffer that has 0 bytes of
space, a size of -1 will be passed to snprintf, resulting in a
segmentation fault. This patch checks for 0 space, and grows the
buffer if needed prior to determining size.
I discovered this when I accidentally made virBufferEscapeString the
first function to add something to a newly minted buffer.
---
src/util/buf.c | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/src/util/buf.c b/src/util/buf.c
index c802aa2..9681635 100644
--- a/src/util/buf.c
+++ b/src/util/buf.c
@@ -318,6 +318,12 @@ virBufferEscapeString(const virBufferPtr buf, const char *format, const char *st
}
*out = 0;
+ if ((buf->use >= buf->size) &&
+ virBufferGrow(buf, 100) < 0) {
+ VIR_FREE(escaped);
+ return;
+ }
+
size = buf->size - buf->use - 1;
while (((count = snprintf(&buf->content[buf->use], size, format,
(char *)escaped)) < 0) || (count >= size - 1)) {
--
1.6.2.5
15 years, 7 months
[libvirt] [PATCH] Don't copy old machines from a domain which has none
by Mark McLoughlin
If the the qemu and kvm binaries are the same, we don't include machine
types in the kvm domain info.
However, the code which refreshes the machine types info from the
previous capabilities structure first looks at the kvm domain's info,
finds it matches and then copies the empty machine types list over
for the top-level qemu domain.
That doesn't make sense, we shouldn't copy an empty machin types list.
* src/qemu/qemu_conf.c: qemudGetOldMachinesFromInfo(): don't copy an
empty machine types list.
---
src/qemu/qemu_conf.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index ac63570..b881f1e 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -505,6 +505,9 @@ qemudGetOldMachinesFromInfo(virCapsGuestDomainInfoPtr info,
virCapsGuestMachinePtr *list;
int i;
+ if (!info->nmachines)
+ return 0;
+
if (!info->emulator || !STREQ(emulator, info->emulator))
return 0;
--
1.6.2.5
15 years, 7 months
[libvirt] Re: Libvir Xen and domain events
by Christopher Pyper
I have been looking into registering some domain events though the
python Libvir API. However, I am getting errors and I believe it may
be due to lack of event support in Xen. This is the error I am getting:
libvir: Xen error : this function is not supported by the hypervisor:
xenUnifiedDomainEventRegister
Traceback (most recent call last):
File "./testcallback.py", line 19, in ?
conn.domainEventRegister(callback,None)
File "/usr/lib64/python2.4/site-packages/libvirt.py", line 1578, in
domainEventRegister
if ret == -1: raise libvirtError ('virConnectDomainEventRegister
() failed', conn=self)
libvirt.libvirtError: this function is not supported by the
hypervisor: xenUnifiedDomainEventRegister
If this lack of support is the case, what would you recommend is the
best route for catching domain events? Currently, I am thinking of
just polling regularly and monitoring for changes in domain state.
Cheers.
Chris Pyper.
P.S. Libvir is awesome.
15 years, 7 months
[libvirt] Release of libvirt-0.7.2
by Daniel Veillard
This is an intermediate release to flush out one month worth of
development and patches, as we have another release scheduled for the
30th October.
It is available on ftp://libvirt.org/libvirt as usual and tagged in GIT
The main new features are AppArmor security driver and the possibility to
define new domain in the ESX driver. The code had a lot of cleanup,
including a big tree refactoring and a fairly long list of bug fixes:
Features:
- sVirt AppArmor security driver (Jamie Strandboge)
- Add public API definition for data stream handling (Daniel P. Berrange)
- ESX add esxDomainDefineXML() (Matthias Bolte)
- LXC: suspend/resume support (Ryota Ozaki)
- Big code tree cleanup (Daniel P. Berrange)
Documentation:
- Documentation and examples for SVirt Apparmor driver (Jamie Strandboge)
- Fix documentation and comment typos (Paolo Bonzini)
- Fix up a few typos in the tree. (Chris Lalancette)
- Fix a typo in virNetHasValidPciAddr() too (Mark McLoughlin)
- Fix a typo in virDiskHasValidPciAddr() (Jiri Denemark)
- Fix a number of small typos (Dan Kenigsberg)
- add doc for graphic and video elements (Florian Vichot)
- Fix up 'neccessary -> necessary' in a comment. (Chris Lalancette)
- Fix up comments for domainXML{To,From}Native. (Chris Lalancette)
- Simple fix of a comment in qemuStringToArgvEnv. (Chris Lalancette)
- Add a README file to src/ explaining the directory structure (Daniel P. Berrange)
- don't emit trailing blanks into generated and VC'd NEWS file (Jim Meyering)
Portability:
- Misc win32 build fixes (Daniel P. Berrange)
- Don't require full daemon install for libvirt python bindings (Daniel P. Berrange)
- Tweak specfile to fix RHEL6 rules & ESX/PHYP enablement (Daniel P. Berrange)
- Bug Fixes:
- network: Fix printing XML 'delay' attribute (Cole Robinson)
- Fix virFileReadLimFD/virFileReadAll to handle EINTR (Daniel P. Berrange)
- storage: Fix generating iscsi 'auth' xml (Cole Robinson)
- Fix QEMU restore from file in raw format (Daniel P. Berrange)
- Take domain type into account when looking up default machine (Mark McLoughlin)
- Fix schema to allow missing machine type (Mark McLoughlin)
- Fix stream abort upon I/O failure during migration (Daniel P. Berrange)
- Create /var/log/libvirt/{lxc,uml} dirs (Mark McLoughlin)
- nodedev: Add locking in nodeNumOfDevices (Cole Robinson)
- test: Throw a proper error in GetBridgeName (Cole Robinson)
- 526769 change logrotate config default to weekly (Daniel Veillard)
- Fix emission of domain events messages (Daniel P. Berrange)
- unbreak `make rpcgen' (Paolo Bonzini)
- unbreak migration (Paolo Bonzini)
- Fix USB device re-labelling (Mark McLoughlin)
- Avoid a libvirtd crash on broken input 523418 (Daniel Veillard)
- Re-label image file backing stores (Mark McLoughlin)
- Fix memory leaks in libvirtd's message processing (Matthias Bolte)
- Fix QEMU test suite with new VNC env variable (Daniel P. Berrange)
- VBox vboxDomainDestroy forgot to wait for completion (Pritesh Kothari)
- Vbox call OpenHardDisk with "" instead of NULL (Pritesh Kothari)
- Avoid double free in errors in virsh (Jim Fehlig)
- Fix crash in device hotplug cleanup code (Daniel P. Berrange)
- Maintain value of ctxt->node in virInterfaceDefParseDhcp (Laine Stump)
- Fix some XPath relative node resets (Daniel Veillard)
- Fix unitialized variable in qemudDomainDetachHostPciDevice() (Charles Duffy)
- ESX: Check if a datastore is accessible first (Matthias Bolte)
- Fix handling of Xen(ner) detection (Daniel P. Berrange)
- Fix xen driver refcounting. (Matthias Bolte)
- prevent attempt to call cat -c during virDomainSave to raw (Charles Duffy)
- Don't do virSetConnError when virDrvSupportsFeature is successful. (Chris Lalancette)
- Fix a double-free in qemudRunLoop() (Chris Lalancette)
- Fix leak in PCI hostdev hot-unplug (Mark McLoughlin)
- Fix net/disk hot-unplug segfault (Mark McLoughlin)
Improvements:
- schema: Update storage pool schema. (Cole Robinson)
- test: Activate interfaces specified through driver config file. (Cole Robinson)
- Rewrite example domain events programm for python (Daniel P. Berrange)
- Support a new peer-to-peer migration mode & public API (Daniel P. Berrange)
- LXC add augeas support for config file (Amy Griffis)
- LXC add driver config file lxc.conf (Amy Griffis)
- LXC do not truncate container log files on restart (Amy Griffis)
- LXC initialize logging configuration (Amy Griffis)
- Add debug for envp[] in virExecWithHook() (Amy Griffis)
- Add accessors for logging filters and outputs (Amy Griffis)
- Add virFileAbsPath() utility (Amy Griffis)
- LXC implement memory control APIs (Ryota Ozaki)
- Add a domain argument to SVirt *RestoreImageLabel (Jamie Strandboge)
- test: Support loading node device info from file/XML (Cole Robinson)
- test: Implement node device driver. (Cole Robinson)
- configure: Add explict --with-python option. (Cole Robinson)
- Tunnelled migration. (Chris Lalancette)
- Various monitor improvements for migration. (Chris Lalancette)
- 523639 Allows a <description> tag for domains (Daniel Veillard)
- Add src/util/storage_file.c to the POTFILES.in. (Chris Lalancette)
- Add a qemu feature flag for unix socket migration. (Chris Lalancette)
- Let remoteClientStream only do RX if requested. (Chris Lalancette)
- Introduce virStorageFileMetadata structure (Mark McLoughlin)
- Allow control over QEMU audio backend (Daniel P. Berrange)
- Handle data streams in remote client (Daniel P. Berrange)
- Handle outgoing data streams in libvirtd (Daniel P. Berrange)
- Handle incoming data streams in libvirtd (Daniel P. Berrange)
- Lots of cleanups and improvement on QEmu monitor code (Daniel P. Berrange)
- ESX add esxVI_Occurence enum to for occurences (Matthias Bolte)
- ESX add x86_64 detection based on the CPUID (Matthias Bolte)
- ESX add tests for the VMX to/from domain XML mapping (Matthias Bolte)
- ESX Add esxDomainXMLToNative() (Matthias Bolte)
- ESX Set challenge for auth callback to hostname (Matthias Bolte)
- ESX Add esxNodeGetFreeMemory() (Matthias Bolte)
- network: add 'bootp' and 'tftp' config (Paolo Bonzini)
- OpenVZ Fix a restriction about domain names (Yuji NISHIDA)
- Make pki_check.sh into an installed & supported tool (Daniel P. Berrange)
- ESX add support for vmxnet3 virtual device (Shahar Klein)
Cleanups:
- remote: Don't print a warning every time a remote call fails (Cole Robinson)
- storage: Report errors in FindPoolSources (Cole Robinson)
- LXC fix return code handling in lxcVmStart (Ryota Ozaki)
- Add a target for libvirt.devhelp (Daniel Veillard)
- Remove some auto-generated files (Daniel P. Berrange)
- Re-arrange doTunnelMigrate to simplify cleanup code (Daniel P. Berrange)
- Separate out code for sending tunnelled data (Daniel P. Berrange)
- Pull connection handling code out of doTunnelMigrate (Daniel P. Berrange)
- Refactor native QEMU migration code (Daniel P. Berrange)
- Don't force dconn to be NULL in virDomainMigrate (Daniel P. Berrange)
- Remove unneccessary uri_in parameter from virMigratePrepareTunnel (Daniel P. Berrange)
- Move the VIR_DRV_FEATURE* constants (Daniel P. Berrange)
- Fix configure.ac message vertical alignment (Daniel P. Berrange)
- cgroup: Fix -Werror breakage (Cole Robinson)
- Fix handling return value of qemuMonitorSetBalloon (Ryota Ozaki)
- Fix up "make check" (Chris Lalancette)
- Fix rebuilding of devhelp files (Daniel P. Berrange)
- Fix ordering of <exports> in API description file (Daniel P. Berrange)
- node conf: Make parsing routines consistent with other drivers (Cole Robinson)
- nodedev: Break out virNodeDeviceHasCap to node_conf (Cole Robinson)
- python: Add a newline after custom classes (Cole Robinson)
- python: Fix generated virInterface method names (Cole Robinson)
- python: Use a pure python implementation of 'vir*GetConnect' (Cole Robinson)
- python: Don't generate bindings for vir*Ref (Cole Robinson)
- python: Don't generate conflicting conn.createXML functions. (Cole Robinson)
- python: Remove use of xmllib in generator.py (Cole Robinson)
- python: Remove FastParser from generator. (Cole Robinson)
- Fix typo in Makefile.am breaking NEWS file generation (Daniel P. Berrange)
- Fix build in separate build directory (Jiri Denemark)
- Incorrect error message in virDomainNetDefParseXML (Florian Vichot)
- Fix a few 'make rpm' breakages (Daniel Veillard)
- Pass remote_message_header to the dispatch functions. (Chris Lalancette)
- Fix up some warnings from stream DEBUG statements. (Chris Lalancette)
- Fix apibuild.py warnings (Matthias Bolte)
- Change signature of remoteSendStreamData() to fix compile warning (Matthias Bolte)
- Add virStorageFileGetMetadata() helper (Mark McLoughlin)
- Move virStorageGetMetadataFromFD() to libvirt_util (Mark McLoughlin)
- Split virStorageGetMetadataFromFD() from virStorageBackendProbeTarget() (Mark McLoughlin)
- Move file format enum to libvirt_util (Mark McLoughlin)
- Remove hand-crafted UUID parsers (Daniel P. Berrange)
- Helper functions for processing data streams in libvirtd (Daniel P. Berrange)
- Standardize debugging messages in QEMU monitor code (Daniel P. Berrange)
- Remove low level monitor APIs from header file (Daniel P. Berrange)
- Rename qemudMonitorSendCont to qemuMonitorStartCPUs (Daniel P. Berrange)
- Pull QEMU monitor interaction out to separate file (Daniel P. Berrange)
- util.h needs libvirt.h for virConnectPtr (Mark McLoughlin)
- Fix API doc extractor to stop munging comment formatting (Daniel P. Berrange)
- Fix secret_driver compile warning, bug. (Charles Duffy)
- ESX remove phantom mode (Matthias Bolte)
- ESX replace esxUtil_EqualSuffix() with virFileHasSuffix() (Matthias Bolte)
- ESX Whitespace cleanup (Matthias Bolte)
- Fix up "make syntax-check" after the tree restructuring. (Chris Lalancette)
- Introduce virStrncpy. (Chris Lalancette)
- Ignore auto-generated header file (Daniel P. Berrange)
- Remove an unnecessary variable from remoteIOReadMessage(). (Chris Lalancette)
- Remove auto-generated header file from repo (Daniel P. Berrange)
- Move example XML files into examples/xml (Daniel P. Berrange)
- Remove all generated docs from source control (Daniel P. Berrange)
- Fix missing data file in qemuhelpdata (Daniel P. Berrange)
- Misc syntax-check fixes (Daniel P. Berrange)
- Move remote protocol definition into src/remote/ (Daniel P. Berrange)
- Move all shared utility files to src/util/ (Daniel P. Berrange)
- Move all XML configuration handling to src/conf/ (Daniel P. Berrange)
- Re-arrange python generator to make it clear what's auto-generated (Daniel P. Berrange)
- Remove obsolete files (Daniel P. Berrange)
- Move docs/examples into examples/ (Daniel P. Berrange)
- Remove unused images from docs/ directory (Daniel P. Berrange)
- Rename daemon main code (Daniel P. Berrange)
- Move config files to align with driver sources (Daniel P. Berrange)
- Move virsh into tools/ directory (Daniel P. Berrange)
- Move security drivers to src/security/ (Daniel P. Berrange)
- Move secret driver into src/secret/ (Daniel P. Berrange)
- Move netcf interface driver into src/interface/ (Daniel P. Berrange)
- Move network driver into src/network (Daniel P. Berrange)
- Move remote driver to src/remote/ (Daniel P. Berrange)
- Move test driver into src/test/ (Daniel P. Berrange)
- Move node device drivers to src/node_device/ (Daniel P. Berrange)
- Move storage drivers into src/storage/ (Daniel P. Berrange)
- Move OpenVZ driver to src/openvz/ (Daniel P. Berrange)
- Move UML driver to src/uml/ (Daniel P. Berrange)
- Move QEMU driver to src/qemu/ (Daniel P. Berrange)
- Move LXC driver into src/lxc/ (Daniel P. Berrange)
- Move xen driver code into src/xen/ directory (Daniel P. Berrange)
- Rename qemud/ directory to daemon/ (Daniel P. Berrange)
- Refactor libvirt.spec to allow client-only builds (Daniel P. Berrange)
Please give it a try, and thanks everybody for reports, patches or
documentation !
Daniel
--
Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/
daniel(a)veillard.com | Rpmfind RPM search engine http://rpmfind.net/
http://veillard.com/ | virtualization library http://libvirt.org/
15 years, 7 months