[libvirt] [RFC PATCH 00/11] qemu: add support to hotplug memory device
by Zhu Guihua
Now qemu has already supported memory hotplug, so this patchset will make
libvirt support hotplug memory device for qemu driver.
First, add two parameters slots and maxmem for memory hotplug, and the xml
format can be like this.
<memory slot='10'>102400</memory>
<maxMemory>1024000</maxMemory>
Second, memory device's xml format can be like this.
<dimm driver='pc-dimm' addr='0' node='0' slot='1'>
<backend type='ram' size='131072'/>
</dimm>
Zhu Guihua (11):
domain_conf: support slots and maxmem properties in memory xml
domain_conf: introduce virDomainDimmGetFreeSlot
domain_conf: add support for memory device configuration in XML
domain_conf: introduce dimm def helpers
domain_conf: introduce dimm device hotplug helpers
qemu: implement dimm device hotplug on config level
qemu_monitor: introduce qemuMonitorAddMemoryBackend
qemu_command: introduce a func for memory device alias
qemu: implement support for pc-dimm
qemu: introduce qemuBuildDimmDeviceStr
qemu: implement dimm device hotplug on live level
src/conf/domain_conf.c | 306 ++++++++++++++++++++++++++++++++++++++++++-
src/conf/domain_conf.h | 54 ++++++++
src/libvirt_private.syms | 6 +
src/qemu/qemu_capabilities.c | 3 +
src/qemu/qemu_capabilities.h | 1 +
src/qemu/qemu_command.c | 110 +++++++++++++++-
src/qemu/qemu_command.h | 7 +
src/qemu/qemu_driver.c | 26 ++++
src/qemu/qemu_hotplug.c | 71 ++++++++++
src/qemu/qemu_hotplug.h | 5 +
src/qemu/qemu_monitor.c | 54 ++++++++
src/qemu/qemu_monitor.h | 4 +
12 files changed, 644 insertions(+), 3 deletions(-)
--
1.9.3
9 years, 10 months
[libvirt] RFC: Building a virtlogd daemon
by Daniel P. Berrange
With QEMU there are a couple of areas where QEMU ends up logging data
to a file on the host.
- stdout/err - connected to /var/log/libvirt/qemu/$GUEST.log
- serial/parallel/console when used with type=file
The stdout/err is typically very small, typically only getting data when
an error occurs in QEMU resulting in it existing. In the past there was
the chance of it getting lots of data - eg spice used to write tonnes of
data on stderr during normal operation, so a guest OS could cause large
data to be saved to the host log file. This is harder todo now, but still
theoretically possible.
The serial/parallel/console log files can be arbitrarily sized and under
complete control of the guest OS - it can write whatever it wants with
no limits.
In both these cases we would prefer to be able to limit the amount of
data a guest can write to the host file, so we have a finite cap on
disk usage. You might suggest using logrotate, but that only runs
periodically so between invocations of logrotate the log files can
still grow to arbitrary size. This is inherant problem in doing the
log rotation out of band / asynchronously
OpenStack has a further problem it would like to solve. It wants to
record all guest serial port data to a log file, as it has an API for
a client user to read historically captured data from the serial port.
This is done using type=file chardev
At the same time it wants to expose an interactive console for client
users to interact with the guest. This is done using type=unix or
type=pty chardevs.
The obvious problem is that a single serial/parallel/console device
can only be connected to one chardev backend at a time. A very long
time ago (5-6 years?) I submitted patches to allow multiple chardev
backends in QEMU but they were rejected.
Downstream projects like OpenStack have considered setting up console
log handling service themselves, but my view is that this is a problem
that all users of libvirt face, so libvirt should provide a standard
solution to it. This avoids each downstream app reinventing the wheel.
So I'm intending to create a standalone virtlogd daemon to address this
problem. Similarly to virtlockd, it will be able to re-exec itelf so
that upgrades can be done with no interruption to logging, and libvirtd
will talk to it over a simple RPC protocol.
- For stdout/stderr
- libvirtd will ask virtlogd will provide a pipe FD that can
be connected to the guest stdout/err, in the sme way libvirtd
provides a file FD today.
- virtlogd will read from this pipe and write the data to
/var/log/libvirt/qemu/$GUEST.log
- virtlogd will either truncate or rotate the $GUEST.log
file when it reaches a declared certain size limit.
- For serial/parallel/console
- libvirtd will ask virtlogd to setup a pair of UNIX domain
sockets listening on
/var/run/virtlogd/qemu/$GUEST.guest
/var/run/virtlogd/qemu/$GUEST.client
- libvirtd will ask virtlogd to (optionally) write the data
to a file /var/log/virtlogd/qemu/$GUEST.log
(Or /var/log/libvirt/qemu/$GUEST-$DEVICE.log perhaps,
where $DEVICE is the <alias> string from the console,
serial or parallel device ?)
- QEMU will be told to connect to this $GUEST.guest socket
with the type=unix chardev backend
- The virDomainOpenConsole API will connect to the
$GUEST.client socket
- virtlogd will read data from $GUEST.guest socket and
write it to $GUEST.client and optionally $GUEST.log too
- virtlogd will read data from $GUEST.client socket and
write it to $GUEST.guest socket
- virtlogd will either truncate or rotate the $GUEST.log
file when it reaches a declared certain size limit.
So at the end of this we will have strictly size limited log files which
can rotated at the size threshold, and the ability to have interactive
console sessions and file logging at the same time.
Regards,
Daniel
--
|: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org -o- http://virt-manager.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
9 years, 10 months
[libvirt] [libvirt-test-API][PATCH] Add connection_cpu_models test case
by jiahu
The connection_cpu_models.py uses getCPUModelNames() to validate
new API virConnectGetCPUModelNames of libvirt.
---
cases/test_connection.conf | 12 +++++
repos/virconn/connection_cpu_models.py | 82 ++++++++++++++++++++++++++++++++++
2 files changed, 94 insertions(+)
create mode 100644 repos/virconn/connection_cpu_models.py
diff --git a/cases/test_connection.conf b/cases/test_connection.conf
index ccde119..e916886 100644
--- a/cases/test_connection.conf
+++ b/cases/test_connection.conf
@@ -29,3 +29,15 @@ virconn:connection_nodeinfo
virconn:connection_version
conn
lxc:///
+
+virconn:connection_cpu_models
+ arch
+ x86_64
+
+virconn:connection_cpu_models
+ arch
+ i686
+
+virconn:connection_cpu_models
+ arch
+ ppc64
diff --git a/repos/virconn/connection_cpu_models.py b/repos/virconn/connection_cpu_models.py
new file mode 100644
index 0000000..4588188
--- /dev/null
+++ b/repos/virconn/connection_cpu_models.py
@@ -0,0 +1,82 @@
+#!/usr/bin/env python
+# test getCPUModelNames() API for libvirt
+
+import os
+import libvirt
+
+from xml.dom import minidom
+from libvirt import libvirtError
+from src import sharedmod
+from utils import utils
+
+required_params = ('arch',)
+optional_params = {}
+
+CPU_MAP_FILE = "/usr/share/libvirt/cpu_map.xml"
+
+def get_cpu_archs_from_xml(logger):
+ """
+ return supported cpu archs from cpu_map.xml
+ """
+ cpu_archs_from_xml = []
+ xml = minidom.parse(CPU_MAP_FILE)
+ for arch in xml.getElementsByTagName('arch'):
+ cpu_archs_from_xml.append(str(arch.getAttribute('name')))
+ return cpu_archs_from_xml
+
+def get_cpu_models_from_xml(arch, logger):
+ """
+ return supported cpu models from cpu_map.xml
+ """
+ cpu_models_from_xml = []
+ if arch == 'x86_64' or arch == 'i686':
+ real_arch = 'x86'
+ else:
+ real_arch = arch
+
+ xml = minidom.parse(CPU_MAP_FILE)
+ for model in xml.getElementsByTagName('model'):
+ if model.parentNode.getAttribute('name') == real_arch:
+ cpu_models_from_xml.append(str(model.getAttribute('name')))
+ return cpu_models_from_xml
+
+def connection_cpu_models(params):
+ """
+ test API for getCPUModelNames in class virConnect
+ """
+ logger = params['logger']
+ arch_value = params['arch']
+ try:
+ logger.info("get cpu archs from cpu_map.xml")
+ if not os.path.exists(CPU_MAP_FILE):
+ logger.error("%s is not exist" % CPU_MAP_FILE)
+ return 1
+ cpu_archs_from_xml = get_cpu_archs_from_xml(logger)
+ logger.info("The supported cpu archs in xml are %s" \
+ % cpu_archs_from_xml)
+ cpu_models_from_xml = get_cpu_models_from_xml(arch_value, logger)
+ logger.info("The supported cpu models in xml are %s" \
+ % cpu_models_from_xml)
+
+ conn = sharedmod.libvirtobj['conn']
+
+ cpu_models_from_libvirt = conn.getCPUModelNames(arch_value ,0)
+ logger.info("The specified architecture is %s" \
+ % arch_value)
+ logger.info("The supported cpu models is %s" \
+ % cpu_models_from_libvirt)
+
+ #compare with cpu_map.xml
+ for cpu_model in cpu_models_from_libvirt:
+ if cpu_model in cpu_models_from_xml:
+ logger.debug("'%s' model: PASS" % cpu_model)
+ else:
+ logger.debug("'%s' model: FAIL, not in libvirt"\
+ % cpu_model)
+ return 1
+ logger.debug("check all cpu models: PASS")
+ except libvirtError, e:
+ logger.error("API error message: %s" % e.message)
+ return 1
+
+ return 0
--
1.8.1.4
9 years, 10 months
[libvirt] [PATCH 0/2]qemu: output error when try to hotplug/coldplug a unsupported device
by Luyao Huang
When use attach-device to hotplug a qemu unsupported console, command
will success and add a XML to the running guest, but donnot do anything
in qemu side. Add a check in qemuBuildConsoleChrDeviceStr, and output a
error when try to attach a qemu unsupport console.
About report error for qemu unsupported Chr device when cold-plug,
I think this maybe unnessary in this place, because we will check it
when we start the guest and it will report a clear error.But if we
use qemu* header func add a qemu unsupported things to qemu guest, it seems
strange.
Luyao Huang (2):
qemu: output error when try to hotplug unsupport console
qemu: add a check when cold-plug a Chr device
src/qemu/qemu_command.c | 6 ++++-
src/qemu/qemu_hotplug.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 69 insertions(+), 1 deletion(-)
--
1.8.3.1
9 years, 10 months
[libvirt] [PATCH 1/2] util: Functions for getting/setting device options
by akrowiak@linux.vnet.ibm.com
From: Tony Krowiak <akrowiak(a)linux.vnet.ibm.com>
This patch provides the utility functions needed to synchronize
the rxfilter changes made to a guest domain with the corresponding
macvtap devices on the host:
* Get/set PROMISC flag
* Get/set ALLMULTI, MULTICAST
Signed-off-by: Tony Krowiak <akrowiak(a)linux.vnet.ibm.com>
---
src/libvirt_private.syms | 6 +
src/util/virnetdev.c | 346 ++++++++++++++++++++++++++++++++++++++++++++++
src/util/virnetdev.h | 14 ++
3 files changed, 366 insertions(+), 0 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index a2eec83..6b49b08 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1646,6 +1646,9 @@ virNetDevGetVirtualFunctionInfo;
virNetDevGetVirtualFunctions;
virNetDevGetVLanID;
virNetDevIsOnline;
+virNetDevIsPromiscuous;
+virNetDevIsRcvAllMulti;
+virNetDevIsRcvMulti;
virNetDevIsVirtualFunction;
virNetDevLinkDump;
virNetDevReplaceMacAddress;
@@ -1663,6 +1666,9 @@ virNetDevSetMTUFromDevice;
virNetDevSetName;
virNetDevSetNamespace;
virNetDevSetOnline;
+virNetDevSetPromiscuous;
+virNetDevSetRcvAllMulti;
+virNetDevSetRcvMulti;
virNetDevSetupControl;
virNetDevValidateConfig;
diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c
index ef96b2b..c610f5b 100644
--- a/src/util/virnetdev.c
+++ b/src/util/virnetdev.c
@@ -2337,6 +2337,333 @@ int virNetDevDelMulti(const char *ifname ATTRIBUTE_UNUSED,
}
#endif
+#if defined(SIOCSIFFLAGS) && defined(HAVE_STRUCT_IFREQ)
+/**
+ * virNetDevSetPromiscuous:
+ * @ifname: the interface name
+ * @promiscuous: true for receive all packets, false for do not receive
+ * all packets
+ *
+ * Function to control if an interface is to receive all
+ * packets (receive all, true) or not (do not receive all, false)
+ *
+ * Returns 0 in case of success or -1 on error.
+ */
+int virNetDevSetPromiscuous(const char *ifname,
+ bool promiscuous)
+{
+ int fd = -1;
+ int ret = -1;
+ struct ifreq ifr;
+ int ifflags;
+
+ if ((fd = virNetDevSetupControl(ifname, &ifr)) < 0)
+ return -1;
+
+ if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
+ virReportSystemError(errno,
+ _("Cannot get interface flags on '%s'"),
+ ifname);
+ goto cleanup;
+ }
+
+ if (promiscuous)
+ ifflags = ifr.ifr_flags | IFF_PROMISC;
+ else
+ ifflags = ifr.ifr_flags & ~IFF_PROMISC;
+
+ if (ifr.ifr_flags != ifflags) {
+ ifr.ifr_flags = ifflags;
+ if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) {
+ virReportSystemError(errno,
+ _("Cannot set interface flags on '%s'"),
+ ifname);
+ goto cleanup;
+ }
+ }
+
+ ret = 0;
+
+ cleanup:
+ VIR_FORCE_CLOSE(fd);
+ return ret;
+}
+#else
+int virNetDevSetPromiscuous(const char *ifname,
+ bool promiscuous ATTRIBUTE_UNUSED)
+{
+ virReportSystemError(ENOSYS, "%s",
+ _("Unable to set device flags for interfaces "
+ "on this platform"));
+ return -1;
+}
+#endif
+
+#if defined(SIOCGIFFLAGS) && defined(HAVE_STRUCT_IFREQ)
+/**
+ * virNetDevIsPromiscuous:
+ * @ifname: the interface name
+ * @promiscuous: where to store the status
+ *
+ * Function to query if an interface is receiving all packets (true) or
+ * not (false)
+ *
+ * Returns 0 in case of success or an errno code in case of failure.
+ */
+int virNetDevIsPromiscuous(const char *ifname,
+ bool *promiscuous)
+{
+ int fd = -1;
+ int ret = -1;
+ struct ifreq ifr;
+
+ if ((fd = virNetDevSetupControl(ifname, &ifr)) < 0)
+ return -1;
+
+ if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
+ virReportSystemError(errno,
+ _("Cannot get interface flags on '%s'"),
+ ifname);
+ goto cleanup;
+ }
+
+ *promiscuous = (ifr.ifr_flags & IFF_PROMISC) ? true : false;
+ ret = 0;
+
+ cleanup:
+ VIR_FORCE_CLOSE(fd);
+ return ret;
+}
+#else
+int virNetDevIsPromiscuous(const char *ifname ATTRIBUTE_UNUSED,
+ bool *promiscuous ATTRIBUTE_UNUSED)
+{
+ virReportSystemError(ENOSYS, "%s",
+ _("Unable to retrieve device flags for interfaces "
+ "on this platform"));
+ return -1;
+}
+#endif
+
+#if defined(SIOCSIFFLAGS) && defined(HAVE_STRUCT_IFREQ)
+/**
+ * virNetDevSetRcvMulti:
+ * @ifname: the interface name
+ * @:receive true for receive multicast packets, false for do not receive
+ * multicast packets
+ *
+ * Function to control if an interface is to receive multicast
+ * packets in which it is interested (receive, true)
+ * or not (do not receive, false)
+ *
+ * Returns 0 in case of success or -1 on error.
+ */
+int virNetDevSetRcvMulti(const char *ifname,
+ bool receive)
+{
+ int fd = -1;
+ int ret = -1;
+ struct ifreq ifr;
+ int ifflags;
+
+ if ((fd = virNetDevSetupControl(ifname, &ifr)) < 0)
+ return -1;
+
+ if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
+ virReportSystemError(errno,
+ _("Cannot get interface flags on '%s'"),
+ ifname);
+ goto cleanup;
+ }
+
+ if (receive)
+ ifflags = ifr.ifr_flags | IFF_MULTICAST;
+ else
+ ifflags = ifr.ifr_flags & ~IFF_MULTICAST;
+
+ if (ifr.ifr_flags != ifflags) {
+ ifr.ifr_flags = ifflags;
+ if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) {
+ virReportSystemError(errno,
+ _("Cannot set interface flags on '%s'"),
+ ifname);
+ goto cleanup;
+ }
+ }
+
+ ret = 0;
+
+ cleanup:
+ VIR_FORCE_CLOSE(fd);
+ return ret;
+}
+#else
+int virNetDevSetRcvMulti(const char *ifname,
+ bool receive ATTRIBUTE_UNUSED)
+{
+ virReportSystemError(ENOSYS, "%s",
+ _("Unable to set device flags for interfaces "
+ "on this platform"));
+ return -1;
+}
+#endif /* defined(SIOCSIFFLAGS) && defined(HAVE_STRUCT_IFREQ) */
+
+#if defined(SIOCGIFFLAGS) && defined(HAVE_STRUCT_IFREQ)
+/**
+ * virNetDevIsRcvMulti:
+ * @ifname: the interface name
+ * @receive where to store the status
+ *
+ * Function to query whether an interface is receiving multicast packets (true)
+ * in which it is interested, or not (false)
+ *
+ * Returns 0 in case of success or -1 on error.
+ */
+int virNetDevIsRcvMulti(const char *ifname,
+ bool *receive)
+{
+ int fd = -1;
+ int ret = -1;
+ struct ifreq ifr;
+
+ if ((fd = virNetDevSetupControl(ifname, &ifr)) < 0)
+ return -1;
+
+ if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
+ virReportSystemError(errno,
+ _("Cannot get interface flags on '%s'"),
+ ifname);
+ goto cleanup;
+ }
+
+ *receive = (ifr.ifr_flags & IFF_MULTICAST) ? true : false;
+ ret = 0;
+
+ cleanup:
+ VIR_FORCE_CLOSE(fd);
+ return ret;
+}
+#else
+int virNetDevIsRcvMulti(const char *ifname,
+ bool *receive ATTRIBUTE_UNUSED)
+{
+ virReportSystemError(ENOSYS, "%s",
+ _("Unable to retrieve device flags for interfaces "
+ "on this platform"));
+ return -1;
+}
+#endif /* defined(SIOCGIFFLAGS) && defined(HAVE_STRUCT_IFREQ) */
+
+#if defined(SIOCSIFFLAGS) && defined(HAVE_STRUCT_IFREQ)
+/**
+ * virNetDevSetRcvAllMulti:
+ * @ifname: the interface name
+ * @:receive true for receive all packets, false for do not receive all packets
+ *
+ * Function to control if an interface is to receive all multicast
+ * packets (receive, true) or not (do not receive, false)
+ *
+ * Returns 0 in case of success or -1 on error.
+ */
+int virNetDevSetRcvAllMulti(const char *ifname,
+ bool receive)
+{
+ int fd = -1;
+ int ret = -1;
+ struct ifreq ifr;
+ int ifflags;
+
+ if ((fd = virNetDevSetupControl(ifname, &ifr)) < 0)
+ return -1;
+
+ if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
+ virReportSystemError(errno,
+ _("Cannot get interface flags on '%s'"),
+ ifname);
+ goto cleanup;
+ }
+
+ if (receive)
+ ifflags = ifr.ifr_flags | IFF_ALLMULTI;
+ else
+ ifflags = ifr.ifr_flags & ~IFF_ALLMULTI;
+
+ if (ifr.ifr_flags != ifflags) {
+ ifr.ifr_flags = ifflags;
+ if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) {
+ virReportSystemError(errno,
+ _("Cannot set interface flags on '%s'"),
+ ifname);
+ goto cleanup;
+ }
+ }
+
+ ret = 0;
+
+ cleanup:
+ VIR_FORCE_CLOSE(fd);
+ return ret;
+}
+
+#else
+
+int virNetDevSetRcvAllMulti(const char *ifname,
+ bool receive ATTRIBUTE_UNUSED)
+{
+ virReportSystemError(ENOSYS, "%s",
+ _("Unable to set device flags for interfaces "
+ "on this platform"));
+ return -1;
+}
+#endif /*defined(SIOCSIFFLAGS) && defined(HAVE_STRUCT_IFREQ)*/
+
+#if defined(SIOCGIFFLAGS) && defined(HAVE_STRUCT_IFREQ)
+/**
+ * virNetDevIsRcvAllMulti:
+ * @ifname: the interface name
+ * @:receive where to store the status
+ *
+ * Function to query whether an interface is receiving all multicast
+ * packets (receiving, true) or not (is not receiving, false)
+ *
+ * Returns 0 in case of success or -1 on error.
+ */
+int virNetDevIsRcvAllMulti(const char *ifname,
+ bool *receive)
+{
+ int fd = -1;
+ int ret = -1;
+ struct ifreq ifr;
+
+ if ((fd = virNetDevSetupControl(ifname, &ifr)) < 0)
+ return -1;
+
+ if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
+ virReportSystemError(errno,
+ _("Cannot get interface flags on '%s'"),
+ ifname);
+ goto cleanup;
+ }
+
+ *receive = (ifr.ifr_flags & IFF_ALLMULTI) ? true : false;
+ ret = 0;
+
+ cleanup:
+ VIR_FORCE_CLOSE(fd);
+ return ret;
+}
+#else
+
+int virNetDevIsRcvAllMulti(const char *ifname,
+ bool *receive ATTRIBUTE_UNUSED)
+{
+ virReportSystemError(ENOSYS, "%s",
+ _("Unable to retrieve device flags for interfaces "
+ "on this platform"));
+ return -1;
+}
+#endif
+
static int virNetDevParseMcast(char *buf, virNetDevMcastEntryPtr mcast)
{
int ifindex;
@@ -2549,6 +2876,7 @@ int virNetDevGetRxFilter(const char *ifname,
virNetDevRxFilterPtr *filter)
{
int ret = -1;
+ bool receive;
virNetDevRxFilterPtr fil = virNetDevRxFilterNew();
if (!fil)
@@ -2560,6 +2888,24 @@ int virNetDevGetRxFilter(const char *ifname,
if (virNetDevGetMulticastTable(ifname, fil))
goto cleanup;
+ if (virNetDevIsPromiscuous(ifname, &fil->promiscuous))
+ goto cleanup;
+
+ if (virNetDevIsRcvAllMulti(ifname, &receive))
+ goto cleanup;
+
+ if (receive)
+ fil->multicast.mode = VIR_NETDEV_RX_FILTER_MODE_ALL;
+ else {
+ if (virNetDevIsRcvMulti(ifname, &receive))
+ goto cleanup;
+
+ if (receive)
+ fil->multicast.mode = VIR_NETDEV_RX_FILTER_MODE_NORMAL;
+ else
+ fil->multicast.mode = VIR_NETDEV_RX_FILTER_MODE_NONE;
+ }
+
ret = 0;
cleanup:
if (ret < 0) {
diff --git a/src/util/virnetdev.h b/src/util/virnetdev.h
index fb7988f..4216957 100644
--- a/src/util/virnetdev.h
+++ b/src/util/virnetdev.h
@@ -200,4 +200,18 @@ int virNetDevDelMulti(const char *ifname,
virMacAddrPtr macaddr)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
+int virNetDevSetPromiscuous(const char *ifname, bool promiscuous)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
+int virNetDevIsPromiscuous(const char *ifname, bool *promiscuous)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
+
+int virNetDevSetRcvMulti(const char *ifname, bool receive)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
+int virNetDevIsRcvMulti(const char *ifname, bool *receive)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
+
+int virNetDevSetRcvAllMulti(const char *ifname, bool receive)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
+int virNetDevIsRcvAllMulti(const char *ifname, bool *receive)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
#endif /* __VIR_NETDEV_H__ */
--
1.7.1
9 years, 10 months
[libvirt] [PATCH v3] qemu: Allow UEFI paths to be specified at compile time
by Michal Privoznik
Up until now there are just two ways how to specify UEFI paths to
libvirt. The first one is editing qemu.conf, the other is editing
qemu_conf.c and recompile which is not that fancy. So, new
configure option is introduced: --with-loader-nvram which takes a
list of pairs of UEFI firmware and NVRAM store. This way, the
compiled in defaults can be passed during compile time without
need to change the code itself.
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
configure.ac | 32 +++++++++++++++++
src/qemu/qemu.conf | 12 +++++--
src/qemu/qemu_conf.c | 41 ++++++++++++++++++----
src/qemu/test_libvirtd_qemu.aug.in | 1 +
.../domaincaps-qemu_1.6.50-1.xml | 1 +
tests/domaincapstest.c | 15 ++++----
6 files changed, 85 insertions(+), 17 deletions(-)
diff --git a/configure.ac b/configure.ac
index 9d12079..164cfad 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2786,6 +2786,38 @@ AC_ARG_WITH([default-editor],
[DEFAULT_EDITOR=vi])
AC_DEFINE_UNQUOTED([DEFAULT_EDITOR], ["$DEFAULT_EDITOR"], [Default editor to use])
+AC_ARG_WITH([loader-nvram],
+ [AS_HELP_STRING([--with-loader-nvram],
+ [Pass list of pairs of <loader>:<nvram> paths. Both
+ pairs and list items are separated by a colon.
+ @<:default=paths to OVMF and its clones@:>@])],
+ [with_loader_nvram=${withval}],
+ [with_loader_nvram=no])
+
+if test "$with_loader_nvram" != "no"; then
+ IFS=':' read -a loader_arr <<< "${with_loader_nvram}"
+
+ loader_str_c="{"
+ nvram_str_c="{"
+ for ((indx=0; indx<${#loader_arr[@]}; indx+=2)); do
+ loader=${loader_arr[[indx]]}
+ nvram=${loader_arr[[indx+1]]}
+
+ if test -z "$loader" || test -z "$nvram"; then
+ AC_MSG_ERROR([Malformed loader-nvram list])
+ fi
+
+ loader_str_c="$loader_str_c \"$loader\","
+ nvram_str_c="$nvram_str_c \"$nvram\","
+ done
+
+ loader_str_c="$loader_str_c }"
+ nvram_str_c="$nvram_str_c }"
+
+ AC_DEFINE_UNQUOTED([DEFAULT_LOADER], [$loader_str_c], [Array of loader paths])
+ AC_DEFINE_UNQUOTED([DEFAULT_NVRAM], [$nvram_str_c], [Array of nvram paths])
+fi
+
# Some GNULIB base64 symbols clash with a kerberos library
AC_DEFINE_UNQUOTED([isbase64],[libvirt_gl_isbase64],[Hack to avoid symbol clash])
AC_DEFINE_UNQUOTED([base64_encode],[libvirt_gl_base64_encode],[Hack to avoid symbol clash])
diff --git a/src/qemu/qemu.conf b/src/qemu/qemu.conf
index c6db568..1c589a2 100644
--- a/src/qemu/qemu.conf
+++ b/src/qemu/qemu.conf
@@ -506,6 +506,12 @@
# however, have different variables store. Therefore the nvram is
# a list of strings when a single item is in form of:
# ${PATH_TO_UEFI_FW}:${PATH_TO_UEFI_VARS}.
-# Later, when libvirt creates per domain variable store, this
-# list is searched for the master image.
-#nvram = [ "/usr/share/OVMF/OVMF_CODE.fd:/usr/share/OVMF/OVMF_VARS.fd" ]
+# Later, when libvirt creates per domain variable store, this list is
+# searched for the master image. The UEFI firmware can be called
+# differently for different guest architectures. For instance, it's OVMF
+# for x86_64 and i686, but it's AAVMF for aarch64. The libvirt default
+# follows this scheme.
+#nvram = [
+# "/usr/share/OVMF/OVMF_CODE.fd:/usr/share/OVMF/OVMF_VARS.fd",
+# "/usr/share/AAVMF/AAVMF_CODE.fd:/usr/share/AAVMF/AAVMF_VARS.fd"
+#]
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index 9539231..728d01e 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -107,13 +107,21 @@ void qemuDomainCmdlineDefFree(qemuDomainCmdlineDefPtr def)
VIR_FREE(def);
}
-#define VIR_QEMU_LOADER_FILE_PATH "/usr/share/OVMF/OVMF_CODE.fd"
-#define VIR_QEMU_NVRAM_FILE_PATH "/usr/share/OVMF/OVMF_VARS.fd"
+#define VIR_QEMU_OVMF_LOADER_PATH "/usr/share/AAVMF/AAVMF_CODE.fd"
+#define VIR_QEMU_OVMF_NVRAM_PATH "/usr/share/AAVMF/AAVMF_VARS.fd"
+#define VIR_QEMU_AAVMF_LOADER_PATH "/usr/share/OVMF/OVMF_CODE.fd"
+#define VIR_QEMU_AAVMF_NVRAM_PATH "/usr/share/OVMF/OVMF_VARS.fd"
virQEMUDriverConfigPtr virQEMUDriverConfigNew(bool privileged)
{
virQEMUDriverConfigPtr cfg;
+#if defined(DEFAULT_LOADER) && defined(DEFAULT_NVRAM)
+ const char *loader[] = DEFAULT_LOADER;
+ const char *nvram[] = DEFAULT_NVRAM;
+ size_t i;
+#endif
+
if (virQEMUConfigInitialize() < 0)
return NULL;
@@ -258,14 +266,33 @@ virQEMUDriverConfigPtr virQEMUDriverConfigNew(bool privileged)
cfg->logTimestamp = true;
- if (VIR_ALLOC_N(cfg->loader, 1) < 0 ||
- VIR_ALLOC_N(cfg->nvram, 1) < 0)
+#if defined(DEFAULT_LOADER) && defined(DEFAULT_NVRAM)
+ verify(ARRAY_CARDINALITY(loader) == ARRAY_CARDINALITY(nvram));
+
+ if (VIR_ALLOC_N(cfg->loader, ARRAY_CARDINALITY(loader)) < 0 ||
+ VIR_ALLOC_N(cfg->nvram, ARRAY_CARDINALITY(loader)) < 0)
+ goto error;
+ cfg->nloader = ARRAY_CARDINALITY(loader);
+
+ for (i = 0; i < ARRAY_CARDINALITY(loader); i++) {
+ if (VIR_STRDUP(cfg->loader[i], loader[i]) < 0 ||
+ VIR_STRDUP(cfg->nvram[i], nvram[i]) < 0)
+ goto error;
+ }
+
+#else /* !defined(DEFAULT_LOADER) || !defined(DEFAULT_NVRAM) */
+
+ if (VIR_ALLOC_N(cfg->loader, 2) < 0 ||
+ VIR_ALLOC_N(cfg->nvram, 2) < 0)
goto error;
- cfg->nloader = 1;
+ cfg->nloader = 2;
- if (VIR_STRDUP(cfg->loader[0], VIR_QEMU_LOADER_FILE_PATH) < 0 ||
- VIR_STRDUP(cfg->nvram[0], VIR_QEMU_NVRAM_FILE_PATH) < 0)
+ if (VIR_STRDUP(cfg->loader[0], VIR_QEMU_OVMF_LOADER_PATH) < 0 ||
+ VIR_STRDUP(cfg->nvram[0], VIR_QEMU_OVMF_NVRAM_PATH) < 0 ||
+ VIR_STRDUP(cfg->loader[1], VIR_QEMU_AAVMF_LOADER_PATH) < 0 ||
+ VIR_STRDUP(cfg->nvram[1], VIR_QEMU_AAVMF_NVRAM_PATH) < 0)
goto error;
+#endif /* !defined(DEFAULT_LOADER) || !defined(DEFAULT_NVRAM) */
return cfg;
diff --git a/src/qemu/test_libvirtd_qemu.aug.in b/src/qemu/test_libvirtd_qemu.aug.in
index 30fd27e..fc4935b 100644
--- a/src/qemu/test_libvirtd_qemu.aug.in
+++ b/src/qemu/test_libvirtd_qemu.aug.in
@@ -76,4 +76,5 @@ module Test_libvirtd_qemu =
{ "log_timestamp" = "0" }
{ "nvram"
{ "1" = "/usr/share/OVMF/OVMF_CODE.fd:/usr/share/OVMF/OVMF_VARS.fd" }
+ { "2" = "/usr/share/AAVMF/AAVMF_CODE.fd:/usr/share/AAVMF/AAVMF_VARS.fd" }
}
diff --git a/tests/domaincapsschemadata/domaincaps-qemu_1.6.50-1.xml b/tests/domaincapsschemadata/domaincaps-qemu_1.6.50-1.xml
index 346ef65..37d2102 100644
--- a/tests/domaincapsschemadata/domaincaps-qemu_1.6.50-1.xml
+++ b/tests/domaincapsschemadata/domaincaps-qemu_1.6.50-1.xml
@@ -5,6 +5,7 @@
<arch>x86_64</arch>
<os supported='yes'>
<loader supported='yes'>
+ <value>/usr/share/AAVMF/AAVMF_CODE.fd</value>
<value>/usr/share/OVMF/OVMF_CODE.fd</value>
<enum name='type'>
<value>rom</value>
diff --git a/tests/domaincapstest.c b/tests/domaincapstest.c
index 70d2ef3..5ca8928 100644
--- a/tests/domaincapstest.c
+++ b/tests/domaincapstest.c
@@ -105,6 +105,7 @@ fillQemuCaps(virDomainCapsPtr domCaps,
struct fillQemuCapsData *data = (struct fillQemuCapsData *) opaque;
virQEMUCapsPtr qemuCaps = data->qemuCaps;
virQEMUDriverConfigPtr cfg = data->cfg;
+ virDomainCapsLoaderPtr loader = &domCaps->os.loader;
if (virQEMUCapsFillDomainCaps(domCaps, qemuCaps,
cfg->loader, cfg->nloader) < 0)
@@ -122,14 +123,14 @@ fillQemuCaps(virDomainCapsPtr domCaps,
/* Moreover, as of f05b6a918e28 we are expecting to see
* OVMF_CODE.fd file which may not exists everywhere. */
- if (!domCaps->os.loader.values.nvalues) {
- virDomainCapsLoaderPtr loader = &domCaps->os.loader;
+ while (loader->values.nvalues)
+ VIR_FREE(loader->values.values[--loader->values.nvalues]);
- if (fillStringValues(&loader->values,
- "/usr/share/OVMF/OVMF_CODE.fd",
- NULL) < 0)
- return -1;
- }
+ if (fillStringValues(&loader->values,
+ "/usr/share/AAVMF/AAVMF_CODE.fd",
+ "/usr/share/OVMF/OVMF_CODE.fd",
+ NULL) < 0)
+ return -1;
return 0;
}
#endif /* WITH_QEMU */
--
2.0.5
9 years, 10 months
[libvirt] [PATCH v2] systemd: fix build without dbus
by Daniel P. Berrange
The virDBusMethodCall method has a DBusError as one of its
parameters. If the caller wants to pass a non-NULL value
for this, it immediately makes the calling code require
DBus at build time. This has led to breakage of non-DBus
builds several times. It is desirable that only the virdbus.c
file should need WITH_DBUS conditionals, so we must ideally
remove the DBusError parameter from the method.
We can't simply raise a libvirt error, since the whole point
of this parameter is to give the callers a way to check if
the error is one they want to ignore, without having the logs
polluted with an error message. So, we add a virErrorPtr
parameter which the caller can then either ignore or raise
using virSetError.
Signed-off-by: Daniel P. Berrange <berrange(a)redhat.com>
---
src/util/virdbus.c | 31 +++++++++++++++++++------------
src/util/virdbus.h | 4 ++--
src/util/virfirewall.c | 29 ++++++-----------------------
src/util/virsystemd.c | 15 +++++++--------
4 files changed, 34 insertions(+), 45 deletions(-)
In v2:
- Removed left over debug statements
diff --git a/src/util/virdbus.c b/src/util/virdbus.c
index d9665c1..3522ae0 100644
--- a/src/util/virdbus.c
+++ b/src/util/virdbus.c
@@ -1522,7 +1522,7 @@ static int
virDBusCall(DBusConnection *conn,
DBusMessage *call,
DBusMessage **replyout,
- DBusError *error)
+ virErrorPtr error)
{
DBusMessage *reply = NULL;
@@ -1530,8 +1530,9 @@ virDBusCall(DBusConnection *conn,
int ret = -1;
const char *iface, *member, *path, *dest;
- if (!error)
- dbus_error_init(&localerror);
+ dbus_error_init(&localerror);
+ if (error)
+ memset(error, 0, sizeof(*error));
iface = dbus_message_get_interface(call);
member = dbus_message_get_member(call);
@@ -1545,13 +1546,20 @@ virDBusCall(DBusConnection *conn,
if (!(reply = dbus_connection_send_with_reply_and_block(conn,
call,
VIR_DBUS_METHOD_CALL_TIMEOUT_MILLIS,
- error ? error : &localerror))) {
+ &localerror))) {
PROBE(DBUS_METHOD_ERROR,
"'%s.%s' on '%s' at '%s' error %s: %s",
iface, member, path, dest,
- error ? error->name : localerror.name,
- error ? error->message : localerror.message);
+ localerror.name,
+ localerror.message);
if (error) {
+ error->level = VIR_ERR_ERROR;
+ error->code = VIR_ERR_DBUS_SERVICE;
+ error->domain = VIR_FROM_DBUS;
+ if (VIR_STRDUP(error->message, localerror.message) < 0)
+ goto cleanup;
+ if (VIR_STRDUP(error->str1, localerror.name) < 0)
+ goto cleanup;
ret = 0;
} else {
virReportError(VIR_ERR_DBUS_SERVICE, _("%s: %s"), member,
@@ -1567,8 +1575,9 @@ virDBusCall(DBusConnection *conn,
ret = 0;
cleanup:
- if (!error)
- dbus_error_free(&localerror);
+ if (ret < 0 && error)
+ virResetError(error);
+ dbus_error_free(&localerror);
if (reply) {
if (ret == 0 && replyout)
*replyout = reply;
@@ -1616,7 +1625,7 @@ virDBusCall(DBusConnection *conn,
*/
int virDBusCallMethod(DBusConnection *conn,
DBusMessage **replyout,
- DBusError *error,
+ virErrorPtr error,
const char *destination,
const char *path,
const char *iface,
@@ -1634,8 +1643,6 @@ int virDBusCallMethod(DBusConnection *conn,
if (ret < 0)
goto cleanup;
- ret = -1;
-
ret = virDBusCall(conn, call, replyout, error);
cleanup:
@@ -1832,7 +1839,7 @@ int virDBusCreateReply(DBusMessage **reply ATTRIBUTE_UNUSED,
int virDBusCallMethod(DBusConnection *conn ATTRIBUTE_UNUSED,
DBusMessage **reply ATTRIBUTE_UNUSED,
- DBusError *error ATTRIBUTE_UNUSED,
+ virErrorPtr error ATTRIBUTE_UNUSED,
const char *destination ATTRIBUTE_UNUSED,
const char *path ATTRIBUTE_UNUSED,
const char *iface ATTRIBUTE_UNUSED,
diff --git a/src/util/virdbus.h b/src/util/virdbus.h
index d0c7de2..e2b8d2b 100644
--- a/src/util/virdbus.h
+++ b/src/util/virdbus.h
@@ -28,7 +28,7 @@
# else
# define DBusConnection void
# define DBusMessage void
-# define DBusError void
+# define dbus_message_unref(m) do {} while (0)
# endif
# include "internal.h"
@@ -62,7 +62,7 @@ int virDBusCreateReplyV(DBusMessage **reply,
int virDBusCallMethod(DBusConnection *conn,
DBusMessage **reply,
- DBusError *error,
+ virErrorPtr error,
const char *destination,
const char *path,
const char *iface,
diff --git a/src/util/virfirewall.c b/src/util/virfirewall.c
index b536912..2fa7f65 100644
--- a/src/util/virfirewall.c
+++ b/src/util/virfirewall.c
@@ -156,7 +156,6 @@ static int
virFirewallValidateBackend(virFirewallBackend backend)
{
VIR_DEBUG("Validating backend %d", backend);
-#if WITH_DBUS
if (backend == VIR_FIREWALL_BACKEND_AUTOMATIC ||
backend == VIR_FIREWALL_BACKEND_FIREWALLD) {
int rv = virDBusIsServiceRegistered(VIR_FIREWALL_FIREWALLD_SERVICE);
@@ -180,16 +179,6 @@ virFirewallValidateBackend(virFirewallBackend backend)
backend = VIR_FIREWALL_BACKEND_FIREWALLD;
}
}
-#else
- if (backend == VIR_FIREWALL_BACKEND_AUTOMATIC) {
- VIR_DEBUG("DBus support disabled, trying direct backend");
- backend = VIR_FIREWALL_BACKEND_DIRECT;
- } else if (backend == VIR_FIREWALL_BACKEND_FIREWALLD) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("firewalld firewall backend requested, but DBus support disabled"));
- return -1;
- }
-#endif
if (backend == VIR_FIREWALL_BACKEND_DIRECT) {
const char *commands[] = {
@@ -755,7 +744,6 @@ virFirewallApplyRuleDirect(virFirewallRulePtr rule,
}
-#ifdef WITH_DBUS
static int
virFirewallApplyRuleFirewallD(virFirewallRulePtr rule,
bool ignoreErrors,
@@ -764,13 +752,13 @@ virFirewallApplyRuleFirewallD(virFirewallRulePtr rule,
const char *ipv = virFirewallLayerFirewallDTypeToString(rule->layer);
DBusConnection *sysbus = virDBusGetSystemBus();
DBusMessage *reply = NULL;
- DBusError error;
+ virError error;
int ret = -1;
if (!sysbus)
return -1;
- dbus_error_init(&error);
+ memset(&error, 0, sizeof(error));
if (!ipv) {
virReportError(VIR_ERR_INTERNAL_ERROR,
@@ -792,7 +780,7 @@ virFirewallApplyRuleFirewallD(virFirewallRulePtr rule,
rule->args) < 0)
goto cleanup;
- if (dbus_error_is_set(&error)) {
+ if (error.level == VIR_ERR_ERROR) {
/*
* As of firewalld-0.3.9.3-1.fc20.noarch the name and
* message fields in the error look like
@@ -820,11 +808,9 @@ virFirewallApplyRuleFirewallD(virFirewallRulePtr rule,
*/
if (ignoreErrors) {
VIR_DEBUG("Ignoring error '%s': '%s'",
- error.name, error.message);
+ error.str1, error.message);
} else {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Unable to apply rule '%s'"),
- error.message);
+ virSetError(&error);
goto cleanup;
}
} else {
@@ -835,12 +821,11 @@ virFirewallApplyRuleFirewallD(virFirewallRulePtr rule,
ret = 0;
cleanup:
- dbus_error_free(&error);
+ virResetError(&error);
if (reply)
dbus_message_unref(reply);
return ret;
}
-#endif
static int
virFirewallApplyRule(virFirewallPtr firewall,
@@ -862,12 +847,10 @@ virFirewallApplyRule(virFirewallPtr firewall,
if (virFirewallApplyRuleDirect(rule, ignoreErrors, &output) < 0)
return -1;
break;
-#if WITH_DBUS
case VIR_FIREWALL_BACKEND_FIREWALLD:
if (virFirewallApplyRuleFirewallD(rule, ignoreErrors, &output) < 0)
return -1;
break;
-#endif
default:
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Unexpected firewall engine backend"));
diff --git a/src/util/virsystemd.c b/src/util/virsystemd.c
index 3eea5c2..0b71b26 100644
--- a/src/util/virsystemd.c
+++ b/src/util/virsystemd.c
@@ -252,8 +252,8 @@ int virSystemdCreateMachine(const char *name,
VIR_DEBUG("Attempting to create machine via systemd");
if (virAtomicIntGet(&hasCreateWithNetwork)) {
- DBusError error;
- dbus_error_init(&error);
+ virError error;
+ memset(&error, 0, sizeof(error));
if (virDBusCallMethod(conn,
NULL,
@@ -280,21 +280,20 @@ int virSystemdCreateMachine(const char *name,
"Before", "as", 1, "libvirt-guests.service") < 0)
goto cleanup;
- if (dbus_error_is_set(&error)) {
+ if (error.level == VIR_ERR_ERROR) {
if (STREQ_NULLABLE("org.freedesktop.DBus.Error.UnknownMethod",
- error.name)) {
+ error.str1)) {
VIR_INFO("CreateMachineWithNetwork isn't supported, switching "
"to legacy CreateMachine method for systemd-machined");
- dbus_error_free(&error);
+ virResetError(&error);
virAtomicIntSet(&hasCreateWithNetwork, 0);
/* Could re-structure without Using goto, but this
* avoids another atomic read which would trigger
* another memory barrier */
goto fallback;
}
- virReportError(VIR_ERR_DBUS_SERVICE,
- _("CreateMachineWithNetwork: %s"),
- error.message ? error.message : _("unknown error"));
+ virSetError(&error);
+ virResetError(&error);
goto cleanup;
}
} else {
--
2.1.0
9 years, 10 months
[libvirt] [libvirt-test-API][PATCH] Add network_dhcp_leases test case to conf
by jiahu
For running the case, should setup testing environment before the
case, and clean up the environment after the case.
---
cases/basic_network.conf | 55 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 55 insertions(+)
diff --git a/cases/basic_network.conf b/cases/basic_network.conf
index e9abd57..3ab9cb1 100644
--- a/cases/basic_network.conf
+++ b/cases/basic_network.conf
@@ -216,3 +216,58 @@ network:destroy
networkname
$defaultnetname
+network:update
+ networkname
+ default
+ command
+ add-first
+ section
+ ip-dhcp-host
+ xml
+ xmls/ip-dhcp-host.xml
+
+domain:install_linux_cdrom
+ guestname
+ dhcplease
+ guestos
+ rhel6
+ guestarch
+ $defaultarch
+ vcpu
+ $defaultvcpu
+ memory
+ $defaultmem
+ hddriver
+ $defaulthd
+ nicdriver
+ $defaultnic
+ macaddr
+ 00:16:3e:77:e2:ed
+
+network:network_dhcp_leases
+ networkname
+ default
+
+network:network_dhcp_leases
+ networkname
+ default
+ macaddr
+ 00:16:3e:77:e2:ed
+
+network:update
+ networkname
+ default
+ command
+ delete
+ section
+ ip-dhcp-host
+ xml
+ xmls/ip-dhcp-host.xml
+
+domain:destroy
+ guestname
+ dhcplease
+
+domain:undefine
+ guestname
+ dhcplease
--
1.8.3.1
9 years, 10 months